Recent

Author Topic: Icon from shell in TImageList, black background (solved)  (Read 5287 times)

Fodox

  • New Member
  • *
  • Posts: 13
Icon from shell in TImageList, black background (solved)
« on: April 01, 2014, 11:18:50 pm »
Hello.
I am using Lazarus 1.0.14 under Win7/64 compiling 32bit.
I need to simulate a shell TreeView using a simple TTreeView. I am trying to associate the shell icons after populating nodes with hard disk folders.

I have:

Code: [Select]
SHGetFileInfo(PChar(folder), 0, FileInfo, SizeOf(FileInfo), SHGFI_ICON or SHGFI_SMALLICON);
myicon:=TIcon.Create;
myicon.Handle:=FileInfo.hIcon;
iconindex:=ImageList.AddIcon(myicon);

A little bit of logic prevents duplicate icons.
The question is that this method works perfectly under win7/64 but in another pc with win 8/64 I have images with black background. See images in attachments.

Can someone help me?
« Last Edit: April 03, 2014, 11:27:56 pm by Fodox »

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Icon from shell in TImageList, black background
« Reply #1 on: April 03, 2014, 03:14:21 am »
Short answer. After you call:
Code: [Select]
iconindex:=ImageList.AddIcon(myicon);
call:
Code: [Select]
  iconindex := ImageList_ReplaceIcon(ImageList.Handle, iconindex, myicon.Handle);
to replace the bad image. ImageList_ReplaceIcon is declared in Windows unit. You need to add it to your uses section if you don't have it there already.

Long (boring) answer. These icons are drawn by DrawToDC in lcl\interfaces\win32\win32wsimglist.pp. The procedure uses one of three different drawing methods based on color depth, drawing effect and Comctl version.

Using Windows, it is possible to borrow the OS ImageList handle and get the index to the same icon in that list. To achieve that, SHGFI_SYSICONINDEX needs to be passed in the flags when calling SHGetFileInfo:
Code: [Select]
var
  SysHandle: THandle;
..
  SysHandle := SHGetFileInfo(PChar(folder), 0, FileInfo, SizeOf(FileInfo), SHGFI_ICON or SHGFI_SMALLICON or SHGFI_SYSICONINDEX);

Comparing the results of drawing two icons, one based on borrowing the OS' ImageList and the other icon based on TImageList, the results were not identical. I used the first method ImageList_DrawEx:
Code: [Select]
  ImageList_DrawEx(SysHandle, FileInfo.iIcon, Canvas.Handle, 10,10, 0,0, CLR_NONE, CLR_NONE, ILD_NORMAL or ILD_NORMAL);
  ImageList_DrawEx(ImageList.Handle, iconindex, Canvas.Handle, 50,10, 0,0, CLR_NONE, CLR_NONE, ILD_NORMAL or ILD_NORMAL);

First I suspected TIcon, but it did draw the image correctly. So I assume ImageList.AddIcon is causing this problem. Simply replacing the icon (or whatever AddIcon is adding?) solved the problem on my PC. Notice that I did not see the problem using color depth setting less then 32 bit and this workaround is just for Windows OS. I don't know if the problem exists on other systems.

Fodox

  • New Member
  • *
  • Posts: 13
Re: Icon from shell in TImageList, black background
« Reply #2 on: April 03, 2014, 11:27:41 pm »
It looks like more a trick than a solution, but it works. Thank you!

Meanwhile I found another solution, using the free class TKicon (http://www.tkweb.eu/en/delphicomp/kicon.html).

Short example:
Code: [Select]
var
myicon : TKicon;
bmp : Graphics.TBitmap;
..
SHGetFileInfo(PChar(folder), 0, FileInfo, SizeOf(FileInfo), SHGFI_ICON or SHGFI_SMALLICON);
myicon:=TKicon.Create;
myicon.LoadFromHandle(FileInfo.hIcon);
bmp:=Graphics.TBitmap.Create;
myicon.CopyToBitmap(0,bmp);
iconindex:=ImageList.Add(bmp,nil);

"bmp" can also be assigned to a TImage and the semi-transparency will be preserved.

Bye
Fodox