/******************************************************************************* * Copyright (c) 2010-2013, Embraer S.A., Budapest University of Technology and Economics * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Rodrigo Rizzi Starr, Lincoln Nascimento - initial API and implementation *******************************************************************************/ package br.com.embraer.massif.commandevaluation.client.util; import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.prefs.Preferences; // Class retrieved originally from: http://www.rgagnon.com/javadetails/java-0630.html // And the modified class was retrieved from: http://stackoverflow.com/questions/62289/read-write-to-windows-registry-using-java/11854901#11854901 /** * 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). *****************************************************************************/ public final class WinRegistry { private static final String HKEY_EQUALS = "hkey="; 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; public static final int KEY_WOW64_32KEY = 0x0200; public static final int KEY_WOW64_64KEY = 0x0100; 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<? 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 (SecurityException e) { throw new IllegalStateException("Could not initialize WinRegistry", e); } catch (NoSuchMethodException e) { throw new IllegalStateException("Could not initialize WinRegistry", e); } } private WinRegistry() { } /** * Read a value from key and value name * * @param hkey * HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE * @param key * @param valueName * @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_EQUALS + hkey); } } /** * Read value(s) and value name(s) form given key * * @param hkey * HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE * @param 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) plus the value(s) * @throws IllegalArgumentException * @throws IllegalAccessException * @throws InvocationTargetException */ public static Map<String, String> readStringValues(int hkey, String key, int wow64) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { if (hkey == HKEY_LOCAL_MACHINE) { return readStringValues(systemRoot, hkey, key, wow64); } else if (hkey == HKEY_CURRENT_USER) { return readStringValues(userRoot, hkey, key, wow64); } else { throw new IllegalArgumentException(HKEY_EQUALS + hkey); } } /** * Read the value name(s) from a given key * * @param hkey * HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE * @param 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_EQUALS + hkey); } } /** * Create a key * * @param hkey * HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE * @param key * @throws IllegalArgumentException * @throws IllegalAccessException * @throws 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[] { Integer.valueOf(ret[0]) }); } else if (hkey == HKEY_CURRENT_USER) { ret = createKey(userRoot, hkey, key); regCloseKey.invoke(userRoot, new Object[] { Integer.valueOf(ret[0]) }); } else { throw new IllegalArgumentException(HKEY_EQUALS + 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 * @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 * @throws IllegalArgumentException * @throws IllegalAccessException * @throws InvocationTargetException */ public static void writeStringValue(int hkey, String key, String valueName, String value, int wow64) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { if (hkey == HKEY_LOCAL_MACHINE) { writeStringValue(systemRoot, hkey, key, valueName, value, wow64); } else if (hkey == HKEY_CURRENT_USER) { writeStringValue(userRoot, hkey, key, valueName, value, wow64); } else { throw new IllegalArgumentException(HKEY_EQUALS + hkey); } } /** * Delete a given key * * @param hkey * @param key * @throws IllegalArgumentException * @throws IllegalAccessException * @throws 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 * @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 * @throws IllegalArgumentException * @throws IllegalAccessException * @throws InvocationTargetException */ public static void deleteValue(int hkey, String key, String value, int wow64) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { int rc = -1; if (hkey == HKEY_LOCAL_MACHINE) { rc = deleteValue(systemRoot, hkey, key, value, wow64); } else if (hkey == HKEY_CURRENT_USER) { rc = deleteValue(userRoot, hkey, key, value, wow64); } 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, int wow64) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { int[] handles = (int[]) regOpenKey.invoke(root, new Object[] { Integer.valueOf(hkey), toCstr(key), Integer.valueOf(KEY_ALL_ACCESS | wow64) }); if (handles[1] != REG_SUCCESS) { return handles[1]; // can be REG_NOTFOUND, REG_ACCESSDENIED } int rc = ((Integer) regDeleteValue.invoke(root, new Object[] { Integer.valueOf(handles[0]), toCstr(value) })) .intValue(); regCloseKey.invoke(root, new Object[] { Integer.valueOf(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[] { Integer.valueOf(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, int wow64) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { int[] handles = (int[]) regOpenKey.invoke(root, new Object[] { Integer.valueOf(hkey), toCstr(key), Integer.valueOf(KEY_READ | wow64) }); if (handles[1] != REG_SUCCESS) { return null; } byte[] valb = (byte[]) regQueryValueEx .invoke(root, new Object[] { Integer.valueOf(handles[0]), toCstr(value) }); regCloseKey.invoke(root, new Object[] { Integer.valueOf(handles[0]) }); String stringValue = convertByteToUTF8String(valb); return (valb != null ? stringValue.trim() : null); } // ======================================================================== private static Map<String, String> readStringValues(Preferences root, int hkey, String key, int wow64) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { HashMap<String, String> results = new HashMap<String, String>(); int[] handles = (int[]) regOpenKey.invoke(root, new Object[] { Integer.valueOf(hkey), toCstr(key), Integer.valueOf(KEY_READ | wow64) }); if (handles[1] != REG_SUCCESS) { return null; } int[] info = (int[]) regQueryInfoKey.invoke(root, new Object[] { Integer.valueOf(handles[0]) }); int count = info[2]; // count int maxlen = info[3]; // value length max for (int index = 0; index < count; index++) { byte[] name = (byte[]) regEnumValue.invoke(root, new Object[] { Integer.valueOf(handles[0]), Integer.valueOf(index), Integer.valueOf(maxlen + 1) }); String stringValue = convertByteToUTF8String(name); String value = readString(hkey, key, stringValue, wow64); results.put(stringValue.trim(), value); } regCloseKey.invoke(root, new Object[] { Integer.valueOf(handles[0]) }); return results; } // ======================================================================== 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, new Object[] { Integer.valueOf(hkey), toCstr(key), Integer.valueOf(KEY_READ | wow64) }); if (handles[1] != REG_SUCCESS) { return null; } int[] info = (int[]) regQueryInfoKey.invoke(root, new Object[] { Integer.valueOf(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[] { Integer.valueOf(handles[0]), Integer.valueOf(index), Integer.valueOf(maxlen + 1) }); String stringValue = convertByteToUTF8String(name); results.add(stringValue.trim()); } regCloseKey.invoke(root, new Object[] { Integer.valueOf(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[] { Integer.valueOf(hkey), toCstr(key) }); } // ======================================================================== private static void writeStringValue(Preferences root, int hkey, String key, String valueName, String value, int wow64) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { int[] handles = (int[]) regOpenKey.invoke(root, new Object[] { Integer.valueOf(hkey), toCstr(key), Integer.valueOf(KEY_ALL_ACCESS | wow64) }); regSetValueEx.invoke(root, new Object[] { Integer.valueOf(handles[0]), toCstr(valueName), toCstr(value) }); regCloseKey.invoke(root, new Object[] { Integer.valueOf(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; } private static String convertByteToUTF8String(byte[] name) { try { return new String(name, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new IllegalStateException("UTF-8 should always be available!", e); } } }