Search code examples
javainno-setuppascalscript

Detect Java version in Inno Setup


When installing my Java app with Inno Setup, I would like the installer to check if Java 7 or above is present, and install it if needed. But apparently, my current code fails to detect Java 8 on the computer of some of my clients. I couldn't reproduce the bug, though. Do you see something that I could be missing? Maybe this code doesn't work with recent Windows?

Basically, I just check the registry for 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;

Edit: This is the final result based on Martin's answer.

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

Solution

  • I do not have the JavaSoft key in HKLM\Software. I have it in HKLM\SOFTWARE\WOW6432Node. What is actually the HKLM\SOFTWARE in Inno Setup (being 32-bit application).

    So it looks like you just need to remove the if IsWin64 then regRoot := HKLM64 block to make it working. Or try both options.

    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;
    

    For your specific needs, you can check, if Java 1.7 or newer is installed like this:

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

    Or did you consider running java -version instead?

    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;
    

    A bit more efficient implementation of the 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;