【问题标题】:Inno Setup, detect Java versionInno Setup,检测Java版本
【发布时间】:2016-10-21 15:47:57
【问题描述】:

使用 Inno Setup 安装我的 Java 应用程序时,我希望安装程序检查是否存在 Java 7 或更高版本,并在需要时安装它。但显然,我当前的代码无法在我的一些客户的计算机上检测到 Java 8。不过,我无法重现该错误。你看到我可能遗漏的东西了吗?也许这段代码不适用于最近的 Windows?

基本上,我只是检查 Java >= 1.7 的注册表。

[Code]

function InitializeSetup(): Boolean;
var
 ErrorCode: Integer;
 JavaInstalled : Boolean;
 ResultMsg : Boolean;
 Versions: TArrayOfString;
 I: Integer;
 regRoot: Integer;
begin
 { Check which view of registry should be taken: }
 regRoot := HKLM
 begin
  if IsWin64 then
  begin
   regRoot := HKLM64
  end;
 end;
 if (RegGetSubkeyNames(regRoot, 'SOFTWARE\JavaSoft\Java Runtime Environment', Versions)) or (RegGetSubkeyNames(regRoot, 'SOFTWARE\JavaSoft\Java Development Kit', Versions)) then
 begin
  for I := 0 to GetArrayLength(Versions)-1 do
   if JavaInstalled = true then
   begin
    //do nothing
   end else
   begin
    if ( Versions[I][2]='.' ) and ( ( StrToInt(Versions[I][1]) > 1 ) or ( ( StrToInt(Versions[I][1]) = 1 ) and ( StrToInt(Versions[I][3]) >= 7 ) ) ) then
    begin
     JavaInstalled := true;
    end else
    begin
     JavaInstalled := false;
    end;
   end;
 end else
 begin
  JavaInstalled := false;
 end;

 if JavaInstalled then
 begin
  Result := true;
 end else
 begin
  ResultMsg := MsgBox(ExpandConstant('{cm:JavaRequired}'), mbConfirmation, MB_YESNO) = idYes;
  if ResultMsg = false then
  begin
   Result := false;
  end else
  begin
   Result := true;
   ShellExec('open', 'http://www.java.com/getjava/', '','',SW_SHOWNORMAL,ewNoWait,ErrorCode);
  end;
 end;
end;

编辑:这是基于 Martin 回答的最终结果。

[Code]
function CutJavaVersionPart(var V: string): Integer;
var
  S: string;
  P: Integer;
begin
  if Length(V) = 0 then
  begin
    Result := 0;
  end
    else
  begin
    P := Pos('.', V);
    if P = 0 then P := Pos('_', V);

    if P > 0 then
    begin
      S := Copy(V, 1, P - 1);
      Delete(V, 1, P);
    end
      else
    begin
      S := V;
      V := '';
    end;
    Result := StrToIntDef(S, 0);
  end;
end;

function MaxJavaVersion(V1, V2: string): string;
var
  Part1, Part2: Integer;
  Buf1, Buf2: string;
begin
  Buf1 := V1;
  Buf2 := V2;
  Result := '';
  while (Result = '') and
        ((Buf1 <> '') or (Buf2 <> '')) do
  begin
    Part1 := CutJavaVersionPart(Buf1);
    Part2 := CutJavaVersionPart(Buf2);
    if Part1 > Part2 then Result := V1
      else
    if Part2 > Part1 then Result := V2;
  end;
end;

function GetJavaVersion(): string;
var
  TempFile: string;
  ResultCode: Integer;
  S: AnsiString;
  P: Integer;
begin
  TempFile := ExpandConstant('{tmp}\javaversion.txt');
  if (not ExecAsOriginalUser(
            ExpandConstant('{cmd}'), '/c java -version 2> "' + TempFile + '"', '',
            SW_HIDE, ewWaitUntilTerminated, ResultCode)) or
     (ResultCode <> 0) then
  begin
    Log('Failed to execute java -version');
  end
    else
  if not LoadStringFromFile(TempFile, S) then
  begin
    Log(Format('Error reading file %s', [TempFile]));
  end
    else
  if Copy(S, 1, 14) <> 'java version "' then
  begin
    Log('Output of the java -version not as expected');
  end
    else
  begin
    Delete(S, 1, 14);
    P := Pos('"', S);
    if P = 0 then
    begin
      Log('Output of the java -version not as expected');
    end
      else
    begin
      SetLength(S, P - 1);
      Result := S;
    end;
  end;

  DeleteFile(TempFile);
