You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LockResource()返回指针非预期VS_VERSION_INFO结构问题排查

问题:直接加载外部EXE的VERSION资源二进制数据异常

我希望从外部EXE文件中加载VERSION资源的二进制数据,操作应较为简单,以下是使用Delphi 7编写的代码:

var
  hFile: HMODULE;  // File=image to load
  hR: HRSRC;  // Resource handle
  hG: HGLOBAL;  // Loaded resource
  p: Pointer;  // Actual accessible data to the resource
  sDebug: AnsiString;
  sFile: Widestring;
begin
  // Commonly known to every Windows installation, 32-bit version.
  sFile:= 'C:\Windows\SysWOW64\calc.exe';

  // WinAPI want both flags.
  hFile:= LoadLibraryExW( PWideChar(sFile), 0, LOAD_LIBRARY_AS_DATAFILE or LOAD_LIBRARY_AS_IMAGE_RESOURCE );

  // 2nd param=resource name/ID; 3rd param=resource type. Unlike FindResourceExA() where these are swapped.
  hR:= FindResourceA( hFile, PAnsiChar('#1'), PAnsiChar('#16') );

  // Same results as above: returns valid handle. Just another valid way of wanting numeric IDs.
  {hR:= FindResourceA( hFile, PAnsiChar(1), PAnsiChar(16) );}

  // Both succeed in returning a valid handle and a non-empty pointer.
  hG:= LoadResource( hFile, hR );
  p:= LockResource( hR );

  // AnsiString will have the bytes $f0 $b2 $0b $00 $84 $03 $00, but not the
  // expected $bd $04 $ef $fe from VS_FIXEDFILEINFO.dwSignature after about 40 bytes.
  SetString( sDebug, PAnsiChar(p), 50 );
end

执行后所有句柄均有效,LockResource返回非nil指针。为调试将字节存入AnsiString查看,发现指针指向的字节位于文件位置$585c0,与Resource Hacker确认的VERSION资源实际位置$b96f0相差甚远,且未找到预期的VS_FIXEDFILEINFO.dwSignature对应的$bd $04 $ef $fe字节。

根据LockResource文档说明,返回值应为资源的首字节指针,无需额外偏移,我预期该指针指向的内容应包含VS_VERSION_INFO伪结构及后续的VS_FIXEDFILEINFO结构。

我不想使用GetFileVersionInfoW()和VerQueryValueW(),希望避免Windows作为中间层,且目标是可靠读取任意资源(不仅限于WinAPI提供辅助函数的资源)。当前环境为Windows 7x64下的32位Delphi 7程序,加载的是32位calc.exe,其他32位EXE也存在该问题。请问我忽略了什么?


解决方法

核心问题是LockResource的参数传错了:你传入的是hR(HRSRC类型的资源查找句柄),但正确的参数应该是hG(LoadResource返回的HGLOBAL类型资源加载句柄)。

原因解释

  • FindResource返回的HRSRC只是资源在模块中的位置索引,并不是实际加载到内存的资源数据句柄。
  • LoadResource会把资源数据加载到进程内存,返回的HGLOBAL才是对应内存块的句柄。
  • LockResource需要接收HGLOBAL参数,才能返回指向资源实际数据的指针。你之前传hR虽然没返回nil,但得到的是无效的内存地址,自然找不到VERSION资源的特征字节。

修改后的关键代码行

把:

p:= LockResource( hR );

改成:

p:= LockResource( hG );

额外注意事项

  1. 资源类型的数值ID可以直接用PChar(16)(VERSION资源的类型ID是16),比字符串形式的#16更可靠。
  2. 操作完成后记得调用FreeLibrary(hFile)释放加载的模块句柄,避免内存泄漏。

内容的提问来源于stack exchange,提问作者AmigoJack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 00:22:40