diff --git a/launcher/build.gradle b/launcher/build.gradle index e212a57..5ef3b76 100644 --- a/launcher/build.gradle +++ b/launcher/build.gradle @@ -15,6 +15,8 @@ compile 'com.beust:jcommander:1.32' compile 'com.miglayout:miglayout:3.7.4' compile 'com.google.code.findbugs:jsr305:3.0.0' + + implementation 'net.java.dev.jna:jna-platform:5.10.0' } processResources { diff --git a/launcher/src/main/java/com/skcraft/launcher/launch/JavaRuntimeFinder.java b/launcher/src/main/java/com/skcraft/launcher/launch/JavaRuntimeFinder.java index 85d953e..54846bd 100644 --- a/launcher/src/main/java/com/skcraft/launcher/launch/JavaRuntimeFinder.java +++ b/launcher/src/main/java/com/skcraft/launcher/launch/JavaRuntimeFinder.java @@ -11,11 +11,11 @@ import com.skcraft.launcher.util.EnvironmentParser; import com.skcraft.launcher.util.Platform; import com.skcraft.launcher.util.WinRegistry; +import com.sun.jna.platform.win32.WinReg; import lombok.extern.java.Log; import java.io.File; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.util.*; import java.util.logging.Level; import java.util.stream.Collectors; @@ -29,6 +29,10 @@ private JavaRuntimeFinder() { } + /** + * Get all available Java runtimes on the system + * @return List of available Java runtimes sorted by newest first + */ public static List getAvailableRuntimes() { Environment env = Environment.getInstance(); Set entries = new HashSet<>(); @@ -36,7 +40,7 @@ if (env.getPlatform() == Platform.WINDOWS) { try { - String launcherPath = WinRegistry.readString(WinRegistry.HKEY_CURRENT_USER, + String launcherPath = WinRegistry.readString(WinReg.HKEY_CURRENT_USER, "SOFTWARE\\Mojang\\InstalledProducts\\Minecraft Launcher", "InstallLocation"); launcherDir = new File(launcherPath); @@ -151,13 +155,13 @@ } } - return new JavaRuntime(target, readVersionFromRelease(target), guessIf64Bit(target)); + return new JavaRuntime(target, readVersionFromRelease(target), guessIf64BitWindows(target)); } private static void getEntriesFromRegistry(Collection entries, String basePath) throws IllegalArgumentException { try { - List subKeys = WinRegistry.readStringSubKeys(WinRegistry.HKEY_LOCAL_MACHINE, basePath); + List subKeys = WinRegistry.readStringSubKeys(WinReg.HKEY_LOCAL_MACHINE, basePath); for (String subKey : subKeys) { JavaRuntime entry = getEntryFromRegistry(basePath, subKey); if (entry != null) { @@ -169,18 +173,18 @@ } } - private static JavaRuntime getEntryFromRegistry(String basePath, String version) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + private static JavaRuntime getEntryFromRegistry(String basePath, String version) { String regPath = basePath + "\\" + version; - String path = WinRegistry.readString(WinRegistry.HKEY_LOCAL_MACHINE, regPath, "JavaHome"); + String path = WinRegistry.readString(WinReg.HKEY_LOCAL_MACHINE, regPath, "JavaHome"); File dir = new File(path); if (dir.exists() && new File(dir, "bin/java.exe").exists()) { - return new JavaRuntime(dir, version, guessIf64Bit(dir)); + return new JavaRuntime(dir, version, guessIf64BitWindows(dir)); } else { return null; } } - private static boolean guessIf64Bit(File path) { + private static boolean guessIf64BitWindows(File path) { try { String programFilesX86 = System.getenv("ProgramFiles(x86)"); return programFilesX86 == null || !path.getCanonicalPath().startsWith(new File(programFilesX86).getCanonicalPath()); diff --git a/launcher/src/main/java/com/skcraft/launcher/util/WinRegistry.java b/launcher/src/main/java/com/skcraft/launcher/util/WinRegistry.java index 9e51983..d7ca542 100644 --- a/launcher/src/main/java/com/skcraft/launcher/util/WinRegistry.java +++ b/launcher/src/main/java/com/skcraft/launcher/util/WinRegistry.java @@ -6,366 +6,44 @@ package com.skcraft.launcher.util; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; +import com.google.common.collect.ImmutableList; +import com.sun.jna.platform.win32.Advapi32Util; +import com.sun.jna.platform.win32.WinReg; + import java.util.List; -import java.util.Map; -import java.util.prefs.Preferences; +/** + * Windows registry helper via JNA platform + */ public class WinRegistry { - public static final int HKEY_CURRENT_USER = 0x80000001; - public static final int HKEY_LOCAL_MACHINE = 0x80000002; - public static final int REG_SUCCESS = 0; - public static final int REG_NOTFOUND = 2; - public static final int REG_ACCESSDENIED = 5; - - private static final int KEY_ALL_ACCESS = 0xf003f; - private static final int KEY_READ = 0x20019; - private static Preferences userRoot = Preferences.userRoot(); - private static Preferences systemRoot = Preferences.systemRoot(); - private static Class userClass = userRoot.getClass(); - private static Method regOpenKey = null; - private static Method regCloseKey = null; - private static Method regQueryValueEx = null; - private static Method regEnumValue = null; - private static Method regQueryInfoKey = null; - private static Method regEnumKeyEx = null; - private static Method regCreateKeyEx = null; - private static Method regSetValueEx = null; - private static Method regDeleteKey = null; - private static Method regDeleteValue = null; - - static { - try { - regOpenKey = userClass.getDeclaredMethod("WindowsRegOpenKey", - new Class[] { int.class, byte[].class, int.class }); - regOpenKey.setAccessible(true); - regCloseKey = userClass.getDeclaredMethod("WindowsRegCloseKey", - new Class[] { int.class }); - regCloseKey.setAccessible(true); - regQueryValueEx = userClass.getDeclaredMethod( - "WindowsRegQueryValueEx", new Class[] { int.class, - byte[].class }); - regQueryValueEx.setAccessible(true); - regEnumValue = userClass.getDeclaredMethod("WindowsRegEnumValue", - new Class[] { int.class, int.class, int.class }); - regEnumValue.setAccessible(true); - regQueryInfoKey = userClass.getDeclaredMethod( - "WindowsRegQueryInfoKey1", new Class[] { int.class }); - regQueryInfoKey.setAccessible(true); - regEnumKeyEx = userClass.getDeclaredMethod("WindowsRegEnumKeyEx", - new Class[] { int.class, int.class, int.class }); - regEnumKeyEx.setAccessible(true); - regCreateKeyEx = userClass.getDeclaredMethod( - "WindowsRegCreateKeyEx", new Class[] { int.class, - byte[].class }); - regCreateKeyEx.setAccessible(true); - regSetValueEx = userClass.getDeclaredMethod("WindowsRegSetValueEx", - new Class[] { int.class, byte[].class, byte[].class }); - regSetValueEx.setAccessible(true); - regDeleteValue = userClass.getDeclaredMethod( - "WindowsRegDeleteValue", new Class[] { int.class, - byte[].class }); - regDeleteValue.setAccessible(true); - regDeleteKey = userClass.getDeclaredMethod("WindowsRegDeleteKey", - new Class[] { int.class, byte[].class }); - regDeleteKey.setAccessible(true); - } catch (Exception e) { - e.printStackTrace(); - } - } - private WinRegistry() { } /** - * Read a value from key and value name + * Read a value from a path and value name * - * @param hkey - * HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE - * @param key - * @param valueName - * @return the value - * @throws IllegalArgumentException - * @throws IllegalAccessException - * @throws java.lang.reflect.InvocationTargetException + * @param hkey Hive key + * @param key Registry path + * @param valueName Value key + * @return String value from the registry + * @throws com.sun.jna.platform.win32.Win32Exception If an error occurs accessing the registry + * or the path does not exist */ - public static String readString(int hkey, String key, String valueName) - throws IllegalArgumentException, IllegalAccessException, - InvocationTargetException { - if (hkey == HKEY_LOCAL_MACHINE) { - return readString(systemRoot, hkey, key, valueName); - } else if (hkey == HKEY_CURRENT_USER) { - return readString(userRoot, hkey, key, valueName); - } else { - throw new IllegalArgumentException("hkey=" + hkey); - } + public static String readString(WinReg.HKEY hkey, String key, String valueName) { + return Advapi32Util.registryGetStringValue(hkey, key, valueName); } /** - * Read value(s) and value name(s) form given key + * Get the subkeys of a given path * - * @param hkey - * HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE - * @param key - * @return the value name(s) plus the value(s) - * @throws IllegalArgumentException - * @throws IllegalAccessException - * @throws java.lang.reflect.InvocationTargetException - */ - public static Map readStringValues(int hkey, String key) - throws IllegalArgumentException, IllegalAccessException, - InvocationTargetException { - if (hkey == HKEY_LOCAL_MACHINE) { - return readStringValues(systemRoot, hkey, key); - } else if (hkey == HKEY_CURRENT_USER) { - return readStringValues(userRoot, hkey, key); - } else { - throw new IllegalArgumentException("hkey=" + hkey); - } - } - - /** - * Read the value name(s) from a given key + * @param hkey Hive key + * @param key Registry path + * @return the subkeys of a given path * - * @param hkey - * HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE - * @param key - * @return the value name(s) - * @throws IllegalArgumentException - * @throws IllegalAccessException - * @throws java.lang.reflect.InvocationTargetException + * @throws com.sun.jna.platform.win32.Win32Exception If an error occurs accessing the registry + * or the path does not exist */ - public static List readStringSubKeys(int hkey, String key) - throws IllegalArgumentException, IllegalAccessException, - InvocationTargetException { - if (hkey == HKEY_LOCAL_MACHINE) { - return readStringSubKeys(systemRoot, hkey, key); - } else if (hkey == HKEY_CURRENT_USER) { - return readStringSubKeys(userRoot, hkey, key); - } else { - throw new IllegalArgumentException("hkey=" + hkey); - } + public static List readStringSubKeys(WinReg.HKEY hkey, String key) { + return ImmutableList.copyOf(Advapi32Util.registryGetKeys(hkey, key)); } - - /** - * Create a key - * - * @param hkey - * HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE - * @param key - * @throws IllegalArgumentException - * @throws IllegalAccessException - * @throws java.lang.reflect.InvocationTargetException - */ - public static void createKey(int hkey, String key) - throws IllegalArgumentException, IllegalAccessException, - InvocationTargetException { - int[] ret; - if (hkey == HKEY_LOCAL_MACHINE) { - ret = createKey(systemRoot, hkey, key); - regCloseKey - .invoke(systemRoot, new Object[] { new Integer(ret[0]) }); - } else if (hkey == HKEY_CURRENT_USER) { - ret = createKey(userRoot, hkey, key); - regCloseKey.invoke(userRoot, new Object[] { new Integer(ret[0]) }); - } else { - throw new IllegalArgumentException("hkey=" + hkey); - } - if (ret[1] != REG_SUCCESS) { - throw new IllegalArgumentException("rc=" + ret[1] + " key=" + key); - } - } - - /** - * Write a value in a given key/value name - * - * @param hkey - * @param key - * @param valueName - * @param value - * @throws IllegalArgumentException - * @throws IllegalAccessException - * @throws java.lang.reflect.InvocationTargetException - */ - public static void writeStringValue(int hkey, String key, String valueName, - String value) throws IllegalArgumentException, - IllegalAccessException, InvocationTargetException { - if (hkey == HKEY_LOCAL_MACHINE) { - writeStringValue(systemRoot, hkey, key, valueName, value); - } else if (hkey == HKEY_CURRENT_USER) { - writeStringValue(userRoot, hkey, key, valueName, value); - } else { - throw new IllegalArgumentException("hkey=" + hkey); - } - } - - /** - * Delete a given key - * - * @param hkey - * @param key - * @throws IllegalArgumentException - * @throws IllegalAccessException - * @throws java.lang.reflect.InvocationTargetException - */ - public static void deleteKey(int hkey, String key) - throws IllegalArgumentException, IllegalAccessException, - InvocationTargetException { - int rc = -1; - if (hkey == HKEY_LOCAL_MACHINE) { - rc = deleteKey(systemRoot, hkey, key); - } else if (hkey == HKEY_CURRENT_USER) { - rc = deleteKey(userRoot, hkey, key); - } - if (rc != REG_SUCCESS) { - throw new IllegalArgumentException("rc=" + rc + " key=" + key); - } - } - - /** - * delete a value from a given key/value name - * - * @param hkey - * @param key - * @param value - * @throws IllegalArgumentException - * @throws IllegalAccessException - * @throws java.lang.reflect.InvocationTargetException - */ - public static void deleteValue(int hkey, String key, String value) - throws IllegalArgumentException, IllegalAccessException, - InvocationTargetException { - int rc = -1; - if (hkey == HKEY_LOCAL_MACHINE) { - rc = deleteValue(systemRoot, hkey, key, value); - } else if (hkey == HKEY_CURRENT_USER) { - rc = deleteValue(userRoot, hkey, key, value); - } - if (rc != REG_SUCCESS) { - throw new IllegalArgumentException("rc=" + rc + " key=" + key - + " value=" + value); - } - } - - // ===================== - - private static int deleteValue(Preferences root, int hkey, String key, - String value) throws IllegalArgumentException, - IllegalAccessException, InvocationTargetException { - int[] handles = (int[]) regOpenKey.invoke(root, new Object[] { - new Integer(hkey), toCstr(key), new Integer(KEY_ALL_ACCESS) }); - if (handles[1] != REG_SUCCESS) { - return handles[1]; // can be REG_NOTFOUND, REG_ACCESSDENIED - } - int rc = ((Integer) regDeleteValue.invoke(root, new Object[] { - new Integer(handles[0]), toCstr(value) })).intValue(); - regCloseKey.invoke(root, new Object[] { new Integer(handles[0]) }); - return rc; - } - - private static int deleteKey(Preferences root, int hkey, String key) - throws IllegalArgumentException, IllegalAccessException, - InvocationTargetException { - int rc = ((Integer) regDeleteKey.invoke(root, new Object[] { - new Integer(hkey), toCstr(key) })).intValue(); - return rc; // can REG_NOTFOUND, REG_ACCESSDENIED, REG_SUCCESS - } - - private static String readString(Preferences root, int hkey, String key, - String value) throws IllegalArgumentException, - IllegalAccessException, InvocationTargetException { - int[] handles = (int[]) regOpenKey.invoke(root, new Object[] { - new Integer(hkey), toCstr(key), new Integer(KEY_READ) }); - if (handles[1] != REG_SUCCESS) { - return null; - } - byte[] valb = (byte[]) regQueryValueEx.invoke(root, new Object[] { - new Integer(handles[0]), toCstr(value) }); - regCloseKey.invoke(root, new Object[] { new Integer(handles[0]) }); - return (valb != null ? new String(valb).trim() : null); - } - - private static Map readStringValues(Preferences root, - int hkey, String key) throws IllegalArgumentException, - IllegalAccessException, InvocationTargetException { - HashMap results = new HashMap(); - int[] handles = (int[]) regOpenKey.invoke(root, new Object[] { - new Integer(hkey), toCstr(key), new Integer(KEY_READ) }); - if (handles[1] != REG_SUCCESS) { - return null; - } - int[] info = (int[]) regQueryInfoKey.invoke(root, - new Object[] { new Integer(handles[0]) }); - - int count = info[0]; // count - int maxlen = info[3]; // value length max - for (int index = 0; index < count; index++) { - byte[] name = (byte[]) regEnumValue.invoke(root, new Object[] { - new Integer(handles[0]), new Integer(index), - new Integer(maxlen + 1) }); - String value = readString(hkey, key, new String(name)); - results.put(new String(name).trim(), value); - } - regCloseKey.invoke(root, new Object[] { new Integer(handles[0]) }); - return results; - } - - private static List readStringSubKeys(Preferences root, int hkey, - String key) throws IllegalArgumentException, - IllegalAccessException, InvocationTargetException { - List results = new ArrayList(); - int[] handles = (int[]) regOpenKey.invoke(root, new Object[] { - new Integer(hkey), toCstr(key), new Integer(KEY_READ) }); - if (handles[1] != REG_SUCCESS) { - return null; - } - int[] info = (int[]) regQueryInfoKey.invoke(root, - new Object[] { new Integer(handles[0]) }); - - int count = info[0]; // Fix: info[2] was being used here with wrong - // results. Suggested by davenpcj, confirmed by - // Petrucio - int maxlen = info[3]; // value length max - for (int index = 0; index < count; index++) { - byte[] name = (byte[]) regEnumKeyEx.invoke(root, new Object[] { - new Integer(handles[0]), new Integer(index), - new Integer(maxlen + 1) }); - results.add(new String(name).trim()); - } - regCloseKey.invoke(root, new Object[] { new Integer(handles[0]) }); - return results; - } - - private static int[] createKey(Preferences root, int hkey, String key) - throws IllegalArgumentException, IllegalAccessException, - InvocationTargetException { - return (int[]) regCreateKeyEx.invoke(root, new Object[] { - new Integer(hkey), toCstr(key) }); - } - - private static void writeStringValue(Preferences root, int hkey, - String key, String valueName, String value) - throws IllegalArgumentException, IllegalAccessException, - InvocationTargetException { - int[] handles = (int[]) regOpenKey.invoke(root, new Object[] { - new Integer(hkey), toCstr(key), new Integer(KEY_ALL_ACCESS) }); - - regSetValueEx.invoke(root, new Object[] { new Integer(handles[0]), - toCstr(valueName), toCstr(value) }); - regCloseKey.invoke(root, new Object[] { new Integer(handles[0]) }); - } - - // utility - private static byte[] toCstr(String str) { - byte[] result = new byte[str.length() + 1]; - - for (int i = 0; i < str.length(); i++) { - result[i] = (byte) str.charAt(i); - } - result[str.length()] = 0; - return result; - } -} \ No newline at end of file +}