开发者

SHGetImageList - SHIL_JUMBO for smaller icons (32,32)

开发者 https://www.devze.com 2023-03-14 19:37 出处:网络
In my code I get a list of images through the function SHGETImageList with size SHIL_JUMBO. IImageList iml;

In my code I get a list of images through the function SHGETImageList with size SHIL_JUMBO.

 IImageList iml;
 var hres = SHGetImageList(SHIL_JUMBO, ref iidImageList, out  iml);
 IntPtr hIcon = IntPtr.Zero;
 iml.GetIcon(i, ILD_TRANSPARENT |  ILD_IMAGE, ref hIcon);

 Icon ico =  (Icon)System.Drawing.Icon.FromHandle(hIcon).Clone();
 ShellAPI.DestroyIcon(hIcon);

Everything is ok, but when it has to get smaller icons (when they don't have a size for 256x256) the function GetIcon returns me an icon with the size of 256x256 but with the icon of size 32x32 in top left corner. I want to resize this icon to the new size (256 x 256).

I don't ha开发者_JAVA百科ve any information how to have the system resize my icon to 256 x 256. Every function in iml (like GetImageInfo, GetImageRect) for this size returns an empty structure.

It's possible to get information that this icon is smaller and i can get icon from another source.


Looks like, since Vista, Microsoft expects developers to rely on IShellItem and IShellItemImageFactory interfaces. Unlike IImageList implementation of the system image lists, which is badly broken (most methods fail with E_NOTIMPL, icon sizes are not reported), IShellItemImageFactory produces images exactly like they are displayed in Explorer. In case of small icons requested in "jumbo" size, they are centered and surrounded by a border (on Windows 7, at least). While it is less efficient and more memory consuming to use than IImageList, Explorer probably uses it too, so it's no big deal.

See IShellItemImageFactory::GetImage method on MSDN for more details.

There's a library for .NET which supports these interfaces: Windows® API Code Pack for Microsoft® .NET Framework.


While this doesn't exactly answer your question (there's still no reliable way to determine size of icons), I think resizing a small 32x32 icon to 256x256 is a bad idea, and Explorer way (resizing only up to 48x48, then centering) should be preffered. This will also provide a consistent behavior which is a good idea.

Considering questions like this have been posted in many places, and none have been answered for years, I'm afraid more information can only be obtained by reverse-engineering Windows Shell, and in particular standard/default IShellItemImageFactory::GetImage implementation. Geoff Chappell did quite a bit of reverse engineering of shell, so maybe it's worth trying to ask him...


You could execute some code to identify the image metrics and use the following when required:

var hres = SHGetImageList(SHIL_LARGE, ref iidImageList, out iml);

SHIL_LARGE is for 32x32.

The IImageList pointer type, such as that returned in the ppv parameter, can be cast as an HIMAGELIST as needed; for example, for use in a list view. Conversely, an HIMAGELIST can be cast as a pointer to an IImageList. As of Windows Vista, SHIL_SMALL, SHIL_LARGE, and SHIL_EXTRALARGE scale with dots per inch (dpi) if the process is marked as dpi-aware. To set these types to be dpi-aware, call SetProcessDPIAware. SHIL_JUMBO is fixed at 256 pixels regardless of the dpi-aware setting.

http://msdn.microsoft.com/en-us/library/windows/desktop/bb762185(v=vs.85).aspx


I have run your example using

const string IID_IImageList = "46EB5926-582E-4017-9FDF-E8998DAA0950";
const string IID_IImageList2 = "192B9D83-50FC-457B-90A0-2B82A8B5DAE1";

defined in CommonControls.h Upon running:

        IEnumerable<int> shils =  new int[]{ 
            ShellAPI.SHIL_EXTRALARGE, 
            ShellAPI.SHIL_JUMBO, 
            ShellAPI.SHIL_SYSSMALL,
            ShellAPI.SHIL_LARGE, 
            ShellAPI.SHIL_SMALL,
            ShellAPI.SHIL_LAST
        };
        ShellAPI.IImageList ppv = null;
        Guid guil = new Guid(IID_IImageList2);//or IID_IImageList
        foreach (int iil in shils)
        {
            ShellAPI.SHGetImageList(iil, ref guil, ref ppv);
            int noImages = 0;
            ppv.GetImageCount(ref noImages);
            //...
        }

the images count stays constant. Therefore I must disagree with

when they don't have a size for 256x256

For every image list type there's a constant number of images, so no icons missing for the jumbo setting.

I have persisted all found icons with all resolutions (16x16,32x32,48x48,256x256). The aspect ratio is identical between all different sizes of the same icon (same image list index/different resolution). Aspect ratio means that the 256x256 version is not the 48x48 version pasted in a corner, and the rest black background padding.

Moreover, all the

icons with the size of 256x256 but with the icon of size 32x32 in top left corner are in fact overlay images, as one can check:

int currentImageListIndex; //loop by noImages above
int idx0Based=0;
ppv.GetOverlayImage(currentImageListIndex+1, ref idx0Based);

Quality degradation can be easily found out using IImageAList::GetItemFlags and checking the output dwFlags parameter for ILIF_LOWQUALITY, msdn quote below

Windows Vista and later. Indicates that the item in the imagelist was generated via a StretchBlt function, consequently image quality may have degraded

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号