65.9K
CodeProject 正在变化。 阅读更多。
Home

检索 Shell 图标

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (13投票s)

2002 年 6 月 9 日

CPOL

3分钟阅读

viewsIcon

258246

downloadIcon

5926

获取外壳图标,即使它们已被自定义

Sample Image - shellicon.png

引言

很久以前,我在一个项目中需要使用文件夹图标。因为我喜欢一致的用户界面,所以我决定使用 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"

Sample Image - shellicon_example.png

代码

作为解决方案,我实现了以下方法

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 中包含的图标列表。第二个参数只是说明您想要大图标还是小图标。

可用外壳图标表

0SI_UNKNOWN未知文件类型
1SI_DEF_DOCUMENT默认文档
2SI_DEF_APPLICATION默认应用程序
3SI_FOLDER_CLOSED关闭的文件夹
4SI_FOLDER_OPEN打开的文件夹
5SI_FLOPPY_5145 1/4 英寸软盘
6SI_FLOPPY_353 1/2 英寸软盘
7SI_REMOVABLE可移动驱动器
8SI_HDD硬盘驱动器
9SI_NETWORKDRIVE网络驱动器
10SI_NETWORKDRIVE_DISCONNECTED网络驱动器离线
11SI_CDROMCD 驱动器
12SI_RAMDISKRAM 磁盘
13SI_NETWORK整个网络
14?
15SI_MYCOMPUTER我的电脑
16SI_PRINTMANAGER打印管理器
17SI_NETWORK_NEIGHBORHOOD网络邻居
18SI_NETWORK_WORKGROUP网络工作组
19SI_STARTMENU_PROGRAMS开始菜单程序
20SI_STARTMENU_DOCUMENTS开始菜单文档
21SI_STARTMENU_SETTINGS开始菜单设置
22SI_STARTMENU_FIND开始菜单查找
23SI_STARTMENU_HELP开始菜单帮助
24SI_STARTMENU_RUN开始菜单运行
25SI_STARTMENU_SUSPEND开始菜单暂停
26SI_STARTMENU_DOCKING开始菜单对接
27SI_STARTMENU_SHUTDOWN开始菜单关机
28SI_SHARE共享叠加(手形图标)
29SI_SHORTCUT快捷方式叠加(小箭头)
30SI_PRINTER_DEFAULT默认打印机叠加(小勾号)
31SI_RECYCLEBIN_EMPTY回收站空
32SI_RECYCLEBIN_FULL回收站满
33SI_DUN拨号网络文件夹
34SI_DESKTOP桌面
35SI_CONTROLPANEL控制面板
36SI_PROGRAMGROUPS程序组
37SI_PRINTER打印机
38SI_FONT字体文件夹
39SI_TASKBAR任务栏
40SI_AUDIO_CD音频 CD
41?
42?
43SI_FAVORITESIE 收藏夹
44SI_LOGOFF开始菜单注销
45?
46?
47SI_LOCK锁定
48SI_HIBERNATEHibernate

您可能已经注意到此表中存在几个空格。不幸的是,我目前不知道这些图标的用途。

演示应用程序

本文提供的演示只是采用了表中所示的常量,并将关联的图标插入到两个 listview 控件中,一个包含大图标,另一个包含小图标。

历史

2002 年 6 月 9 日

  • 初始发布/上传

2002 年 6 月 10 日

  • 为演示应用程序源添加了 VC6 工作区和项目
  • 现在,压缩的演示可执行文件是 VC6 构建的,因此不再需要 MFC7 库(并非所有人都可能已经安装了 VS.NET)
  • ShellIcons.h 进行了一些清理

结语

如果有人知道缺失图标的用途,请随时写下适当的评论,以便我更新本文。

修订历史

2002 年 6 月 20 日 - 初始修订
2002 年 6 月 20 日 - 重新格式化代码和文本

© . All rights reserved.