启动某些 .lnk 文件并使用 Process.Start 和 SHGetFileInfo() 获取其图标时出错
Error when launching some .lnk files and getting their icon using Process.Start and SHGetFileInfo()
由于一些奇怪和未知的原因,我在启动一些快捷方式和获取它们的图标时遇到问题,使用以下方法:
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)
- 将它们每个复制到桌面
- 使用 right-click-drag,为这 3 个文件中的每一个创建 3 个链接快捷方式,从它们的原始位置到桌面。重命名这些快捷方式(为方便起见)“[Filename] linkorig”
- 使用 right-click-drag,为从桌面到桌面的 3 个复制文件中的每一个创建 3 个链接快捷方式。重命名这些快捷方式(为方便起见)“[Filename] linkcopy”
创建一个 Visual basic 项目,将 4 个 PictureBoxes 放到一个 Form 上并命名它们:
- ExeOrigPictureBox
- ExeCopyPictureBox
- LnkOrigPictureBox
- LnkCopyPictureBox
还有一些标签可以帮助您自己。
然后copy/paste下面的代码变成Form代码window:
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 应用程序。
单击显示错误的图标会显示此错误:
用像 "C:\Users\Moi\Desktop\WinRARdontexistshere.exe linkorig.lnk"
这样的错误路径更改 Me.LnkOrigPictureBox.Tag
的值并做同样的事情会显示另一个视觉效果和错误(如预期的那样):
这不适用于 DVDMaker.exe
但是 wordpad.exe
、图标和应用程序启动一切正常。
(我已经测试了 lower/uppercase 的情况,看它是否干扰,但这不是问题)
我在其他一些应用程序上注意到了这个问题,但不了解其原因,例如:
- Paint .net
- 虚拟盒子
- 克隆间谍
- 虚拟配音
和其他标准 Windows 应用程序。
当 copy/pasting 有问题的文件路径 C:\Users\Moi\Desktop\WinRAR.exe linkorig.lnk
到 Windows 资源管理器标题栏时,WinRAR.exe 应用程序启动。
当然同样的事情是我double-click.lnk 文件。
当 copy/pasted 进入 Windows-R 命令 window.
时,它也能很好地启动
如果通过从放置在 C:\Users\Moi\Desktop\
文件夹中的 command-line window 中键入 WinRAR.lnk
来调用,也会启动。
我 运行 到 Windows 7 64 位。该应用程序是使用 Visual Studio Express 2015 编译的。我以管理员身份登录(在 Windows 安装时创建的唯一默认帐户)。运行编译后的应用程序 "as an administrator" 不会改变任何东西。
我尝试使用以下配置,但没有成功:
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)
如何解决这个启动问题,以及这些文件的图标检索问题?
哇...我很幸运地找到了答案,当我看到,用在网上找到的一些例子进行了一些测试,使用时也出现了图标问题和尝试使用相应文件时的错误消息一个标准 OpenFileDialog
。我怀疑 .Net 框架中存在错误。解决方案就在这附近,我仍然不太了解其深层原因。
问题如下:
该项目在项目设置中默认定义为 运行 with .Net Framework 4.5
我使用 Framework 4
将其切换为 运行
运行应用程序:没有问题
我使用 Framework 4.5
将其切换回 运行
完全没有问题。
由于一些奇怪和未知的原因,我在启动一些快捷方式和获取它们的图标时遇到问题,使用以下方法:
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)
- 将它们每个复制到桌面
- 使用 right-click-drag,为这 3 个文件中的每一个创建 3 个链接快捷方式,从它们的原始位置到桌面。重命名这些快捷方式(为方便起见)“[Filename] linkorig”
- 使用 right-click-drag,为从桌面到桌面的 3 个复制文件中的每一个创建 3 个链接快捷方式。重命名这些快捷方式(为方便起见)“[Filename] linkcopy”
创建一个 Visual basic 项目,将 4 个 PictureBoxes 放到一个 Form 上并命名它们:
- ExeOrigPictureBox
- ExeCopyPictureBox
- LnkOrigPictureBox
- LnkCopyPictureBox
还有一些标签可以帮助您自己。
然后copy/paste下面的代码变成Form代码window:
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 应用程序。
单击显示错误的图标会显示此错误:
用像 "C:\Users\Moi\Desktop\WinRARdontexistshere.exe linkorig.lnk"
这样的错误路径更改 Me.LnkOrigPictureBox.Tag
的值并做同样的事情会显示另一个视觉效果和错误(如预期的那样):
这不适用于 DVDMaker.exe
但是 wordpad.exe
、图标和应用程序启动一切正常。
(我已经测试了 lower/uppercase 的情况,看它是否干扰,但这不是问题)
我在其他一些应用程序上注意到了这个问题,但不了解其原因,例如:
- Paint .net
- 虚拟盒子
- 克隆间谍
- 虚拟配音
和其他标准 Windows 应用程序。
当 copy/pasting 有问题的文件路径 C:\Users\Moi\Desktop\WinRAR.exe linkorig.lnk
到 Windows 资源管理器标题栏时,WinRAR.exe 应用程序启动。
当然同样的事情是我double-click.lnk 文件。
当 copy/pasted 进入 Windows-R 命令 window.
时,它也能很好地启动如果通过从放置在 C:\Users\Moi\Desktop\
文件夹中的 command-line window 中键入 WinRAR.lnk
来调用,也会启动。
我 运行 到 Windows 7 64 位。该应用程序是使用 Visual Studio Express 2015 编译的。我以管理员身份登录(在 Windows 安装时创建的唯一默认帐户)。运行编译后的应用程序 "as an administrator" 不会改变任何东西。
我尝试使用以下配置,但没有成功:
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)
如何解决这个启动问题,以及这些文件的图标检索问题?
哇...我很幸运地找到了答案,当我看到,用在网上找到的一些例子进行了一些测试,使用时也出现了图标问题和尝试使用相应文件时的错误消息一个标准 OpenFileDialog
。我怀疑 .Net 框架中存在错误。解决方案就在这附近,我仍然不太了解其深层原因。
问题如下:
该项目在项目设置中默认定义为 运行 with .Net Framework 4.5
我使用 Framework 4
将其切换为 运行
运行应用程序:没有问题
我使用 Framework 4.5
将其切换回 运行
完全没有问题。