3

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.

Community
  • 1
  • 1
spurgeon
  • 1,082
  • 11
  • 34

1 Answers1

4

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;
teran
  • 3,214
  • 1
  • 21
  • 30
  • Thanks for this approach. The thumbnails are great, but I really don't want the thumbnail. For example, for a JPEG file, I'd like the .jpg file type icon rather than the thumbnail of the .jpg image. Same goes for other image, video, etc. files. – spurgeon Feb 27 '13 at 15:57
  • @spurgeon use `SIIGBF_ICONONLY` as the second parameter in `GetImage` method call for file-type icons. it gets icons only, but has propblems with transparency (may be there is some magic with `TImage` settings) – teran Feb 27 '13 at 21:56
  • Ah sorry, somehow missed that. Indeed, the icons are returned for the different sizes but with a nasty black background. I used [this AlphaBlend post](http://stackoverflow.com/questions/5964701/how-to-draw-transparent-image-on-a-form) to draw the bitmap with alpha to the canvas, which worked. But, the program crashes on XP, even if I strip the code down to just the IShellItemImageFactory above. The error is "External exception c06d007f." Any ideas? It works on Windows Vista and 7. +1 for answer, but I can't accept b/c of my original question about getting the .ICO file. – spurgeon Feb 28 '13 at 16:15
  • yep, seems IShellItemImagefactory is not supported in WinXP, only Vista and above; http://msdn.microsoft.com/en-us/library/windows/desktop/bb761084%28v=vs.85%29.aspx – teran Mar 01 '13 at 06:42