delphiwinapidelphi-7embedded-resourcefileversioninfo

Data pointer from LockResource() is not the expected VS_VERSION_INFO structure


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:

pointer to $585c0 in CALC.EXE

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:

actual VERSIONINFO at $b96f0

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:

Resource Hacker confirms $b96f0

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 WORDs + 15 WCHARs = 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.


Solution

  • You're passing the wrong parameter to LockResource(). You should pass hG instead of hR.