2016-01-29 85 views
2

我已經成功地使用shell32提取在列表視圖中顯示文件的圖標,但是何時使用文件夾執行此操作,圖標似乎並未顯示出來。怎麼會這樣?在列表視圖中顯示文件夾圖標

這是我的殼提取代碼:

' declare the Win32 API function SHGetFileInfo' 
Public Declare Auto Function SHGetFileInfo Lib "shell32.dll" (ByVal pszPath As String, ByVal dwFileAttributes As Integer, ByRef psfi As SHFILEINFO, ByVal cbFileInfo As Integer, ByVal uFlags As Integer) As IntPtr 
' declare some constants that SHGetFileInfo requires' 
Public Const SHGFI_ICON As Integer = &H100 
Public Const SHGFI_SMALLICON As Integer = &H1 
' define the SHFILEINFO structure' 
Structure SHFILEINFO 
    Public hIcon As IntPtr 
    Public iIcon As Integer 
    Public dwAttributes As Integer 
    <Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=260)> _ 
    Public szDisplayName As String 
    <Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=80)> _ 
    Public szTypeName As String 
End Structure 

Function RetrieveShellIcon(ByVal argPath As String) As Image 
    Dim mShellFileInfo As SHFILEINFO 
    Dim mSmallImage As IntPtr 
    Dim mIcon As System.Drawing.Icon 
    Dim mCompositeImage As Image 
    mShellFileInfo = New SHFILEINFO 
    mShellFileInfo.szDisplayName = New String(Chr(0), 260) 
    mShellFileInfo.szTypeName = New String(Chr(0), 80) 
    mSmallImage = SHGetFileInfo(argPath, 0, mShellFileInfo, System.Runtime.InteropServices.Marshal.SizeOf(mShellFileInfo), SHGFI_ICON Or SHGFI_SMALLICON) 
    ' create the icon from the icon handle' 
    Try 
     mIcon = System.Drawing.Icon.FromHandle(mShellFileInfo.hIcon) 
     mCompositeImage = mIcon.ToBitmap 
    Catch ex As Exception 
     ' create a blank black bitmap to return' 
     mCompositeImage = New Bitmap(16, 16) 
    End Try 
    ' return the composited image' 
    Return mCompositeImage 
End Function 

Function GetIcon(ByVal argFilePath As String) As Image 
    Dim mFileExtension As String = System.IO.Path.GetExtension(argFilePath) 
    ' add the image if it doesn't exist'' 
    If cIcons.ContainsKey(mFileExtension) = False Then 
     cIcons.Add(mFileExtension, RetrieveShellIcon(argFilePath)) 
    End If 
    ' return the image' 
    Return cIcons(mFileExtension) 
End Function 

,這是我如何顯示文件的圖標。

Dim lvi As ListViewItem 
    Dim di As New DirectoryInfo(Form2.TextBox1.Text) 
    Dim exts As New List(Of String) 
    ImageList1.Images.Clear() 
    If di.Exists = False Then 
     MessageBox.Show("Source path is not found", "Directory Not Found", MessageBoxButtons.OK, MessageBoxIcon.Error) 
    Else 
     For Each fi As FileInfo In di.EnumerateFiles("*.*") 

      lvi = New ListViewItem 
      lvi.Text = fi.Name 

      lvi.SubItems.Add(((fi.Length/1024)).ToString("0.00")) 
      lvi.SubItems.Add(fi.CreationTime) 

      If exts.Contains(fi.Extension) = False Then 
       Dim mShellIconManager As New Form1 
       For Each mFilePath As String In My.Computer.FileSystem.GetFiles(Form2.TextBox1.Text) 
        ImageList1.Images.Add(fi.Extension, GetIcon(mFilePath)) 
        exts.Add(fi.Extension) 
       Next 

      End If 
      lvi.ImageKey = fi.Extension 
      ListView1.Items.Add(lvi) 
     Next 

我這是怎麼顯示的文件夾圖標,但似乎並沒有工作

