如何在Delphi中添加和使用自定义包/组件中的资源?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在Delphi中添加和使用自定义包/组件中的资源?相关的知识,希望对你有一定的参考价值。
我想创建一个使用我的包项目中编译的资源的组件。我的组件将尝试在运行时(在其构造函数中)使用此资源(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。我想这就是诀窍。感谢所有的答案。
您需要使用FindClassHInstance()
,指定组件的类类型,而不是使用全局HInstance
变量或GetModuleHandle()
。这样,无论包是静态链接还是动态链接到主可执行文件,您都可以获得正确的模块句柄。
您正在将HInstance
(可执行模块的句柄)传递给资源加载函数。这失败是因为资源存在于包模块中。因此,您需要传递包的模块句柄。您可以像这样获取包的模块句柄:
PackageModuleHandle := GetModuleHandle(PChar('MyPackage.bpl'));
如果要动态加载包,则调用LoadPackage
会返回模块句柄。
更新:Remy建议使用FindClassHInstance
显然是获取模块句柄的更好方法。
使用在名为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文件,那么它将在两个重要的情况下工作:
- 当BPL在设计时加载。
- 当组件在运行时从关闭运行时软件包编译的应用程序中加载时。
为了处理第三种情况,即另一种情况(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);
以上是关于如何在Delphi中添加和使用自定义包/组件中的资源?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Delphi Form Designer 中为自定义组件添加上下文菜单操作?
Delphi 自定义 TImage 组件 - 组件中的 MouseEnter、MouseLeave
Delphi (CM_) 中的组件消息和自定义图形设计时组件