?
Solved

Tree View with icons for all folders and files (including special folders)

Posted on 2009-02-12
5
Medium Priority
?
848 Views
Last Modified: 2012-05-06
I have searched all over and have found only bits of information and samples available...
Like this www.experts-exchange.com/Programming/Languages/Visual_Basic/Q_20867921.html

I need to add system default icons to folders and files in a treeview controll...

a sample would be helpfull...
0
Comment
Question by:KMusatoff
  • 3
  • 2
5 Comments
 
LVL 25

Expert Comment

by:SStory
ID: 23626808
Well that is a difficult task. I have done it before.  Basically folders should be no big deal, but for files, you have actual files and then shortcuts.  Shortcuts must be resolved to the actual file, then for exe files, the icon is usually contained within the EXE.  Now let's assume it is a .doc or .pdf, then you need to get the Word icon (assuming word, it might not be), then for pdf the same...this involves looking in the registry to find the application associated with the extension, then going to the EXE for that application and extracting the icon.  This can be very time consuming, so if you want to make it quick, you'd need to build an icon cache like Microsoft has done since at least NT 4.0.  Occasionally you'd want to refresh the cache.  It would be a place containing the file extension and the related icon.  It would has a way to quickly index (find the icon needed).  Then when you're app loaded you'd load all of these into an ImageList that is bound to the Treeview and assign the correct icon to each document as needed.

I hope this helps some. I don't have the code with me.
0
 
LVL 3

Author Comment

by:KMusatoff
ID: 23626876
All of that is understandable... ) The main question is how to extract default icons from SHELL  for special folders, folders and files... If any - exe could use dafault icons as well...
0
 
LVL 25

Expert Comment

by:SStory
ID: 23627752
I think each special folder like Recyle bin, has a corresponding GUID in the registry where you can look to find out.  It probably points to Shell32.dll and gives and index number to the current icon.  I'll have to look further.
0
 
LVL 3

Author Comment

by:KMusatoff
ID: 23688299
Any samples?
0
 
LVL 25

Accepted Solution

by:
SStory earned 2000 total points
ID: 23688485
This is what I had in vb.net 2003
I hope it helps.  Some of the code was originally mine--I think--and the rest I found on the Internet somewhere.  I don't remember where.
Imports System
Imports System.Collections.Specialized
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Threading
Imports Microsoft.Win32
Imports System.Windows.Forms
Imports System.IO
Public Class clsIconExtractor
   Private Const SHGFI_SMALLICON = &H1
   Private Const SHGFI_LARGEICON = &H0
   Private Const SHGFI_ICON = &H100
   Private Const SHGFI_USEFILEATTRIBUTES = &H10
 
   Public Enum IconSize
      SmallIcon = SHGFI_SMALLICON
      LargeIcon = SHGFI_LARGEICON
   End Enum
 
   <StructLayout(LayoutKind.Sequential)> _
   Private Structure SHFILEINFO
      ' pointer to icon handle
      Public hIcon As IntPtr
      ' icon index
      Public iIcon As Integer
      ' not used in this example
      Public dwAttributes As Integer
      ' file pathname--marshal this as an unmanaged LPSTR of MAX_SIZE 
      <MarshalAs(UnmanagedType.LPStr, SizeConst:=260)> _
      Public szDisplayName As String
      ' file type--marshal as unmanaged LPSTR of 80 chars
      <MarshalAs(UnmanagedType.LPStr, SizeConst:=80)> _
      Public szTypeName As String
   End Structure
 
   Private Declare Function DestroyIcon Lib "user32" Alias "DestroyIcon" (ByVal hIcon As IntPtr) As Integer
   Private Declare Auto Function SHGetFileInfo Lib "shell32" (ByVal pszPath As String, ByVal dwFileAttributes As Integer, ByRef psfi As SHFILEINFO, ByVal cbFileInfo As Integer, ByVal uFlags As Integer) As Integer
 
   'get large or small icons based on filesysteminfo
   'Public Shared Function GetSmallIcon(ByVal fsi As FileSystemInfo) As Icon
   '   Return clsIconExtractor.GetIcon(fsi, SHGFI_SMALLICON)
   'End Function
   'Public Shared Function GetLargeIcon(ByVal fsi As FileSystemInfo) As Icon
   '   Return clsIconExtractor.GetIcon(fsi, SHGFI_LARGEICON)
   'End Function
 
   'overloaded--   'get large or small icons based on path passed in (could be .exe)
   Public Shared Function GetSmallIcon(ByVal strPath As String) As Icon
      Return clsIconExtractor.GetIcon(strPath, SHGFI_SMALLICON)
   End Function
 
   Public Shared Function GetLargeIcon(ByVal strPath As String) As Icon
      Return clsIconExtractor.GetIcon(strPath, SHGFI_LARGEICON)
   End Function
 
   Private Shared Function GetIcon(ByVal strFile As String, ByVal anIconSize As Integer) As Icon
      Dim temp As Icon = Nothing
      Dim result As Icon = Nothing
 
      Dim aSHFileInfo As New SHFILEINFO
      Dim cbFileInfo As Integer = Marshal.SizeOf(aSHFileInfo)
      Dim uflags As Integer = SHGFI_ICON Or SHGFI_USEFILEATTRIBUTES Or anIconSize
      If SHGetFileInfo(strFile, 0, aSHFileInfo, cbFileInfo, uflags) <> 0 Then
         'the icon does not own the handle......
         temp = Icon.FromHandle(aSHFileInfo.hIcon)
         Try
            'so we copy it
            result = New Icon(temp, temp.Size)
            temp.Dispose()
         Finally
            DestroyIcon(aSHFileInfo.hIcon)
         End Try
      End If
      Return result
   End Function