end;

function HasJava1Dot7OrNewer: Boolean;
begin
  Result := (MaxJavaVersion('1.6.9', GetJavaVersion) <> '1.6.9');
end;

function InitializeSetup(): Boolean;
var
  ErrorCode: Integer;
begin
  Result := HasJava1Dot7OrNewer;
  if not Result then
  begin
    Result := MsgBox(ExpandConstant('{cm:JavaRequired}'), mbConfirmation, MB_YESNO) = idYes;
    if Result then
    begin
      ShellExec(
        'open', 'https://www.java.com/getjava/', '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode);
    end;
  end;
end;

【问题讨论】:

  • 有人更新了这段代码以使用新的 Java 版本控制方案和 OpenJDK 版本吗?

标签: java inno-setup


【解决方案1】:

我在HKLM\Software 中没有JavaSoft 键。我在HKLM\SOFTWARE\WOW6432Node 有它。 Inno Setup 中的 HKLM\SOFTWARE 实际上是什么(作为 32 位应用程序)。

所以看起来您只需要删除 if IsWin64 then regRoot := HKLM64 块即可使其正常工作。或者尝试这两个选项。

function CutJavaVersionPart(var V: string): Integer;
var
  S: string;
  P: Integer;
begin
  if Length(V) = 0 then
  begin
    Result := 0;
  end
    else
  begin
    P := Pos('.', V);
    if P = 0 then P := Pos('_', V);

    if P > 0 then
    begin
      S := Copy(V, 1, P - 1);
      Delete(V, 1, P);
    end
      else
    begin
      S := V;
      V := '';
    end;
    Result := StrToIntDef(S, 0);
  end;
end;

function MaxJavaVersion(V1, V2: string): string;
var
  Part1, Part2: Integer;
  Buf1, Buf2: string;
begin
  Buf1 := V1;
  Buf2 := V2;
  Result := '';
  while (Result = '') and
        ((Buf1 <> '') or (Buf2 <> '')) do
  begin
    Part1 := CutJavaVersionPart(Buf1);
    Part2 := CutJavaVersionPart(Buf2);
    if Part1 > Part2 then Result := V1
      else
    if Part2 > Part1 then Result := V2;
  end;
end;

function GetJavaVersionFromSubKey(RootKey: Integer; SubKeyName: string): string;
var
  Versions: TArrayOfString;
  I: Integer;
begin
  if RegGetSubkeyNames(RootKey, SubKeyName, Versions) then
  begin
    for I := 0 to GetArrayLength(Versions) - 1 do
    begin
      Result := MaxJavaVersion(Result, Versions[I]);
    end;
  end;
end;

function GetJavaVersionFromRootKey(RootKey: Integer): string;
begin
  Result := 
    MaxJavaVersion(
      GetJavaVersionFromSubKey(RootKey, 'SOFTWARE\JavaSoft\Java Runtime Environment'),
      GetJavaVersionFromSubKey(RootKey, 'SOFTWARE\JavaSoft\Java Development Kit'));
end;

function GetJavaVersion: string;
begin
  Result := GetJavaVersionFromRootKey(HKLM);
  if IsWin64 then
  begin
    Result := MaxJavaVersion(Result, GetJavaVersionFromRootKey(HKLM64));
  end;
end;

根据您的特定需求,您可以检查是否安装了 Java 1.7 或更新版本:

function HasJava1Dot7OrNewer: Boolean;
begin
  Result := (MaxJavaVersion('1.6.9', GetJavaVersion) <> '1.6.9');
end;

或者您是否考虑改为运行java -version

function GetJavaVersion2: string;
var
  TempFile: string;
  ResultCode: Integer;
  S: AnsiString;
  P: Integer;
begin
  TempFile := ExpandConstant('{tmp}\javaversion.txt');
  if (not ExecAsOriginalUser(
            ExpandConstant('{cmd}'), '/c java -version 2> "' + TempFile + '"', '',
            SW_HIDE, ewWaitUntilTerminated, ResultCode)) or
     (ResultCode <> 0) then
  begin
    Log('Failed to execute java -version');
  end
    else
  if not LoadStringFromFile(TempFile, S) then
  begin
    Log(Format('Error reading file %s', [TempFile]));
  end
    else
  if Copy(S, 1, 14) <> 'java version "' then
  begin
    Log('Output of the java -version not as expected');
  end
    else
  begin
    Delete(S, 1, 14);
    P := Pos('"', S);
    if P = 0 then
    begin
      Log('Output of the java -version not as expected');
    end
      else
    begin
      SetLength(S, P - 1);
      Result := S;
    end;
  end;
  
  DeleteFile(TempFile);
end;

更有效地实现InitializeSetup

function InitializeSetup(): Boolean;
var
  ErrorCode: Integer;
begin
  Result := HasJava1Dot7OrNewer;
  if not Result then
  begin
    Result :=
      MsgBox(ExpandConstant('{cm:JavaRequired}'), mbConfirmation, MB_YESNO) = idYes;
    if Result then
    begin
      ShellExec(
        'open', 'https://www.java.com/getjava/', '', '', SW_SHOWNORMAL,
        ewNoWait, ErrorCode);
    end;
  end;
end;

【讨论】:

  • 天哪,你救了我这么多!我没有 Pascal 的开发环境,我根本不懂这种语言。
【解决方案2】:

回答我自己的评论,这是我的变体,无论安装的 JRE 是 Oracle 还是 OpenJDK,以及 Java 9 之前和之后的 Java 版本,它都应该有效。

GetJavaMajorVersion() 函数以整数形式返回 Java 版本。对于java -version 报告“1.x.*”的版本(直到并包括 Java 8),它将返回 x,否则(Java 9 和更高版本)它将返回实际的主编号。如果由于某种原因对 java -version 的调用失败,它将返回 0。

function GetJavaMajorVersion(): integer;
var
  TempFile: string;
  ResultCode: Integer;
  S: AnsiString;
  P: Integer;
begin
  Result := 0;

  { execute java -version and redirect output to a temp file }
  TempFile := ExpandConstant('{tmp}\javaversion.txt');
  if (not ExecAsOriginalUser(ExpandConstant('{cmd}'), '/c java -version 2> "' + TempFile + '"', '',SW_HIDE, ewWaitUntilTerminated, ResultCode)) 
    or (ResultCode <> 0) then
  begin
    Log('Failed to execute java -version');
    exit;
  end;

  { read file into variable S }
  LoadStringFromFile(TempFile, S)
  DeleteFile(TempFile);
  Log(Format('java -version output: ' + #13#10 + '%s', [S]));

  { extract version (between quotes) }
  P := Pos('"', S);
  Delete(S, 1, P);
  P := Pos('"', S);
  SetLength(S, P - 1);
  Log(Format('Extracted version: %s', [S]));

  { extract major }
  if Copy(S, 1, 2) = '1.' then
  begin
    Delete(S, 1, 2)
  end;
  P := Pos('.', S);
  SetLength(S, P - 1);
  Log(Format('Major version: %s', [S]));

  Result := StrToIntDef(S, 0);
end;

function InitializeSetup(): boolean;
var
  ResultCode: Integer;
begin
  if GetJavaMajorVersion >= 8 then
  begin
    Result := true;    
    exit;
  end;

  if MsgBox('This tool requires a Java Runtime Environment version 1.8 or newer to run. ' +
    'Please download and install the JRE and run this setup again. ' +
    'Would you like to open the JRE download page now?', mbCriticalError, MB_YESNO) = idYes then 
  begin
    Result := false;
    ShellExec('open', 'https://java.com/download/', '', '', SW_SHOWNORMAL, ewNoWait, ResultCode);
  end;  
end;

还有很多改进的余地,但确实可以。

【讨论】:

    【解决方案3】:

    我想要一些我可以在多个 Inno Setup 项目中使用的东西,所以我编写了一个 DLL 来检测 Java 详细信息(主目录等):

    https://github.com/Bill-Stewart/JavaInfo

    从这里下载:https://github.com/Bill-Stewart/JavaInfo/releases

    下载包含一个示例 Inno Setup .iss 脚本,该脚本演示了如何使用 DLL 函数。

    【讨论】:

      猜你喜欢
      • 2011-07-04
      • 2019-03-28
      • 1970-01-01
      • 2015-11-09
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多