0

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;

1 Answers1

0

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:

  • check if the %JAVA_HOME% environment variable is set.

  • check the HKLM\SOFTWARE\JavaSoft\Java Runtime Environment\<version> Registry key for a JavaHome value (there may be multiple <version> subkeys!).

  • search the %PATH% environment variable for any listed folder that has java.exe in it (there may be multiple folders!). You can parse the %PATH% yourself manually, or you can use SearchPath() with its lpPath parameter set to NULL (if you only care about the first copy of java.exe found).

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"');
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    using `SearchPath()` function, my jar software will execute with `C:\ProgramData\Oracle\Java\javapath\java.exe` (found by **`SearchPath()`**). Is right? –  Oct 01 '18 at 23:55
  • @user Yes, if `C:\ProgramData\Oracle\Java\javapath\java.exe` is the first path from your `%PATH%` that it finds `java.exe` at. On my system, it finds `C:\Program Files (x86)\Common Files\Oracle\Java\javapath\java.exe` instead – Remy Lebeau Oct 02 '18 at 00:10
  • With Delphi 11 on Windows 11 searching the registry does not work in iny environment. I changed to reg := TRegistry.Create(KEY_READ); but still get no result although I verified that the keys exist. – MichaSchumann Jul 20 '22 at 15:23
  • @MichaSchumann "*I changed to `reg := TRegistry.Create(KEY_READ);`*" - why? `reg.OpenKeyReadOnly()` handles `KEY_READ` for you (amongst several other combinations of read-only rights it attempts). – Remy Lebeau Jul 20 '22 at 18:46
  • Sorry for my shart and incomplete comment. Of course I tried your original code in the first place then I read about this parameter and tried this too. Both versions just wouldn't find my Java registry entries. As I am also using this technique for HKCU a lot (what works well also in D11.1/Win11) I wonder if Microsoft has changed something in Win11. I will try in a VM with Win 10 and post the results here. – MichaSchumann Jul 21 '22 at 10:46