I want to extract icons from an exe or a DLL. Well easy, you’re thinking. Yes, sure. You know this little dialog box with very nice full colored icons:
But in your application, you use the standard way to extract the icon (
ExtractIconEx) and if you ask for the recycle bin ( resID 32), you will have this :
The problem is with
ExtractIconEx. You can’t say anything about the size or the color of the icon you want.
Of course, the shell can help you with the function
SHGetFileInfo. But what about the size and the 32nd icon of a DLL?
Generality on system and icons
First of all, we need a little explanation of icon in systems like XP. From the article Icons in Win32 we have some information.
Windows Uses Different Sized Icons
Title Bar of Windows
Shell Small / Shell Large
In Windows, the system maintains the concept of two sizes of icons, small and large. Further, the shell also has a concept of small and large icons. This means that in total, Windows is aware of four different icon sizes—System Small, System Large, Shell Small, and Shell Large.
The System Large size is defined by the video driver and therefore cannot be changed dynamically. The System Large size can be queried by calling
GetSystemMetrics with the
The Shell Small size is defined by Windows, and currently Windows does not support changing this value, nor is there currently a direct way to query this value. But today in my system, the size seem to be half the size of Large Icon Size, and I don’t think Microsoft will change that very soon.
The Shell Large size is stored in the registry under the following key:
HKEY_CURRENT_USER\Control Panel\desktop\WindowMetrics\Shell Icon Size
The Shell Large size can be changed by modifying the registry or from the "Appearance" tab in the Display Properties dialog, which allows values from 16 to 72.
ExtractIcon, the SDK way
Here is the solution from the SDK:
But with these functions, you can’t specify the size or the color. So all icons are always in the form
PrivateExtractIcons looks cool …
You can specify the preferred size and the flag “
But at the end of this article you can read :
“It is recommended that you do not use it in new programs because it might be altered or unavailable in subsequent versions of Windows.” Because this function was published by Microsoft in 2002 after the settlement of the government's antitrust case.
The warning is clear, don’t use it.
ExtractIcon, the raw way
Ok, so how can we emulate
PrivateExtractIcon with documented information?
First, I just make a rapid explanation on the Portable Executable Format, because resources are stored in it.
The Portable Executable (PE) entire format consists of an MS-DOS MZ header, followed by a Real-Mode Stub Program, the PE file signature, the PE file header, the PE optional header, all of the section headers, and finally, all of the section bodies.
The MS-DOS header occupies the first 64 bytes of the PE file. The contents of this header are represented by
IMAGE_DOS_HEADER data structure. The
e_magic field of this structure is used to identify an MS-DOS compatible file type. All MS-DOS compatible executable files set this value to 0x54AD, which represents the ASCII characters MZ. The final field,
e_lfanew, is a 4-byte offset into the file where the PE file header is located.
The Real-Mode Stub Program is an actual program run by MS-DOS when the executable is loaded. For an actual MS-DOS executable image file, the application begins executing here.
For the PE file format, this signature occurs immediately before the PE file header structure.
The signature for NT is :
#define IMAGE_NT_SIGNATURE 0x00004550
Once we have the location of the file signature, the PE file follows four bytes later. The next 224 bytes in the executable file make up the PE optional header. The information corresponding to optional header is defined by
IMAGE_OPTIONAL_HEADER data structure. The optional header contains most of the meaningful information about the executable image, such as initial stack size, program entry point location, preferred base address, Operating System version, section alignment information...
The Section Table is an array of
IMAGE_NUMBER_OF_DIRECTORY ENTRIES (16 spaces reserved for entries)
IMAGE_DATA_DIRECTORYs. Each of these directories describes the location (32 bits RVA called 'Relative Virtual Address') and size (also 32 bit, called 'Size of Raw Data') of a particular piece of information, which is located in one of the sections that follow the directory entries.
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2
The resources, such as dialog boxes, menus, icons and so on, are in the data directory pointed to by
The topmost directory is analogous to the root directory of a file system. Each directory entry below the "root" is always a directory. Each of these second-level directories corresponds to a resource type (strings tables, dialogs, menus … ). Underneath each of the second-level "resource type" directories, you'll find third-level subdirectories. There's a third-level subdirectory for each resource instance.
For example, if there were five icons, there would be a second-level icons directory with five directory entries beneath it. Each of the five directory entries would themselves be a directory. The name of the directory entry corresponds to the name or ID of the resource instance. Under each of these directory entries is a single item which contains the offset to the resource data.
offset to data (
in relative virtual address form (RVA) )
offset to data
offset to data
offset to data
offset to data
So now the easy part, after finding the address in PE, we just have to call
LookupIconIdFromDirectoryEx to find the resource ID of the right icon and after
Use the code
Very easy, call:
ExtractIcons::Get with the same parameters as
Launch the demo and try the code.
I’m not sure if the raw way is better than
PrivateExtractIcons, but I’m quite sure that the PE Format will not be changed by Microsoft very soon….
If you’re looking for changes in PE for Win64, you can check whether this code will work (not tested for the moment).
Anyway, it’s working and now I can use the nice icon from shell32 with the right size and right color.
Ref PE and resource:
and of course,