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 );
额外注意事项
- 资源类型的数值ID可以直接用
PChar(16)(VERSION资源的类型ID是16),比字符串形式的#16更可靠。 - 操作完成后记得调用
FreeLibrary(hFile)释放加载的模块句柄,避免内存泄漏。
内容的提问来源于stack exchange,提问作者AmigoJack
相关产品推荐
相关产品推荐

