!Help with API call from vb. Must be trampling memory or something!

S

SStory

Hi all,

I really needed to get the icons associated with each file that I want to
show in a listview.

I used the follow modified code sniplets found on the internet.

I have left in commented code for anyone else who may be looking to do the
same.

I only care about the small icons in my program--detail view only.

Private Structure SHFileInfo ' Shell File Info structure
Public hIcon As IntPtr ' Icon handle
Public iIcon As Integer ' Icon index
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

'Gets the small icon for a file extension
Private Function GetIconViaExt(ByVal FileExt As String) As
System.Drawing.Icon
Const SHGFI_DISPLAYNAME = &H200
Const SHGFI_ICON = &H100
Const SHGFI_SMALLICON = &H1 ' Small icon
Const SHGFI_USEFILEATTRIBUTES = &H10 ' use passed dwFileAttribute
Const SHGFI_LARGEICON = &H0 ' Large icon
Const SHGFI_TYPENAME = &H400 ' get type name
Const DEFAULT_FLAGS = SHGFI_TYPENAME Or SHGFI_ICON Or SHGFI_SMALLICON Or
SHGFI_USEFILEATTRIBUTES
Const FILE_ATTRIBUTE_NORMAL = &H80

Dim hImg As IntPtr
Dim shinfo As New SHFileInfo

' Depending on the size, get the icon from the file
' If iSize = IconSize.Small Then ' Return small icon

hImg = SHGetFileInfo(FileExt, FILE_ATTRIBUTE_NORMAL, shinfo,
Marshal.SizeOf(shinfo), DEFAULT_FLAGS)

' ElseIf iSize = IconSize.Large Then ' Return large icon
' hImg = SHGetFileInfo(Filename, 0, shinfo, Marshal.SizeOf(shinfo),
SHGFI_ICON Or SHGFI_LARGEICON)
' End If
' strFileTypeName = shinfo.szTypeName

'The icon is returned in the hIcon member of the shinfo struct.
Debug.Write("calling GetIconViaExt....")
GetIconViaExt = System.Drawing.Icon.FromHandle(shinfo.hIcon)
Debug.WriteLine("....GetIconViaExt call returned")
End Function

from another method I do this

'fi is a fileinfo obj
Dim ico As Icon
ico = GetIconViaExt(fi.Extension)
'if GetIconViaExt returned something then lets add it to the image list
and remember it in the sorted array
If Not IsNothing(ico) Then
'add the icon to the image list
imlFileIcons.Images.Add(ico)

as you can see I get the filenames and then place them into an imagelist--I
actually keep up with them by another array and the extension to avoid
regetting the icon for the same extension once I have it, but anyhow....

The above code is some how trampling memory. It shows up in strange ways,
systemexecutionexception or even stackoverflowexceptions

commenting out this call makes it run fine so I know the problem is there.

Do I need to somehow release this icon pointer or something?

If so how can I add the icon I want to the imagelist, and release this icon
ptr to it and still have the image available in the imagelist?

Please help me solve this. My app really needs it if I will show icons.

If there is a simpler way that definitely works, please let me know.
I tried many before this one.

It works great except for this.

Thanks,

Shane
 
K

Ken Tucker [MVP]

Hi,

Here is a Class that I use to get the icons.


Imports System.Runtime.InteropServices

Public Class clsGetIcon

Public Structure SHFILEINFO

Dim hIcon As IntPtr

Dim iIcon As Integer

Dim dwAttributes As Integer

<VBFixedString(260),
System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr,
SizeConst:=260)> Public szDisplayName As String

'String that contains the name of the file as it appears in the Microsoft®
Windows® Shell, or the path and file name of the file that contains the icon
representing the file.

<VBFixedString(80),
System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr,
SizeConst:=80)> Public szTypeName As String

End Structure


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

Private Const SHGFI_ICON = &H100

Private Const SHGFI_SMALLICON = &H1 'Small icon

Public Function getIcon(ByVal szFilename As String) As Icon

Try

Dim aSHFileInfo As New SHFILEINFO

Dim cbFileInfo As Integer = _

Marshal.SizeOf(aSHFileInfo)

Dim uflags As Integer = SHGFI_ICON Or SHGFI_SMALLICON

SHGetFileInfo(szFilename, 0, aSHFileInfo, cbFileInfo, uflags)

Dim myIcon As Icon

myIcon = Icon.FromHandle(aSHFileInfo.hIcon)

Return myIcon

Catch ex As Exception

Debug.WriteLine(ex.ToString)

Return Nothing

End Try

End Function

End Class



Ken

-------------------------
 
S

SStory

Thank you Ken,

This seems to work.

Had to modify a little though.

I needed to get the icons via file extension.
That requires two more flags or it fails.

But with that added, works great.

The only different I see in what you have and what I had was the return
value of the api call
you used Integer and I had intptr.

That will probably do it.

Thanks a bunch. It was showing up in wierd places.

Shane
 
S

SStory

Ken,

I took you class and modified it to do what I need but still seem to have
problems. I thought it was working but I am still having
system.executionengine exceptions in a place down below the call into this
class. If I comment out the call all goes well.

The error always shows up in sharpziplib classes--but when I do the
following

dim IconGetter as new clsGetIcon
dim ico as icon

'get the icon
ico=getIconViaFileExtension(".EXE")

next I put the icon into the imagelist if it is not already in there.
(tracking that by an arraylist--what extensions already looked up)

if it getIconViaFileExtension call is left intact then I get all sorts of
bizarre errors later on down and usually in trying to get the datetime in
the ZipEntry class of SharpZipLib.

