如何在Inno Setup中安装JRE?

6
我正在尝试通过Inno Setup(以及另一个应用程序)安装最新的平台(x64或x86)适当的Java运行时环境。我找到了一些脚本示例,用于检测版本并在正确时进行安装,并根据我的需求进行了调整,但是我一直遇到以下问题:
无法打开文件“path\to\JREInstall.exe”: CreateProcess失败:Code 5: 访问被拒绝
这是严格负责安装JRE的代码:
[Setup]
AppName="JRE Setup"
AppVersion=0.1
DefaultDirName="JRE Setup"

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Files]
Source: "jre-8u11-windows-x64.exe"; DestDir: "{tmp}\JREInstall.exe"; \
    Check: IsWin64 AND InstallJava();
Source: "jre-8u11-windows-i586.exe"; DestDir: "{tmp}\JREInstall.exe"; \
    Check: (NOT IsWin64) AND InstallJava();

[Run]
Filename: "{tmp}\JREInstall.exe"; Parameters: "/s"; \
    Flags: nowait postinstall runhidden runascurrentuser; Check: InstallJava()

[Code]

procedure DecodeVersion(verstr: String; var verint: array of Integer);
var
  i,p: Integer; s: string;
begin
  { initialize array }
  verint := [0,0,0,0];
  i := 0;
  while ((Length(verstr) > 0) and (i < 4)) do
  begin
    p := pos ('.', verstr);
    if p > 0 then
    begin
      if p = 1 then s:= '0' else s:= Copy (verstr, 1, p - 1);
      verint[i] := StrToInt(s);
      i := i + 1;
      verstr := Copy (verstr, p+1, Length(verstr));
    end
    else
    begin
      verint[i] := StrToInt (verstr);
      verstr := '';
    end;
  end;
end;

function CompareVersion (ver1, ver2: String) : Integer;
var
  verint1, verint2: array of Integer;
  i: integer;
begin
  SetArrayLength (verint1, 4);
  DecodeVersion (ver1, verint1);

  SetArrayLength (verint2, 4);
  DecodeVersion (ver2, verint2);

  Result := 0; i := 0;
  while ((Result = 0) and ( i < 4 )) do
  begin
    if verint1[i] > verint2[i] then
      Result := 1
    else
      if verint1[i] < verint2[i] then
        Result := -1
      else
        Result := 0;
    i := i + 1;
  end;
end;

function InstallJava() : Boolean;
var
  ErrCode: Integer;
  JVer: String;
  InstallJ: Boolean;
begin
  RegQueryStringValue(
    HKLM, 'SOFTWARE\JavaSoft\Java Runtime Environment', 'CurrentVersion', JVer);
  InstallJ := true;
  if Length( JVer ) > 0 then
  begin
    if CompareVersion(JVer, '1.8') >= 0 then
    begin
      InstallJ := false;
    end;
  end;
  Result := InstallJ;
end;

在完整的安装脚本中,仍然会出现相同的消息。 我该如何让JRE安装程序从这个脚本化的安装文件运行?

你的 [Run] 部分看起来相当奇怪。你使用了 postinstall,它会在最后一页创建复选框,这对于安装先决条件来说非常不寻常。但更糟糕的是,在安装程序完成时应该删除从中运行该设置的 {temp} 文件夹。不要提供用户从 Inno Setup 安装程序的临时文件夹运行应用程序的选项。最好使用 PrepareToInstall 事件来安装先决条件。 - TLama
是的,你说得对。我不知道“post install”选项确切的作用是什么。我也找到了问题所在。 - Will
2个回答

7

我能够找出问题所在: 显然,我对这些行的使用方式存在误解:

Source: "jre-8u11-windows-x64.exe"; DestDir: "{tmp}\JREInstall.exe"; Check: IsWin64 AND InstallJava();
Source: "jre-8u11-windows-i586.exe"; DestDir: "{tmp}\JREInstall.exe"; Check: (NOT IsWin64) AND InstallJava();

它们应该像这样放置:

Source: "jre-8u11-windows-x64.exe"; DestDir: "{tmp}"; DestName: "JREInstall.exe"; Check: IsWin64 AND InstallJava();
Source: "jre-8u11-windows-i586.exe"; DestDir: "{tmp}"; DestName: "JREInstall.exe"; Check: (NOT IsWin64) AND InstallJava();

看起来这个问题已经解决了。

还有这一行我搞错了:

Filename: "{tmp}\JREInstall.exe"; Parameters: "/s"; Flags: nowait postinstall runhidden runascurrentuser; Check: InstallJava()

应该是:

Filename: "{tmp}\JREInstall.exe"; Parameters: "/s"; Flags: nowait runhidden runascurrentuser; Check: InstallJava()

这是我有限的经验能够提供的最佳解决方案。等我有机会时,我会研究PrepareToInstall选项,但目前这个方案可行。


еҪ“жӮЁеҝҪз•Ҙpostinstallж Үеҝ—ж—¶пјҢж— йңҖдҪҝз”Ёrunascurrentuserж Үеҝ—пјҢеӣ дёәй»ҳи®Өжғ…еҶөдёӢдјҡдҪҝз”Ёе®ғгҖӮ - TLama

