0

I'm trying to retrieve the java.exe installation path on Windows. However, I can't succeed so far.

What I have tried are:

  1. getenv("JAVA_HOME"), which is rarely set in my opinion (mostly returns nothing, since it isn't set?)
  2. CMD the command for %i in (java.exe) do @echo. %~$PATH:i, which returns me the path when executed manually in cmd, however I can't retrieve it programmatically in c++? _popen returns me nothing when I execute this code, however a simple dir statement does return me the right output (directory listing).

So, all I want is to retrieve the path where java.exe is located, which I need in my application. Please if you have any good ideas, let me know. I'm willing to fix this issue.

string cmd(char *command) {
    FILE *fpipe;
    string response = "";
    char c = 0;
    if (0 == (fpipe = (FILE*)_popen(command, "r"))) {
        Exit("popen() failed.");
    }
    while (fread(&c, sizeof c, 1, fpipe)) {
        //printf("%c", c);
        response += c;
    }
    _pclose(fpipe);
    return response;
}
cout << cmd("for %i in (java.exe) do @echo. %~$PATH:i") << endl; //EMPTY (MANUAL ON CMD RETURNS THE RIGHT PATH)
cout << cmd("dir"); //RETURNS LIST OF CONTENTS
TVA van Hesteren
  • 1,031
  • 3
  • 20
  • 47
  • Calling `_popen` with your command line works perfectly for me. There is probably a bug in your code. If you want to follow up on this approach, please edit the question to include a [mcve]. – Harry Johnston Jul 11 '17 at 22:11
  • @HarryJohnston, I have added the command and function in the question above – TVA van Hesteren Jul 12 '17 at 11:22
  • @HarryJohnston, I have found the problem. MSVC can't access the path variable java, therefore it can't find java.exe. Why can't MSVC use my PATH variables? – TVA van Hesteren Jul 12 '17 at 11:54
  • Your code works for me. What does it do when run from the command line instead of from the debugger? What do you get from `cmd("PATH")`, please post the output. – Harry Johnston Jul 12 '17 at 21:14
  • Thanks for your reply. Like I said, the debugger couldn't find just java.exe so I had to use the full path. I use the windows registry now to find JavaHome which works good so far. – TVA van Hesteren Jul 13 '17 at 05:10

2 Answers2

4

If you want your application to run on a wide variety of machines, you cannot assume any fixed paths and you usually cannot assume that certain environment variables are set. The user can almost always choose a completely arbitrary install location. More often than not the only decently reliable way to get information about the install location of a program is through the Windows registry. And even that assumes installation through an installer that actually writes that information to the registry.

Finding the JRE install path in the Win Registry

For the Oracle Java Runtime all the info you need is stored in the registry provided it was installed with its own installer.

The relevat registry paths depend on the type of Java and the type of Windows.

64bit Java on 64bit Windows or 32bit Java on 32bit Windows:

HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment

32bit Java on 64bit Windows:

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\JavaSoft\Java Runtime Environment

That key has an entry CurrentVersion that contains the newest installed version number. It also has a number of sub-keys, at least one for each installed version of the Java Runtime. Those keys have an entry JavaHome that contains the top-level Java installation directory. I’m not too familiar with Java, but I assume that starting at that location the directory and file layout is fixed so that you can assume that java.exe can always be found in the same path relative to JavaHome.

To make this a bit clearer assume you have version 1.8.0_111 installed as the newest version.

  • Your CurrentVersion entry will be “1.8”.
  • You’ll have two sub-keys for that version.

    ...\Java Runtime Environment\1.8
    ...\Java Runtime Environment\1.8.0_111
    
  • Both sub-keys will have a JavaHome entry pointing to the install directory, for example: “C:\Program Files (x86)\Java\jre1.8.0_111”.

Accessing the Registry with C++

You could use the WinAPI directly. For your simple task of querying a few keys that could even be reasonable. There is also a whole bunch of libraries out there that wrap the WinAPI and give you a more C++ like interface to the WinAPI registry functions. I haven’t used any of them, so I can’t recommend one.

besc
  • 2,507
  • 13
  • 10
  • Thanks for your answer, I am able to determine JavaHome through the registry on two machines where I couldn't get JavaHome before. Wonderful! Now it has to be proven how solid this is across multiple different machines – TVA van Hesteren Jul 12 '17 at 13:23
2

Using JAVA_HOME has been deprecated for a while, so any solution you use involving that variable is going to age badly.

If Java was installed using the standard Oracle installer, then %ProgramData%\Oracle\Java\javapath\java.exe should be a link to the current launcher. And it's an actual link, not a "Windows shortcut" crappy fake symlink-wannabe, so you can simply use that pathname directly (after retrieving the ProgramData environment variable, anyhow). The javapath part is where some NTFS hardlink/junction magic takes place, specifically so that it can be added to $PATH instead of constantly having to mess with updating "Java/jre-X.Y.Z/bin" and similar.

If Java was installed some other way -- for example, the "Server JRE" that deliberately has no installer and can be placed anywhere you have write permissions -- then you'll need to mess with that $PATH trick in CMD. I've no idea why popen wouldn't work, other than Windows once again doing its own thing instead of simply following the POSIX standard (which is why my office has largely abandoned writing code directly on Windows).

Ti Strga
  • 1,353
  • 18
  • 40
  • Thanks for the clearification of `JAVA_HOME`, I will abandon that one. However, I just have to hardcode the `%ProgramData%\Oracle\Java\javapath\java.exe` path in my application is what you suggest? Because I would like to automatically detect JAVA, whatever installation the client has performed, so the application works on a wide variety of machines? – TVA van Hesteren Jul 11 '17 at 17:55
  • This seems like a mostly sound answer, but what does POSIX have to do with anything? – Harry Johnston Jul 11 '17 at 22:00
  • POSIX specifies the behavior of `popen`, but on Windows a lot of POSIX behavior is disabled or unavailable without special effort on the part of the programmer. – Ti Strga Jul 17 '17 at 15:19
  • POSIX specifies the behaviour of `popen` *on POSIX-compliant operating systems*. Are you upset that your car wasn't built according to the [ISO 15401 standard](https://www.iso.org/news/2000/04/Ref773.html)? – Harry Johnston Oct 13 '17 at 21:42
  • 1
    Windows specifically claimed POSIX compliance when they added the `popen` call, that's kinda the point. Actual compliance, however, requires using the "POSIX subsystem", which is not the default, and switching to it loses other features present only in (for example) the Win32 subsystem. It's a tradeoff, and the programmer must choose carefully. If you want Windows-specific functionality, it's better to use a Windows-only API instead of one which implies a POSIX environment. – Ti Strga Oct 16 '17 at 14:51