Reputation: 142
Using Delphi 2009, trying to make a launcher. In order to make it "snappy" I would really like to load icons in a background thread.
I have used the solution found here : Can 48x48 or 64x64 icons be obtained from the Vista Shell?
This works fine, if NOT run in a thread. As soon as I put it in a thread, some icons are not "fetched", or being some kind of generic icon. I even tried serializing the threads (making them obsolote, in effect) but it yields the same results.
So, the question is: How do I load icons (with the same available options as the linked example) in a thread?
/Lars
Edit: Added some very basic error-checking in GetIconFromFile
if SHGetFileInfo( PChar( aFile ),
FILE_ATTRIBUTE_NORMAL,
SFI,
SizeOf( TSHFileInfo ),
SHGFI_ICON
or SHGFI_LARGEICON
or SHGFI_SHELLICONSIZE
or SHGFI_SYSICONINDEX
or SHGFI_TYPENAME
or SHGFI_DISPLAYNAME ) <> 0 then
begin
if not Assigned( aIcon ) then
aIcon := TIcon.Create;
aImgList := GetImageListSH( SHIL_FLAG );
aIndex := SFI.iIcon;
if aImgList <> 0 then
aIcon.Handle := ImageList_GetIcon( aImgList, aIndex, ILD_NORMAL );
end;
This doesn't make any diffenrence. I am still getting some generic icons (only when this is called in a thread, though)
Edit2 : Threading-code (very simple) :
procedure TIconLoader.Execute;
var
Item : TGridItem;
I : TIcon;
begin
inherited;
while not terminated do
begin
Item := nil;
if assigned(FOnNeedGridItem) then
begin
Synchronize(
procedure
begin
FOnNeedGridItem(Self, Item);
end
);
end;
if assigned(Item) then
begin
GetIconFromFile(Item.FFilename, I, SHIL_EXTRALARGE);
Synchronize(
procedure
begin
Item.SetIcon(I);
end
);
// I.Free;
end
else
Terminate;
end;
end;
Upvotes: 4
Views: 606
Reputation: 612934
The documentation for SHGetFileInfo
specifies that you must initialize COM before calling the function. Since COM initialization is per-thread, you need to initialise COM in the thread. That means calling CoInitialize
or CoInitializeEx
from the Execute
method of the thread.
Upvotes: 2
Reputation: 31
Try moving this:
GetIconFromFile(Item.FFilename, I, SHIL_EXTRALARGE);
into synchronize
block. And you should call DestroyIcon() after using SHGetFileInfo()
.
Upvotes: -1
Reputation: 36644
Maybe you can simplify your threading code by using the TThread.Queue methods introduced in Delphi 2009.
An article which gives some examples and background information is here:
Synchronize and Queue with Parameters
TThread.Queue is non-blocking. This allows to sequentially create background worker threads for all your icons and then let them load asynchronously.
Upvotes: 0