For Each fldr As String In Directory.GetDirectories(Form2.TextBox1.Text) 
      Dim mShellIconManager As New Form1 

      lvi = New ListViewItem 
      lvi.Text = Path.GetFileName(fldr) 

      lvi.SubItems.Add(((fldr.Length/1024)).ToString("0.00")) 
      lvi.SubItems.Add(Directory.GetCreationTime(fldr)) 


      ImageList1.Images.Add(GetIcon(fldr)) 
      ListView1.Items.Add(lvi)    
Next 
+0

跳車!請幫幫我。 – Dhan

回答

2

有代碼中的幾件事情。有些看起來像以前嘗試的殘餘物。無論如何,這個工程:

Public Partial 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(pszPath As String, 
              dwFileAttributes As Integer, 
              ByRef psfi As SHFILEINFO, 
              cbFileInfo As Integer, 
              uFlags As Integer) As IntPtr 
    End Function 

    <DllImport("user32.dll", SetLastError:=True)> 
    Private Shared Function DestroyIcon(hIcon As IntPtr) As Boolean 
    End Function 

    Public Shared Function GetShellIcon(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 

把PInvoke的代碼在自己的班級有幾個好處。首先,它有助於隔離所有這些幻數,結構和常量的代碼。 PInvoke(s)可以是私有的,並通過一個方法(GetShellIcon)進行公開,該方法完成所有的scut工作並調用API方法。此外,VS CodeAnalysis工具在使用NativeMethods類時不會對此抱怨。

你的代碼沒有做的事情之一是破壞檢索到的圖標並釋放該資源;也SHGetFileInfo看起來不正確,這可能會導致不好的事情。當它無法獲取圖標時,我不會在PInvoke代碼中創建空白/空位圖,而是返回代碼處理的Nothing

在最後,它更容易使用和更短的包封的PInvoke的代碼:

Dim fPath As String = "C:\Temp" 
Dim di = New DirectoryInfo(fPath) 
' store imagelist index for known/found file types 
Dim exts As New Dictionary(Of String, Int32) 

Dim img As Image 
Dim lvi As ListViewItem 
For Each d In di.EnumerateDirectories("*.*", SearchOption.TopDirectoryOnly) 
    lvi = New ListViewItem(d.Name) 
    lvi.SubItems.Add("")  ' no file name 
    lvi.SubItems.Add(Directory.GetFiles(d.FullName).Count().ToString) 

    myLV.Items.Add(lvi) 

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

For Each f In di.EnumerateFiles("*.*") 
    lvi = New ListViewItem(f.DirectoryName) 
    lvi.SubItems.Add(f.Name)  ' no file name 
    lvi.SubItems.Add("n/a") 

    myLV.Items.Add(lvi) 
    If exts.ContainsKey(f.Extension) = False Then 
     ' try simplest method 
     img = Drawing.Icon.ExtractAssociatedIcon(f.FullName).ToBitmap 
     If img Is Nothing Then 
      img = NativeMethods.GetShellIcon(f.FullName) 
     End If 
     If img IsNot Nothing Then 
      imgLst.Images.Add(img) 
      exts.Add(f.Extension, imgLst.Images.Count - 1) 
     Else 
      ' ?? use some default or custom '?' one? 
     End If 

    End If 

    lvi.ImageIndex = exts(f.Extension) 
Next 

對於文件時,它首先嚐試使用NET Icon.ExtractAssociatedIcon方法和手段來獲得的圖標的PInvoke的由於某種原因失敗了。

我將extsList(Of String更改爲Dictionary(Of String, Int32)。代碼獲取擴展名圖標後,會將該圖像的索引保存在ImageList中,以便不必再次查找擴展名/圖標。這在大文件夾上加速了很多。

如果您在方法外聲明Dictionary,然後每次都不清除ImageList,則可以讓它們在運行時累積圖像。文件夾Foo中的text file圖標不會與其他文本文件的圖像不同。

結果:
enter image description hereenter image description here

+0

它的工作!非常感謝您的信息!但是當通過網絡訪問其他計算機時,我無法測試它。 – Dhan

+0

先生,我試圖通過網絡訪問計算機,爲什麼我不能看到網絡文件夾?帶有綠色管狀圖標的那個。 – Dhan

+0

這個問題沒有提到有關網絡的任何事情。我很確定這是一個PInvoke,但我沒有網絡在這裏測試。如果有幫助,請提高答案。 – Plutonix