Somehow it is as if memory is getting stomped on. I get stackoverflow
execeptions and also sometimes the system.executionengine exception.


(your class modified for my needs--needed to be able to pass in an extension
("*.exe") or whatever--don't have the filename uncompressed. That seems to
require
these flags
SHGFI_TYPENAME Or SHGFI_ICON Or SHGFI_SMALLICON Or SHGFI_USEFILEATTRIBUTES)

Public Class clsGetIcon
Private Structure SHFILEINFO
Dim hIcon As IntPtr
Dim iIcon As Integer
Dim dwAttributes As Integer
<VBFixedString(260),
System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.Unma
nagedType.ByValTStr, _
SizeConst:=260)> Public szDisplayName As String
'String that contains the name of the file as it appears in the
Microsoft®
'Windows® Shell, or the path and file name of the file that contains the
icon
'representing the file.
<VBFixedString(80),
System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.Unma
nagedType.ByValTStr, _
SizeConst:=80)> Public szTypeName As String
End Structure

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

Const SHGFI_DISPLAYNAME = &H200
Const SHGFI_ICON = &H100
Const SHGFI_SMALLICON = &H1 ' Small icon
Const SHGFI_USEFILEATTRIBUTES = &H10 ' use passed dwFileAttribute
Const SHGFI_LARGEICON = &H0 ' Large icon
Const SHGFI_TYPENAME = &H400 ' get type name
Const FILE_ATTRIBUTE_NORMAL = &H80

'if bGetSmallIcon is false, large is used
Public Function getIconForFile(ByVal szFilename As String, Optional ByVal
bGetSmallIcon As Boolean = True) As Icon
Const SMALL_DEFAULT_FLAGS As Integer = SHGFI_ICON Or SHGFI_SMALLICON
Const LARGE_DEFAULT_FLAGS As Integer = SHGFI_ICON Or SHGFI_LARGEICON
Try
Dim aSHFileInfo As New SHFILEINFO
Dim cbFileInfo As Integer = Marshal.SizeOf(aSHFileInfo)
If bGetSmallIcon Then
SHGetFileInfo(szFilename, 0, aSHFileInfo, cbFileInfo,
SMALL_DEFAULT_FLAGS)
Else
SHGetFileInfo(szFilename, 0, aSHFileInfo, cbFileInfo,
LARGE_DEFAULT_FLAGS)
End If

Dim myIcon As Icon
myIcon = Icon.FromHandle(aSHFileInfo.hIcon)
Return myIcon
Catch ex As Exception
Throw New Exception("There was a problem in getting the icon
associated with the file " & szFilename & ".", ex)
Debug.WriteLine(ex.ToString)
Return Nothing
End Try
End Function

'if bGetSmallIcon is false, large is used
Public Function getIconViaFileExtension(ByVal szFileExtension As String,
Optional ByVal bGetSmallIcon As Boolean = True) As Icon
Const SMALL_DEFAULT_FLAGS As Integer = SHGFI_TYPENAME Or SHGFI_ICON Or
SHGFI_SMALLICON Or SHGFI_USEFILEATTRIBUTES
Const LARGE_DEFAULT_FLAGS As Integer = SHGFI_TYPENAME Or SHGFI_ICON Or
SHGFI_LARGEICON Or SHGFI_USEFILEATTRIBUTES
Try
Dim aSHFileInfo As New SHFILEINFO
Dim cbFileInfo As Integer = Marshal.SizeOf(aSHFileInfo)


If bGetSmallIcon Then
SHGetFileInfo(szFileExtension, 0, aSHFileInfo, cbFileInfo,
SMALL_DEFAULT_FLAGS)
Else
SHGetFileInfo(szFileExtension, 0, aSHFileInfo, cbFileInfo,
LARGE_DEFAULT_FLAGS)
End If

Dim myIcon As Icon
myIcon = Icon.FromHandle(aSHFileInfo.hIcon)
Return myIcon
Catch ex As Exception
Throw New Exception("There was a problem in getting the icon
associated with the " & szFileExtension & " file extension.", ex)
Debug.WriteLine(ex.ToString)
Return Nothing
End Try
End Function
End Class

So again, is there something that I need to do with that icon--releasing
memory or some graphics release or something after getting it? What could
cause this problem?

Any help from you or ANYONE, would be greatly appreciated.

Shane
 
S

SStory

FOLLOWUP THOUGHT:

Ken, this seems to be an intermittent problem.
At present it is working, but 5 minutes ago it wasn't. Something is amuck.
(worse kind of problems).

THanks,
 
S

SStory

New oddity....

It seems that if I don't launch the splash screen which runs on a different
thread, it appears to be working.....
Maybe this is a multithreading problem.

Got the code for the splash screen from CodeProject so I wouldn't think it
would be a problem.

I didn't want to do.

frmsplash.showdialog for a few seconds and show my app.. Wanted to show the
splash and when the app was opened wait a few seconds before closing. This
has caused some ridiculous problems for a simple splash screen.

maybe showdialog is the way to go with the splash for a small app--forget
multithreading.

My app starts from Sub Main in a module that declares an Application object
of my own making which has the repsponsibility of calling an MDI window via
ShowDialog.

Seemed not to work until I made the splash on another thread--but now have
this intermittent problem that appears to go away if I don't show the
splash.

Any thoughts, ideas, help would be GREATLY APPRECIATED! I'm going nuts here
over something that should be simple.

Thanks,

Shane
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top