3
votes

I would like a function that takes any file path in Windows (any file system object--file, folder, drive, shortcut, etc.) and returns the associated .ICO file (or some handle to the icon with all image size representations). For example, if I specified 'C:\MyTextFile.txt' in Windows 7, I would get all of the 256x256, 48x48, 32x32, and 16x16 representations for the .txt file in an .ICO file, which is located in imageres.dll at offset 102:

Text file icon in imageres.dll

^ The Icon tab installed by Stardock IconPackager, which locates the icon for the file system object

From my research so far, it doesn't appear to be that easy. There's the ExtractIconEx function, but it only gives the 16 and 32px representations. There's also this post that shows how to get the SHIL_SMALL, SHIL_LARGE, SHIL_EXTRALARGE, and SHIL_JUMBO sizes, which are generally 16, 32, 48, and 256 pixels respectively. However, that doesn't necessarily cover other sizes that would be stored in the .ICO file as well. For example, some icons store 10 or more different sizes rather than just four.

So, I'm trying to:

  1. Find the location of the file system object's icon, and
  2. Retrieve it from the DLL, EXE, or whatever resource that encapsulates it.

I guess one question would be: Is this a task for the Windows registry? As you can see below, the registry's txtfile->DefaultIcon value contains the location of the icon for the .txt file type.

txtfile in Windows registry

But, there are also standalone .exe files, for example, that self-contain an icon that wouldn't be stored in the registry.

Ultimately, I'd like to display all of the different sizes within a TImage and potentially output them together in an .ICO file. Any help would be appreciated.

1

1 Answers

4
votes

As an option, there is an IShellItemImageFactory interface which provides information about IShellItem (file) thumbnails. This interface can return desired sized, but it needs some magic with icons transparency. there are 2 options - thumbnails or icons. For Folder it always return the same image (update: that not true, folder thumbnail also contains small previews of files, wich it contains). But for example for png it returns small preview image with thumbnail flag and png-image-icon with icon flag (0 is default value). For your task you should use SIIGBF_ICONONLY flag to get file/folder/drive system icons.

Here is sample code, which loads different sizes of image.

type
    TIconSize = (is16, is32, is48, is64, is96, is128, is256);
const
    ICON_SIZE : array[TIconSize] of integer = (16,32,48,64,96,128,256);

I added SizeRadioGroup : TRadioGroup and Image1 : TImage on the form. Image1.Size is set to 256. SizeRadioGroup click event hanlder loads thumbnail to Image1:

procedure TForm7.SizeRadioGroupClick(Sender: TObject);
const FILE_NAME = 'd:\_projects\';
var icoSize : TIconSize;
    wh : integer;
    siif : IShellItemImageFactory;
    size : TSize;
    icon_handle : HBitmap;
    bm : TBitmap;
begin
    icoSize := TIconSize(SizeRadioGroup.ItemIndex);
    wh := ICON_SIZE[icoSize];

    SHCreateItemFromParsingName(FILE_NAME, nil, IID_IShellItemImageFactory, siif);

    size.cx := wh;
    size.cy := wh;

    siif.GetImage(size, 0 {SIIGBF_THUMBNAILONLY}{SIIGBF_ICONONLY}, icon_handle);
    bm := TBitmap.Create();
    bm.PixelFormat := pf32bit;
    try
        bm.Handle := icon_handle;
        Image1.Picture.Assign(bm);
    finally
        bm.Free();
    end;
end;