Using SHGetFileInfo for icons - problems with adding to ImageList
Messages   Related Types
This message was discovered on microsoft.public.dotnet.languages.vb.
Responses highlighted in red are from those people who are likely to be able to contribute good, authoratitive information to this discussion. They include Microsoft employees, MVP's and others who IMHO contribute well to these kinds of discussions.
Post a new message to this list...

Andre Viens (VIP)
Hello,

I am using the following variation of code from
<http://support.microsoft.com/default.aspx?scid=kb;EN-US;319340> to add icons
to an imagelist for use in a listview:

Private Structure SHFILEINFO
Public hIcon As IntPtr ' : icon
Public iIcon As Integer ' : icondex
Public dwAttributes As Integer ' : SFGAO_ flags
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> Public
szDisplayName As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> Public
szTypeName As String
End Structure

Private Declare Ansi 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

Private Const SHGFI_ICON As Integer = &H100
Private Const SHGFI_SMALLICON As Integer = &H1
Private Const SHGFI_LARGEICON As Integer = &H0 ' Large icon

Sub IconExtract(ByVal sFileName As String, ByRef lvListView As ListView)
'This sub takes the filename of the icon to extract and a reference
to the listview
'to add the large and small icons to...

Dim hImgSmall As IntPtr 'The handle to the system image list.
Dim hImgLarge As IntPtr 'The handle to the system image list.
Dim fName As String 'The file name to get the icon from.
Dim shinfo As SHFILEINFO
shinfo = New SHFILEINFO

shinfo.szDisplayName = New String(Chr(0), 260)
shinfo.szTypeName = New String(Chr(0), 80)

'Use this to get the small icon.
hImgSmall = SHGetFileInfo(sFileName, 0, shinfo,
Marshal.SizeOf(shinfo), SHGFI_ICON Or SHGFI_SMALLICON)

'The icon is returned in the hIcon member of the shinfo struct.
Dim myIcon As Drawing.Icon = Drawing.Icon.FromHandle(shinfo.hIcon)
lvListView.SmallImageList.Images.Add(myIcon)

'Use this to get the large icon.
hImgLarge = SHGetFileInfo(sFileName, 0, shinfo,
Marshal.SizeOf(shinfo), SHGFI_ICON Or SHGFI_LARGEICON)

myIcon = Drawing.Icon.FromHandle(shinfo.hIcon)
lvListView.LargeImageList.Images.Add(myIcon)
End Sub

I call the subroutine IconExtract and pass it the full path and filename of
the icon I want to extract, and a reference (note the ByRef) to my listview.
I want to extract the icons for the file and add it to the appropriate Small
or Large imagelist on the existing listview.

This is my problem... it doesn't work. The code gets to the first line of
adding the icon to the imagelist
(lvListView.SmallImageList.Images.Add(myIcon)) and just seems to stop. When
in debug, the program jumps back to the foreground and allows me to keep
executing it, but the subroutine never completed. There is also no error
thrown.

I'm sure the strangeness I'm experiencing is due to the Interop I'm
utilizing to get the icons, but why does the addition of the icon fail on an
existing imagelist? If I don't use the reference to my existing listview and
rather initialize a new ImageList and add the icon to it, it then works. Then
I can reference that new image list to the imagelist in my listview, except I
have existing images in my imagelist on my listview, so I just want to add to
them, and that's where my problem lies.

Is this a bug with dealing with the Interop or something I'm doing wrong?
Thanks.

- Andre
Reply to this message...
 
    
Herfried K. Wagner [MVP] (VIP)
* "=?Utf-8?B?QW5kcmUgVmllbnM=?=" <Click here to reveal e-mail address> scripsit:
[Original message clipped]

This won't solve the problem: Make sure you understand the difference
between 'ByVal' and 'ByRef' for reference types. In this case, it's
better to change the 'ByRef' to 'ByVal'.

--
M S Herfried K. Wagner
M V P <URL:http://dotnet.mvps.org/>
V B <URL:http://dotnet.mvps.org/dotnet/faqs/>
Reply to this message...
 
    
Andre Viens (VIP)
Hello, thanks for responding...

