4

I am developing a listview baised on the shell. When trying to extract a shell icon/image... I try to extract thumbnail using IExtractImage if that fail I try to extract icons using IExtractIcon, to get maximum iconsize, but IExtractIcon gives strange results. Problem is I tried to use a methode that extracts icons from an imagelist but if there is no large icon (256x256) it will render the smaller icon at the topleft position of the icon and that does not look good. That is why I am trying to use the IExtractIcon instead. But icons that show up as 256x256 icons in my imagelist extraction methode reports icon sizes as 33 large and 16 small. So how do I check if a large (256x256) icon exists? If you need more info I can provide some sample code.

if PThumb.Image = nil then
begin
  OleCheck(ShellFolder.ParseDisplayName(0, nil, StringToOleStr(PThumb.Name), Eaten, PIDL, Atribute));
  ShellFolder.GetUIObjectOf(0, 1, PIDL, IExtractIcon, nil, XtractIcon);
  CoTaskMemFree(PIDL);
  bool:= False;
  if Assigned(XtractIcon) then
  begin
    GetLocationRes := XtractIcon.GetIconLocation(GIL_FORSHELL, @Buf, sizeof(Buf), IIdx, IFlags);
    if (GetLocationRes = NOERROR) or (GetLocationRes = E_PENDING) then
    begin
      Bmp := TBitmap.Create;
      try
        OleCheck(XtractIcon.Extract(@Buf, IIdx, LIcon, SIcon, 32 + (16 shl 16)));
        Done:= False;

Roy M Klever

Roy M Klever
  • 353
  • 5
  • 15
  • see this link http://stackoverflow.com/questions/1703186/can-48x48-or-64x64-icons-be-obtained-from-the-vista-shell – RRUZ Jun 13 '10 at 19:38
  • Thanks, but that is one of my problems... if the item does not have a large icon(256x256) but only a normal (32x32) icon you still get a 256x256 bitmap back but now with 32x32 icon in the topleft corner of the bitmap... looks silly and is not useful for me since I scale it from 56 to 256 pixels. I am trying to find out how I am supposed to get the image/icon represented in Explorer so I can get the same look. – Roy M Klever Jun 13 '10 at 20:42
  • AFAIK Explorer uses the system image list, it does not extract an icon for each single file. –  Jun 14 '10 at 13:17

1 Answers1

-1

Take your 256x256 bitmap and simply check for alpha. Make sure the bmp is 32bits. Any part that has 0 for the pixel value (that is BGRA 0,0,0,0, use TBitmap.Scanline to access) is transparent. You can find the smallest x and smallest y coord that has a nonzero value and that's the actual size of your icon. Now, this number may be smaller than the "icon size" as it was designed. For instance, a 16x16 icon can contain an image of 2x2, which would be a weird design.

But of course an 8x16 icon is very well possible. Considering the images are always square, take the max if the x and y coordinates found (with and height of actual image) and round it up to the nearest of 16,24,32,48,64,128 or 256. You can be quite certain that you'll have the icon centered in your bitmap if you crop to this size next. Use Bmp.Width=sz; Bmp.Height=sz;. You could then scale it up, or center it onto your standard bitmap (56x56? 256x256?).

So, even if windows doesn't feel like giving you the right info, you can bypass the need for this info by simply finding out yourself. This may not be the "correct" way to do it, but you'll know that it'll work when you're done, as opposed to browsing MSDN for 4 hours and never finding an answer.

DDS
  • 4,325
  • 22
  • 33
  • -1. Um, what? There's no answer to the question asked, and what you did write is almost incomprehensible. – Ken White Jul 22 '11 at 02:24
  • @kenw: A quote: "If there is no large icon (256x256) it will render the smaller icon at the topleft position. ... So how do I check if a large (256x256) icon exists?". Well, you can check if it exists by requesting it, but it will return a 256x256 with a small ico on it, so to really check (step 2), you have to figure out programmatically if the icon is _actually_ that size, which the method is decribed above. I assume some actual knowledge of Delphi in the post and it's not a manual, I know. Also note the comment "you still get a 256x256 bitmap back but with a 32x32 icon in the corner". – DDS Jul 22 '11 at 07:46
  • @DDS Well this is exactly what I did and it is working very well... and yes I did spend a lot more than four hours in msdn trying to figure it out. You can see my solution in this sample application [Link](http://rmklever.com/?p=266) – Roy M Klever Jul 22 '11 at 07:58
  • Very nice. I just have one comment: You may be chopping too much off of your icons. Again, if the _actual_ ico is 8x16 (a "tall" image) centered on a 16x16 ico canvas, your method crops the icon to 12x16, with the assumption that it's centered in there. It isn't, it's now right-aligned. Essentially, all icons processed this way are bottom-right aligned. To find the original icon size, you should do `sz:=max(crop.x,crop.y); case sz of 0..16: sz:=16; 17..24:sz:=24; (etc, see list in answer); end;` Then sz is both the width and the height of the _original_ icon before windows mucked it up. – DDS Jul 22 '11 at 08:34
  • 1
    @DDS: I do have "some actual knowledge of Delphi", as I've been using it since Delphi 1 was released. :) Your post is still almost incomprehensible the way it's worded,IMO. Apparently, Roy didn't feel the same way (which is perfectly fine, BTW). – Ken White Jul 22 '11 at 14:04
  • @DDS Ah good observed ... I do see what you mean here. Thanks! – Roy M Klever Jul 24 '11 at 14:48