19

I'm creating an Inno Setup installer for a jar app. What I want to do right now is to check if java is present before proceeding with the install. So I only need to be sure the users will be able to run:

java -jar my-app.jar

What I'm doing right now is:

[Code]

function InitializeSetup(): Boolean;
var
  ErrorCode: Integer;
  JavaInstalled : Boolean;
  Result1 : Boolean;
begin
  JavaInstalled := RegKeyExists(HKLM,'SOFTWARE\JavaSoft\Java Runtime Environment\1.6');
  if JavaInstalled then
  begin
    Result := true;
  end else
    begin
      Result1 := MsgBox('This tool requires Java Runtime Environment version 1.6 or newer to run. Please download and install the JRE and run this setup again. Do you want to download it now?',
        mbConfirmation, MB_YESNO) = idYes;
      if Result1 = false then
      begin
        Result:=false;
      end else
      begin
        Result:=false;
        ShellExec('open',
          'http://javadl.sun.com/webapps/download/AutoDL?BundleId=33787',
          '','',SW_SHOWNORMAL,ewNoWait,ErrorCode);
      end;
    end;
  end;
end;

My questions are:

  • Is checking the registry enough to be sure java's home dir will be in the PATH? (to be able to run "java" in the console)

  • If a higher version of java is installed, will that key in the registry exist anyway or I will have to check for each higher version possible?

  • Does anyone have a better way to download java than just showing a popup and taking the users to the download page?

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Santi
  • 4,428
  • 4
  • 24
  • 28

8 Answers8

15

I hope someone finds this useful, what I did is reusing some piece of the code placed in Inno Setups wiki to make a < > comparison with the version as a number:

{ Both DecodeVersion and CompareVersion functions where taken from the  wiki }
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;

{ Here's my code }
function InitializeSetup(): Boolean;
var
  ErrorCode: Integer;
  JavaVer : String;
  Result1 : Boolean;
begin
    RegQueryStringValue(HKLM, 'SOFTWARE\JavaSoft\Java Runtime Environment', 'CurrentVersion', JavaVer);
    Result := false;
    if Length( JavaVer ) > 0 then
    begin
        if CompareVersion(JavaVer,'1.6') >= 0 then
        begin
            Result := true;
        end;
    end;
    if Result = false then
    begin
        Result1 := MsgBox('This tool requires Java Runtime Environment v1.6 or older to run. Please download and install JRE and run this setup again.' + #13 + #10 + 'Do you want to download it now?',
          mbConfirmation, MB_YESNO) = idYes;
        if Result1 = true then
        begin
            ShellExec('open',
              'http://www.java.com/en/download/manual.jsp#win',
              '','',SW_SHOWNORMAL,ewNoWait,ErrorCode);
        end;
    end;
end;

Thanks all for your help

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Santi
  • 4,428
  • 4
  • 24
  • 28
  • Does your script supporting to install the JRE/JDK also? Many users get Java and then not installing JDK. –  Mar 03 '12 at 20:33
5

I changed your code a little, I think this way newer versions of Java will be supported ;-)

function InitializeSetup(): Boolean;
var
 ErrorCode: Integer;
 JavaInstalled : Boolean;
 Result1 : Boolean;
 Versions: TArrayOfString;
 I: Integer;
begin
 if RegGetSubkeyNames(HKLM, 'SOFTWARE\JavaSoft\Java Runtime Environment', 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]) >= 6 ) ) ) then
    begin
     JavaInstalled := true;
    end else
    begin
     JavaInstalled := false;
    end;
   end;
 end else
 begin
  JavaInstalled := false;
 end;


 //JavaInstalled := RegKeyExists(HKLM,'SOFTWARE\JavaSoft\Java Runtime Environment\1.9');
 if JavaInstalled then
 begin
  Result := true;
 end else
    begin
  Result1 := MsgBox('This tool requires Java Runtime Environment version 1.6 or newer to run. Please download and install the JRE and run this setup again. Do you want to download it now?',
   mbConfirmation, MB_YESNO) = idYes;
  if Result1 = false then
  begin
   Result:=false;
  end else
  begin
   Result:=false;
   ShellExec('open',
    'http://www.java.com/getjava/',
    '','',SW_SHOWNORMAL,ewNoWait,ErrorCode);
  end;
    end;
end;


end.
jose.rob.jr
  • 51
  • 1
  • 1
3

There is another way now. You can include a Stub setup - online installer, which will download and install actual setup.
The filename name as for now is JavaSetup8u121.exe, which suggests it might be version specific. I don't have an older one to test if it will download actual or specific, older version.
And for now, it seems it only does install 32bit JRE.

[Files]
#define JavaInstaller "JavaSetup8u121.exe"
Source: "include\{#JavaInstaller}"; DestDir: "{tmp}";

[Code]
const
  REQUIRED_JAVA_VERSION = '1.7';

function isJavaInstalled(): Boolean;
var
  JavaVer : String;
  tmpFileName,
  pathJavaExe: String;
  isGoodJavaVersion,
  isFoundJavaPath: Boolean;
  ResultCode: Integer;
  ExecStdout: AnsiString;
