Retrieving shell icons
Retrieving shell icons
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"
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.