End Class
 
Public Class clsFileTypeInfo
   Private _Ext As String
   Private _Desc As String
   Private _Icon As System.Drawing.Icon = Nothing
   Private Shared IconGetter As New clsIconExtractor
 
   Public ReadOnly Property Extension() As String
      Get
         Return _Ext
      End Get
   End Property
 
   Public ReadOnly Property Description() As String
      Get
         Return _Desc
      End Get
   End Property
 
   'to speed up getting all icons, the icon is only gotten one time and only when needed; so the colFileTypeInfoCollection which gets all fileext/types registered, will not be getting the icons also, they are gotten only as needed by their representative clsFileTypeInfo class Icon Property
   Public ReadOnly Property Icon(Optional ByVal bRefreshIcon As Boolean = False) As Icon
      Get
         'if we haven't gotten the icon yet,or the bRefreshIcon flag was set then get the icon; otherwise will just return the one in the member variable
         If bRefreshIcon OrElse IsNothing(_Icon) Then
            _Icon = IconGetter.GetSmallIcon(_Ext)
         End If
 
         'return the current icon
         Return _Icon
      End Get
   End Property
 
   'gets the icon inside the class; to access the icon use the icon property; this mainly for use by collection that wants to tell each to get its icon
   Public Sub GetIcon()
      _Icon = IconGetter.GetSmallIcon(_Ext)
   End Sub
 
   Public Function IconIsSet() As Boolean
      Return Not IsNothing(_Icon)
   End Function
 
 
   'bGetFileIcon may choose to get the icon right of the bat, but if used via the collection object this should be false to speed up loading large # of items
   Sub New(ByVal strFileExtension As String, ByVal strFileDescription As String, Optional ByVal bGetFileIcon As Boolean = False)
      _Ext = strFileExtension
      _Desc = strFileDescription
 
      'if told to get the icon get it; else only get it when Icon Property is referenced which seems to be wiser.
      If bGetFileIcon Then _Icon = IconGetter.GetSmallIcon(_Ext)
   End Sub
 
   'INSTANCE METHOD -- strFileExtension should include the period
   Public Function GetFileType() As String
      _Desc = GetFileType(_Ext)
      Return _Desc
   End Function
 
   'SHARED METHOD-- strFileExtension should include the period
   Shared Function GetFileType(ByVal strFileExtension As String) As String
      Dim reg As Registry
      Dim rk As RegistryKey
      Dim strFileTypeNode, strFileType As String
 
      'if nullstring passed in, send it back out
      If strFileExtension.Length = 0 Then
         Return String.Empty
      End If
 
      'try reading the matching entry for the files extension from registry
      Try
         rk = reg.ClassesRoot.OpenSubKey(strFileExtension, False)
         If IsNothing(rk) Then
            'just say i.e SMP File; if you don't know
            Return strFileExtension.Substring(1).ToUpper & " File"
         End If
      Catch
         'if it set to something then close it
         If Not IsNothing(rk) Then rk.Close()
      End Try
 
      'get the default value for this node
      Try
         strFileTypeNode = CStr(rk.GetValue("", String.Empty))
         If strFileTypeNode = String.Empty Then
            'just say i.e SMP File; if you don't know
            Return strFileExtension.Substring(1).ToUpper & " File"
         End If
      Catch
         'just say i.e SMP File; if you don't know
         Return strFileExtension.Substring(1).ToUpper & " File"
      Finally
         'if it set to something then close it
         If Not IsNothing(rk) Then rk.Close()
      End Try
 
      'now try to take that node and get the actual text for the type of file this is
      Try
         rk = reg.ClassesRoot.OpenSubKey(strFileTypeNode, False)
         'get the actual type of file; if it was found
         If Not IsNothing(rk) Then strFileType = rk.GetValue("")
      Catch
         'just say i.e SMP File; if you don't know
         Return strFileExtension.Substring(1).ToUpper & " File"
      Finally
         'if it set to something then close it
         If Not IsNothing(rk) Then rk.Close()
      End Try
 
      If IsNothing(strFileType) Then
         Return String.Empty
      Else
         Return strFileType
      End If
   End Function
