I want to load the binary data of a VERSION resource from an external EXE file. This should be fairly simple:
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 and https://stackoverflow.com/a/23035857/4299358 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 );
I get valid handles all the way through, and also a non-nil
pointer. For debugging purposes I stuff the bytes into an AnsiString
to then view its content. If I search for those bytes in the file I find them off by far from the resource I wanted (file position $585c0) - and it's the only occurrence of those bytes:
The VS_VERSION_INFO
resource I wanted is found 388 KiB later at $b96f0 (one can even spot a preceding resource storing a PNG file - note the IEND
chunk, most likely one of its icons). The expected bytes $bd $04 $ef $fe
from VS_FIXEDFILEINFO.dwSignature
can be seen 40 bytes later:
This is also confirmed by Resource Hacker, showing where the resource resides in the binary file (see Status Bar with file position "B96F0") - it also confirms the resource has the name 1
(like many others) and is the only VERSION
resource, so I'm not accidentially finding a different resource:
What am I missing? LockResource()
clearly explains:
the return value is a pointer to the first byte of the resource
So there's not an offset I'm missing to add. I expected the bytes to contain the VS_FIXEDFILEINFO
structure, which should be nearby after 38 bytes of the VS_VERSIONINFO
pseudo structure (3 WORD
s + 15 WCHAR
s = 36 bytes at least with variable padding).
I don't want to use GetFileVersionInfoW()
and VerQueryValueW()
because I want to avoid Windows being a man in the middle and because the file version is only one step - my goal is to read any resource reliably (not only those where the WinAPI provides helper functions).
I'm using Delphi 7 on Windows 7x64, so the debugged EXE is 32-bit and the loaded CALC.EXE is also ensured to be 32-bit (although that shouldn't matter). I failed to access the expected bytes of the version resource of other 32-bit EXE files, too.
You're passing the wrong parameter to
LockResource()
. You should passhG
instead ofhR
.