在 Stackoverflow 上找到它:
如何确定 Delphi 应用程序版本
我已经知道如何确定应用程序版本,但@StijnSanders 提出了“更好”的方法,这正是我遇到的原因:
当您想知道当前正在运行的可执行文件的版本时,我强烈建议不要使用 GetFileVersion!我有两个很好的理由这样做:
- 可执行文件可能无法访问(断开驱动器/共享),或已更改(.exe 重命名为 .bak 并被新的 .exe 替换,而没有停止正在运行的进程)。
- 您尝试读取的版本数据实际上已经加载到内存中,并且通过加载此资源可供您使用,这总是比执行额外(相对较慢)的磁盘操作更好。
我适应了:
function GetModuleVersion(Instance: THandle; out iMajor, iMinor, iRelease, iBuild: Integer): Boolean;
var
fileInformation: PVSFIXEDFILEINFO;
verlen: Cardinal;
rs: TResourceStream;
m: TMemoryStream;
resource: HRSRC;
begin
//You said zero, but you mean "us"
if Instance = 0 then
Instance := HInstance;
//UPDATE: Workaround bug in Delphi if resource doesn't exist
resource := FindResource(Instance, 1, RT_VERSION);
if resource = 0 then
begin
iMajor := 0;
iMinor := 0;
iRelease := 0;
iBuild := 0;
Result := False;
Exit;
end;
m := TMemoryStream.Create;
try
rs := TResourceStream.CreateFromID(Instance, 1, RT_VERSION);
try
m.CopyFrom(rs, rs.Size);
finally
rs.Free;
end;
m.Position:=0;
if not VerQueryValue(m.Memory, '\', (*var*)Pointer(fileInformation), (*var*)verlen) then
begin
iMajor := 0;
iMinor := 0;
iRelease := 0;
iBuild := 0;
Exit;
end;
iMajor := fileInformation.dwFileVersionMS shr 16;
iMinor := fileInformation.dwFileVersionMS and $FFFF;
iRelease := fileInformation.dwFileVersionLS shr 16;
iBuild := fileInformation.dwFileVersionLS and $FFFF;
finally
m.Free;
end;
Result := True;
end;
警告:由于 Delphi 中的错误,上述代码有时会崩溃:
rs := TResourceStream.CreateFromID(Instance, 1, RT_VERSION);
如果没有版本信息,Delphi 会尝试引发异常:
procedure TResourceStream.Initialize(Instance: THandle; Name, ResType: PChar);
procedure Error;
begin
raise EResNotFound.CreateFmt(SResNotFound, [Name]);
end;
begin
HResInfo := FindResource(Instance, Name, ResType);
if HResInfo = 0 then Error;
...
end;
当然,错误在于PChar
它并不总是指向 ansi char的指针。对于未命名的资源,它们是整数常量,转换为PChar
. 在这种情况下:
Name: PChar = PChar(1);
当 Delphi 尝试构建异常字符串并取消引用0x00000001
它触发和访问冲突的指针时。
解决方法是先手动调用FindResource(Instance, 1, RT_VERSION)
:
var
...
resource: HRSRC;
begin
...
resource := FindResource(Instance, 1, RT_VERSION);
if (resource = 0)
begin
iMajor := 0;
iMinor := 0;
iRelease := 0;
iBuild := 0;
Result := False;
Exit;
end;
m := TMemoryStream.Create;
...
注意:任何代码都会发布到公共领域。无需归属。