0

使用以下方法,由于某些奇怪和未知的原因,我无法启动一些快捷方式并获取它们的图标:

Public Shared Sub Launch(itemToLaunch As String)
        Process.Start(itemToLaunch)
End Sub



Public Function GetShellIcon(ByVal path As String) As Icon

        Dim info As SHFILEINFO = New SHFILEINFO()
        Dim retval As IntPtr = SHGetFileInfo(path, 0, info, Marshal.SizeOf(info), SHGFI_ICON Or SHGFI_SMALLICON Or SHGFI_LARGEICON)

        If retval = IntPtr.Zero Then
            Return New Icon(GetType(Control), "Error.ico")
        End If

        Dim cargt() As Type = {GetType(IntPtr)}
        Dim ci As ConstructorInfo = GetType(Icon).GetConstructor(BindingFlags.NonPublic Or BindingFlags.Instance, Nothing, cargt, Nothing)
        Dim cargs() As Object = {info.IconHandle}
        Dim icon As Icon = CType(ci.Invoke(cargs), Icon)

        Return icon
    End Function

 <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
    Private Structure SHFILEINFO
        Public IconHandle As IntPtr
        Public IconIndex As Integer
        Public Attributes As UInteger
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)>
        Public DisplayString As String
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)>
        Public TypeName As String
    End Structure

    Private Declare Auto Function SHGetFileInfo Lib "Shell32.dll" (path As String, attributes As Integer, ByRef info As SHFILEINFO, infoSize As Integer, flags As Integer) As IntPtr

    Public Const SHGFI_ICON = &H100
    Public Const SHGFI_SMALLICON = &H1
    Public Const SHGFI_LARGEICON = &H0         ' Large icon

这些方法几乎适用于任何项目,但有时它们会在尝试执行快捷方式文件时在 System.dll 中向我发送 System.ComponentModel.Win32Exception,并在这些相同的文件上获取它们的图标。

它给了我以下消息(由 Process.Start 给出,使用带有 ErrorDialog=True 的 ProcessStartInfo 参数调用):

在此处输入图像描述

此错误不同于 .lnk 文件的路径不正确指向不存在的文件时引发的错误:

在此处输入图像描述

例如,您可以通过这种方式重现此问题:

在 Windows 7 上找到安装以下文件:
C:\Program Files\DVD Maker\DVDMaker.exe(Windows 7 原生)

C:\Program Files\WinRAR\WinRAR.exe(v5.0 64位,但我想这与另一个版本有相同的效果)

C:\Program Files\Windows NT\Accessories\wordpad.exe(Windows 7 原生)

  • 将它们中的每一个复制到桌面
  • 右键单击并拖动,为这 3 个文件中的每一个从其原始位置创建 3 个链接快捷方式到桌面。重命名这些快捷方式(为方便起见)“[文件名] linkorig”
  • 通过右键单击拖动,为从桌面复制到桌面的 3 个文件中的每一个创建 3 个链接快捷方式。重命名这些快捷方式(为方便起见)“[文件名]链接复制”

创建一个 Visual basic 项目,将 4 个 PictureBoxes 放到一个 Form 上并命名它们:

  • ExeOrigPictureBox
  • 执行复制图片框
  • LnkOrigPictureBox
  • LnkCopy图片框

还有一些标签可以帮助自己。

然后将以下代码复制/粘贴到表单代码窗口中:

Imports System.Reflection
Imports System.Runtime.InteropServices

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
        Me.ExeOrigPictureBox.Tag = "C:\Program Files\WinRAR\WinRAR.exe"
        Me.ExeCopyPictureBox.Tag = "C:\Users\Moi\Desktop\WinRAR.exe"

        Me.LnkOrigPictureBox.Tag = "C:\Users\Moi\Desktop\WinRAR.exe linkorig.lnk"
        Me.LnkCopyPictureBox.Tag = "C:\Users\Moi\Desktop\WinRAR.exe linkcopy.lnk"

        Me.ExeOrigPictureBox.Image = GetShellIcon(Me.ExeOrigPictureBox.Tag).ToBitmap
        Me.ExeCopyPictureBox.Image = GetShellIcon(Me.ExeCopyPictureBox.Tag).ToBitmap

        Me.LnkOrigPictureBox.Image = GetShellIcon(Me.LnkOrigPictureBox.Tag).ToBitmap
        Me.LnkCopyPictureBox.Image = GetShellIcon(Me.LnkCopyPictureBox.Tag).ToBitmap
    End Sub

    Private Sub ExeOrigPictureBox_Click(sender As Object, e As EventArgs) Handles ExeOrigPictureBox.Click, ExeCopyPictureBox.Click, LnkOrigPictureBox.Click, LnkCopyPictureBox.Click
        Dim pBox As PictureBox = DirectCast(sender, PictureBox)

        Dim pi As ProcessStartInfo = New ProcessStartInfo
        pi.FileName = pBox.Tag
        pi.ErrorDialog = True
        Process.Start(pi)
    End Sub
