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

时间:2012-03-22 14:35:07

标签: 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文件中。我想这就是诀窍。谢谢你的所有答案。

3 个答案:

答案 0 :(得分:8)

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

答案 1 :(得分:3)

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

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

如果您正在动态加载包,则对LoadPackage的调用会返回模块句柄。

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

答案 2 :(得分: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. 当组件在运行时从关闭运行时软件包编译的应用程序中加载时。

  3. 要处理第三种情况,即另一种情况(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 ..

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

           png.LoadFromResourceName( FindClassHInstance(TSampleControl),
                     button.DefaultResourceId);