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 )
{
HICON hIcon = NULL;
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 );
}
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.
History
09-Jun-2002
10-Jun-2002
- Added VC6 workspace and project to demo application source
- The zipped demo executable is now VC6 build, so the MFC7 libraries are not needed anymore (not all of you might have installed VS.NET yet)
- Some clean-up in ShellIcons.h
Epilogue
If someone knows the purpose of the missing icons, please feel free to write an appropriate comment, so I can update this article.
Revision History
20 Jun 2002 - Initial Revision
20 Jun 2002 - Reformatted Code and Text