SHGetImageList - SHIL_JUMBO用于较小的图标(32,32)

时间:2011-06-23 17:14:42

标签: c# windows-vista icons

在我的代码中,我通过函数SHGETImageList得到一个图像列表,大小为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);

一切都很好,但是当它必须得到更小的图标(当它们的大小不是256x256时),GetIcon函数会返回一个大小为256x256的图标,但左上角的图标大小为32x32 。我想将此图标调整为新大小(256 x 256)。

我没有任何关于如何让系统将我的图标大小调整为256 x 256的信息。对于这个大小,iml中的每个函数(如GetImageInfo,GetImageRect)都会返回一个空结构。

可以获得此图标较小的信息,我可以从其他来源获取图标。

3 个答案:

答案 0 :(得分:2)

看起来,自Vista以来,微软希望开发人员依赖IShellItemIShellItemImageFactory接口。与IImageList系统映像列表的实现不同(大多数方法都失败了E_NOTIMPL,未报告图标大小),IShellItemImageFactory生成的图像与在资源管理器中显示的图像完全相同。如果以“巨型”大小请求小图标,它们将居中并被边框包围(至少在Windows 7上)。虽然使用它比IImageList效率更低,内存消耗更多,但资源管理器也可能使用它,所以这没什么大不了的。

有关详细信息,请参阅MSDN上的IShellItemImageFactory::GetImage method

.NET有一个支持这些接口的库:Windows® API Code Pack for Microsoft® .NET Framework


虽然这并没有完全回答你的问题(仍然没有可靠的方法来确定图标的大小),我认为将一个小的32x32图标调整为256x256是一个坏主意,而且Explorer方式(仅调整大小为48x48,然后居中)应该优先考虑。这也将提供一致的行为,这是一个好主意。

考虑到这样的问题已在很多地方发布,多年来都没有得到解答,我担心只能通过逆向工程Windows Shell获得更多信息,特别是标准/默认IShellItemImageFactory::GetImage实现。 Geoff Chappell对shell进行了相当多的逆向工程,所以也许值得尝试问他......

答案 1 :(得分:0)

您可以执行一些代码来识别图像指标,并在需要时使用以下内容:

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

SHIL_LARGE适用于32x32。

IImageList指针类型,例如ppv参数中返回的指针类型,可以根据需要转换为HIMAGELIST;例如,用于列表视图。相反,HIMAGELIST可以被转换为指向IImageList的指针。 自Windows Vista起,SHIL_SMALL, SHIL_LARGE 和SHIL_EXTRALARGE 缩放,每英寸点数(dpi),如果进程标记为dpi-aware 。要将这些类型设置为dpi-aware,请调用SetProcessDPIAware。无论dpi-aware设置如何,SHIL_JUMBO都固定为256像素。

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

答案 2 :(得分:-1)

我已经使用

运行了您的示例
const string IID_IImageList = "46EB5926-582E-4017-9FDF-E8998DAA0950";
const string IID_IImageList2 = "192B9D83-50FC-457B-90A0-2B82A8B5DAE1";

在CommonControls.h中定义 运行时:

        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);
            //...
        }

图像计数保持不变。因此,我必须不同意

  

当他们没有256x256的大小时

对于每个图像列表类型,都有一定数量的图像,因此不会丢失巨型设置的图标。

我坚持使用所有分辨率(16x16,32x32,48x48,256x256)保存所有找到的图标。 纵横比在相同图标的所有不同尺寸(相同图像列表索引/不同分辨率)之间是相同的。宽高比意味着256x256版本不是粘贴在角落的48x48版本,其余是黑色背景填充。

而且,所有的

  

图标大小为256x256,但左上角的图标大小为32x32   实际上是覆盖图像,可以检查:

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

使用IImageAList :: GetItemFlags可以轻松找到质量下降,并检查输出dwFlags参数是否为ILIF_LOWQUALITY,下面是msdn引用

  

Windows Vista及更高版本。表示图像列表中的项目是通过StretchBlt函数生成的,因此图像质量可能会降低