Yes, I do understand the difference, which is why I want to pass the
reference of the ListView object, but nevertheless, using ByRef or ByVal, I
end up with the same result... the code just exits out with no error message,
but also allows me to continue.

Pardon my earlier duplicate posts on this subject... was having trouble
posting them, and now I see them all here.

Am I just doing this incorrectly, or is this an issue with dealing with the
API through Interop?

- Andre

"Herfried K. Wagner [MVP]" wrote:

[Original message clipped]

Reply to this message...
 
    
Tom Shelton
In article <Click here to reveal e-mail address>, Andre Viens wrote:
[Original message clipped]

Andre... Herfried is absolutely right - you should not be passing the
listview byref - but byval. That said - are you associating a imagelist
with the imagelist properties? If not, that is most likely the reason
if fails at that point - it would be throwing a NullReferenceException.
The IDE behavior makes me have to ask - are you doing this on another
thread? Because if you are, your only going to come to grief with your
code...

--
Tom Shelton [MVP]
Reply to this message...
 
    
Andre Viens (VIP)
Hi Tom,

Thanks for responding...

The reason why I chose ByRef is I want to modify both the SmallImageList and
LargeImageList properties on the ListView object I am passing over.

I want to take both the large icon and small icon and add it to the existing
ImageList already present.

As previously stated to Herfried, I did try switching it ByVal with the same
result.

Now, I am able to declare a new ImageList and let the appropriate ImageList
property on the ListView object equal it, however I want to take what is
already there and add to it, and that is where my problem arises.

All of the processing is occurring on one thread. I am not multithreading.

The ListView is simply designed to accept files that are dragged and dropped
onto it, taking the full path information and this is the part where I'm
trying to retrieve the icon to display in the ListView. The trick is, the
user can continue to drag more files as they go, so I need to keep adding to
my existing SmallImageList and LargeImageList properties.

- Andre

"Tom Shelton" wrote:
[Original message clipped]

Reply to this message...
 
    
Tom Shelton
On Thu, 9 Sep 2004 18:03:02 -0700, Andre Viens wrote:

[Original message clipped]

You don't have to pass it byref to do that. A listview object is just a
reference - so unless you actually intend to set the listview object to a
new listview object, then passing it in byref is pointless...

[Original message clipped]

Is it present? Because the listview doesn't get one by default unless you
set it to one...

listview.largeimagelist = new imagelist()

[Original message clipped]

Because there is no imagelist by default...

[Original message clipped]

Ok...

if lvw.largeimagelist is nothing then
    lvw.largeimagelist = new imagelist
end if

....
lvw.largeimagelist.images.add (youricon)

[Original message clipped]

good.

[Original message clipped]

Option Strict On
Option Explicit On

Imports System.Runtime.InteropServices

Public Class Form1
Inherits System.Windows.Forms.Form

Private Structure SHFILEINFO
Public hIcon As IntPtr ' : icon
Public iIcon As Integer ' : icondex
Public dwAttributes As Integer ' : SFGAO_ flags
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> _
Public szDisplayName As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
Public szTypeName As String
End Structure

Private 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

Private Const SHGFI_ICON As Integer = &H100
Private Const SHGFI_SMALLICON As Integer = &H1
Private Const SHGFI_LARGEICON As Integer = &H0 ' Large icon
Private nIndex As Integer = 0

#Region " Windows Form Designer generated code "

Public Sub New()
MyBase.New()

'This call is required by the Windows Form Designer.
InitializeComponent()

'Add any initialization after the InitializeComponent() call

End Sub

'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub

'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer

'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
Friend WithEvents imageList As System.Windows.Forms.ImageList
Friend WithEvents ListView1 As System.Windows.Forms.ListView
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
Me.components = New System.ComponentModel.Container
Me.imageList = New System.Windows.Forms.ImageList(Me.components)
Me.ListView1 = New System.Windows.Forms.ListView
Me.SuspendLayout()
'
'imageList
'
Me.imageList.ImageSize = New System.Drawing.Size(16, 16)
Me.imageList.TransparentColor = System.Drawing.Color.Transparent
'
'ListView1
'
Me.ListView1.AllowDrop = True
Me.ListView1.Dock = System.Windows.Forms.DockStyle.Fill
Me.ListView1.LargeImageList = Me.imageList
Me.ListView1.Location = New System.Drawing.Point(0, 0)
Me.ListView1.Name = "ListView1"
Me.ListView1.Size = New System.Drawing.Size(292, 266)
Me.ListView1.SmallImageList = Me.imageList
Me.ListView1.StateImageList = Me.imageList
Me.ListView1.TabIndex = 0
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(292, 266)
Me.Controls.Add(Me.ListView1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)

