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.
| 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
|
|
| |
| |
| 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/>
|
|
| |
| |
| 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]
|
|
| |
|
|
| |
| 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]
|
|
| |
| |
| 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]
|
|
| |
| |
| 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]
|
|
| |
| |
| 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]
|
|
| |
| |
| 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]
|
|
| |
|
|
|
|
|
|
|
|
|