All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.invation.code.toval.os.WindowsRegistry Maven / Gradle / Ivy

/*
 * Copyright (c) 2015, Thomas Stocker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted (subject to the limitations in the disclaimer
 * below) provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * * Neither the name of IIG Telematics, Uni Freiburg nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
 * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BELIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package de.invation.code.toval.os;

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;

/**
 * 

* Static class to access the Windows Registry. The Windows Registry is the * configuration catalogue from Microsoft Windows. *

*

* It is divided into different hives for different purposes * (HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, * HKEY_LOCAL_MACHINE, etc.), which contain hierarchically * structured keys. Each key can contain values, which have a name * and a content. Every key contains a default value, usually indicated by an * empty name ({@value #DEFAULT_KEY_NAME}). *

*

* This class contains methods to read and write keys and values in different * hives. *

* * @version 1.0 * @author Adrian Lange */ public final class WindowsRegistry { public static final String DEFAULT_KEY_NAME = ""; public static final char REG_PATH_SEPARATOR = '\\'; public static final String REG_PATH_SEPARATOR_REGEX = "\\\\"; private static final int KEY_READ = 0x20019; private static final int KEY_WRITE = 0x20006; private static final int ERROR_ACCESS_DENIED = 5; private static final int ERROR_FILE_NOT_FOUND = 2; private static final int ERROR_SUCCESS = 0; private static Throwable initError; private WindowsRegistry() { } private static void checkError(int e) throws RegistryException { if (e == ERROR_SUCCESS) { return; } if (e == ERROR_FILE_NOT_FOUND) { throw new RegistryException("Key not found"); } else { if (e == ERROR_ACCESS_DENIED) { throw new RegistryException("Access denied"); } else { throw new RegistryException("Error number " + e, null); } } } /** * Creates a key. Parent keys in the path will also be created if necessary. * This method returns without error if the key already exists. * * @param keyName Key name (i.a. with parent keys) to be created. * @throws RegistryException */ public static void createKey(String keyName) throws RegistryException { int[] info = invoke(Methods.REG_CREATE_KEY_EX.get(), keyParts(keyName)); checkError(info[InfoIndex.INFO_ERROR_CODE.get()]); invoke(Methods.REG_CLOSE_KEY.get(), info[InfoIndex.INFO_HANDLE.get()]); } /** * Deletes a key and all values within it. If the key has subkeys, an * "Access denied" error will be thrown. Subkeys must be deleted separately. * * @param keyName Key name to delete. * @throws RegistryException */ public static void deleteKey(String keyName) throws RegistryException { checkError(invoke(Methods.REG_DELETE_KEY.get(), keyParts(keyName))); } /** * Deletes a value within a key. * * @param keyName Name of the key, which contains the value to delete. * @param valueName Name of the value to delete. * @throws RegistryException */ public static void deleteValue(String keyName, String valueName) throws RegistryException { try (Key key = Key.open(keyName, KEY_WRITE)) { checkError(invoke(Methods.REG_DELETE_VALUE.get(), key.id, toByteArray(valueName))); } } /** * Checks if a given key exists. * * @param keyName Key name to check for existence. * @return true if the key exists, otherwise * false. * @throws RegistryException */ public static boolean existsKey(String keyName) throws RegistryException { String[] keyNameParts = keyName.split(REG_PATH_SEPARATOR_REGEX); // first part must be valid hive if (Hive.getHive(keyNameParts[0]) == null) { return false; } for (int i = 1; i < keyNameParts.length; i++) { // build path StringBuilder path = new StringBuilder(); for (int j = 0; j < i; j++) { path.append(keyNameParts[j]); if (j < i) { path.append(REG_PATH_SEPARATOR); } } // check if next element in path exists List subkeys = readSubkeys(path.toString()); if (!subkeys.contains(keyNameParts[i])) { return false; } } return true; } private static String fromByteArray(byte[] bytes) { if (bytes == null) { return null; } char[] chars = new char[bytes.length - 1]; for (int i = 0; i < chars.length; i++) { chars[i] = (char) ((int) bytes[i] & 0xFF); } return new String(chars); } private static T invoke(Method method, Object... args) throws RegistryException { if (initError != null) { throw new RegistryException("Registry methods are not available", initError); } try { return (T) method.invoke(null, args); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new RegistryException(null, e); } } /** * Tells if the Windows registry functions are available. * * @return true if the Windows Registry is avalable, * false otherwise. */ public static boolean isAvailable() { return initError == null && WindowsUtils.instance().isApplicable(); } /** * Splits a path such as HKEY_LOCAL_MACHINE\Software\Microsoft into a pair * of values used by the underlying API: An integer hive constant and a byte * array of the key path within that hive. * * @param fullKeyName Key name to split in its single keys. * @return Array with the hive key as first element and a following byte * array for each key name as second element. */ private static Object[] keyParts(String fullKeyName) throws RegistryException { int x = fullKeyName.indexOf(REG_PATH_SEPARATOR); String hiveName = x >= 0 ? fullKeyName.substring(0, x) : fullKeyName; String keyName = x >= 0 ? fullKeyName.substring(x + 1) : ""; if (Hive.getHive(hiveName) == null) { throw new RegistryException("Unknown registry hive: " + hiveName, null); } Integer hiveKey = Hive.getHive(hiveName).getId(); return new Object[]{hiveKey, toByteArray(keyName)}; } /** * Returns a list of the names of all the subkeys of a key. * * @param keyName Key name to read all subkeys from. * @return {@link List} of key names directly contained in the specified * key. * @throws RegistryException */ public static List readSubkeys(String keyName) throws RegistryException { try (Key key = Key.open(keyName, KEY_READ)) { int[] info = invoke(Methods.REG_QUERY_INFO_KEY.get(), key.id); checkError(info[InfoIndex.INFO_ERROR_CODE.get()]); int count = info[InfoIndex.INFO_COUNT_KEYS.get()]; int maxLength = info[InfoIndex.INFO_MAX_KEY_LENGTH.get()] + 1; List subkeys = new ArrayList<>(count); for (int i = 0; i < count; i++) { subkeys.add(fromByteArray(invoke(Methods.REG_ENUM_KEY_EX.get(), key.id, i, maxLength))); } return subkeys; } } /** * Reads a string value from the given key and value name. * * @param keyName Name of the key, which contains the value to read. * @param valueName Name of the value to read. * @return Content of the specified value. * @throws RegistryException */ public static String readValue(String keyName, String valueName) throws RegistryException { try (Key key = Key.open(keyName, KEY_READ)) { return fromByteArray(invoke(Methods.REG_QUERY_VALUE_EX.get(), key.id, toByteArray(valueName))); } } /** * Returns a map of all the name-value pairs in the given key. * * @param keyName Name of the key to read all values from. * @return {@link Map} of value name and value content pairs. * @throws RegistryException */ public static Map readValues(String keyName) throws RegistryException { try (Key key = Key.open(keyName, KEY_READ)) { int[] info = invoke(Methods.REG_QUERY_INFO_KEY.get(), key.id); checkError(info[InfoIndex.INFO_ERROR_CODE.get()]); int count = info[InfoIndex.INFO_COUNT_VALUES.get()]; int maxLength = info[InfoIndex.INFO_MAX_VALUE_LENGTH.get()] + 1; Map values = new HashMap<>(); for (int i = 0; i < count; i++) { String valueName = fromByteArray(invoke(Methods.REG_ENUM_VALUE.get(), key.id, i, maxLength)); values.put(valueName, readValue(keyName, valueName)); } return values; } } /** * Conversion of strings to/from null-terminated byte arrays. * * @param string String to convert to null-terminated byte array. * @return Null-terminated byte array. */ private static byte[] toByteArray(String string) { byte[] bytes = new byte[string.length() + 1]; for (int i = 0; i < string.length(); i++) { bytes[i] = (byte) string.charAt(i); } return bytes; } /** * Writes a string value with a given key and value name. * * @param keyName Name of the key to write the value in. * @param valueName Name of the value. * @param value Content of the value. * @throws RegistryException */ public static void writeValue(String keyName, String valueName, String value) throws RegistryException { try (Key key = Key.open(keyName, KEY_WRITE)) { checkError(invoke(Methods.REG_SET_VALUE_EX.get(), key.id, toByteArray(valueName), toByteArray(value))); } } /** * Mapping of hive names to constants from winreg.h. */ public static enum Hive { HKEY_CLASSES_ROOT(0x80000000), HKCR(0x80000000), HKEY_CURRENT_USER(0x80000001), HKCU(0x80000001), HKEY_LOCAL_MACHINE(0x80000002), HKLM(0x80000002), HKEY_USERS(0x80000003), HKU(0x80000003), HKEY_CURRENT_CONFIG(0x80000005), HKCC(0x80000005); private final Integer id; private Hive(Integer id) { this.id = id; } public static Integer get(Hive hive) { return hive.getId(); } public static Hive getHive(String name) { for (Hive h : Hive.values()) { if (h.toString().toLowerCase().equals(name.toLowerCase())) { return h; } } return null; } public Integer getId() { return id; } public String getName() { return this.toString(); } } /** * Enumeration type encapsulating info array indexes. */ private static enum InfoIndex { INFO_COUNT_KEYS(0), INFO_COUNT_VALUES(2), INFO_ERROR_CODE(1), INFO_HANDLE(0), INFO_MAX_KEY_LENGTH(3), INFO_MAX_VALUE_LENGTH(4); private int num; private InfoIndex(int num) { this.num = num; } public int get() { return num; } } /** * Enumeration type for the different methods to access the Windows * Registry. */ private static enum Methods { REG_CLOSE_KEY("WindowsRegCloseKey", int.class), REG_CREATE_KEY_EX("WindowsRegCreateKeyEx", int.class, byte[].class), REG_DELETE_KEY("WindowsRegDeleteKey", int.class, byte[].class), REG_DELETE_VALUE("WindowsRegDeleteValue", int.class, byte[].class), REG_ENUM_KEY_EX("WindowsRegEnumKeyEx", int.class, int.class, int.class), REG_ENUM_VALUE("WindowsRegEnumValue", int.class, int.class, int.class), REG_OPEN_KEY("WindowsRegOpenKey", int.class, byte[].class, int.class), REG_QUERY_VALUE_EX("WindowsRegQueryValueEx", int.class, byte[].class), REG_QUERY_INFO_KEY("WindowsRegQueryInfoKey", int.class), REG_SET_VALUE_EX("WindowsRegSetValueEx", int.class, byte[].class, byte[].class); private Method method; private Methods(String methodName, Class... parameterTypes) { try { Method m = java.util.prefs.Preferences.systemRoot().getClass().getDeclaredMethod(methodName, parameterTypes); m.setAccessible(true); method = m; } catch (NoSuchMethodException | SecurityException t) { initError = t; } } /** * Returns the method. * * @return The desired method */ public Method get() { return method; } } /** * Type encapsulating a native handle to a registry key. */ private static class Key implements AutoCloseable { final int id; private Key(int id) { this.id = id; } static Key open(String keyName, int accessMode) throws RegistryException { Object[] keyParts = keyParts(keyName); int[] ret = invoke(Methods.REG_OPEN_KEY.get(), keyParts[0], keyParts[1], accessMode); checkError(ret[InfoIndex.INFO_ERROR_CODE.get()]); return new Key(ret[InfoIndex.INFO_HANDLE.get()]); } @Override public void close() throws RegistryException { invoke(Methods.REG_CLOSE_KEY.get(), id); } } /** * The exception type that will be thrown if a registry operation fails. */ public static class RegistryException extends OSException { public RegistryException(String message) { super(message); } public RegistryException(String message, Throwable cause) { super(message, cause); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy