Extracting Icon Images
In general, when you want to load an icon from an external file, you use the ExtractIcon API function. Icons can contain multiple images of varying sizes (usually 16, 32, or 48 and color depths (usually 2, 16, or 256 colors), but ExtractIcon always returns the image that's most appropriate for the current system settings. Unfortunately, that may not be what DecoMenu needs. For example, if the current color depth is 256 colors or greater but the system does not support 256-color Start menu icons, then the Start menu will use the 16-color images; but ExtractIcon will return 256-color images, and these may be visibly different from the 16-color images shown in the Start menu. If DecoMenu is to provide an accurate simulation of the Start menu, it needs to be able to extract one specific image of an icon, regardless of the system settings.

The XtractIconImage function, also defined in Decoshar.pas, does the job. Given the name of a 32-bit EXE or DLL file, the icon index, the desired dimension, and the desired bit count, it returns an icon handle for an image that precisely matches those parameters, or 0 if no such image is available. The process is very similar to what was used in XtractBitmap but is both more and less complex. It's more complex because in order to locate a specified icon image, it first must load the icon directory resource and iterate through the list of images, and then it must load the image resource separately. It's less complex because once the resource information has been obtained, there's no difficulty in converting the data for use as an icon handle.

XtractIconImage loads the icon directory resource in much the same way that XtractBitmap loads the bitmap resource. The image directory resource consists of a 6-byte header that indicates the number of different images defined, followed by an IconDirectoryEntry for each image. Each image entry includes the dimensions and color depth of the image as well as the number of bytes in the image resource. In a multi-image ICO file, the last field is the offset of the image within the file. In an icon directory resource, however, that last field is the resource ID of the image resource.

Once XtractIconImage has an accessible pointer to the image directory resource, it steps through the array of image-entry data seeking the image whose icon size and color depth match the requested values. When a match is found, it examines the dwImageOffset field of the IconDirectoryEntry to get the resource ID for the icon image resource. It goes through the now-familiar routine of FindResource, LoadResource, and LockResource to get access to the image resource. Then it passes the resource data to the API function CreateIconFromResource, and it returns the resulting handle. If no image matches the requested size and color depth, it returns 0.

DecoMenu could have been an extremely simple utility: Just tweak the registry and alert Explorer to the change. However, giving it the ability to display a preview of the changed Start menu made it a much more useful and usable utility. That approach also made the project a lot more interesting from the programmer's point of view.

Neil J. Rubenking, the author of DecoMenu, is contributing technical editor of PC Magazine. Sheryl Canter is the editor of the Utilities column and a contributing editor of PC Magazine.