Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EnumResourceNames returns Windows error 998 (Invalid access to memory location)

Tags:

dll

delphi

(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.

like image 438
Marek Jedliński Avatar asked Feb 13 '23 05:02

Marek Jedliński


1 Answers

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;
like image 198
Sertac Akyuz Avatar answered Mar 22 '23 23:03

Sertac Akyuz