使用TFileStream从文件中读取版本信息



我需要使用TSream从文件(exe或dll)中读取VersionInfo。

我不能使用windows API GetFileVersionInfo,因为我的文件是在内存(TMemoryStream),我不想写文件到磁盘获取此信息,我有一些性能限制。

有人能帮帮我吗?

如果原始文件数据在内存中,那么Win32 API无法帮助您定位文件的版本资源。您必须手动读取和解释文件的PE头,以定位文件的资源表,然后遍历表查找所需的版本资源。一旦找到了它,就可以使用Win32 API VerQueryValue()函数访问资源内部的一些(但不是全部)值。我说一些是因为VerQueryValue()内部依赖于GetFileVersionInfo()在运行时建立的查找。然而,访问VS_FIXEDFILEINFO结构,例如,不首先调用GetFileVersionInfo(),工作得很好。

可以使用下面的技术进行存档。

使用.EXE内存空间中已经加载的模块的HInstance值来使用TResourceStream获取RT_VERSION资源。

通过示例,获取MainModule hInstace和各自的Version:

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

如果你不能像下面这样从内存中加载资源,你可以使用PE头解析.EXE,并使用TMemoryStream找到RT_VERSION资源。

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.

最新更新