Sign in to follow this  
f8k8

SHGetFileInfo

Recommended Posts

f8k8    171
I'm using SHGetFileInfo in C# and .Net to get the large icon for an exe file to dispay it in a ListView, but the icon is not the same quality as the one displayed in an Explorer window. Just wondering if anyone knows how to get the high quality icons to display the way explorer does.

Share this post


Link to post
Share on other sites
Evil Steve    2017
An executable can contain several icons, and an icon can have several resolutions. Any idea what resolution the one in explorer and the one returned are? E.g. 16x16, 32x32, 48x48 or 64x64.

What you could do, is use LoadLibrary() to load the EXE (exe's load just the same as DLLs), then use the standard resource functions to load the icon, passing the HMODULE returned from LoadLibrary() as the HINSTANCE. I'm not sure what the C# equivalent is, but I'd imagine it'll be similar.

Share this post


Link to post
Share on other sites
TFS_Waldo    146
Well, are you using an ImageList? That's the only way I can think you could do this anyhow. LoL. =P

Anyhow, the "ImageList" class includes a "ColorDepth" property which is the "ColorDepth" Enumeration type. The default, from MSDN, is Depth8Bit. Which, of course, is only an 8-bit image. You need to specify "Depth24Bit" or "Depth32Bit" as the "ColorDepth" property of your "ImageList" object. =)

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWindowsFormsImageListPropertiesTopic.asp

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformscolordepthclasstopic.asp

Share this post


Link to post
Share on other sites
f8k8    171
Yeah, it's set at 32bit, it's just when I add the icon I get from SHGetFileInfo and try to display it at 48x48 (The size in explorer), it's obviously a lower resolution icon than 48x48. Looks like it's a 32x32 being scaled up.

Share this post


Link to post
Share on other sites
Evil Steve    2017
What flags are you passing to SHGetFileInfo()? Are you using SHGFI_LARGEICON (Or whatever the C# equivalent is)?

From what I can tell, if that doesn't help, then SHGetFileInfo() isn't able to get the 48x48 icon, and you'll have to load it as a resource manually.

Share this post


Link to post
Share on other sites
rmsimpson    228
Here's how I do it:

I call SHGetFileInfo() with these flags:
SHGFI_PIDL|SHGFI_SYSICONINDEX|SHGFI_SMALLICON

Then I use ImageList_GetIcon() with ILD_NORMAL to fetch the icon.

You can probably do this without a PIDL and the corresponding flag. I was enumerating a lot more than just the filesystem, so I needed PIDL's.

Robert

Share this post


Link to post
Share on other sites
f8k8    171
Here's the Win32 code:

[StructLayout(LayoutKind.Sequential)]
public struct SHFILEINFO
{
public IntPtr hIcon;
public IntPtr iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
};

class Win32
{
public const uint SHGFI_ICON = 0x100;
public const uint SHGFI_LARGEICON = 0x0; // 'Large icon
public const uint SHGFI_SMALLICON = 0x1; // 'Small icon

// Gets the icon for a file
[DllImport("shell32.dll")]
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
}



The call to SHGetFileInfo:

Icon NewIcon = null;
// Get the icon for the file
if(Info.IconFile != "")
{
// Get the icon from the file
SHFILEINFO SHInfo = new SHFILEINFO();

string IconFile = Info.BasePath + Info.IconFile;
Win32.SHGetFileInfo(IconFile, 0, ref SHInfo, (uint)Marshal.SizeOf(SHInfo), Win32.SHGFI_ICON | Win32.SHGFI_LARGEICON);

if(SHInfo.hIcon != IntPtr.Zero)
NewIcon = Icon.FromHandle(SHInfo.hIcon);
}



And the results:
Picture

Share this post


Link to post
Share on other sites
rmsimpson    228
I threw a quick C# Windows app together to test this. I added a ListView to the form, and an ImageList. I assigned the LargeImageList property of the ListView to the ImageList.

I then set the ImageList's size to 32x32, and the bit-depth to 32bit. I then copied and pasted your code over and modified it to load the icon for notepad.exe.

The icon was fetched and the entry added to the listview. What I got was a non alpha-blended icon, but one that otherwise looked proper.

Robert

Share this post


Link to post
Share on other sites
f8k8    171
If you set your explorer view to either thumbnails or tiles, the icons are actually 48x48 images. That's the icon I want to get. Just setting the size of the image list to 48x48 results in the 32x32 image being scaled horribly. What I really want is a method of extracting the 48x48 icon from an exe file.

Share this post


Link to post
Share on other sites
rmsimpson    228
Quote:
Original post by f8k8
If you set your explorer view to either thumbnails or tiles, the icons are actually 48x48 images. That's the icon I want to get. Just setting the size of the image list to 48x48 results in the 32x32 image being scaled horribly. What I really want is a method of extracting the 48x48 icon from an exe file.


Ah ha! Now we're getting somewhere. I'll get back to you on that.

What if the file doesn't have a 48x48 icon?

Share this post


Link to post
Share on other sites
rmsimpson    228
Hold up ... there's easy and there's hard.

Do you want easy -- get the first icon in an executable's resource in 48x48 mode?

Or do you want hard -- get the same icon Explorer shows for a given file regardless of filetype, in 48x48 mode?

And does it have to be C#? I cringe every time I have to write interop code especially when it uses a lot of interfaces. I could probably whip something up in no time in C++.

Robert

Share this post


Link to post
Share on other sites
rmsimpson    228
In a nutshell, you call SHGetFileInfo() to get the system imagelist index, then call SHGetImageList() to get the extra-large imagelist, then you can get the 48x48 icon from that imagelist. Only works on XP and above, though.

Fortunately for me, rather than wade through interop, someone already wrote it up:

Getting the icons for a file, including the big icons

Robert

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this