delphidelphi-10-seattle

How return the complete path of java.exe file ignoring java version installed?


I want associate my .jar file to open with java.exe using Windows registry and have a doubt about how return the complete path of java.exe file ignoring java version installed on computer.

Ex:

in my case i have:

C:\Program Files\Java\jdk1.7.0_45\bin\java.exe

then how access java.exe file ignoring this part 1.7.0_45?

uses
  Windows, Registry;

function GetProgramFilesDir: string;
  var
    reg: TRegistry;
  begin
    reg := TRegistry.Create;
    try
      reg.RootKey := HKEY_LOCAL_MACHINE;
      reg.OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion', False);
      Result := reg.ReadString('ProgramFilesDir');
    finally
      reg.Free;
    end;
  end;

procedure RegisterFileType(cMyExt, cMyFileType, ExeName: string);
var
  reg: TRegistry;
begin
  reg := TRegistry.Create;
  try
    reg.RootKey := HKEY_CURRENT_USER;
    if reg.OpenKey('\Software\Classes\.jar', True) then
      reg.WriteString('', 'MyAppDataFile');
    if reg.OpenKey('\Software\Classes\MyAppDataFile', True) then
      reg.WriteString('', 'myappname'); 
    if reg.OpenKey('\Software\Classes\MyAppDataFile\DefaultIcon', True) then
      reg.WriteString('', GetProgramFilesDir + '\Java\jdk1.7.0_45\bin\java.exe');
    if reg.OpenKey('\Software\Classes\MyAppDataFile\shell\open\command', True)
    then
      reg.WriteString('', GetProgramFilesDir + '\Java\jdk1.7.0_45\bin\java.exe "%1"');
  finally
    reg.Free;
  end;
  SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
end;

Solution

  • Don't use the Registry to discover the path to system folders, like Program Files. Use SHGetFolderPath() or SHGetKnownFolderPath() instead, eg:

    function GetProgramFilesDir: string;
    var
      path: array[MAX_PATH] of Char;
    begin
      if SHGetFolderPath(0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path) = S_OK then
        Result := IncludeTrailingPathDelimiter(path)
      else
        Result := '';
    end;
    
    function GetProgramFilesDir: string;
    var
      path: PChar;
    begin
      if SHGetKnownFolderPath(FOLDERID_ProgramFiles, 0, 0, path) = S_OK then
      begin
        try
          Result := IncludeTrailingPathDelimiter(path);
        finally
          CoTaskMemFree(path);
        end;
      end else
        Result := '';
    end;
    

    That being said, to get the current installed path of java.exe, there are a few options you can try:

    function GetJavaPathViaEnvironment: string;
    begin
      Result := GetEnvironmentVariable('JAVA_HOME');
      if Result <> '' then
      begin
        Result := IncludeTrailingPathDelimiter(Result) + 'bin' + PathDelim + 'java.exe';
        // if not FileExists(Result) then Result := '';
      end;  
    end;
    
    function GetJavaPathViaRegistry: string;
    const
      JAVA_KEY: string = '\SOFTWARE\JavaSoft\Java Runtime Environment\';
      Wow64Flags: array[0..2] of DWORD = (0, KEY_WOW64_32KEY, KEY_WOW64_64KEY);
    var
      reg: TRegistry;
      s: string;
      i: integer;
    begin
      Result := '';
      reg := TRegistry.Create;
      try
        reg.RootKey := HKEY_LOCAL_MACHINE;
        for i := Low(Wow64Flags) to High(Wow64Flags) do
        begin
          reg.Access := (reg.Access and not KEY_WOW64_RES) or Wow64Flags[i];
          if reg.OpenKeyReadOnly(JAVA_KEY) then
          begin
            s := reg.ReadString('CurrentVersion');
            if s <> '' then
            begin
              if reg.OpenKeyReadOnly(s) then
              begin
                s := reg.ReadString('JavaHome');
                if s <> '' then
                begin
                  Result := IncludeTrailingPathDelimiter(s) + 'bin' + PathDelim + 'java.exe';
                  // if not FileExists(Result) then Result := '' else
                  Exit;
                end;
              end;
            end;
            reg.CloseKey;
          end;
        end;
      finally
        reg.Free;
      end;
    end;
    
    function GetJavaPathViaSearchPath: string;
    var
      path: array[0..MAX_PATH] of Char;
      s: string;
      len: DWORD;
    begin
      Result := '';
      len := SearchPath(nil, 'java.exe', nil, Length(path), path, PPChar(nil)^);
      if len <= Length(path) then
        SetString(Result, path, len)
      else
      begin
        repeat
          SetLength(s, len);
          len := SearchPath(nil, 'java.exe', nil, len, PChar(s), PPChar(nil)^);
        until len <= Length(s);
        SetString(Result, PChar(s), len);
      end;
    end;
    
    function GetJavaPath: string;
    begin
      Result := GetJavaPathViaEnvironment;
      if Result = '' then
        Result := GetJavaPathViaRegistry;
      if Result = '' then
        Result := GetJavaPathViaSearchPath;
    end;
    

    Also, don't forget that paths with spaces must be wrapped in double-quotes. You can use Delphi's AnsiQuotedStr() to help you with that, eg:

    reg.WriteString('', AnsiQuotedStr(GetJavaPath, '"') + ' "%1"');