Показать значок сетевой папки в списке просмотра VB.NET

Как показать значок сетевой папки в виде списка? тот, с зеленой трубкой под папкой, у меня есть код, который отлично работает с файлами и папками, но при посещении другого компьютера по сети я не вижу сетевых папок, которые выглядят так, как эта.

что я должен добавить?

вот мой код: так я отображаю значок в ListView

Dim fPath As String = Form2.TextBox1.Text
Dim di = New DirectoryInfo(fPath)

  ' store imagelist index for known/found file types
  Dim exts As New Dictionary(Of String, Int32)

  If di.Exists = True Then
      Dim img As Image
      Dim lvi As ListViewItem
      For Each d In di.EnumerateDirectories("*.*", SearchOption.TopDirectoryOnly)
          lvi = New ListViewItem(d.Name)
          lvi.SubItems.Add("")
          lvi.SubItems.Add(d.CreationTime.Date)

          ListView1.Items.Add(lvi)

          img = NativeMethods.GetShellIcon(d.FullName)
          ImageList1.Images.Add(img)
          lvi.ImageIndex = ImageList1.Images.Count - 1
      Next

вот как я получаю иконки из shell32.

Partial Public Class NativeMethods
Private Const MAX_PATH As Integer = 256
Private Const NAMESIZE As Integer = 80
Private Const SHGFI_ICON As Int32 = &H100
<StructLayout(LayoutKind.Sequential)>
    Private Structure SHFILEINFO
        Public hIcon As IntPtr
        Public iIcon As Integer
        Public dwAttributes As Integer
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=MAX_PATH)>
        Public szDisplayName As String
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=NAMESIZE)>
        Public szTypeName As String
    End Structure
    <DllImport("Shell32.dll")>
    Private Shared Function SHGetFileInfo(ByVal pszPath As String,
                                      ByVal dwFileAttributes As Integer,
                                      ByRef psfi As SHFILEINFO,
                                      ByVal cbFileInfo As Integer,
                                      ByVal uFlags As Integer) As IntPtr
    End Function
    <DllImport("user32.dll", SetLastError:=True)>
    Private Shared Function DestroyIcon(ByVal hIcon As IntPtr) As Boolean
    End Function
    Public Shared Function GetShellIcon(ByVal path As String) As Bitmap
        Dim shfi As SHFILEINFO = New SHFILEINFO()
        Dim ret As IntPtr = SHGetFileInfo(path, 0, shfi, Marshal.SizeOf(shfi), SHGFI_ICON)
        If ret <> IntPtr.Zero Then
            Dim bmp As Bitmap = System.Drawing.Icon.FromHandle(shfi.hIcon).ToBitmap
            DestroyIcon(shfi.hIcon)
            Return bmp
        Else
            Return Nothing
        End If
    End Function
End Class

1 ответ

Вы можете получить эту иконку от Shell32 как маленькое или большое изображение. Как указывает Коди Грей в комментарии, в "imageres.dll" больше значков (200+). Чтобы получить их по индексу, добавьте этот метод к NativeMethods учебный класс:

<DllImport("shell32.dll", CharSet:=CharSet.Auto)>
Private Shared Function ExtractIconEx(szFileName As String,
                            nIconIndex As Integer,
                            ByRef phiconLarge As IntPtr,
                            ByRef phiconSmall As IntPtr,
                            nIcons As UInteger) As UInteger
End Function

Private Shared ImgResFile As String = "imageres.dll"
Private Shared ShellFile As String = "shell32.dll"

Friend Shared Function GetShellIconByIndex(ndx As Int32,
                         largeIcon As Boolean = False,
                         Optional FromShell As Boolean = True) As Bitmap
    Dim largeIco As IntPtr
    Dim smallIco As IntPtr
    Dim thisIco As IntPtr
    Dim ico As Icon
    Dim bmp As Bitmap = Nothing

    Dim targtFile = If(FromShell, ShellFile, ImgResFile)
    ExtractIconEx(targtFile, ndx, largeIco, smallIco, 1)

    Try
        If largeIcon Then
            ico = Icon.FromHandle(largeIco)
            thisIco = largeIco
        Else
            ico = Icon.FromHandle(smallIco)
            thisIco = smallIco
        End If
        bmp = ico.ToBitmap()
    Catch ex As Exception           ' swallow exception to return nothing
        ' really stupid index values can throw ArgumentException
        ' when the result is IntPtr.Zero
        ' Rather than test it, catch it an any other(s)
    Finally
        DestroyIcon(thisIco)
    End Try

    Return bmp
End Function

Первый аргумент - это индекс значка, который вы хотите получить, второй указывает, хотите ли вы большую или маленькую версию, последний - необязательный флаг, из которого нужно выбрать imageres.dll против shell32.dll, Обратите внимание, что метод может привести Nothing если что-то пойдет не так.

Затем измените ваш цикл папок, чтобы получить изображение папки (#275) shell32.dll при обнаружении сетевого диска:

For Each d In di.EnumerateDirectories("*.*", SearchOption.TopDirectoryOnly)
    ...
    If IsNetworkFolder(d) Then
        ' get #275 as small image from Shell 
        img = NativeMethods.GetShellIconByIndex(275, False)
        If img Is Nothing Then
            ' ToDo: perhaps load a default image from Resources?
        End If
    Else
        img = NativeMethods.GetShellIcon(d.FullName)
        If img Is Nothing Then
            img = IconFromFile(d.FullName)
        End If
    End If
    '... add code 
Next

Private Function IsNetworkFolder(di As DirectoryInfo) As Boolean
    Dim drv As New DriveInfo(di.Root.Name)
    Return (drv.DriveType = DriveType.Network)
End Function

При этом используется вспомогательная функция, чтобы определить, подключена ли папка к сети или нет. Если это так, он выбирает этот конкретный значок папки, который является #275, из DLL. Результат:

Это же изображение папки также находится в imageres.dll как #137 (и #68 и #69 подобны с наложениями мира). Чтобы получить от этого вместо этого:

'  137 is the index, false for large icon, false to use imageres instead: 
img = NativeMethods.GetShellIconByIndex(137, False, False)

Если вы хотите избежать использования магических чисел в своем коде, используйте константы или перечисление используемых значков. Вы можете определить их все в NativeMethods класс, но это 500 предметов, и вы можете не вспомнить, что они означают 6 месяцев спустя:

Private Enum ShellIcons
    NetworkFolder1 = 275
    NetworkFolder2 = 103
    SharedFolder = 158
    AddNetworkFolder = 278
End Enum
...
img = NativeMethods.GetShellIconByIndex(ShellIcons.NetworkFolder1, False)

Это отобразит значки, хранящиеся в shell32.dll и их индекс в Listview установлен в LargeIcon Посмотреть, чтобы вы могли просматривать их:

Dim ndx As Int32 = 0
Dim img As Image = Nothing
Dim lvi As ListViewItem

Do
    ' change second Bool to False to get the ones in imageres.dll
    img = NativeMethods.GetShellIconByIndex(ndx, True, True)

    If img IsNot Nothing Then
        lvi = New ListViewItem(ndx.ToString)

        ImageList1.Images.Add(img)
        lvi.ImageIndex = ImageList1.Images.Count - 1
        myLV.Items.Add(lvi)
        ndx += 1
    Else
        Exit Do
    End If
Loop Until img Is Nothing

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