Beto Neto
Beto Neto

Reputation: 4112

READ VersionInfo from file with a TFileStream

I need to read the VersionInfo from a file (exe or dll) using a TSream.

I cannot use the windows API GetFileVersionInfo, because my file is at memory (TMemoryStream) and I don't want to write the file to disk for get this information, I have some performance restrictions.

Someone can help me?

Upvotes: 1

Views: 628

Answers (2)

Luiz Vaz
Luiz Vaz

Reputation: 1839

It can be archived using the technique below.

Use the HInstance value of modules already loaded in .EXE memory space to get the RT_VERSION resource using TResourceStream.

By example, to get the MainModule hInstace and respective Version:

var module: HMODULE;
    version: String;
...
module := GetModuleHandle(nil);
version := FileVersion(base);

If you can't load as a resource from memory like I did below, you can parse the .EXE using PE HEADERS and find RT_VERSION resource using a TMemoryStream.

unit Version;

interface

implementation

uses
  Winapi.Windows, System.SysUtils, System.Classes, Math;

function FileVersion(Module: HINST = 0): String;
var
  verblock:PVSFIXEDFILEINFO;
  versionMS,versionLS:cardinal;
  verlen:cardinal;
  rs:TResourceStream;
  m:TMemoryStream;
  p:pointer;
  s:cardinal;
begin
  m:=TMemoryStream.Create;
  try
    if Module = 0 then
      Module := HInstance;

    rs:=TResourceStream.CreateFromID(Module,1,RT_VERSION);
    try
      m.CopyFrom(rs,rs.Size);
    finally
      rs.Free;
    end;
    m.Position:=0;
    if VerQueryValue(m.Memory,'\',pointer(verblock),verlen) then
      begin
        VersionMS:=verblock.dwFileVersionMS;
        VersionLS:=verblock.dwFileVersionLS;
        Result:=
          IntToStr(versionMS shr 16)+'.'+
          IntToStr(versionMS and $FFFF)+'.'+
          IntToStr(VersionLS shr 16)+'.'+
          IntToStr(VersionLS and $FFFF);
      end;
    if VerQueryValue(m.Memory,PChar('\\StringFileInfo\\'+
      IntToHex(GetThreadLocale,4)+IntToHex(GetACP,4)+'\\FileDescription'),p,s) or
        VerQueryValue(m.Memory,'\\StringFileInfo\\040904E4\\FileDescription',p,s) then //en-us
          Result:=PChar(p)+' '+Result;
  finally
    m.Free;
  end;
end;

end.

Upvotes: 0

Remy Lebeau
Remy Lebeau

Reputation: 598031

If the raw file data is in memory, then the Win32 API cannot help you locate the file's version resource. You will have to manually read and interpret the file's PE header to locate the file's resources table and then loop through the table looking for the desired version resource. Once you have located it, you can use the Win32 API VerQueryValue() function to access some (but not all) of the values inside of the resource. I say some because VerQueryValue() internally relies on lookups that GetFileVersionInfo() establishes at runtime. However, accessing the VS_FIXEDFILEINFO structure, for instance, works fine without calling GetFileVersionInfo() first.

Upvotes: 3

Related Questions