package net.ftb.util.winreg; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.prefs.Preferences; /** * Pure Java Windows Registry access. * Modified by petrucio@stackoverflow(828681) to add support for * reading (and writing but not creating/deleting keys) the 32-bits * registry view from a 64-bits JVM (KEY_WOW64_32KEY) * and 64-bits view from a 32-bits JVM (KEY_WOW64_64KEY). *****************************************************************************/ import net.ftb.log.Logger; public class WinRegistry { private static final int HKEY_CURRENT_USER = 0x80000001; public static final int HKEY_LOCAL_MACHINE = 0x80000002; private static final int REG_SUCCESS = 0; public static final int KEY_WOW64_32KEY = 0x0200; public static final int KEY_WOW64_64KEY = 0x0100; private static final int KEY_READ = 0x20019; private static final Preferences userRoot = Preferences.userRoot(); private static final Preferences systemRoot = Preferences.systemRoot(); private static final Class<? extends Preferences> 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) { Logger.logError("Error accessing windows registry classes", e); } } private WinRegistry () {} /** * Read a value from key and value name * @param hkey HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE * @param key registry key * @param valueName registry value * @param wow64 0 for standard registry access (32-bits for 32-bit app, 64-bits for 64-bits app) * or KEY_WOW64_32KEY to force access to 32-bit registry view, * or KEY_WOW64_64KEY to force access to 64-bit registry view * @return the value * @throws IllegalArgumentException * @throws IllegalAccessException * @throws InvocationTargetException */ public static String readString (int hkey, String key, String valueName, int wow64) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { if (hkey == HKEY_LOCAL_MACHINE) { return readString(systemRoot, hkey, key, valueName, wow64); } else if (hkey == HKEY_CURRENT_USER) { return readString(userRoot, hkey, key, valueName, wow64); } else { throw new IllegalArgumentException("hkey=" + hkey); } } /** * Read the value name(s) from a given key * @param hkey HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE * @param key registry key * @param wow64 0 for standard registry access (32-bits for 32-bit app, 64-bits for 64-bits app) * or KEY_WOW64_32KEY to force access to 32-bit registry view, * or KEY_WOW64_64KEY to force access to 64-bit registry view * @return the value name(s) * @throws IllegalArgumentException * @throws IllegalAccessException * @throws InvocationTargetException */ public static List<String> readStringSubKeys (int hkey, String key, int wow64) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { if (hkey == HKEY_LOCAL_MACHINE) { return readStringSubKeys(systemRoot, hkey, key, wow64); } else if (hkey == HKEY_CURRENT_USER) { return readStringSubKeys(userRoot, hkey, key, wow64); } else { throw new IllegalArgumentException("hkey=" + hkey); } } // ======================================================================== private static String readString (Preferences root, int hkey, String key, String value, int wow64) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { int[] handles = (int[])regOpenKey.invoke(root, hkey, toCstr(key), KEY_READ | wow64); if (handles[1] != REG_SUCCESS) { return null; } byte[] valb = (byte[])regQueryValueEx.invoke(root, handles[0], toCstr(value)); regCloseKey.invoke(root, handles[0]); return (valb != null ? new String(valb).trim() : null); } // ======================================================================== private static List<String> readStringSubKeys (Preferences root, int hkey, String key, int wow64) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { List<String> results = new ArrayList<String>(); int[] handles = (int[])regOpenKey.invoke(root, hkey, toCstr(key), KEY_READ | wow64); if (handles[1] != REG_SUCCESS) { return null; } int[] info = (int[])regQueryInfoKey.invoke(root, 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, handles[0], index, maxlen + 1); results.add(new String(name).trim()); } regCloseKey.invoke(root, handles[0]); return results; } // ======================================================================== // 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; } }