End Class

Module Shell32
    Public Function GetShellIcon(ByVal path As String) As Icon

        Dim info As SHFILEINFO = New SHFILEINFO()
        Dim retval As IntPtr = SHGetFileInfo(path, 0, info, Marshal.SizeOf(info), SHGFI_ICON Or SHGFI_SMALLICON Or SHGFI_LARGEICON)

        If retval = IntPtr.Zero Then
            Return New Icon(GetType(Control), "Error.ico")
        End If

        Dim cargt() As Type = {GetType(IntPtr)}
        Dim ci As ConstructorInfo = GetType(Icon).GetConstructor(BindingFlags.NonPublic Or BindingFlags.Instance, Nothing, cargt, Nothing)
        Dim cargs() As Object = {info.IconHandle}
        Dim icon As Icon = CType(ci.Invoke(cargs), Icon)

        Return icon
    End Function

    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
    Private Structure SHFILEINFO
        Public IconHandle As IntPtr
        Public IconIndex As Integer
        Public Attributes As UInteger
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)>
        Public DisplayString As String
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)>
        Public TypeName As String
    End Structure

    Private Declare Auto Function SHGetFileInfo Lib "Shell32.dll" (path As String, attributes As Integer, ByRef info As SHFILEINFO, infoSize As Integer, flags As Integer) As IntPtr

    Public Const SHGFI_ICON = &H100
    Public Const SHGFI_SMALLICON = &H1
    Public Const SHGFI_LARGEICON = &H0         ' Large icon
End Module

然后执行。

您将获得以下内容:

在此处输入图像描述

单击任何显示良好的图标将启动 WinRar 应用程序。
单击显示的错误图标会显示此错误:

在此处输入图像描述

Me.LnkOrigPictureBox.Tag使用错误的路径更改值"C:\Users\Moi\Desktop\WinRARdontexistshere.exe linkorig.lnk"并执行相同的操作会显示另一个视觉和错误(如预期的那样):

在此处输入图像描述

这也不适用于DVDMaker.exe

在此处输入图像描述

但一切都很好wordpad.exe,图标和应用程序启动。

在此处输入图像描述

(我已经测试了小写/大写的情况,看看它是否会干扰,但这不是问题)

我在不了解原因的情况下注意到其他一些应用程序的问题,例如:

  • 油漆.net
  • 虚拟盒子
  • 克隆间谍
  • 虚拟配音

和其他标准 Windows 应用程序。

将有问题的文件路径复制/粘贴C:\Users\Moi\Desktop\WinRAR.exe linkorig.lnk到 Windows 资源管理器标题栏时,会启动 WinRAR.exe 应用程序。

当然同样的事情是我双击 .lnk 文件。

当复制/粘贴到 Windows-R 命令窗口时,它也能很好地启动。

WinRAR.lnk如果通过从放置在C:\Users\Moi\Desktop\文件夹中的命令行窗口键入来调用,也会启动。

我正在运行 Windows 7 64 位。该应用程序是使用 Visual Studio Express 2015 编译的。我以管理员身份登录(在 Windows 安装中创建的唯一默认帐户)。“以管理员身份”运行已编译的应用程序不会改变任何内容。

我尝试使用以下一些配置但没有成功:

        Dim info As ProcessStartInfo = New ProcessStartInfo(--- here the path ---)
        info.CreateNoWindow = False
        info.UseShellExecute = False
        info.RedirectStandardError = True
        info.RedirectStandardOutput = True
        info.RedirectStandardInput = True
        Dim whatever As Process = Process.Start(info)

我该如何解决这个启动问题,以及这些文件的图标检索问题?

4

1 回答 1

0

哇...当我看到时,我很幸运地找到了答案,通过网络上找到的一些示例进行了一些测试,在使用标准OpenFileDialog. 我怀疑 .Net 框架中存在错误。解决方案就在这个附近,我仍然不太了解它的深层原因。

问题如下:

该项目默认定义为项目设置以使用 .Net Framework 4.5 运行

我将其切换为使用 Framework 4 运行运行
应用程序:没有问题了

我将其切换回使用 Framework 4.5 运行
完全没有问题。

于 2015-12-02T22:54:38.453 回答