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
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