Resolved Icon not showing in TreeView

aaaron

Well-known member
Joined
Jan 23, 2011
Messages
213
Programming Experience
10+
Years ago I wrote some code using a TreeView.
It worked all this while showing icons on the items.

Lately I revised the code and when I tested it the icons did not show.
I compared the new code with old backups and can find no changes that might effect the icons.
Then I ran the old .exe file and the icon did not show.

I checked the Internet and found similar problems but, not exactly the same.
One mentioned that Build/Publish Selection was grayed out.
Mine is grayed out but I never use it and do not know if it should be or not.

Anyway, can you direct me as to how I should proceed to get the icons to show?
 
Solution
Got it! The Images have a IndexOfKey which works perfectly.
I'm surprised because the internet repeatedly suggest using a Dictionary as I did earlier.
Anyway, thanks for listening. Sometime it help to talk about a problem.
I wish I could share the below with the many poster that I can across.



VB.NET:
                'iIcon is the index of the icon image within the source file..
                'We need to return the index for the ImageList
                'I don't want to add an image to the ImageList more than once. 
                If imageListIn.Images.ContainsKey(CType(fileInfo.iIcon, String)) Then                     'If ImageList already contains the key and the image, return
                    GetImageListIndex =...
You should show us what you're doing so we can determine what you're doing wrong.
I wouldn't know where to begin. 62 projects, some are libraries used by the TreeView code.
I'd like very much to but the effort would be enormous.
I was hopping you had some knowledge of something like I reported.
Thanks for trying (I'll look at the Internet again).
 
It's been a while because I've checked the Internet which has many hits for no icons but for many different causes.
I didn't believe it when I first read your reply but now I think all the code you need is this one function.
For one thing, it behaves differently when I convert the type of the key (which I don't believe I should).
If I use fileInfo.iIcon directly as the key I get no icons. If I change type I get some but they are the wrong ones.

Typical usage is:
subNode.ImageIndex = GetImageListIndex(.SelectedNode.Tag), SHGFI_ICON Or SHGFI_SMALLICON Or SHGFI_SYSICONINDEX, ImageList_1)

Thanks for you any help at all.


Public Shared Function GetImageListIndex(nodePath As String, flags As Integer, imageListIn As ImageList) As Integer
' Dim nodePath As String = InsureSlashIfDevice(objPath)
Dim fileInfo As New ShellApiH.SHFILEINFO 'Structure
Dim fileInfoSize As Integer
Dim ok As Integer
Static iconIds As New Hashtable
'The statement: You must initialize Component Object Model (COM) with CoInitialize or OleInitialize prior to calling SHGetFileInfo
'in Help at location Window Shell and Control does not apply to Vb.Net because it's done by the runtime before the code runs
Try
fileInfoSize = Marshal.SizeOf(fileInfo)
'Size of Icon is determined by values in flags
ok = SHGetFileInfo(nodePath, 0, fileInfo, fileInfoSize, flags)
If ok = 0 Then 'If the above fails try to get the icon for a file type without SHGetFileInfo checking to see if the file exist
SHGetFileInfo(nodePath, FILE_ATTRIBUTE_NORMAL, fileInfo, fileInfoSize, flags Or SHGFI_USEFILEATTRIBUTES)
End If
If fileInfo.hIcon.ToInt32 <> 0 Then
'iIcon is the index of the icon image within the system image list.
'We need to store the index
'I don't want to add an image to the ImageList more than once.
If iconIds.ContainsKey(fileInfo.iIcon) Then 'If hash table already contains the index (fileInfo.iIcon)
GetImageListIndex = CInt(iconIds.Item(CType(fileInfo.iIcon, UInteger))) 'use that index with the system image list. Gets value for key
Else
'Add an index as the key and the icon
imageListIn.Images.Add(Icon.FromHandle(fileInfo.hIcon)) 'Add the new icon to the imagelist
iconIds.Add(CType(fileInfo.iIcon, UInteger), imageListIn.Images.Count - 1) 'and add the index (fileInfo.iIcon) to
GetImageListIndex = imageListIn.Images.Count - 1 'the hashtable and return that index
End If
DestroyIcon(fileInfo.hIcon)
Else
'Should never get here
Return -1
End If
Catch
End Try
Debug.WriteLine($"OK:{ok} ; index:{fileInfo.iIcon} ; Path:{nodePath} ; hIcon:{fileInfo.hIcon.ToInt32}")
Return fileInfo.iIcon
End Function
 
insertcode.png
 
This is just to see what the quotes do
VB.NET:
  Public Shared Function GetImageListIndex(nodePathQ As String, flags As Integer, imageListIn As ImageList) As Integer
        Dim nodePath As String = Disk.InsureBackslash(nodePathQ)

        Debug.WriteLine($" Path:{nodePath}")

        Dim fileInfo As New ShellApiH.SHFILEINFO  'Structure
        Dim fileInfoSize As Integer
        Dim ok As Integer
        Static iconIds As New Hashtable
        'The statement: You must initialize Component Object Model (COM) with CoInitialize or OleInitialize prior to calling SHGetFileInfo
        'in Help at location Window Shell and Control does not apply to Vb.Net because it's done by the runtime before the code runs
        Try
            fileInfoSize = Marshal.SizeOf(fileInfo)
            'Size of Icon is determined by values in flags
            ok = SHGetFileInfo(nodePath, 0, fileInfo, fileInfoSize, flags)
            If ok = 0 Then  'If the above fails try to get the icon for a file type without SHGetFileInfo checking to see if the file exist
                SHGetFileInfo(nodePath, FILE_ATTRIBUTE_NORMAL, fileInfo, fileInfoSize, flags Or SHGFI_USEFILEATTRIBUTES)
            End If
            If fileInfo.hIcon.ToInt32 <> 0 Then
                'iIcon is the index of the icon image within the system image list.
                'We need to store the index
                'I don't want to add an image to the ImagList more than once. 
                If iconIds.ContainsKey(fileInfo.iIcon) Then                                     'If hash table already contains the index (fileInfo.iIcon)
                    GetImageListIndex = CInt(iconIds.Item(CType(fileInfo.iIcon, UInteger)))     'use that index with the system image list. Gets value for key
                Else
                    'Add an index as the key and the icon
                    imageListIn.Images.Add(Icon.FromHandle(fileInfo.hIcon))                      'Add the new icon to the imagelist
                    iconIds.Add(CType(fileInfo.iIcon, UInteger), imageListIn.Images.Count - 1)   'and add the index (fileInfo.iIcon) to
                    GetImageListIndex = imageListIn.Images.Count - 1                             'the hashtable and return that index
                End If
                DestroyIcon(fileInfo.hIcon)
            Else
                'Should never get here
                Return -1
            End If
        Catch
        End Try
        Debug.WriteLine($"OK:{ok} ; index/Icon:{fileInfo.iIcon} ; Path:{Disk.GetLastItem(nodePath)} ; hIcon:{fileInfo.hIcon.ToInt32}")
        Return fileInfo.iIcon
    End Function
 
Because I wrote it first for VisualBasic 6. I know that not a reason for not changing it.

I do use the iIcon value as a key, I suppose I could use the entire path but it seems like an overkill if iIcon would work.

I can get my head around:
Returns an icon representation of an image that is contained in the specified file.
Is that what I need. Seems like this is for when the path is to the image file.
I think SHGetFileInfo is different. No?


I value your suggestions and would like o hear more!
 
No, it actually Extract Associated Icon for specified file path, isn't that surprising? :)
 
Static iconIds As Dictionary(Of Integer, Integer)

'''stuff here

'I don't want to add an image to the ImageList more than once.
If iconIds.ContainsKey(fileInfo.iIcon) Then 'If Dictionary already contains the index (fileInfo.iIcon)
GetImageListIndex = CInt(iconIds.Item(fileInfo.iIcon)) 'use that index with the s. Item gets value for key
Else
'Add the key and the icon
imageListIn.Images.Add(Icon.FromHandle(fileInfo.hIcon)) 'Add the new icon to the imagelist
iconIds.Add(fileInfo.iIcon, imageListIn.Images.Count - 1) 'and add it and the index (fileInfo.iIcon) to
GetImageListIndex = imageListIn.Images.Count - 1 'the Dictionary and return that index
End If




I found the problem. Think of my program as an independent collection of apps.

They all use a library that contains the above function.

Therefore they share iconids! They thus interfere each other.

The problem is quite simple. I need to map the location in the source file to the location in the ImageList.

Imagelist does contain a key that I can use for the location in the source file.

But how to I relate that to to the location in the ImageList?

I think there is a tag but I was warned not to use it.

What say you?
 
Got it! The Images have a IndexOfKey which works perfectly.
I'm surprised because the internet repeatedly suggest using a Dictionary as I did earlier.
Anyway, thanks for listening. Sometime it help to talk about a problem.
I wish I could share the below with the many poster that I can across.



VB.NET:
                'iIcon is the index of the icon image within the source file..
                'We need to return the index for the ImageList
                'I don't want to add an image to the ImageList more than once. 
                If imageListIn.Images.ContainsKey(CType(fileInfo.iIcon, String)) Then                     'If ImageList already contains the key and the image, return
                    GetImageListIndex = imageListIn.Images.IndexOfKey(CType(fileInfo.iIcon, String))      'the index of the key which is also the index of the image
                Else
                    'Add the index of the image in the source file as the key
                    imageListIn.Images.Add(CType(fileInfo.iIcon, String), Icon.FromHandle(fileInfo.hIcon)) 'Add the new icon to the imagelist
                    GetImageListIndex = imageListIn.Images.Count - 1
                End If
 
Solution
I've just used the file extension as key when doing this before, that's been simpler cases though, it wouldn't suffice for example for .exe's with different icons.
 
Back
Top