Ошибка при запуске некоторых файлов.lnk и получении их значков с помощью Process.Start и 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.ComponentModel.Win32Exception в System.dll при попытке выполнить файл ярлыка и для этих же файлов, получая их значок.

Это дает мне следующее сообщение (данное Process.Start вызывается с параметром ProcessStartInfo с ErrorDialog=True):

Эта ошибка отличается от той, которая возникает, если неверный путь к файлу.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 файлов из исходного местоположения на рабочий стол. Переименовывает эти ярлыки (для удобства) "[Filename] linkorig"
  • С помощью перетаскивания правой кнопкой мыши создайте ярлыки с 3 ссылками для каждого из 3 скопированных файлов с рабочего стола на рабочий стол. Переименовывает эти ярлыки (для удобства) "[Filename] linkcopy"

Создайте проект Visual Basic, поместите 4 PictureBox на форму и назовите их:

  • 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

Затем выполните.

Вы получите следующее:

При нажатии на любой из хорошо отображаемых значков запускается приложение WinRar.
Нажатие на плохо отображаемый значок отображает эту ошибку:

Изменение значения Me.LnkOrigPictureBox.Tag с неправильным путем, как "C:\Users\Moi\Desktop\WinRARdontexistshere.exe linkorig.lnk" и выполнение того же действия отображает другое визуальное изображение и ошибку (как и ожидалось):

Это не работает ни с DVDMaker.exe

Но все в порядке с wordpad.exe, значок и запуск приложения.

(Я проверил регистр в нижнем / верхнем регистре, чтобы убедиться, что он мешает, но это не проблема)

Я заметил проблему в некоторых других приложениях, не понимая причин этого, например:

  • Краска.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). Запуск скомпилированного приложения "как администратор" ничего не меняет.

Я попытался использовать некоторые конфигурации, такие как следующие, но безуспешно:

        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 ответ

Решение

Ух ты... Я нашел удачу, когда увидел, когда проводил несколько тестов с некоторыми примерами, найденными в сети, что проблема со значком и сообщение об ошибке при попытке использовать соответствующий файл также присутствовали при использовании стандартного OpenFileDialog, Я подозревал ошибку в.Net Framework. И решение было близко к этому, и я все еще не очень понимаю его глубокие причины.

Проблема заключалась в следующем:

Проект был определен по умолчанию в настройках проекта для запуска с.Net Framework 4.5

Я переключил его для запуска с Framework 4
Запустил приложение: больше никаких проблем

Я переключил его обратно, чтобы работать с Framework 4.5
Больше никаких проблем.

Другие вопросы по тегам