EnumResourceNames返回Windows错误998(对内存位置的无效访问)

时间:2014-04-11 23:55:06

标签: delphi dll

(见底部编辑)

使用EnumResourceNames,我试图在我自己的dll中找到存储为资源的图标。这是整个DLL代码:

library focusRes;

{$R focusResResource.res} // contains the icons I need to load
{$R *.res}

begin
end.

我可以使用LoadLibrary和LoadLibraryEx(已验证)正确加载dll。但是对EnumResourceNames的调用返回false,而GetLastError返回998(对内存位置的无效访问)。调用代码是:

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)

和回调函数:

function EnumResFlags( hDll : HMODULE; ResType, ResName : PChar; 
   notUsed : pointer ) : integer; stdcall;
begin
  // NEVER GETS CALLED
  // log( ResName);
  result := 1; // continue enumeration
end;

回调是一个独立的函数(不是对象方法或本地函数)。

在我的调查中,我发现了一些令人困惑的线索:

  • 问题似乎与我的dll有关,因为如果我替换随机 来自第三方应用程序的DLL,问题就消失了。

  • 我的dll问题似乎,因为我可以打开它 在第三方图标编辑器中,以及存储在dll中的所有图标都是 正确加载。

  • 当我尝试为特定图标名称创建资源流时, 异常是“未找到资源[名称]”。 (但图标编辑器发现没问题)

(Windows 7 32位上的Delphi XE)

编辑1:创建一个新的Delphi项目并在其中加入以下行:

enumResult := EnumResourceNames( hInstance, RT_ICON, @EnumCallback, 0 );

结果:错误998.将RT_ICON更改为其他内容,例如RT_RTCDATA,问题就消失了。

编辑2 如果我没有在回调中引用ResName参数,则问题不会发生。 (如果我在回调中只说“结果:= 1”,则没有错误。)返回Delphi 3(!)并得到相同的确切结果,因此它并不特定于XE。如果我尝试枚举RT_RCDATA而不是RT_ICON,则没有问题,我可以读取ResName。

1 个答案:

答案 0 :(得分:8)

您未正确解析回调的lpszTypelpszName参数。您的测试失败涉及将资源ID传递给您的回调,而不是资源名称。当您尝试通过指针访问进程内存的第一个64kb时,它是无效的内存访问。

您需要测试ResType / ResName是否为名称或ID,然后对其进行相应处理,如下所示:

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;

如果您的Delphi版本没有定义IS_INTRESOURCE(),您可以手动定义它:

function IS_INTRESOURCE(lpszType: PChar): BOOL;
begin
  Result := ULONG_PTR(lpszType) shr 16 = 0;
end;