系统图像列表(有时亦被称作 Shell 图标缓存)是一个由 Windows Shell 维护的图标资源,资源管理器和其它应用程序使用这个列表来显示系统对象、程序和文件类型的图标。其实就是一个简单的 HIMAGELIST(可以用图像列表 API 存取的标准图像列表),一些应用程序可能会发现显示系统提供的图标更好一些,而不是自己内部存储这些图标的副本。所以,本教程的目的就是解说如何存取系统的图像列表,并在你的应用程序里使用它。
简单的方法
如果你先前从未花时间浏览过 MSDN 的话,你可能就会调用 SHGetFileInfo API(由 shell32.dll 导出,Win9x/WinNT4/2000/XP 都可使用)。这个函数看起来是这样的:
DWORD_PTR SHGetFileInfo(
    LPCTSTR     pszPath,              
    DWORD       dwFileAttributes,
    SHFILEINFO *psfi,
    UINT        cbFileInfo,
    UINT        uFlags
);
复制代码
此函数可被用来获得指定文件的信息,uFlags 参数则指定了要获取的具体哪些信息。对于这个参数来说,有两个非常有趣的取值: SHGFI_ICON 和 SHGFI_SYSICONINDEX 。当指定了这两个值之后,SHGetFileInfo 会返回系统图像列表的句柄,并将相应的图标类型索引保存到 SHFILEINFO 结构中。
下面的调用示范了可能的使用方法:
SHFILEINFO shfi;
HIMAGELIST hSysImgList;
...
hSysImgList = (HIMAGELIST)SHGetFileInfo(
       "C:", 
       0, 
       &shfi, 
       sizeof(SHFILEINFO), 
       SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_ICON);
平台差异
在 Windows 9x 和 Windows NT 系列的操作系统之间,存在一个很微小但又十分重要的区别。在 Windows 9x 下,SHGetFileInfo 返回系统图像列表的句柄,这个句柄是被所有进程共享的。这个图像列表与资源管理器所使用的以及 Shell 用来显示系统图标的图像列表是同一个图像列表,这就意味着如果一个进程对这个图像列表进行了任何的误操作,那么所有的进程(包括资源管理器)都会受到影响。
在 Windows NT (以及 2000/XP )之下,就会略有不同。由于系统架构的不同,亦为保持一个稳定的操作环境,SHGetFileInfo 会为每个请求系统图像列表的进程返回一份单独的拷贝。详而述之,SHGetFileInfo 并不会像 Windows 9x 那样返回一个完整的系统图像列表——只有在 SHGetFileInfo 调用中所请求的图标会出现在返回的图像列表中。对于 99% 的情况来说并没有什么关系,但是由于我们要制作一个浏览整个图像列表的应用程序,这就向我们提出了一个问题。
在所有的 Windows 版本中定位系统图像列表
闲话休叙,在 shell32.dll 中有一个名为 Shell_GetImageLists 的未公开 API ,——你可能猜到了,它会返回系统图像列表的句柄(注意函数名的复数形式,有大图标和小图标的版本)。这个 shell32.dll 中未公开的 API 适用于所有的 Windows 版本。
BOOL WINAPI Shell_GetImageLists(HIMAGELIST *lphimlLarge, HIMAGELIST *lphimlSmall);
我们需要的另一个 API 是 FileIconInit, 它只适用于 Windows NT/2000/XP 。这不是问题,因为我们只需要在 Windows NT 下调用它。
BOOL WINAPI FileIconInit(BOOL bFullInit);
这些 API 并未用函数名导出,而只有序号:
// shell32 未公开的函数
Shell_GetImageLists @71
FileIconInit        @660
复制代码
获得了这一信息后,我们现在可以编写一个函数来返回系统图像列表的句柄了。第一步是定义两个 typedef ,以使我们的工作更容易些。
typedef BOOL (WINAPI * SH_GIL_PROC)(HIMAGELIST *phLarge, HIMAGELIST *phSmall);
typedef BOOL (WINAPI * FII_PROC)   (BOOL fFullInit);
复制代码
SH_GIL_PROC 是 Shell_GetIconLists_Procecedure 简写,同理 FII_PROC 是 FileIconInit_Procedure 的简写。现在我们可以定位这些 shell32.dll 未公开的的函数了,以便调用。
HMODULE      hShell32;
SH_GIL_PROC  Shell_GetImageLists;
FII_PROC     FileIconInit;    
// 装载 shell32.dll ,如果它尚未装载的话
hShell32 = LoadLibrary("shell32.dll");
if(hShell32 == 0)
    return FALSE; //
