Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi XE2: Invoke WinAPI EnumResourceNames cause access violation in Win64 platform

Running the following code in Delphi XE2 Win32 platform works. However, the same code compile in win64 platform will cause access violation in "EnumRCDataProc" if run in debug mode:

procedure TForm2.Button1Click(Sender: TObject);
  function EnumRCDataProc(hModule: THandle; lpszType, lpszName: PChar; lParam:
      NativeInt): Boolean; stdcall;
  begin
    TStrings(lParam).Add(lpszName);
    Result := True;
  end;

var k: NativeInt;
    L: TStringList;
    H: THandle;
begin
  H := LoadPackage('resource.bpl');
  L := TStringList.Create;
  try
    EnumResourceNames(H, RT_RCDATA, @EnumRCDataProc, NativeInt(L));
    ShowMessage(L.Text);
  finally
    L.Free;
    UnloadPackage(H);
  end;
end;

When debug the code in Delphi XE2 IDE on Win64 platform, I found the value of hModule in EnumRCDataProc doesn't match with variable H. I suspect that might be something wrong about the parameters I constructed for the EnumRCDataProc. However, I can't figure out how. Any ideas?

like image 272
Chau Chee Yang Avatar asked Jan 12 '12 14:01

Chau Chee Yang


1 Answers

The problem is that you have made EnumRCDataProc a local procedure. You need to move it outside the method.

function EnumRCDataProc(hModule: HMODULE; lpszType, lpszName: PChar; lParam:
    NativeInt): BOOL; stdcall;
begin
  TStrings(lParam).Add(lpszName);
  Result := True;
end;

procedure TForm2.Button1Click(Sender: TObject);
var k: NativeInt;
    L: TStringList;
    H: HMODULE;
begin
  H := LoadPackage('resource.bpl');
  L := TStringList.Create;
  try
    EnumResourceNames(H, RT_RCDATA, @EnumRCDataProc, NativeInt(L));
    ShowMessage(L.Text);
  finally
    L.Free;
    UnloadPackage(H);
  end;
end;

On first inspection I expected that the compiler would emit an error with your code:

E2094 Local procedure/function 'Callback' assigned to procedure variable

But it does not do so. I dug a little deeper and discovered that the callback parameter for EnumResourceNames is declared as type Pointer. If the header translation had declared this as a typed callback parameter then the above error message would indeed have been emitted. To my mind the header translation is poor in this regard. There seems very little to be gained from abandoning the safety of the type system.

The fact that your code works in 32 bit code is just a happy coincidence that relies on implementation details. Your luck runs out on 64 bit. Again, if the type checking system had been enabled, the compiler could have told you what was wrong immediately.

Some other comments:

  1. The EnumRCDataProc has a couple of incorrect types in its declaration: hModule should be of type HMODULE and the function result should be BOOL.
  2. LoadPackage is a rather heavyweight approach to getting a module handle. I would prefer to see LoadLibraryEx with the LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE and LOAD_LIBRARY_AS_IMAGE_RESOURCE options.
like image 176
David Heffernan Avatar answered Sep 30 '22 16:09

David Heffernan