将 float 数据转换为 Cardinal,反之亦然,以一种友好的方式比较版本号

Convert float data to Cardinal or vice versa for a friendly way to compare version numbers

玩过一些版本后,我遇到了数据转换问题。

我正在使用 GetVersionNumbers 方法获取版本部件作为 MS 和 LS。两个输出变量都是基数类型。现在我遇到了问题——我想将它们与其他一些版本进行比较,但最后一个版本存储在 Single 中(例如 1.3)。因此,我想将 Single 转换为 Cardinal 或将 Cardinal 转换为 Single(例如,对于 Single 中的 1.3,对应的 Cardinal 为 65539)。

至于现在,我发现了一些有趣且简单的 Delphi 解决方案,它依赖于直接内存访问:

function FloatToCardinal(val: Single): Cardinal;
var
p: ^Cardinal;          
begin
  p:=@(val);
  Result:=p^;
end;

这里的问题是 Inno Setup 显然不能以这种方式使用指针 - 它在尝试编译时为 p: ^Cardinal; 部分给出 "Identifier expected" 错误。因此,我想为 Inno Setup 调整此功能,或者寻找其他转换或比较方式。

在此问题上如有任何帮助,我们将不胜感激。

You cannot use floats for comparison reliably。版本号不是(浮动)数字。这是一个整数序列。你甚至可以拥有像 1.2.3 这样的版本,你甚至不能将其表示为浮点数。


你最好实现一些方便的实用函数,比如:

function AreVersionNumbersAtLeast(
  Major, Minor, MajorAtLeast, MinorAtLeast: Cardinal): Boolean;
begin
  Result :=
    (Major > MajorAtLeast) or
    ((Major = MajorAtLeast) or (Minor >= MinorAtLeast));
end;

并像这样使用它:

if AreVersionNumbersAtLeast(Major, Minor, 1, 3) then
  Log('Program is 1.3 or newer');

如果你经常使用GetVersionNumbers返回的MS,你可以把它包装成:

function IsVersionMSAtLeast(VersionMS, MajorAtLeast, MinorAtLeast: Cardinal): Boolean;
var
  Major: Cardinal;
  Minor: Cardinal;
begin
  Major := VersionMS shr 16;
  Minor := VersionMS and $FFFF;

  Result := AreVersionNumbersAtLeast(Major, Minor, MajorAtLeast, MinorAtLeast);
end;

并像这样使用它:

if IsVersionMSAtLeast(VersionMS, 1, 3) then
  Log('Program is 1.3 or newer');

甚至是 shorthand 特定文件,如:

function IsFileVersionAtLeast(
  FileName: string; MajorAtLeast, MinorAtLeast: Integer): Boolean;
var
  VersionMS, VersionLS: Cardinal;
begin
  Result := 
    GetVersionNumbers(FileName, VersionMS, VersionLS) and
    IsVersionMSAtLeast(VersionMS, MajorAtLeast, MinorAtLeast);
end;

并像这样使用它:

if IsFileVersionAtLeast(ExpandConstant('{app}\MyProg.exe'), 1, 3) then
  Log('Program is 1.3 or newer');

如果您更喜欢 1.3 语法,请使用字符串,而不是浮点数。

使用如下函数解析字符串:

function VersionStrToNumbers(Version: string; var Major, Minor: Cardinal): Boolean;
var
  V1, V2: Integer;
  P: Integer;
begin
  P := Pos('.', Version);
  Result := (P > 0);
  if Result then
  begin
    V1 := StrToIntDef(Copy(Version, 1, P - 1), -1);
    V2 := StrToIntDef(Copy(Version, P + 1, Length(Version) - P), -1);
    Result := (V1 >= 0) and (V2 >= 0);
    if Result then
    begin
      Major := Cardinal(V1);
      Minor := Cardinal(V2);
    end;
  end;
end;

并用它来实现一个方便的功能,例如:

function IsFileVersionAtLeastStr(FileName, Version: string): Boolean;
var
  MajorAtLeast, MinorAtLeast: Cardinal;
begin
  Result :=
    VersionStrToNumbers(Version, MajorAtLeast, MinorAtLeast) and
    IsFileVersionAtLeast(FileName, MajorAtLeast, MinorAtLeast);
end;

并像这样使用它:

if IsFileVersionAtLeast(ExpandConstant('{app}\MyProg.exe'), '1.3') then
  Log('Program is 1.3 or newer');

(这只是一个概念代码,我没有测试任何这些代码)


另一种方法是计算 "MS" 并比较:

function Version(Major, Minor: Cardinal): Cardinal;
begin
  Result := (Major shl 16) + Minor;
end;

像这样使用它:

if VersionMS >= Version(1, 3) then
  Log('Program is 1.3 or newer');