End Class
 
'gets and contains all file types registered
'provides lookup by extension via hastable
Public Class colFileTypeInfoCollection
   Inherits CollectionBase
   Private _extHashTable As New Hashtable
 
   Public ReadOnly Property Item(ByVal index As Integer)
      Get
         Return CType(list.Item(index), clsFileTypeInfo)
      End Get
   End Property
 
   Public ReadOnly Property Item(ByVal strFileExtension As String)
      Get
         Return _extHashTable.Item(strFileExtension.ToLower)
      End Get
   End Property
 
   Public Sub Add(ByVal FileTypeInfo As clsFileTypeInfo)
      list.Add(FileTypeInfo)
      'add to hashtable for easy lookup
      _extHashTable.Add(FileTypeInfo.Extension.ToLower, FileTypeInfo)
   End Sub
 
   Public Sub Remove(ByVal index As Integer)
      If index >= 0 And index < Count Then
         list.Remove(index)
      End If
   End Sub
 
   Public Shadows Sub Clear()
      MyBase.Clear()
      _extHashTable.Clear()
   End Sub
 
   Public Sub Remove(ByVal FileTypeInfo As clsFileTypeInfo)
      Me.List.Remove(FileTypeInfo)
 
      _extHashTable.Remove(FileTypeInfo.Extension.ToLower)
   End Sub
 
   Public Shadows Sub RemoveAt(ByVal index As Integer)
      Remove(Item(index))
   End Sub
 
   Private Sub GetAllFileTypes()
      Dim reg As Registry
      Dim strRegFileExtensions() As String
      Dim strFileType As String
      Dim fti As clsFileTypeInfo
      Dim Count As Integer = 0
      Dim iErrCount As Integer = 0
 
      'be sure to clear the list
      list.Clear()
 
      'try to get all of the registry extensions
      Try
         strRegFileExtensions = reg.ClassesRoot.GetSubKeyNames
      Catch ex As Exception
         Throw New Exception("Error getting the extensions registered in the registry.", ex)
      End Try
 
      For ext As Short = 0 To strRegFileExtensions.Length - 1
         'only use those that are of the . extension type
         If strRegFileExtensions(ext).Chars(0) = "." Then
            Try
               'Debug.Write(String.Format(".. desc for file ext ({0})", strRegFileExtensions(ext)))
               'get the filetype from registry
               strFileType = clsFileTypeInfo.GetFileType(strRegFileExtensions(ext))
               'if something was returned then add to collection
               If strFileType = String.Empty Then
                  'say it was .MANIFEST file ext and couldn't find desc. just put .MANIFEST File
                  fti = New clsFileTypeInfo(strRegFileExtensions(ext), strRegFileExtensions(ext).ToUpper & " File", False)
                  Add(fti)
                  Count += 1
                  'Debug.WriteLine("(!!couldn't find just used generic based on file extension!!)")
               Else
                  fti = New clsFileTypeInfo(strRegFileExtensions(ext), strFileType, False)
                  Add(fti)
                  Count += 1
                  'Debug.WriteLine("(added)")
               End If
            Catch ex As Exception
               Debug.WriteLine("!!!!ERROR while getting filetypes for " & strRegFileExtensions(ext))
               iErrCount += 1
            End Try
         End If
      Next
      Debug.WriteLine(String.Format("added {0} associations with {1} error(s).", Count, iErrCount))
   End Sub
 
   'called to read all icons
   Public Sub GetAllAssociatedIcons()
      For i As Integer = 0 To Me.List.Count - 1
         CType(Me.List.Item(i), clsFileTypeInfo).GetIcon()
      Next
   End Sub
 
 
   'just dimensioning this collection gets all the file types
   Sub New()
      Dim ts As New TimeSpan(Now.Ticks)
 
      Debug.WriteLine("started:" & ts.ToString)
      GetAllFileTypes()
      Debug.WriteLine(New TimeSpan(Now.Ticks).Subtract(ts))
   End Sub
