如何在Windows中获取任意文件的关联图标(.ICO),并在Delphi中显示所有图标图像大小?

3
我想要一个函数,它可以获取 Windows 中任何文件路径(任何文件系统对象——文件、文件夹、驱动器、快捷方式等)并返回与之对应的 .ICO 文件(或带有所有图像大小表示的图标句柄)。例如,如果我在 Windows 7 中指定 'C:\MyTextFile.txt',我将获得 .txt 文件的所有 256x256、48x48、32x32 和 16x16 大小的 .ICO 文件,位置在 imageres.dll 的偏移量为 102:

imageres.dll 中的文本文件图标

^ Stardock IconPackager 安装的图标选项卡,可定位到文件系统对象的图标

从我的研究所得,这似乎并不容易。有 ExtractIconEx 函数,但它只能提供 16px 和 32px 的表示。还有 这篇文章显示了如何获取一般为 16、32、48 和 256 像素的 SHIL_SMALL、SHIL_LARGE、SHIL_EXTRALARGE 和 SHIL_JUMBO 大小,但这并不一定涵盖存储在 .ICO 文件中的其他尺寸。例如,某些图标存储的不仅仅是四个尺寸,而是 10 多个不同尺寸。

所以我想:

  1. 找到文件系统对象图标的位置,并
  2. 从 DLL、EXE 或任何封装它的资源中检索它。

我猜一个问题是:这是 Windows 注册表的任务吗?如下面所示,注册表的 txtfile->DefaultIcon 值包含了 .txt 文件类型的图标位置。

Windows 注册表中的 txtfile

但是,也有一些独立的 .exe 文件,例如自包含一个不会存储在注册表中的图标。

最终,我希望能在 TImage 中显示所有不同大小,并且可能将它们一起输出到一个 .ICO 文件中。感谢任何帮助。

1个回答

4
作为一种选择,有一个 IShellItemImageFactory 接口,提供关于 IShellItem(文件)缩略图的信息。该接口可以返回所需大小的缩略图,但需要使用透明度来实现一些魔法。有两个选项 - 缩略图或图标。对于 Folder,它始终返回相同的图像(更新:这不是真的,文件夹缩略图还包含其包含的小文件预览)。但例如对于 png,它会返回带有 thumbnail 标志的小预览图像和带有 icon 标志的 png 图片图标(0 是默认值)。对于您的任务,您应该使用 SIIGBF_ICONONLY 标志来获取文件/文件夹/驱动器系统图标。
以下是加载不同尺寸图像的示例代码。
type
    TIconSize = (is16, is32, is48, is64, is96, is128, is256);
const
    ICON_SIZE : array[TIconSize] of integer = (16,32,48,64,96,128,256);

我在表单上添加了 SizeRadioGroup : TRadioGroupImage1 : TImageImage1.Size 设置为 256。点击 SizeRadioGroup 的事件处理程序会将缩略图加载到 Image1

procedure TForm7.SizeRadioGroupClick(Sender: TObject);
const FILE_NAME = 'd:\_projects\';
var icoSize : TIconSize;
    wh : integer;
    siif : IShellItemImageFactory;
    size : TSize;
    icon_handle : HBitmap;
    bm : TBitmap;
begin
    icoSize := TIconSize(SizeRadioGroup.ItemIndex);
    wh := ICON_SIZE[icoSize];

    SHCreateItemFromParsingName(FILE_NAME, nil, IID_IShellItemImageFactory, siif);

    size.cx := wh;
    size.cy := wh;

    siif.GetImage(size, 0 {SIIGBF_THUMBNAILONLY}{SIIGBF_ICONONLY}, icon_handle);
    bm := TBitmap.Create();
    bm.PixelFormat := pf32bit;
    try
        bm.Handle := icon_handle;
        Image1.Picture.Assign(bm);
    finally
        bm.Free();
    end;
end;

感谢您提供这种方法。缩略图很棒,但我真的不想要缩略图。例如,对于JPEG文件,我希望显示.jpg文件类型图标,而不是.jpg图像的缩略图。其他图像、视频等文件也是如此。 - spurgeon
@spurgeon 在调用 GetImage 方法时,将 SIIGBF_ICONONLY 作为第二个参数使用以获取文件类型图标。它只获取图标,但在透明度方面存在问题(可能与 TImage 设置有关)。 - teran
啊,抱歉,不知怎么错过了。确实,图标以不同的大小返回,但是带有令人讨厌的黑色背景。我使用了这个AlphaBlend帖子将具有alpha的位图绘制到画布上,它起作用了。但是,在XP上程序崩溃,即使我将代码简化为只有上面的IShellItemImageFactory。错误是“外部异常c06d007f。” 有什么想法吗?它在Windows Vista和7上运行。+1的答案,但我不能接受,因为我的原始问题是关于获取.ICO文件的。 - spurgeon
是的,在WinXP中不支持IShellItemImagefactory,只有Vista及以上版本支持;http://msdn.microsoft.com/en-us/library/windows/desktop/bb761084%28v=vs.85%29.aspx - teran

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接