End Sub

#End Region

Private Sub ListView1_DragDrop(ByVal sender As Object, ByVal e As
System.Windows.Forms.DragEventArgs) Handles ListView1.DragDrop

Try
Me.ImportIcon(DirectCast(e.Data.GetData("FileName"),
String())(0), Me.ListView1)
Catch ex As Exception
MessageBox.Show(ex.ToString())
End Try
End Sub

Private Sub ListView1_DragEnter(ByVal sender As Object, ByVal e As
System.Windows.Forms.DragEventArgs) Handles ListView1.DragEnter
If e.Data.GetDataPresent("FileName") Then
e.Effect = DragDropEffects.Copy
Else
e.Effect = DragDropEffects.None
End If
End Sub

Private Sub ImportIcon(ByVal filename As String, ByVal lvw As ListView)
Dim hImgSmall As IntPtr 'The handle to the system image list.
Dim hImgLarge As IntPtr 'The handle to the system image list.
Dim fName As String = filename 'The file name to get the icon
from.
Dim shinfo As SHFILEINFO
shinfo = New SHFILEINFO
shinfo.szDisplayName = New String(Chr(0), 260)
shinfo.szTypeName = New String(Chr(0), 80)

'Use this to get the small icon.
hImgSmall = SHGetFileInfo(fName, 0, shinfo, Marshal.SizeOf(shinfo),
_
SHGFI_ICON Or SHGFI_SMALLICON)

'Use this to get the large icon.
'hImgLarge = SHGetFileInfo(fName, 0,
'ref shinfo, (uint)Marshal.SizeOf(shinfo),
'SHGFI_ICON | SHGFI_LARGEICON);

'The icon is returned in the hIcon member of the shinfo struct.
Dim myIcon As System.Drawing.Icon
myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon)

imageList.Images.Add(myIcon) 'Add icon to imageList.

ListView1.Items.Add(fName, nIndex) 'Add file name and icon to
listview.
nIndex = nIndex + 1

End Sub

End Class

--
Tom Shelton [MVP]
Reply to this message...
 
    
Andre Viens (VIP)
Hi Tom,

Okay, that was what was throwing me off. I was not aware the SmallImageList
and LargeImageList properties had no reference until I assigned a new
ImageList.

I also changed the parameter back to ByVal.

This now works. Thank you for your help as well as Herfried. :)

- Andre

"Tom Shelton" wrote:

[Original message clipped]

Reply to this message...
 
    
Tom Shelton
In article <Click here to reveal e-mail address>, Andre Viens wrote:
[Original message clipped]

Andre - I'm glad to see that you got it working... Good luck on your
project.

--
Tom Shelton [MVP]
Reply to this message...
 
 
System.ComponentModel.Container
System.ComponentModel.IContainer
System.Drawing.Color
System.Drawing.Icon
System.Drawing.Point
System.Drawing.Size
System.IntPtr
System.NullReferenceException
System.Runtime.InteropServices.Marshal
System.Runtime.InteropServices.UnmanagedType
System.Windows.Forms.DockStyle
System.Windows.Forms.DragDropEffects
System.Windows.Forms.DragEventArgs
System.Windows.Forms.Form
System.Windows.Forms.ImageList
System.Windows.Forms.ListView
System.Windows.Forms.MessageBox




Ad
MBR BootFX
Best-of-breed application framework for .NET projects, developed by Matthew Baxter-Reynolds and MBR IT
 
 Copyright © Matthew Baxter-Reynolds 2001-2008. '.NET 247 Software Development Services' is a trading style of MBR IT Solutions Ltd.
Contact Us - Terms of Use - Privacy Policy - www.dotnet247.com