begin

  { *** check in registry }
  { sets variables: }
  {   JavaVer }
  {   isGoodJavaVersion }
  if RegQueryStringValue(HKLM, 'SOFTWARE\JavaSoft\Java Runtime Environment',
           'CurrentVersion', JavaVer) AND (JavaVer <> '') OR
     RegQueryStringValue(HKLM64, 'SOFTWARE\JavaSoft\Java Runtime Environment',
           'CurrentVersion', JavaVer) AND (JavaVer <> '') then begin
    Log('* Java Entry in Registry present. Version: ' + JavaVer);
    isGoodJavaVersion := CompareStr(JavaVer, REQUIRED_JAVA_VERSION) >= 0;
  end;

  { add additional checks, for example by searching the PATH, }
  { or by running `java -version` }

  Result := isGoodJavaVersion;
end;

[Run]
Filename: "{tmp}\{#JavaInstaller}"; Parameters: "SPONSORS=0"; \
   StatusMsg: "Java Runtime Enviroment not installed on your system. Installing..."; \
   Check: not isJavaInstalled

Searches for 32 and 64 bit versions in registry, internal function CompareStr() is actually usable for comparing versions in String, you can change >= 0 to =0 if you want to check against the exact version and not 'at least'.

Alternatively Exec() could be used instead of [Run], if you want to cancel the whole install in case when the user will not go through with the Java install by cancelling it or because of an error.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
papo
  • 1,606
  • 19
  • 18
2

For your third question, see here, under the Trademark and Licensing section. Exec summary: you can distribute the JRE along with your app. I think a few apps do this to ensure they do not have version compatibility issues - i.e install the JRE in a subfolder of the app itself.

As far as being in the PATH, why is that important? You can create a shortcut that refers to java.exe by its full path to run your app. Is it important that the user start the program via the command line themselves?

JimG
  • 1,782
  • 8
  • 9
  • I would not want to bundle a whole JRE with my app, it adds too much weight to the installer and can be unnecessary if the users already have it. The second suggestion looks good. Looks like I can find where to get the java home dir from the registry also... – Santi Aug 19 '09 at 05:06
  • do you have any link to how to do the full path to java.exe? – rogerdpack Jun 17 '13 at 22:16
2

More enhancement for the already defined code:

  1. Check for existence of JRE / JDK.
  2. Verify in either 32bit or 64bit view of registry.

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('Oracle Java v1.7 or newer not found in the system. Java 1.7 or later is required to run this application (can be installed after this installation too). Do you want to continue?',
   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;

end.
Subhash Chandran
  • 1,275
  • 1
  • 13
  • 20
  • 1
    You've added only view into a different registry root as far as I can see. Besides, you've copied the code with all the mistakes done there... – TLama Jun 22 '14 at 09:12
  • As correctly mentioned by you, I added the check in Win64 machines to registry root _HKLM64_. What you have not noticed is, the check now includes the path _SOFTWARE\JavaSoft\Java Development Kit_ too. – Subhash Chandran Jun 22 '14 at 13:44
2

A simple alternative to the already proposed answers:

[Code]
function InitializeSetup(): boolean;
var
  ResultCode: integer;
begin
  if Exec('java', '-version', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then begin
    Result := true;    
  end
  else begin          
    if MsgBox('This tool requires Java Runtime Environment version 1.6 or newer to run. Please download and install the JRE and run this setup again. Do you want to download it now?', mbConfirmation, MB_YESNO) = idYes then begin
      Result := false;
      ShellExec('open', 'https://java.com/download/', '', '', SW_SHOWNORMAL, ewNoWait, ResultCode);
    end;  
  end;
end;
varnaud
  • 237
  • 3
  • 12
0

Instead of checking for a specific version, you can use

function RegKeyExists(const RootKey: Integer; const SubKeyName: String): Boolean;

to get the subkeys of HKLM\SOFTWARE\JavaSoft\Java Runtime Environment. (Is parallel installation of different versions possible? Don't know...) You would need to do some string fiddling to check if 1.6 or higher is installed, but it would be more flexible than checking for a specific version number.

Treb
  • 19,903
  • 7
  • 54
  • 87
0

For those that may find it useful, I wrote an open-source (LPGL license) Windows DLL for detecting Java installation details.

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

Download link: https://github.com/Bill-Stewart/JavaInfo/releases

The download includes a sample Inno Setup .iss script that demonstrates how to use the DLL functions.

JavaInfo.dll lets you accomplish the following (useful from an installer):

  • Detect whether Java is installed
  • Check whether the installed Java is 32-bit or 64-bit
  • Check if the installed Java is at least a minimum version
  • Get the installed Java home directory
  • Get the installed Java's version

One of the nice things about the DLL is that it supports multiple "brands" of Java (Sun, AdoptOpenJDK, Zulu, Amazon, etc.) and intelligently detects Java no matter which "brand" is installed.

Bill_Stewart
  • 22,916
  • 4
  • 51
  • 62