// 从 shell32.dll 中获取未公开的 API
//
Shell_GetImageLists  = (SH_GIL_PROC) GetProcAddress(hShell32, (LPCSTR)71);
FileIconInit         = (FII_PROC)    GetProcAddress(hShell32, (LPCSTR)660);
复制代码
请注意我们是如何把序号参数传给 GetProcAddress 的。OK ,现在我们已经获得了所需的函数指针,可以进行处理了。
// 初始化本进程的图像列表——在 Win95/98 下函数是不可用的
if(FileIconInit != 0)
    FileIconInit(TRUE);
// 获得大图标和小图标的系统图像列表句柄

Shell_GetImageLists(phLarge, phSmall);

// 初始化本进程的图像列表, 为加载系统图标列表做准备
typedef BOOL (WINAPI * pfn_FileIconInit) (BOOL fFullInit);
pfn_FileIconInit FileIconInit = (pfn_FileIconInit) GetProcAddress(LoadLibrary("shell32.dll"), (LPCSTR)660);
FileIconInit(TRUE);

// 不要卸载 shell32.dll !
上面代码段最后的注释指出“不要卸载 shell32.dll ”,这是非常重要的。因为只要 shell32.dll 被卸载,系统图像列表就会被销毁,这样一来我们是前的所有工作都会付之东流。
永远不要修改或删除系统图像列表!
在我们往下进行之前,你应该了解另外一条重要的信息。你永远不要去尝试在系统图像列表中添加、删除图标,也不要删除系统图像列表。这一点在 SHGetFileInfo 的文档中已经解释得很清楚了,而且这也是个很好的意见。但是,仍然有一个很简单的方法会将系统图像列表误删。
现在来说这个问题。在默认情况下,当一个列表视图(ListView)控件被销毁后,它会自动调用 ImageList_Destroy API 来删除与之关联的图像列表。也就是说,在默认的情况下你甚至要求你的程序删除系统图像列表!——是的,当时就是这样。所幸,列表视图控件有一个 LVS_SHAREIMAGELISTS 样式可以防止它删除它的图像列表。(在这种情况下,请确认你设置了这个样式!)
十分诡异,树型视图(TreeView)控件却不会引起这一问题—— MSDN 指出树型视图不会销毁与之关联的图像列表,所以只有列表视图控件需要特别注意。

