2016-01-29 3 views
2

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

Это моя Shell экстракция Код:

' 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

Bump! Помоги мне, пожалуйста. – 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 (ы) могут быть частными и открытыми через метод (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 каждый раз, вы можете позволить им как накапливать изображения по мере их запуска. Значок text file в папке Foo не будет отличаться от изображения для текстовых файлов, где.

Результат:
enter image description hereenter image description here

+0

Это сработало! Большое спасибо и за информацию! но я не могу проверить его еще при посещении других компьютеров через сеть. – Dhan

+0

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

+0

Вопрос ничего не говорит о сетях. Я уверен, что для этого есть PInvoke, но у меня нет сети для тестирования. Пожалуйста, поддержите ответ, если это поможет. – Plutonix

Смежные вопросы