Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add and use a resource from a custom package/component in Delphi?

Tags:

delphi

I want to make a component that uses some resources compiled in my package's project. My component will try to use this resource (a PNG image) during runtime (at its constructor).

I want to use it in my application's project, but as soon as the component gets created, I get the following exception:

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

What am I missing here?

EDIT

The calling code for the resource in the package's project is like this:

Png.LoadFromResourceName(HInstance, 'png_resource_name');

EDIT 2

As suggested by David, I tried using the function GetModuleHandle, but it will always return 0 if I call it from the package's project or the application's project. The code being called in the package's project is like this:

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

Absolute paths to the bpl file won't work either.

EDIT 3

New attempt based on new answer:

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

Fails with the same exception.

EDIT 4

Using ResourceHacker, and if I used it right, the resources doesn't seem to be in my bpl file. What could I be doing wrong about this? Seems such a complicated matter to such a simple feature.

CONCLUSION

I had to add the .res file of my package to the package's .dpr just after the {$R *.res} line. Like this:

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

Also, I had to include the my_package.rc file to my project, so the resources would get compiled to the .res after each build. That did the trick, I guess. Thanks for all the answers.

like image 675
ivarec Avatar asked Mar 22 '12 14:03

ivarec


2 Answers

You need to use FindClassHInstance(), specifying your component's class type, instead of using the global HInstance variable or GetModuleHandle(). That way, you obtain the correct module handle regardless of whether the package gets statically linked or dynamically linked into the main executable.

like image 112
Remy Lebeau Avatar answered Nov 02 '22 02:11

Remy Lebeau


You are passing HInstance, the handle of the executable module to the resource loading function. That fails because the resource lives in the package module. Therefore you need to pass the module handle for the package. You can obtain the module handle of the package like this:

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

If you are loading your package dynamically then the call to LoadPackage returned the module handle.

Update: Remy's suggestion of using FindClassHInstance is clearly a better way to obtain the module handle.

like image 39
David Heffernan Avatar answered Nov 02 '22 00:11

David Heffernan