browser icon
You are using an insecure version of your web browser. Please update your browser!
Using an outdated browser makes your computer unsafe. For a safer, faster, more enjoyable user experience, please update your browser today or try a newer browser.

向系统图像列表中添加图标

Posted by on 2009 年 12 月 28 日

你可以任意转载本文,但请在转载后的文章中注明作者和原始链接。
媒体约稿请联系 titilima_AT_163.com(把“_AT_”换成“@”)。

我的译作《系统图像列表》中提到过这么一句:永远不要修改或删除系统图像列表,这是由于系统图像列表是被 Shell 维护的,Shell 除了维护图像本身之外,还会维护一些有关缓存和哈希的信息以供快速存取。因此,如果直接通过 ImageList_* 相关函数贸然进行修改的话,将会导致不可预知的错误。
但是,我的确遇到了需要向这个列表中添加图标的情况,那么该怎么办呢?我固然可以对 Shell 中所维护的缓存进行直接操作,不过这样做的隐患很多,兼容性没有任何的保证。所以,我还是希望能有个更加通用的办法。在查阅了 MSDN 文档之后,我将目光聚焦在如下的函数上:

1
2
3
4
5
int SHMapPIDLToSystemImageListIndex(
    IShellFolder *psf,
    PCUITEMID_CHILD pidl,
    int *piIndex
);

这个函数的作用是,根据给定的 IShellFolder 接口和一个 PIDL,获取该 PIDL 在 Shell 图像列表中的图标索引。
经过逆向分析,发现这个函数的调用过程大致如下:

  1. 调用 IShellFolder::GetUIObjectOf,获取 IExtractIcon 接口指针;
  2. 调用 IExtractIcon::GetIconLocation,获取图标的位置信息;
  3. 调用 IExtractIcon::Extract 提取图标。

那么,我们相应的解决方案如下:

  1. 编写一个类,使其继承自 IShellFolder 和 IExtractIcon;
  2. 将所有不感兴趣的方法直接返回 E_NOTIMPL;
  3. 实现 IShellFolder::GetUIObjectOf,当接口请求为 IID_IExtractIcon 时返回 this;
  4. 实现 IExtractIcon::GetIconLocation,返回要提取的图标路径及索引;
  5. 实现 IExtractIcon::Extract,自行提取图标,或返回 S_FALSE 以使 Shell 自行提取图标。

由于无用代码太占篇幅了,因此略去。

订阅本站

4 Comments

  • At 2009.12.28 18:03, kukukuan said:

    沙发,备案没?

    • At 2009.12.29 08:50, 李马 said:

      主机不在天朝。

      • At 2009.12.30 18:48, 来者 said:

        前一段时间怎么那个titilima.cn的域名不能访问了?

        • At 2009.12.31 08:49, 李马 said:

          现在能访问,这就够了。

          (Required)
          (Required, will not be published)