如何在Delphi中添加和使用自定义包/组件中的资源?

问题描述 投票:4回答:3

我想创建一个使用我的包项目中编译的资源的组件。我的组件将尝试在运行时(在其构造函数中)使用此资源(PNG图像)。

我想在我的应用程序的项目中使用它,但是只要组件被创建,我就会得到以下异常:

First chance exception at $7579B9BC. Exception class EResNotFound with message 'Resource xxx not found'. Process yyy.exe (6060)

我在这里错过了什么?

编辑

包项目中资源的调用代码如下:

Png.LoadFromResourceName(HInstance, 'png_resource_name');

编辑2

正如David所建议的,我尝试使用函数GetModuleHandle,但是如果我从包的项目或应用程序的项目中调用它,它将始终返回0。在包的项目中调用的代码是这样的:

PackageModuleHandle := GetModuleHandle(PChar('my_package.bpl'));
Png := TPngImage.Create;
Png .LoadFromResourceName(PackageModuleHandle, 'png_resource_name');

bpl文件的绝对路径也不起作用。

编辑3

基于新答案的新尝试:

PackageModuleHandle := FindClassHInstance(TMyComponent);
Png := TPngImage.Create;
Png .LoadFromResourceName(PackageModuleHandle, 'png_resource_name');

失败也有同样的例外。

编辑4

使用ResourceHacker,如果我正确使用它,资源似乎不在我的bpl文件中。我能做些什么呢?这么简单的功能似乎有这么复杂的问题。

结论

我必须在{$ R * .res}行之后将我的包的.res文件添加到包的.dpr中。像这样:

{$R *.res}
{$R 'my_pacakge.res'}

此外,我必须将my_package.rc文件包含到我的项目中,因此在每次构建之后,资源将被编译到.res。我想这就是诀窍。感谢所有的答案。

delphi
3个回答
8
投票

您需要使用FindClassHInstance(),指定组件的类类型,而不是使用全局HInstance变量或GetModuleHandle()。这样,无论包是静态链接还是动态链接到主可执行文件,您都可以获得正确的模块句柄。


3
投票

您正在将HInstance(可执行模块的句柄)传递给资源加载函数。这失败是因为资源存在于包模块中。因此,您需要传递包的模块句柄。您可以像这样获取包的模块句柄:

PackageModuleHandle := GetModuleHandle(PChar('MyPackage.bpl'));

如果要动态加载包,则调用LoadPackage会返回模块句柄。

更新:Remy建议使用FindClassHInstance显然是获取模块句柄的更好方法。


2
投票

使用在名为MyUnit1.pas的单元中实现的资源的组件应包含以下内容:

{$R MyUnitRc.res MyUnitRc.rc}

请注意,上述语法不适用于某些旧的delphi版本(Delphi 7)。以上工作在2010,XE,XE2等上,当项目构建该单元时,它将.rc编译为.res。或者,您可以将{$R}声明添加到每个静态链接的应用程序以及BPL的.dpr文件中。

.RC文件mYUnitRc.res将包含一行或多行声明您的资源。我使用RCDATA声明来加载PNG,如下所示:

MYIMAGENAME RCDATA "MyFile.png"

如果你这样做,而不是只使用添加到.dproj / .dpr的RC文件,那么它将在两个重要的情况下工作:

  1. 当BPL在设计时加载。
  2. 当组件在运行时从关闭运行时软件包编译的应用程序中加载时。

为了处理第三种情况,即另一种情况(Remy和David)处理的情况,你需要调用FindClassHinstance,正如Remy所说。但是,我相信您还应该了解如何包含资源文件,并在程序包内以及使用该组件的应用程序中编译和链接。

下面是一些示例代码,显示在运行时将资源加载到TPngImage中,我在自己的组件中使用:

procedure TSampleControl.LoadImageFromResource( button:TSubControl);
var
    png:TPngImage;
begin
  if button.DefaultResourceId='' then exit;
      png := TPngImage.Create;
      try
        try
        png.LoadFromResourceName(HInstance,button.DefaultResourceId);
          button.Glyph.Assign(png);
        except
          on E:Exception do begin
               OutputDebugString( PChar(button.DefaultResourceId+' load error:'+E.Message) );

          end;

        end;
      finally
        png.Free;
      end;

end;

请注意,我捕获资源加载异常,这使得我的控件中的一些元素没有它们的字形,但至少不会使Delphi崩溃。 HInstance可能需要更改,因为David和Remy指出要使用LoadFromResourceName处理你需要从.BPL加载的情况,但我认为你不能认为使用你的组件的人总是会重新分配你的BPL文件,因此FindClassHinstance优于GetModuleHandle ..

更新:我应该使用雷米建议的内容:

       png.LoadFromResourceName( FindClassHInstance(TSampleControl),
                 button.DefaultResourceId);
© www.soinside.com 2019 - 2024. All rights reserved.