Delphi XE2:调用WinAPI EnumResourceNames导致Win64平台中的访问冲突

在Delphi XE2 Win32平台上运行以下代码.但是,如果在调试模式下运行,在win64平台中编译相同的代码将导致“EnumRCDataProc”中的访问冲突:

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;

在Win64平台上调试Delphi XE2 IDE中的代码时,我发现EnumRCDataProc中的hModule值与变量H不匹配.我怀疑我为EnumRCDataProc构造的参数可能有问题.但是,我无法弄清楚如何.有任何想法吗?

解决方法

问题是你已经使EnumRCDataProc成为本地程序.您需要将其移出方法之外.

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,NativeInt(L));
    ShowMessage(L.Text);
  finally
    L.Free;
    UnloadPackage(H);
  end;
end;

在第一次检查时,我预计编译器会使用您的代码发出错误:

E2094 Local procedure/function ‘Callback’ assigned to procedure variable

但它没有这样做.我深入挖掘并发现EnumResourceNames的回调参数被声明为类型指针.如果标头转换已将此声明为类型化的回调参数,则确实会发出上述错误消息.在我看来,标题翻译在这方面很差.放弃类型系统的安全性几乎没有什么好处.

您的代码使用32位代码工作的事实只是依赖于实现细节的快乐巧合.你的运气用完了64位.同样,如果启用了类型检查系统,编译器可能会立即告诉您错误.

其他一些评论:

> EnumRCDataProc在其声明中有几个不正确的类型:hModule应该是HMODULE类型,函数结果应该是BOOL.
> LoadPackage是获取模块句柄的一种相当重要的方法.我更希望看到LoadLibraryEx与LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE和LOAD_LIBRARY_AS_IMAGE_RESOURCE选项.

相关文章

 从网上看到《Delphi API HOOK完全说明》这篇文章,基本上都...
  从网上看到《Delphi API HOOK完全说明》这篇文章,基本上...
ffmpeg 是一套强大的开源的多媒体库 一般都是用 c/c+&#x...
32位CPU所含有的寄存器有:4个数据寄存器(EAX、EBX、ECX和ED...
1 mov dst, src dst是目的操作数,src是源操作数,指令实现的...