End Class
 
'clsIconPrefetchWorker is a background thread used to get all icons in the collection so the app can continue running
Public Class clsIconPrefetchWorker
   'maintains an internal collection object which will be passed back when full or may be passed back if
   'asks to get a subset of icons; will passback the collection object as it stands after doing that task
 
   'thread management stuff
   Private _thread As Thread                                         'separate thread to run on
   Private _bIsCancelled As Boolean                                  'should cancel thread 
   Private _paused As New ManualResetEvent(False)                    'thread signaler; set to thread waiting
 
   'other members
   Private _colFetchImmediately As New StringCollection              'to hold file extensions that were are to get immediately
   Private _FetchImmediateLock As New ReaderWriterLock               'sync lock for getting Reading colFetchImmediate values
   Private _colFileTypeInfos As colFileTypeInfoCollection            'internal collection
   Private _FileTypeInfosLock As New ReaderWriterLock                'sync for when we are first copying collection to here
   Private _curIndex As Integer                                      'index as to where it got in getting icons in the collection;needs to know in case paused to do a subset
   Private _bDoQuickFetch As Boolean = False                         'if true, iteration of getting icons, is paused, index remembered and specific fetching starts, finishes and returns collection, then sets this to false and iteration continues.
 
   'delegates
   Public OnAllIconsLoaded As AllIconsLoaded                         'called when everything is read; passes completed collection
   Public OnQuickFetchCompleted As QuickFetchCompleted               'called if we were told to get icons for a certain subset of file extensions immediately--passes collection as stands after getting these items;in addition to those that had already been fetched
 
   'delgate definitions
   Public Delegate Sub AllIconsLoaded(ByVal colFileTypeInfos As colFileTypeInfoCollection)
   Public Delegate Sub QuickFetchCompleted(ByVal colFileTypeInfos As colFileTypeInfoCollection)
 
   Private Sub GetIcons()
      Dim i, cnt As Integer
      '_curIndex = 0
      cnt = _colFileTypeInfos.Count - 1
 
      For i = 0 To cnt
         Debug.WriteLine(String.Format("fetching {0} ({1})", i, CType(_colFileTypeInfos.Item(i), clsFileTypeInfo).Extension))
         If _bDoQuickFetch Then
            'handle quick fetch
            If _colFetchImmediately.Count > 0 Then
               Debug.WriteLine("started quickfetching list @ " & Now.ToLongTimeString)
               Dim s As String
               Dim fti As clsFileTypeInfo
               'get associated icon for each item in the collection
               For Each s In _colFetchImmediately
                  Try
                     'get assoc for the item
                     fti = CType(_colFileTypeInfos.Item(s), clsFileTypeInfo)
                     If fti Is Nothing Then
                        Debug.WriteLine("  ! " & s.ToUpper & " file extension isn't registered! Couldn't quick fetch icon for it!")
                     Else
                        'has a clsFileTypeInfo object
                        fti.GetIcon()
                        Debug.WriteLine("  + quick fetched icon for file ext. " & fti.Extension.ToUpper)
                     End If
                  Catch ex As Exception
                     Debug.WriteLine("!!ERROR: couldn't quick fetch icon for extension: " & ex.Message & s)
                  End Try
               Next
               Debug.WriteLine("finished quickfetching @ " & Now.ToLongTimeString)
            End If
 
            'set flag back to false
            _bDoQuickFetch = False
 
            'finished getting icons for subset of file exts.
            OnQuickFetchCompleted.Invoke(_colFileTypeInfos)
         Else
            'just keep interating
            'call the method for the current index to get it's associated icon
            CType(_colFileTypeInfos.Item(i), clsFileTypeInfo).GetIcon()
         End If
      Next i
 
      'finished so pass back completed collection
      OnAllIconsLoaded.Invoke(_colFileTypeInfos)
 
      'wait until awoken again
      _paused.Reset()
   End Sub
 
   Private Sub Start()
      Do While True
         _paused.WaitOne()
         If _bIsCancelled Then Exit Do
         'do the work
         GetIcons()
      Loop
   End Sub
 
   Public Sub FetchTheseImmediately(ByVal colFetchImmediately As StringCollection)
      'this sub allows HIGH priority fetching of a specific list of extensions
      'when we can get access we will write over the internal collection of extensions to get immediately
      _FetchImmediateLock.AcquireReaderLock(-1)
      'clear the list
      _colFetchImmediately.Clear()
      _colFetchImmediately = colFetchImmediately
      _FetchImmediateLock.ReleaseReaderLock()
 
      Debug.WriteLine("told to immed. fetch")
      'iterating routine will pause to do the immediate get
      _bDoQuickFetch = True
   End Sub
 
   Public Sub Cancel()
      _bIsCancelled = True
      Try
         _paused.Set()
      Catch ex As ObjectDisposedException
         Debug.WriteLine(ex.Message & "  ignorning this exception")
      End Try
   End Sub
 
   Public Sub SpinUp()
      Dim start As New ThreadStart(AddressOf Me.Start)
      _thread = New Thread(start)
      _thread.Name = "Icon Prefetcher"
      _thread.Start()
   End Sub
 
   Public Sub SpinDown()
      Cancel()
 
      _thread.Join(1000)                                             'waits for thread to finish
      _thread.Abort()         'shane changed to timeout and then abort; was hanging in memory. 2-18-04
      _thread = Nothing                                              'set thread to nothing
   End Sub
 
   Public Sub StartFetching(ByVal colFileTypeInfos As colFileTypeInfoCollection)
      'set our internal collection
      _FileTypeInfosLock.AcquireWriterLock(-1)
      _colFileTypeInfos = colFileTypeInfos
      _FileTypeInfosLock.ReleaseLock()
 
      'signal thread to start working
      _paused.Set()
   End Sub
 
End Class

Open in new window

0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Parsing a CSV file is a task that we are confronted with regularly, and although there are a vast number of means to do this, as a newbie, the field can be confusing and the tools can seem complex. A simple solution to parsing a customized CSV fi…
The ECB site provides FX rates for major currencies since its inception in 1999 in the form of an XML feed. The files have the following format (reducted for brevity) (CODE) There are three files available HERE (http://www.ecb.europa.eu/stats/exch…
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signat…
With just a little bit of  SQL and VBA, many doors open to cool things like synchronize a list box to display data relevant to other information on a form.  If you have never written code or looked at an SQL statement before, no problem! ...  give i…

840 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question