Click here to Skip to main content
15,885,130 members
Articles / Multimedia / GDI
Article

Get icons from Exe or DLL the PE way

Rate me:
Please Sign up or sign in to vote.
4.89/5 (23 votes)
14 Jan 20055 min read 126.7K   6.3K   74   14
Get icons from Exe or DLL the PE way or how to emulate PrivateExtractIcons.

Introduction

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:

Image 1

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 :

Image 2

The problem is with ExtractIcon or 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

Location

Icon Size

Desktop

Shell Large

Title Bar of Windows

System Small

<Alt><Tab> Dialog

System Large

Start Menu

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 SM_CXICON and SM_CYICON parameters.

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:

ExtractIconEx

But with these functions, you can’t specify the size or the color. So all icons are always in the form DEFAULTCOLOR, DEFAULTSIZE.

PrivateExtractIcons looks cool …

You can specify the preferred size and the flag “LR_COLOR”.

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.

PE Format

Header

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// PE00

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...

Section Table

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  // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT    1  // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE  2  // Resource Directory

The resources, such as dialog boxes, menus, icons and so on, are in the data directory pointed to by IMAGE_DIRECTORY_ENTRY_RESOURCE.

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.

Root \
            DIRECTORY_ENTRY \
                        IDR_ICON_1 \
                                    offset to data ( 
                                      in relative virtual address form (RVA) )
                        IDR_ICON_2 \
                                    offset to data
                        IDR_ICON_3 \
                                    offset to data
                        IDR_ICON_4 \
                                    offset to data
                        IDR_ICON_5 \
                                    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 CreateIconFromResourceEx.

Use the code

Very easy, call: ExtractIcons::Get with the same parameters as PrivateExtractIcons.

Launch the demo and try the code.

Image 3

Conclusion

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,

Ref Icon:

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United Kingdom United Kingdom
http://dev.jesover.net

Comments and Discussions

 
Answersupport X64 modify Pin
heijiu23-Feb-14 4:17
heijiu23-Feb-14 4:17 
BugCannot Extract icon from 64bit PE Pin
Member 46608059-Oct-11 21:42
Member 46608059-Oct-11 21:42 
GeneralRe: Cannot Extract icon from 64bit PE Pin
ejor10-Oct-11 8:19
ejor10-Oct-11 8:19 
GeneralThank you so much for this!!! Pin
stephane.hennebert@gmail.com5-Feb-11 4:21
stephane.hennebert@gmail.com5-Feb-11 4:21 
GeneralGreat! Pin
Geert van Horrik19-May-10 12:10
Geert van Horrik19-May-10 12:10 
GeneralCompiles on VC2005 Pin
T800G24-Oct-08 13:49
T800G24-Oct-08 13:49 
GeneralDoesn't compile on Visual C++ 2008 Pin
Laurent Cozic25-Sep-08 10:27
Laurent Cozic25-Sep-08 10:27 
GeneralBug found! Pin
are_all_nicks_taken_or_what20-Oct-07 13:43
are_all_nicks_taken_or_what20-Oct-07 13:43 
GeneralRe: Bug found! Pin
ejor21-Oct-07 1:49
ejor21-Oct-07 1:49 
QuestionBlock Icon Extraction on My .EXE Pin
Bruno Scopigno16-Mar-07 1:27
Bruno Scopigno16-Mar-07 1:27 
AnswerRe: Block Icon Extraction on My .EXE Pin
ejor18-Mar-07 11:04
ejor18-Mar-07 11:04 
AnswerRe: Block Icon Extraction on My .EXE Pin
Member 384042827-Aug-08 8:55
Member 384042827-Aug-08 8:55 
GeneralVery nice. Pin
wzliu2-Jun-06 15:58
wzliu2-Jun-06 15:58 
GeneralNice Article!!! Pin
ThatsAlok17-Jan-05 17:48
ThatsAlok17-Jan-05 17:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.