(see edits at bottom)
Using EnumResourceNames, I am trying to find icons stored as resources in my own dll. Here is the entire dll code:
library focusRes;
{$R focusResResource.res} // contains the icons I need to load
{$R *.res}
begin
end.
I can load the dll correctly using LoadLibrary and LoadLibraryEx (verified). But a call to EnumResourceNames returns false, and GetLastError returns 998 (Invalid access to memory location). The calling code is:
hdll := LoadLibraryEx( PChar( DLLFilename ), 0, LOAD_LIBRARY_AS_DATAFILE );
// OR: hdll := LoadLibrary( PChar( DLLFilename ));
enumResult := EnumResourceNames( hDll, RT_ICON, @EnumResFlags, 0 );
// (hDll is the handle returned from LoadLibrary)
and the callback function:
function EnumResFlags( hDll : HMODULE; ResType, ResName : PChar;
notUsed : pointer ) : integer; stdcall;
begin
// NEVER GETS CALLED
// log( ResName);
result := 1; // continue enumeration
end;
The callback is a standalone function (not an object method or a local function).
In my investigation I have found some confusing clues:
The problem seems to be with my dll, because if I substitute a random dll from a third-party application, the problem goes away.
The problem seems not to be with my dll, because I can open it in a third-party icon editor, and all the icons stored in the dll are loaded correctly.
When I try to create a resourcestream for a specific icon name, the exception is "Resource [name] not found". (But the icon editor finds it fine)
(Delphi XE on Windows 7 32-bit)
EDIT 1: Create a new Delphi project and put the following line in it:
enumResult := EnumResourceNames( hInstance, RT_ICON, @EnumCallback, 0 );
Result: error 998. Change RT_ICON to something else, like RT_RTCDATA, and the problem goes away.
EDIT 2: The problem does not occur if I do not reference the ResName parameter in the callback. (If I only say "result := 1" in the callback, no error.) Went back to Delphi 3 (!) and got the same exact result, so it is not particular to XE. And if I try to enum RT_RCDATA instead of RT_ICON, no problem wither and I can read ResName.
You are not correctly resolving the lpszType
and lpszName
parameters of the callback. Your failing test involves resource IDs being passed to your callback, not resource names. When you try to access the first 64kb of your process memory via a pointer, it is an invalid memory access.
You need to test if ResType
/ResName
is a name or ID and then treat it accordingly, like so:
function EnumResFlags( hDll : HMODULE; ResType, ResName : PChar; notUsed : pointer ) : integer; stdcall;
begin
if IS_INTRESOURCE(ResName) then
log(IntToStr(Integer(ResName)))
else
log(ResName);
...
end;
If your Delphi version does not have IS_INTRESOURCE()
defined, you can define it manually:
function IS_INTRESOURCE(lpszType: PChar): BOOL;
begin
Result := ULONG_PTR(lpszType) shr 16 = 0;
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With