By the by here’s how I detect if the end user has a compatible version of Java installed using C# and .NET 2.0 methods:
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace YourNamespaceHere
{
public static class OSOps
{
private static readonly string javaKey = "SOFTWARE\\JavaSoft\\Java Runtime Environment";
public static Boolean isJavaCompatible(float targetJava)
{
if (Is64BitOS())
{
return java64Compatible(targetJava);
}
else
{
return java32Compatible(targetJava);
}
}
private static Boolean java32Compatible(float targetJava)
{
string currentVersion = GetRegKey32(HKEY_LOCAL_MACHINE, javaKey, "CurrentVersion");
if (currentVersion != null)
{
if (float.Parse(currentVersion) >= targetJava)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
private static Boolean java64Compatible(float targetJava)
{
string currentVersion = GetRegKey64(HKEY_LOCAL_MACHINE, javaKey, "CurrentVersion");
if (currentVersion != null)
{
if (float.Parse(currentVersion) >= targetJava)
{
return true;
}
else
{
return false;
}
}
else
{
return java32Compatible(targetJava);
}
}
public static string getJavaPath(float targetJava)
{
if (Is64BitOS())
{
return getJava64(targetJava);
}
else
{
return getJava32(targetJava);
}
}
private static string getJava32(float targetJava)
{
string currentVersion = GetRegKey32(HKEY_LOCAL_MACHINE, javaKey, "CurrentVersion");
if (currentVersion != null)
{
if (float.Parse(currentVersion) >= targetJava)
{
return GetRegKey32(HKEY_LOCAL_MACHINE, javaKey + "\\" + currentVersion, "JavaHome");
}
else
{
return null;
}
}
else
{
return null;
}
}
private static string getJava64(float targetJava)
{
string currentVersion = GetRegKey64(HKEY_LOCAL_MACHINE, javaKey, "CurrentVersion");
if (currentVersion != null)
{
if (float.Parse(currentVersion) >= targetJava)
{
return GetRegKey64(HKEY_LOCAL_MACHINE, javaKey + "\\" + currentVersion, "JavaHome");
}
else
{
return null;
}
}
else
{
return getJava32(targetJava);
}
}
//check for 64-bit OS
internal static bool Is64BitOS()
{
if (IntPtr.Size == 8)
{
return true;
}
else
{
bool flag;
return ((DoesWin32MethodExist("kernel32.dll", "IsWow64Process") && IsWow64Process(GetCurrentProcess(), out flag)) && flag);
}
}
static bool DoesWin32MethodExist(string moduleName, string methodName)
{
IntPtr moduleHandle = GetModuleHandle(moduleName);
if (moduleHandle == IntPtr.Zero)
{
return false;
}
return (GetProcAddress(moduleHandle, methodName) != IntPtr.Zero);
}
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentProcess();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static extern IntPtr GetModuleHandle(string moduleName);
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)]string procName);
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWow64Process(IntPtr hProcess, out bool wow64Process);
//check 32 or 64 bit registry with .NET 2.0 or higher
private enum RegSAM
{
QueryValue = 0x0001,
SetValue = 0x0002,
CreateSubKey = 0x0004,
EnumerateSubKeys = 0x0008,
Notify = 0x0010,
CreateLink = 0x0020,
WOW64_32Key = 0x0200,
WOW64_64Key = 0x0100,
WOW64_Res = 0x0300,
Read = 0x00020019,
Write = 0x00020006,
Execute = 0x00020019,
AllAccess = 0x000f003f
}
private static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);
private static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);
[DllImport("Advapi32.dll")]
static extern uint RegOpenKeyEx(
UIntPtr hKey,
string lpSubKey,
uint ulOptions,
int samDesired,
out int phkResult);
[DllImport("Advapi32.dll")]
static extern uint RegCloseKey(int hKey);
[DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
public static extern int RegQueryValueEx(
int hKey, string lpValueName,
int lpReserved,
ref uint lpType,
System.Text.StringBuilder lpData,
ref uint lpcbData);
private static string GetRegKey64(UIntPtr inHive, String inKeyName, String inPropertyName)
{
return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_64Key, inPropertyName);
}
private static string GetRegKey32(UIntPtr inHive, String inKeyName, String inPropertyName)
{
return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_32Key, inPropertyName);
}
private static string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, String inPropertyName)
{
int hkey = 0;
try
{
uint lResult = RegOpenKeyEx(inHive, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
if (lResult != 0) return null;
uint lpType = 0;
uint lpcbData = 1024;
StringBuilder AgeBuffer = new StringBuilder(1024);
RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, AgeBuffer, ref lpcbData);
string Age = AgeBuffer.ToString();
return Age;
}
finally
{
if (hkey != 0) RegCloseKey(hkey);
}
}
}
}
usage:
private static readonly float javaVersion = 1.8f;
if (OSOps.isJavaCompatible(javaVersion))
{
//Install your application
}
else
{
//Prompt to download JRE/JDK and launch JRE/JDK installer.
//You could also bundle the JRE/JDK installer with the executable
//and just launch that rather than downloading it.
//Or you could just bundle the JRE/JDK with your installer so
//that, like jME, it is extracted into your applications
//install directory rather than being installed system wide.
}
P.S. Oh yeah, the getJavaPath method returns the path to installed Java or null if it’s not found.
So if you were going to launch an application using installed Java you might:
using System;
using System.IO;
String javaHome = OSOps.getJavaPath();
if (javaHome != null)
{
Process prc = new Process();
prc.StartInfo = new ProcessStartInfo(Path.Combine(javaHome, "bin\\java.exe"));
string exeDir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
prc.StartInfo.WorkingDirectory = exeDir;
prc.StartInfo.Arguments = @"-jar pathtomyappRelativeToExe\myapp.jar";
prc.StartInfo.UseShellExecute = false;
prc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
prc.StartInfo.CreateNoWindow = true;
prc.StartInfo.RedirectStandardOutput = true;
prc.StartInfo.RedirectStandardError = true;
prc.Start();
StreamReader sr = prc.StandardOutput;
StreamReader err = prc.StandardError;
//redirects output from the launched application's
//console to the launching application's console
while (prc.HasExited == false)
{
string output = sr.ReadLine();
if (output != null)
{
if (output.Length > 0)
{
Console.WriteLine(output);
}
}
string eOutput = err.ReadLine();
if (eOutput != null)
{
if (eOutput.Length > 0)
{
Console.WriteLine(eOutput);
}
}
}
}
And that’s something you might use when your application installer has finished successfully and you want to give the user the option to launch the newly installed application.
Edit: Now the above shows how to detect if the JRE is installed, but in reading I found that the JDK apparently does not make use of the system registry so there’s no way to know if the JDK is installed using the registry. Though I suppose you could use the Java path provided by the registry and look at its parent directory to see if it’s in the JDK directory.
Other than that I suppose you’d just install the JDK into your application directory like jME does and use that to launch your application. With a Windows executable you could modify the code I provided and swap out OSOps.getJavaPath(); with the path to the JDK you want to use.
Relative to the executable launcher:
string exeDir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
string javaHome = Path.Combine(exeDir, "pathtoJDK_RelativeToExe");
Now with Linux you could instruct the user to always launch the application from the application directory and/or install a .desktop launcher to /home/username/.local/share/applications that might look something like:
[Desktop Entry]
Name=MyApp
Comment=A Java application
Exec=/path/to/app/jdk/bin/java -jar “/path/to/app/myapp.jar”
Icon=/path/to/app/icon.png
Terminal=false
Type=Application
Categories=Game
As for OSX, I don’t have a Mac.