C++获取系统图标方法相关推荐

  1. Qt中如何获取系统图标

    Qt中获取系统图标.类型是通过QFileIconProvider来实现的,具体如下: 一.Qt获取系统文件图标 1.获取文件夹图标 QFileIconProvider icon_provider; Q ...

  2. 根据文件扩展名获取系统图标

    1 /// <summary> 2 /// 根据文件后缀名获取系统图标. 3 /// </summary> 4 /// <param name="extensi ...

  3. vb.net 获取系统图标_【系统更新V4】优麒麟 20.04 LTS持续完善!优化高清屏支持,上架6款新应用!...

    自优麒麟 20.04 LTS 发布后,官方一直积极从各个渠道汇总大家的反馈建议,并针对存在的问题进行记录和处理.对于系统使用过程中遇到的任何问题或者建议,欢迎大家通过系统中用户反馈程序.微信交流群.Q ...

  4. vb.net 获取系统图标_win10美化:全面更改系统图标

    昨天发了一个修改电脑系统字体的工具之后,不少小伙伴都觉得小帮使用的系统图标非常好看.今天我们就来聊聊如何一键更改win10系统图标. iConadams 700 icons iPack 这个图标包一共 ...

  5. vb.net 获取系统图标_优麒麟19.10.1正式发布:控制面板新增图标主题与字体高级设置...

    今日,Linux开源桌面操作系统优麒麟宣布推出19.10.1版本,内核升级到5.3.0.19.22,火狐浏览器升级到70.0版本,主要修复了用户通过论坛.微信.官网等平台反馈的问题,新增了控制面板中图 ...

  6. STM32F407获取系统时钟方法

    获取当前时钟频率方法(库函数) RCC_ClocksTypeDef是一个结构体,定义一个全局变量: RCC_ClocksTypeDef Get_RCC_Clocks; RCC_ClocksTypeDe ...

  7. vb.net 获取系统图标_「快捷指令」桌面图标任意摆放

    在往期文章中已经为大家分享了桌面图标任意摆放的方法,通过快捷指令进行设置,但只能使用纯色壁纸,部分小伙伴并不是很喜欢,希望可以有不受壁纸限制的方法. 今天为大家更新快捷指令规则文件,桌面图标任意摆放, ...

  8. vb.net 获取系统图标_微商城和小程序商城图标8个设计注意事项

    我们每天都在设计图标,并且保持这样的状态超过15年.身为设计师,想必你已经阅读过很多关于图标设计的文章,但是今天的文章不一样. 今天的文章不会花费很长时间来单独介绍某一个图标的设计.而是设计任何一套图 ...

  9. IO流文件的相对路径及获取系统路径方法

    本机测试的时候经常没有问题,但是一上服务器就出现无法读取文件的事情可以通过class反射的方法获取文件的系统路径,免得出现异常. 以下是一个测试的demo,通过注释的方式说明了一下问题与解决方案. p ...

最新文章

  1. ASP.NET MVC的生命周期与网址路由
  2. 39所强基计划试点高校已全部公布招生简章
  3. spark学习-52-Spark的org.apache.spark.SparkException: Task not serializable
  4. Android 开发未来的出路何在? | 技术头条
  5. 刚刚,北京正式允许无人车上路路测!准入门槛500万元
  6. Java集合框架源码解读(2)——HashMap
  7. 安卓listview点击空白事件_王者荣耀安卓苹果ios改空白名;重复名字特殊昵称教程...
  8. 华为微博抽奖头目两次中奖:大哥咱玩不起,不玩行不行?
  9. Golang之并发资源竞争(互斥锁)
  10. 解决ubuntu 20.04 打不开设置的问题
  11. docker安装oracle11g史上最全步骤(带图文)
  12. centOS安装yasm
  13. SqlServer 查询一段时间,没有数据自动补充0
  14. 阿里巴巴大数据学院落地成都,计划5年培养2000名高端专业人才
  15. 如何查看Tomcat是否安装配置成功
  16. 日本疫情 和 goto旅行优惠
  17. CTR 预测理论(九):Boosting 集成算法中 Adaboost, GBDT 与 XGBoost 的区别
  18. poj 1088 滑雪 (dp)
  19. 《横向领导力》思维导图
  20. Node之父发布新项目deno:下一代Node;百度推出没有广告的简单搜索;甲骨文计划砍掉Java序列化功能;丨Q新闻...

热门文章

  1. DBeaver Ultimate 开始教程
  2. 用Linux内核的瑞士军刀-eBPF实现socket转发offload
  3. 无心剑英汉双语诗001.《春游》
  4. MHDD不识别被检测的硬盘解决方法   (BIOS)可识别
  5. c语言实现年月日用ASCII码显示
  6. linux mknod command
  7. MongoDB(6)- BSON 数据类型
  8. Pytorch实现CapsuleNet
  9. java获取域名CNAME 或A 记录解析值 lookup 和 dig 方式
  10. Pycharm设置字体放大(缩小)快捷键,滑轮放大缩小(手把手教!超容易!)