检索 Shell 图标






4.90/5 (13投票s)
获取外壳图标,即使它们已被自定义
引言
很久以前,我在一个项目中需要使用文件夹图标。因为我喜欢一致的用户界面,所以我决定使用 Windows Explorer 中使用的图标。正如你们中的一些人可能知道的,这个图标包含在 shell32.dll 中,关闭的文件夹是第 3 个,打开的文件夹是第 4 个。您可以使用 ExtractIconEx
来提取此类图标。所以这很容易实现。到目前为止,一切都很好。
不幸的是,几天后一位同事指出,我的代码没有尊重他自定义的外壳图标。经过一番研究,我发现了如何更改 Windows 用于显示文件夹以及其他一些项目的图标。
基础
您只需在注册表中 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Icons
添加一个值。它的名称是您要更改的外壳图标的索引,而值数据包含图标的文件名及其索引,用“,
”分隔。例如,以下注册表值会将打开的文件夹的图标更改为 C:\OpenFolder.ico 中的图标(对于 .ico 文件,您必须将索引设置为 0)
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Icons] "4"="C:\OpenFolder.ico,0"
代码
作为解决方案,我实现了以下方法
HICON ExtractShellIcon (int nIndex, bool bLargeIcons /*= false*/) { HICON hIcon = NULL; // Shell icons can be customized by the registry: // HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\ // Explorer\Shell Icons // "<ShellIconIndex>" = "<Filename>,<IconIndex>" // E.g. // "3" = "c:\MyFolderIcon.ico,1" HKEY hkeyShellIcons; if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows\\ CurrentVersion\\Explorer\\Shell Icons"), 0, KEY_READ, &hkeyShellIcons) == ERROR_SUCCESS) { TCHAR szBuffer[ MAX_PATH * sizeof TCHAR]; DWORD dwSize = MAX_PATH * sizeof TCHAR; TCHAR szIndex[6] = {0}; _stprintf (szIndex, _T("%d"), nIndex); if (RegQueryValueEx (hkeyShellIcons, szIndex, NULL, NULL, (LPBYTE)szBuffer, &dwSize) == ERROR_SUCCESS) { #ifdef _AFXDLL CString strFileName, strIndex; VERIFY (AfxExtractSubString (strFileName, szBuffer, 0, _T(','))); VERIFY (AfxExtractSubString (strIndex, szBuffer, 1, _T(','))); ExtractIconEx ( strFileName, atoi(strIndex), bLargeIcons ? &hIcon : NULL, bLargeIcons ? NULL : &hIcon, 1); #else std::vector<std::tstring> ls; tokenize (std::back_inserter(ls), szBuffer, _T(",")); ExtractIconEx ( ls[0].c_str(), atoi(ls[1].c_str()), bLargeIcons ? &hIcon : NULL, bLargeIcons ? NULL : &hIcon, 1); #endif } RegCloseKey( hkeyShellIcons ); } // Not customized? Then get the original icon from // shell23.dll if (!hIcon) ExtractIconEx ( _T("SHELL32.DLL"), nIndex, bLargeIcons ? &hIcon : NULL, bLargeIcons ? NULL : &hIcon, 1); return hIcon; }
注释
您可能注意到在非 MFC 版本中调用了 tokenize
函数。它只是一个包含在源文件中的简单分词器。
用法
要使用我的方法,您可以直接调用 ExtractShellIcon
。第一个参数指定您要检索哪个图标。我在下面编译了 shell32.dll 中包含的图标列表。第二个参数只是说明您想要大图标还是小图标。
可用外壳图标表
0 | SI_UNKNOWN | 未知文件类型 |
1 | SI_DEF_DOCUMENT | 默认文档 |
2 | SI_DEF_APPLICATION | 默认应用程序 |
3 | SI_FOLDER_CLOSED | 关闭的文件夹 |
4 | SI_FOLDER_OPEN | 打开的文件夹 |
5 | SI_FLOPPY_514 | 5 1/4 英寸软盘 |
6 | SI_FLOPPY_35 | 3 1/2 英寸软盘 |
7 | SI_REMOVABLE | 可移动驱动器 |
8 | SI_HDD | 硬盘驱动器 |
9 | SI_NETWORKDRIVE | 网络驱动器 |
10 | SI_NETWORKDRIVE_DISCONNECTED | 网络驱动器离线 |
11 | SI_CDROM | CD 驱动器 |
12 | SI_RAMDISK | RAM 磁盘 |
13 | SI_NETWORK | 整个网络 |
14 | ? | |
15 | SI_MYCOMPUTER | 我的电脑 |
16 | SI_PRINTMANAGER | 打印管理器 |
17 | SI_NETWORK_NEIGHBORHOOD | 网络邻居 |
18 | SI_NETWORK_WORKGROUP | 网络工作组 |
19 | SI_STARTMENU_PROGRAMS | 开始菜单程序 |
20 | SI_STARTMENU_DOCUMENTS | 开始菜单文档 |
21 | SI_STARTMENU_SETTINGS | 开始菜单设置 |
22 | SI_STARTMENU_FIND | 开始菜单查找 |
23 | SI_STARTMENU_HELP | 开始菜单帮助 |
24 | SI_STARTMENU_RUN | 开始菜单运行 |
25 | SI_STARTMENU_SUSPEND | 开始菜单暂停 |
26 | SI_STARTMENU_DOCKING | 开始菜单对接 |
27 | SI_STARTMENU_SHUTDOWN | 开始菜单关机 |
28 | SI_SHARE | 共享叠加(手形图标) |
29 | SI_SHORTCUT | 快捷方式叠加(小箭头) |
30 | SI_PRINTER_DEFAULT | 默认打印机叠加(小勾号) |
31 | SI_RECYCLEBIN_EMPTY | 回收站空 |
32 | SI_RECYCLEBIN_FULL | 回收站满 |
33 | SI_DUN | 拨号网络文件夹 |
34 | SI_DESKTOP | 桌面 |
35 | SI_CONTROLPANEL | 控制面板 |
36 | SI_PROGRAMGROUPS | 程序组 |
37 | SI_PRINTER | 打印机 |
38 | SI_FONT | 字体文件夹 |
39 | SI_TASKBAR | 任务栏 |
40 | SI_AUDIO_CD | 音频 CD |
41 | ? | |
42 | ? | |
43 | SI_FAVORITES | IE 收藏夹 |
44 | SI_LOGOFF | 开始菜单注销 |
45 | ? | |
46 | ? | |
47 | SI_LOCK | 锁定 |
48 | SI_HIBERNATE | Hibernate |
您可能已经注意到此表中存在几个空格。不幸的是,我目前不知道这些图标的用途。
演示应用程序
本文提供的演示只是采用了表中所示的常量,并将关联的图标插入到两个 listview 控件中,一个包含大图标,另一个包含小图标。
历史
2002 年 6 月 9 日
- 初始发布/上传
2002 年 6 月 10 日
- 为演示应用程序源添加了 VC6 工作区和项目
- 现在,压缩的演示可执行文件是 VC6 构建的,因此不再需要 MFC7 库(并非所有人都可能已经安装了 VS.NET)
- 对 ShellIcons.h 进行了一些清理
结语
如果有人知道缺失图标的用途,请随时写下适当的评论,以便我更新本文。
修订历史
2002 年 6 月 20 日 - 初始修订
2002 年 6 月 20 日 - 重新格式化代码和文本