如何从资源中加载图标到TImage?

3
我尝试了下面的代码,但它无法正常工作...LoadIconWithScaleDown返回一个负错误代码。
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls,
  Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    procedure FormCreate(Sender: TObject);
    procedure LoadResToImg(RID: String; const Img: TImage);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
{$R UserResources.res}

uses Winapi.CommCtrl;

procedure TForm1.LoadResToImg(RID: String; const Img: TImage);
var Ico: TIcon;
    hI: HICON;
    HR: HResult;
begin
 Ico:= TIcon.Create;
 HR:= LoadIconWithScaleDown(HInstance, PChar(RID), Img.Width, Img.Height, hI);
 Ico.Handle:= hI;
 Img.Picture.Bitmap.Assign(Ico);
 Ico.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 LoadResToImg('OFFLINE', Image1);
end;

end.

UserResources.rc

OFFLINE      ICON    "gray_button.ico"
ONLINE       ICON    "green_button.ico" 

你在图片上使用了const,但是字符串上却没有。应该是相反的! - Andreas Rejbrand
那么像 TImage 这样的对象即使没有 const 修饰符,也是通过引用传递的吗? - Marus Gradinaru
2
是的,对象总是通过引用传递的。字符串使用COW语义,并且在使用const时,编译器不需要更新引用计数。 - Andreas Rejbrand
2个回答

3
这可能是因为 VCL 对该 Win32 函数的包装(在 Winapi.CommCtrl.pas 中)有误,或者至少不能直接使用。所以你需要自己声明它:
function LoadIconWithScaleDown(hinst: HINST; pszName: LPCWSTR; cx: Integer;
    cy: Integer; var phico: HICON): HResult; stdcall; external 'ComCtl32';

但请注意,此功能仅存在于Windows Vista+(如果我没有记错的话)。


太好了!现在它可以工作了...谢谢!这让我疯狂了将近4个小时... - Marus Gradinaru
1
或者,在使用LoadIconWithScaleDown之前,您可以调用InitCommonControlsEx,但我认为从Win32的角度来看,这并不是必要的。 - Andreas Rejbrand
但要注意,此功能仅适用于Windows Vista+(如果我没记错的话)。 在这种情况下,您应该在函数声明中包含delayed关键字,然后在预-Vista系统上不在运行时调用该函数。 - Remy Lebeau
@RemyLebeau:或者老派一点,用LoadLibrary + GetProcAddress。如果你使用的是旧版本的Delphi,这是必要的。 - Andreas Rejbrand
@AndreasRejbrand真的是非常旧的版本,因为delayed是在D2010中引入的。 - Remy Lebeau

0

正如评论中提到的,您也可以使用 InitCommonControlsEx 来完成相同的事情。 我认为 Andreas 的方法更简单,但如果有人更喜欢使用 InitCommonControlsEx,这里是代码:

uses
  Winapi.Windows, Winapi.CommCtrl;

...

var
  IconHandle : HICON;
  ICC: TInitCommonControlsEx;
begin
  ICC.dwSize := SizeOf(TInitCommonControlsEx);
  ICC.dwICC := ICC_BAR_CLASSES;

  if(not InitCommonControlsEx(ICC)) then
    raise Exception.Create('InitCommonControlsEx error');

  if(LoadIconWithScaleDown(0, MAKEINTRESOURCE(<your res id>), 32, 32, IconHandle) <> S_OK) then
    raise Exception.Create('LoadIconWithScaleDown error');

  <here you can use IconHandle as you need>
end;

注意:我已经测试过,将IDI_INFORMATION作为<你的资源ID>传递给它。


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