.net - Show folder icon in a listview -


i've managed display icons files in listview using shell32 extraction, when folders, icon doesn't seem show. how be?

this shell extraction code:

' declare win32 api function shgetfileinfo' public declare auto function shgetfileinfo lib "shell32.dll" (byval pszpath string, byval dwfileattributes integer, byref psfi shfileinfo, byval cbfileinfo integer, byval uflags integer) intptr ' declare constants shgetfileinfo requires' public const shgfi_icon integer = &h100 public const shgfi_smallicon integer = &h1 ' define shfileinfo structure' structure shfileinfo     public hicon intptr     public iicon integer     public dwattributes integer     <runtime.interopservices.marshalas(runtime.interopservices.unmanagedtype.byvaltstr, sizeconst:=260)> _     public szdisplayname string     <runtime.interopservices.marshalas(runtime.interopservices.unmanagedtype.byvaltstr, sizeconst:=80)> _     public sztypename string end structure  function retrieveshellicon(byval argpath string) image     dim mshellfileinfo shfileinfo     dim msmallimage intptr     dim micon system.drawing.icon     dim mcompositeimage 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 icon icon handle'     try         micon = system.drawing.icon.fromhandle(mshellfileinfo.hicon)         mcompositeimage = micon.tobitmap     catch ex exception         ' create blank black bitmap return'         mcompositeimage = new bitmap(16, 16)     end try     ' return composited image'     return mcompositeimage end function  function geticon(byval argfilepath string) image     dim mfileextension string = system.io.path.getextension(argfilepath)     ' add image if doesn't exist''     if cicons.containskey(mfileextension) = false         cicons.add(mfileextension, retrieveshellicon(argfilepath))     end if     ' return image'     return cicons(mfileextension) end function 

and how show icon files.

    dim lvi listviewitem     dim di new directoryinfo(form2.textbox1.text)     dim exts new list(of string)     imagelist1.images.clear()     if di.exists = false         messagebox.show("source path not found", "directory not found", messageboxbuttons.ok, messageboxicon.error)     else         each fi 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                 dim mshelliconmanager new form1                 each mfilepath 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 

this how show folder icons doesn't seem work

for each fldr string in directory.getdirectories(form2.textbox1.text)             dim mshelliconmanager 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 

there couple of things in code. of looks remnants previous attempts. @ rate, works:

public partial class nativemethods     private const max_path integer = 256     private const namesize integer = 80     private const shgfi_icon int32 = &h100      <structlayout(layoutkind.sequential)>      private structure shfileinfo         public hicon intptr         public iicon integer         public dwattributes integer         <marshalas(unmanagedtype.byvaltstr, sizeconst:=max_path)>         public szdisplayname string         <marshalas(unmanagedtype.byvaltstr, sizeconst:=namesize)>         public sztypename string     end structure      <dllimport("shell32.dll")>      private shared function shgetfileinfo(pszpath string,                                           dwfileattributes integer,                                           byref psfi shfileinfo,                                           cbfileinfo integer,                                           uflags integer) intptr     end function      <dllimport("user32.dll", setlasterror:=true)>     private shared function destroyicon(hicon intptr) boolean     end function      public shared function getshellicon(path string) bitmap         dim shfi shfileinfo = new shfileinfo()          dim ret intptr = shgetfileinfo(path, 0, shfi, marshal.sizeof(shfi), shgfi_icon)         if ret <> intptr.zero             dim bmp bitmap = system.drawing.icon.fromhandle(shfi.hicon).tobitmap             destroyicon(shfi.hicon)             return bmp         else             return nothing         end if     end function end class 

putting pinvoke code in own class has several benefits. first, helps isolate code form magic numbers, structures , constants. pinvoke(s) can private , exposed thru method (getshellicon) scut work , invokes api method. also, vs codeanalysis tool wont complain when used nativemethods class.

one of things code not doing destroying icon retrieved , releasing resource; shgetfileinfo doesn't right can lead bad things. when can't icon, not create blank/empty bitmap in pinvoke code, instead returns nothing code handle.

in end, easier use , shorter pinvoke code encapsulated:

dim fpath string = "c:\temp" dim di = new directoryinfo(fpath) ' store imagelist index known/found file types dim exts new dictionary(of string, int32)  dim img image dim lvi listviewitem 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  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         ' try simplest method         img = drawing.icon.extractassociatedicon(f.fullname).tobitmap         if img nothing             img = nativemethods.getshellicon(f.fullname)         end if         if img isnot nothing             imglst.images.add(img)             exts.add(f.extension, imglst.images.count - 1)         else             ' ?? use default or custom '?' one?         end if      end if      lvi.imageindex = exts(f.extension) next 

for file, first tries icon using net icon.extractassociatedicon method , resorts pinvoke of failed reason.

i changed exts list(of string dictionary(of string, int32). once code gets icon extension, saves index of image in imagelist extension/icon doesn't need looked again. speeds quite bit on large folders.

if declare dictionary outside method , don't clear imagelist each time, let them both accumulate images runs. text file icon in folder foo wont different image text files else where.

result:
enter image description hereenter image description here


Comments