SHGetFileInfo

Started by
15 comments, last by wasd 17 years, 11 months ago
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.
Advertisement
Does no one know how to get and display high quality icons in an image list?
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.
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
:==-_ Why don't the voices just leave me alone?! _-==:
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.
Have you tried "_imageList.Size.X = 48;" and "_imageList.Size.Y = 48;"?? If so, it may be loading 32x32 or something from "SHGetFileInfo".
:==-_ Why don't the voices just leave me alone?! _-==:
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.
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
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
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

This topic is closed to new replies.

Advertisement