Delphi中的图标线程加载

4
使用Delphi 2009,尝试制作一个启动器。为了使它更加“敏捷”,我真的很想在后台线程中加载图标。
我已经使用在这里找到的解决方案:Can 48x48 or 64x64 icons be obtained from the Vista Shell? 如果不在线程中运行,这个方法很好用。但是一旦我把它放在一个线程中,有些图标就不能被获取,或者成为某种通用图标。我甚至尝试序列化线程(使它们过时),但结果仍然相同。
所以问题是:如何在线程中加载图标(具有与链接示例相同的可用选项)?
/Lars
编辑: 在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;

这没有任何区别。 我仍然会得到一些通用图标(只有在调用线程时才会出现)。
编辑2: 线程代码(非常简单):
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;

没有任何错误返回。我调用了CoInitialize,但是它没有起到作用。 - Lars Bargmann
1
你已经添加了代码,但是你没有调用CoInitialize。文档明确说明你必须这样做。你在上面的评论中说过你已经这样做了。你是否意识到调用CoInitialize的操作必须来自调用SHGetFileInfo的线程? - David Heffernan
1
TThread的构造函数在主线程中运行! - LU RD
1
这意味着您必须在执行部分调用CoInitialize。 - LU RD
1
@LURD是正确的。你需要在线程中初始化com。也就是在Execute函数内部进行初始化。 - David Heffernan
显示剩余9条评论
3个回答

2

SHGetFileInfo的文档说明在调用该函数之前必须初始化COM。由于COM初始化是每个线程的,因此您需要在线程中初始化COM。这意味着从线程的Execute方法中调用CoInitializeCoInitializeEx


你接受了答案,然后取消了接受。有什么问题吗? - David Heffernan

0
也许你可以通过使用Delphi 2009中引入的TThread.Queue方法来简化线程代码。
这里有一篇文章提供了一些示例和背景信息: 带参数同步和排队 TThread.Queue是非阻塞的。这允许为所有图标顺序创建后台工作线程,然后让它们异步加载。

我几乎可以百分之百确定这不是线程代码问题。我有一个简单的对象列表,其中包含文件名和TIcon。我尝试为每个对象创建一个线程,以及在创建线程时手动提供所需的对象。无论我如何在线程内调用GetIconFromFile,它最终都会给我错误的图标。如果我从主线程中进行调用,一切正常...?? - Lars Bargmann
哦,只是为了好玩,我尝试在 GetIconFromFile 中包装一个 TCriticalSection。但是这并没有产生任何区别... - Lars Bargmann

-1

尝试移动这个:

GetIconFromFile(Item.FFilename, I, SHIL_EXTRALARGE);

进入synchronize块。在使用SHGetFileInfo()后,您应该调用DestroyIcon()


1
这将完全违背使用线程的初衷,不是吗? - Lars Bargmann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接