使用Process.Start和SHGetFileInfo()

时间:2015-11-29 12:42:10

标签: visual-studio process icons shortcut win32exception

我在使用以下方法启动一些快捷方式并出于某些奇怪和未知原因获取其图标时遇到问题:

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参数调用):

enter image description here

如果.lnk文件的路径指向不存在的文件不正确,则此错误与引发的错误不同:

enter image description here

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

在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个链接快捷方式,从原始位置到桌面。重命名这些快捷方式(为方便起见)&#34; [文件名] linkorig&#34;
  • 通过右键单击拖动,为从桌面到桌面的3个复制文件中的每个文件创建3个链接快捷方式。重命名这些快捷方式(为方便起见)&#34; [文件名] linkcopy&#34;

创建一个Visual Basic项目,将4个PictureBox放到Form上并命名:

  • ExeOrigPictureBox
  • ExeCopyPictureBox
  • LnkOrigPictureBox
  • LnkCopyPictureBox

还有一些帮助自己的标签。

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

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

然后执行。

您将获得以下内容:

enter image description here

点击任何一个显示良好的图标即可启动WinRar应用程序 单击显示错误的图标会显示以下错误:

enter image description here

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

enter image description here

这不适用于DVDMaker.exe

enter image description here

wordpad.exe,图标和应用程序启动一切正常。

enter image description here

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

我已经注意到其他一些应用程序的问题,但没有理解其中的原因,例如:

  • Paint .net
  • VirtualBox
  • CloneSpy
  • VirtualDub中

和其他标准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安装中创建的唯一默认帐户)。运行已编译的应用程序&#34;作为管理员&#34;不改变任何东西。

我尝试使用以下某些配置但未成功:

        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)

我怎样才能解决这个启动问题,以及这些文件的图标检索问题?

1 个答案:

答案 0 :(得分:0)

Woow ...当我看到,通过网络上发现的一些示例进行一些测试时,我找到了运气的答案,当使用标准时,图标问题和尝试使用相应文件时的错误消息也存在OpenFileDialog。我怀疑.Net框架中有一个错误。解决方案就在这附近,我仍然不太了解它的深层原因。

问题如下:

默认情况下,项目已定义为与.Net Framework 4.5一起运行的项目设置

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

我将其切换回与Framework 4.5一起运行 没有更多问题。

相关问题