2
根据最初的问题,“如何在Inno脚本中安装JRE?”,并以最佳提议为起点,我提出了一个更加连贯的解决方案。
我理解用户希望在目标计算机上安装JRE,如果该计算机没有安装Java运行环境或其版本低于所需版本。好的,我的建议是使用AfterInstall参数,并以不同的方式重新排序分发文件。
我们将首先以另一种方式对[Files]部分的文件进行排序,首先放置redist安装文件。
Source: "redist\jre-8u121-windows-i586.exe"; DestDir: "{tmp}"; DestName: "JREInstaller.exe";\
    Flags: deleteafterinstall; AfterInstall: RunJavaInstaller(); \
    Check: (NOT IsWin64) AND InstallJava();
Source: "redist\jre-8u121-windows-x64.exe"; DestDir: "{tmp}"; DestName: "JREInstaller.exe"; \
    Flags: deleteafterinstall; AfterInstall: RunJavaInstaller(); \
    Check: IsWin64 AND InstallJava();
Source: "Myprog.exe"; DestDir: "{app}"; Flags: ignoreversion

我们接下来需要做的是修改[Run]部分,具体如下。
[Run]
Filename: "{app}\{#MyAppExeName}"; \
    Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; \
    Flags: nowait postinstall skipifsilent

最后但并非最不重要的是,我们在[Code]部分实现了以下RunJavaInstaller()过程:

[Code]

procedure RunJavaInstaller();
var
  StatusText: string;
  ResultCode: Integer;
  Path, Parameters: string;
begin
  Path := '{tmp}\JREInstaller.exe';
  { http://docs.oracle.com/javase/8/docs/technotes/guides/install/config.html#table_config_file_options }
  Parameters := '/s INSTALL_SILENT=Enable REBOOT=Disable SPONSORS=Disable REMOVEOUTOFDATEJRES=1';
  StatusText:= WizardForm.StatusLabel.Caption;
  WizardForm.StatusLabel.Caption:='Installing the java runtime environment. Wait a moment ...';
  WizardForm.ProgressGauge.Style := npbstMarquee;
  try
    if not Exec(ExpandConstant(Path), Parameters, '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
    begin
      { we inform the user we couldn't install the JRE }
      MsgBox('Java runtime environment install failed with error ' + IntToStr(ResultCode) + 
        '. Try installing it manually and try again to install MyProg.', mbError, MB_OK);
    end;
  finally
    WizardForm.StatusLabel.Caption := StatusText;
    WizardForm.ProgressGauge.Style := npbstNormal;
  end;
end;

你可能需要将Enabled的值替换为1,将Disabled的值替换为0,如果Java运行时安装程序无法正常工作。我以这种方式没有遇到任何问题。无论如何,在代码中,如果您想查看Oracle链接,您可以找到一个注释。
最后,由于不幸的是我们无法以任何方式接收JRE的安装进度状态,因此我们会显示一条消息和进度条,以便用户不会感到安装程序已挂起。 为了做到这一点,我们在执行Exec命令之前保存状态,并使用ewWaitUntilTerminated标志等待安装完成,然后才继续进行我们的操作,并在函数执行完毕后恢复先前的状态。

+1 - 尽管如此 1)[Run]部分与问题有什么关系? 2)您坚持对[Files]部分进行特定排序的原因是什么? 3)即使Exec返回true,您也应该测试ResultCode <> 0 - Martin Prikryl
我想知道 Source: "Myprog.exe"; DestDir: "{app}"; Flags: ignoreversion 这段代码的含义。对我来说,这意味着该应用程序已经被转换为 Windows 本地可执行文件。这是如何完成的?我一直在使用 NetBeans 的本地部署选项,但它包含了 JRE。如果是这样的话,似乎有点多余。为什么不直接使用 MyProg.jar 呢?需要设置文件关联,但我相信 jar 文件可以正常运行。作为一个新手,我还在努力学习,希望有人能帮助我更好地理解。 - Ed S
嗨,我同意@Martin的评论,你的答案太好了,不可能不完美。1)令人困惑。你写了“必须”..修改,但实际上你的[Run]部分与一个空的inno文件是相同的。2)我没有看到顺序上有太大的区别,也许如果你的应用程序太大,而且你不想回滚巨大的数据,如果安装被取消,但再说一遍,3)你坚持不想检查Java安装(ResultCode)是否被取消,并且即使Java安装被取消,也会继续安装。请修复它。 - papo
嗨@papo,感谢您的留言。正如我在先前的回答中所说,使用ResultCode会提供更多有关导致JRE安装失败原因的信息,在我的示例中,由于用户和JRE安装程序之间没有可能的交互(标志INSTALL_SILENT=Enabled),在失败的情况下Exec将返回false,但代码可以根据您的喜好进行修改。至于顺序问题,我认为最好先安装以前的要求,最后再安装程序。这样,在出现故障的情况下,我们可以采取行动。 - CodeCat
如果成功启动了进程,Exec()返回true,即使该进程随后失败也是如此。仅在缺少或损坏的exe文件等情况下才返回false。如果Exec()返回true并且指定了ewWaitUntilTerminated,则ResultCode显示进程的退出代码,但是如果Exec()无法启动进程,则显示该错误的代码。同一变量中的非常不同的事情。这就是为什么应该检查两种情况的原因。实际上,在这里,即使取消(使用/s运行也不足以假设它不会),JRE也会返回0。如果需要,我们必须通过其他方式检查Java是否已正确安装。 - papo
显示剩余14条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接