我需要使用TSream从文件(exe或dll)中读取VersionInfo。
我无法使用Windows API GetFileVersionInfo,因为我的文件位于内存(TMemoryStream),我不想将文件写入磁盘以获取此信息,我有一些性能限制。
有人可以帮助我吗?
答案 0 :(得分:3)
如果原始文件数据在内存中,则Win32 API无法帮助您找到文件的版本资源。您必须手动读取和解释文件的PE头以找到文件的资源表,然后遍历该表以查找所需的版本资源。找到它之后,您可以使用Win32 API VerQueryValue()
函数访问资源内部的一些(但不是全部)值。我说一些因为VerQueryValue()
内部依赖于GetFileVersionInfo()
在运行时建立的查找。但是,例如,访问VS_FIXEDFILEINFO
结构可以正常工作,而无需先调用GetFileVersionInfo()
。
答案 1 :(得分:0)
使用已经加载到.EXE
内存空间中的模块的HInstance值,使用TResourceStream获取RT_VERSION
资源。
通过示例,获取MainModule hInstace和相应的Version:
var module: HMODULE;
version: String;
...
module := GetModuleHandle(nil);
version := FileVersion(base);
如果无法像下面那样从内存中加载资源,则可以使用PE HEADERS解析.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.