在运行时用另一个 .exe 文件的图标替换 VCL 窗体的图标?

Replace the icon of a VCL form with the icon of another .exe file at runtime?

使用 Delphi XE7,我想在运行时更改当前 VCL 窗体(不是应用程序)的图标。所以我尝试了这段代码:

procedure TForm1.LoadExeIcon(const AExeFileName: string);
var
  Icon: TIcon;
begin
  Icon := TIcon.Create;
  try
    Icon.Handle := ExtractIcon(HInstance, PWideChar(AExeFileName), 0);
    Self.Icon.Assign(Icon);
  finally
    Icon.Free;
  end;
end;

更改后的图标应该会出现在 window(小图像格式)和任务栏(大图像格式)的左上角。

它有效,但有一个小问题:window 左上角的新小图标看起来很模糊,据说是因为 exe 文件中的大图像被拉伸到较小的尺寸。

这是小图像在原始 exe 程序 window 中的样子:

这是替换后小图像在测试程序中的样子:

任务栏中的大图标看起来很完美。

那么如何让小图标看起来像原始exe文件中的那样好看呢?

编辑:

我听从了 David 的建议,这里是可行的解决方案。为了使蛋糕真的很甜,我在任务栏图标上添加了一个叠加图标:

procedure TForm1.LoadExeIcon(const AExeFileName: string);
// Load Large and Small Icon from Exe file and assign them to the Form Icon
// Add Overlay to Taskbar Icon
var
  LIcon: HICON;
  SIcon: HICON;
  OLIcon: TIcon;
  NumberOfIconsInExeFile: Integer;
begin
  NumberOfIconsInExeFile := ExtractIconEx(PWideChar(AExeFileName), -1, LIcon, SIcon, 0);
  if NumberOfIconsInExeFile > 0 then // if there are any icons in the exe file
  begin
    ExtractIconEx(PWideChar(AExeFileName), 0, LIcon, SIcon, 1);
    SendMessage(Form1.Handle, WM_SETICON, 1, LIcon);
    SendMessage(Form1.Handle, WM_SETICON, 0, SIcon);
  end;

  // apply an overlay icon to the taskbar icon with new TTaskbar component:
  OLIcon := TIcon.Create;
  try
    ilTest.GetIcon(0, OLIcon);
    Taskbar1.OverlayIcon.Assign(OLIcon);
    Taskbar1.OverlayHint := 'My Hint'; // does not work?
    Taskbar1.ApplyOverlayChanges;
  finally
    OLIcon.Free;
  end;
end;

尝试删除 Icon.Free; ,如果有效,则意味着 Icon.Free; 也会使分配的图标句柄无效

调用ExtractIconEx提取大图标和小图标。

但是,请注意 VCL 在 Delphi1 中有一个设计缺陷,它不允许您同时设置小图标和大图标。在我看来,您最好忽略 Icon 属性 并手动发送 WM_SETICON。每个图标大小一次。