How do I install a JRE from an Inno Setup?

10,906

Solution 1

I was able to figure out the issue: Evidently I was mistaken in my use of these lines:

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();

and they should have been in place like so:

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();

That seems to have solved the problem.

Also this line I was mistaken in:

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

It should have been:

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

This is the best solution my limited experience with this particular tool is able to come up with. I will look into the PrepareToInstall option when I have a chance but this works for now.

Solution 2

According to the initial question, "How do I install a JRE from an Inno script?", and taking as a starting solution the best proposed one, I propose a solution that I think works more coherently.

I understand that the user wants to install a JRE for their application if the target computer does not have installed a Java runtime environment or its version is lower than the required one. Ok, what I propose is to use the AfterInstall parameter and reorder a bit the distribution files in a different way.

We will first sort the files in the [Files] section in another way, putting first the redist install files.

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

The next step we must do is to modify the section [Run] as follows.

[Run]
Filename: "{app}\{#MyAppExeName}"; \
    Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; \
    Flags: nowait postinstall skipifsilent

And last but not least, we implemented in the [Code] section the RunJavaInstaller() procedure as follows:

[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;

You may need to replace the Enabled value with 1 and the Disabled value with 0 if the Java runtime installer is not working properly. I have not experienced any problem doing it this way. Anyways, in the code you have a comment with the Oracle link if you want to take a look.

Finally, since unfortunately we can not receive the installation progress status of the JRE in any way, we show a message and a progress bar so that the user does not have the feeling that the installer has hung. To do this, we save the state before, execute Exec with the flag ewWaitUntilTerminated, to wait for that installation to finish before continuing with ours, and we restore the previous state once the function execution has finished.

Share:
10,906

Related videos on Youtube

Will
Author by

Will

Updated on June 04, 2022

Comments

  • Will
    Will almost 2 years

    I'm trying to install the most current platform (x64 or x86) appropriate Java Runtime Environment via Inno Setup (along with another application). I've found some script examples for how to detect the version and install if correct and adapted them to my needs but I keep running into this:

    Unable to open file "path\to\JREInstall.exe":
    CreateProcess failed: Code 5:
    Access Is Denied

    This is the code strictly responsible for installing the 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;
    

    In the full setup script the same message continues to come up. How can I get the JRE Setup to run from this scripted setup file?

    • TLama
      TLama almost 10 years
      Your [Run] section seems to be pretty weird. You have used postinstall which creates the check box on the final page, which is quite unusual for installing prerequisite. But what's worse, the {temp} folder from where you run that setup should be deleted at the time when the installer finishes. Do not offer the user to run an app. from a temp folder of the Inno Setup installer. Better use PrepareToInstall event for installing prerequisites.
    • Will
      Will almost 10 years
      Yes you are right. I didn't know exactly what that (the post install) option did. I figured out the issue as well.
  • TLama
    TLama almost 10 years
    You don't need to use runascurrentuser flag when you omit the postinstall one as it is used by default.
  • Martin Prikryl
    Martin Prikryl about 7 years
    +1 - Though 1) What does the [Run] section have to do with the question? 2) What's the reason you insist on a specific sorting of the [Files] section? 3) You should test ResultCode <> 0 even if Exec return true.
  • Ed S
    Ed S about 7 years
    I'm wondering about Source: "Myprog.exe"; DestDir: "{app}"; Flags: ignoreversion To me that says that the app (program ) has somehow been converted to a Windows Native executable. How did that get done? I've been doing it with the NetBeans Native deployment option, but that incorporates JRE. If so, there seems to be a bit of belts & braces. Why not just use MyProg.jar? It would be necessary to set file associations, but I believe the jar file would run just fine. I'm somewhat of a novice here, still struggling, so maybe someone can help me understand better.
  • CodeCat
    CodeCat about 7 years
    Hi @EdS thanks for your comment.Yes I have converted the jar file with the Wrapper Launch4J [link](www.launch4j.sourceforge.net) but of course you can distribute the jar file (and the associated ones in lib directory) and even a bat file, Icon file, etc. Greetings
  • CodeCat
    CodeCat about 7 years
    @MartinPrikryl thanks for your comment, let me reply to you begining from the last question. Yes, test the ResultCode var is much more usefull, as is much more rich in details, but for this sample was enought to evaluate the result of Exec. 2 question - Why: Cause if something goes wrong with the installation of the JRE, essential for the program, we can, for example, cancel the installation, hence the installation order. 1 Run section, I run everything I need there once I have successfully completed the installation. Greetings
  • Martin Prikryl
    Martin Prikryl about 7 years
    3) But the Exec returns False only, if it fails to run the installer. If the installer starts, but fails to install, the Exec returns true, but the exit code will indicate the installation failure. 2) But then you should show, how to abort/rollback the installation, otherwise the ordering has no effect. 1) But that has nothing to do with the question. It looks confusing to me.
  • CodeCat
    CodeCat about 7 years
    Hello again @MartinPrikryl as I said in my first comment, evaluate ResultCode is much more powerfull, so do it if you need so. About the 2nd question, and just as a first approximation to the solution we could use a global variable in the code section to keep the ResultCode value and use it in a function (InstallProgramFile() for example) we can use in the check section of the source program file (Myprog.exe in the example) to install or not the program file, it's just an idea, I also suggest you to take a look at the Inno code events in the Inno setup help. Greetings.
  • Ed S
    Ed S about 7 years
    This approach, with CodeCat suggestions, worked for me... actually got a simple Java app to install and work on my backup Windows machine without Java. However, it actually installs a JRE on the users machine, and, if I understand correctly, could overwrite one already there. Is this a good idea? Other approaches (which I have yet to make work) bundle a private JRE used only by the app being installed.
  • CodeCat
    CodeCat about 7 years
    Hi @EdS, about if it's a good Idea or not it depends of your needs, the InstallJava() function controls my project needs and look and find if we have JRE installed and if its version is greather or equal the needed one, there you can program your own needs. On the other hand the JRE installer flag AUTO_UPDATE is Enabled by default so if you have to install the JRE, it will be updated to the last version. see [docs.oracle.com/javase/8/docs/technotes/guides/install/…
  • Ed S
    Ed S about 7 years
    The concern is some user might have an outdated version installed because he/she has some "legacy app" uses deprecated Java code. That seems unlikely in my case because there will be a small number of users (30-50 max) who are use computers primarily to read email.
  • CodeCat
    CodeCat about 7 years
    Hi again @EdS, Well, in the case you propose, we could modify the RunJavaInstaller() function to request the user conformity to update to the new JRE version. Obviously, if the user does not want to update the JRE, we must implement some method to cancel the installation, since the InstallJava() function returns true in case JRE installation does not exist, or exists but its version is lower than the one needed by our application. Greetings.
  • papo
    papo about 7 years
    Hi, I agree with @Martin comments, your answer is too good to not be perfect. 1) confusing. you wrote "must" .. modify, but actually your [Run] section is identical with a blank inno file. 2) I don't see much difference in the order, maybe if your App is too big and you don't want to rollback huge data if install was cancelled, but than again, 3) You insist you don't want to check for cancellations of Java install (ResultCode) and would just go on with the install even if Java install was cancelled. Please fix it.
  • CodeCat
    CodeCat about 7 years
    Hi @papo, thanks for your message. As I said in my previous answers, The use of ResultCode offers more information about the causes that caused the failure of the JRE installation, in the case of my example since there is no possible interaction between the user and the JRE installer (flag INSTALL_SILENT=Enabled) Exec will return false in case of faliure, however the code is there to modify it to your liking. The order thing, I think that is much more better to install the previous requirements and finally install the program.That way, in case of failures, we could take action.
  • papo
    papo about 7 years
    Hi. The think is, people often copy - paste code found here, so from that point of view, it's not ok to intentionally leave possible issues in sample code for someone to fix them to his/her likings. That's why we invited you to consider editing it. The quality of this server is sustained by permanently perfecting each answer. @Martin and few others browse questions in this section every day, offer answers and edits. btw. Martin is respected developer and contributor, I don't think he needs to read Inno setup help files. :) I will try to explain in more detail the issues:
  • papo
    papo about 7 years
    Exec() returns true if a process was started successfully, even if that process then fails. It returns false only in cases such as missing or corrupted exe file. If Exec() returns true and if ewWaitUntilTerminated is specified, ResultCode shows exit code of the process, but if Exec() fails to start the process, it shows a code of that error. Very different thing in the same variable. That's why both cases should be checked.Actually here, JRE returns 0 even if canceled (running with /s is not enough to assume it won't be) We must check if Java is installed correctly by other means, if needed.
  • papo
    papo about 7 years
    I am not sure if you are aware of the Inno setup's rollback feature. If setup is canceled, by user or programmatically, at any time, it will undo all changes done to the system. I prefer to install program files before external setups which it can't unroll by itself. Also I like to set progress bar to go only to 80% then start with external unzips/setups. Feels smoother. But again, the order is much or less a preference, it's just that your post says, to reorder files in the [Files] section in other way, while not providing any reason for it. And that's the imperfection, which we have noted
  • CodeCat
    CodeCat about 7 years
    Firstly, I do not see the need to be so susceptible, as you have said, this is a forum to try to help each other, not a forum to "see who is right", any solution (mine or of any other) is susceptible to be improved by the community. By the way, I do not think that suggests @MartinPrikryl to take a look at a help file imply questioning his skills and reputation, so I do not think Martin needs a "defender" of them, especially when he has not made any comment about. Another thing is that you have tried to "put me in my place", in which case I will tell you that I really do not care.
  • CodeCat
    CodeCat about 7 years
    About your second comment @papo, I'm sorry but I think you are a bit wrong in your comment. The inno setup Help file version 5.5.9 says "If True is returned and Wait is ewWaitUntilTerminated then ResultCode returns the exit code of the process. If False is returned then ResultCode specifies the error that occurred. Use SysErrorMessage(ResultCode) to get a description of the error. " so there's no place where it says what you say returns true if a process was started successfully and let me remember you that in the code the flag INSTALL_SILENT=Enabled do not let you cancel the process.
  • CodeCat
    CodeCat about 7 years
    Yes I know it @papo, I have readed the Help file too, but I do not need to use in this example, and about the order files, it's easy, you can't run your java aplication without a java virtual machine so, why to install all your program files before you can verify that you have the necesary JRE to execute it? It's my point of view, you can have a diferent one, which one is better....? Greetings.
  • papo
    papo about 7 years
    It's your answer. We can try to improve it, but you have the last word. Either if you are right or not, or if you want to have it improved or not. I wrote my comments also in hope they might be useful for other users, if the answer won't get edited. But this is not a place for a discussion and there is nothing constructive to add. Please check your code, experiment a bit with Exec() and Rollback feature, if in further doubts.