Show network folder icon in listview VB.NET

后端 未结 1 649
没有蜡笔的小新
没有蜡笔的小新 2021-01-24 11:38

how do I show network folder icon in a listview? the one with the green tube under the folder, I have the code that works great with files and folders but when visiting other co

相关标签:
1条回答
  • 2021-01-24 12:06

    You can get that icon from Shell32 as a small or large image. As Cody Gray points out in a comment, there are more icons (200+) in "imageres.dll". To get these by index, add this method to your NativeMethods class:

    <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
    

    The first argument is the index of the icon to get, the second indicates whether you want the large or small version, the last is an optional flag to fetch from imageres.dll versus shell32.dll. Note that the method can result Nothing if something goes wrong.

    Then modify your folders loop to get the pipe-folder image (#275) from shell32.dll when you detect a network drive:

    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
    

    This uses a helper function to determine whether the folder is networked or not. If it is, it fetches that specific folder icon, which is #275, from the DLL. Result:

    That same folder image is also in imageres.dll as #137 (and #68 and #69 are similar with world overlays). To get from that instead:

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

    If you want to avoid Magic Numbers in your code, use constants or an enum of the icons used. You could define them all in the NativeMethods class, but that is 500 items and you may well not recall what they mean 6 months later:

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

    This will display the icons stored in shell32.dll and their index to a Listview set to LargeIcon View so you can browse them:

    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
    

    0 讨论(0)
提交回复
热议问题