Retrieving shell icons

Retrieving shell icons

 

Sample Image - shellicon.png

Introduction

Some time ago I had to use a folder icon in one of my projects. Because I like consistent UI's, I decided to dispose the icon that is used by the Windows Explorer. As some of you may know, this icon is contained in the shell32.dll at position 3 for a closed folder, and 4 for an open folder. You can extract such icons by using ExtractIconEx. So this has been easy to implement. So far, so good.

Unfortunately, a few days later a co-worker annotated, that my code did not respect his customized shell icons. After some research, I discovered how you can change the icons used by Windows to present folders as well as some other items.

Basics

You just have to add a value to the registry at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Icons. Its name is the index of the shell icon you want to change, and the value data contains the filename of the icon and its index, separated by ','. E.g. following registry value changes the icon of open folders to that icon in C:\OpenFolder.ico (for .ico files you have to set the index to 0):

 
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Icons]
"4"="C:\OpenFolder.ico,0"

Sample Image - shellicon_example.png

The Code

As a solution, I have implemented the following method:

 
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;
}

Annotation

You may have noticed the tokenize function called in the non-MFC version. It's just a simple tokenizer included in the source file.

Usage

To use my method, you can just call ExtractShellIcon. The first parameter specifies, which icon you want to retrieve. I've compiled a list of icons contained in shell32.dll below. The second parameter just says whether you want a small or a large icon.

Table of available shell icons

0 SI_UNKNOWN Unknown File Type
1 SI_DEF_DOCUMENT Default document
2 SI_DEF_APPLICATION Default application
3 SI_FOLDER_CLOSED Closed folder
4 SI_FOLDER_OPEN Open folder
5 SI_FLOPPY_514 5 1/4 floppy
6 SI_FLOPPY_35 3 1/2 floppy
7 SI_REMOVABLE Removable drive
8 SI_HDD Hard disk drive
9 SI_NETWORKDRIVE Network drive
10 SI_NETWORKDRIVE_DISCONNECTED network drive offline
11 SI_CDROM CD drive
12 SI_RAMDISK RAM disk
13 SI_NETWORK Entire network
14   ?
15 SI_MYCOMPUTER My Computer
16 SI_PRINTMANAGER Printer Manager
17 SI_NETWORK_NEIGHBORHOOD Network Neighborhood
18 SI_NETWORK_WORKGROUP Network Workgroup
19 SI_STARTMENU_PROGRAMS Start Menu Programs
20 SI_STARTMENU_DOCUMENTS Start Menu Documents
21 SI_STARTMENU_SETTINGS Start Menu Settings
22 SI_STARTMENU_FIND Start Menu Find
23 SI_STARTMENU_HELP Start Menu Help
24 SI_STARTMENU_RUN Start Menu Run
25 SI_STARTMENU_SUSPEND Start Menu Suspend
26 SI_STARTMENU_DOCKING Start Menu Docking
27 SI_STARTMENU_SHUTDOWN Start Menu Shutdown
28 SI_SHARE Sharing overlay (hand)
29 SI_SHORTCUT Shortcut overlay (small arrow)
30 SI_PRINTER_DEFAULT Default printer overlay (small tick)
31 SI_RECYCLEBIN_EMPTY Recycle bin empty
32 SI_RECYCLEBIN_FULL Recycle bin full
33 SI_DUN Dial-up Network Folder
34 SI_DESKTOP Desktop
35 SI_CONTROLPANEL Control Panel
36 SI_PROGRAMGROUPS Program Group
37 SI_PRINTER Printer
38 SI_FONT Font Folder
39 SI_TASKBAR Taskbar
40 SI_AUDIO_CD Audio CD
41   ?
42   ?
43 SI_FAVORITES IE favorites
44 SI_LOGOFF Start Menu Logoff
45   ?
46   ?
47 SI_LOCK Lock
48 SI_HIBERNATE Hibernate

You might have noticed that they're a several gaps in this table. Unfortunately, I do not know currently what these icons are used for.

The demo application

The demo provided with this article simply takes the constants depicted in the table above and inserts the associated icons into two listview ctrl's, one with large icons, the other with small ones.

posted @ 2022-12-13 15:02  小风风的博客  阅读(43)  评论(0编辑  收藏  举报