Added WindowsRegistry.

This commit is contained in:
Adam Murdoch
2013-12-10 18:02:35 +11:00
parent a7eb521383
commit 077298ddf4
10 changed files with 225 additions and 2 deletions

View File

@@ -19,6 +19,7 @@
#include "native.h"
#include "generic.h"
#include <windows.h>
#include <Shlwapi.h>
#include <wchar.h>
/*
@@ -475,4 +476,81 @@ JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_WindowsHandleFunctions_restoreStandardHandles(JNIEnv *env, jclass target, jobject result) {
}
HKEY get_key_from_ordinal(jint keyNum) {
return keyNum == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
}
JNIEXPORT jstring JNICALL
Java_net_rubygrapefruit_platform_internal_jni_WindowsRegistryFunctions_getStringValue(JNIEnv *env, jclass target, jint keyNum, jstring subkey, jstring valueName, jobject result) {
HKEY key = get_key_from_ordinal(keyNum);
wchar_t* subkeyStr = java_to_wchar(env, subkey, result);
wchar_t* valueNameStr = java_to_wchar(env, valueName, result);
DWORD size = 0;
LONG retval = SHRegGetValueW(key, subkeyStr, valueNameStr, SRRF_RT_REG_SZ, NULL, NULL, &size);
if (retval != ERROR_SUCCESS) {
free(subkeyStr);
free(valueNameStr);
if (retval != ERROR_FILE_NOT_FOUND) {
mark_failed_with_code(env, "could not determine size of registry value", retval, NULL, result);
}
return NULL;
}
wchar_t* value = (wchar_t*)malloc(sizeof(wchar_t) * (size+1));
retval = SHRegGetValueW(key, subkeyStr, valueNameStr, SRRF_RT_REG_SZ, NULL, value, &size);
free(subkeyStr);
free(valueNameStr);
if (retval != ERROR_SUCCESS) {
free(value);
mark_failed_with_code(env, "could not get registry value", retval, NULL, result);
return NULL;
}
jstring jvalue = wchar_to_java(env, value, wcslen(value), result);
free(value);
return jvalue;
}
JNIEXPORT jboolean JNICALL
Java_net_rubygrapefruit_platform_internal_jni_WindowsRegistryFunctions_getSubkeys(JNIEnv *env, jclass target, jint keyNum, jstring subkey, jobject subkeys, jobject result) {
wchar_t* subkeyStr = java_to_wchar(env, subkey, result);
jclass subkeys_class = env->GetObjectClass(subkeys);
jmethodID method = env->GetMethodID(subkeys_class, "add", "(Ljava/lang/Object;)Z");
HKEY key;
LONG retval = RegOpenKeyExW(get_key_from_ordinal(keyNum), subkeyStr, 0, KEY_READ, &key);
if (retval != ERROR_SUCCESS) {
free(subkeyStr);
if (retval != ERROR_FILE_NOT_FOUND) {
mark_failed_with_code(env, "could open registry key", retval, NULL, result);
}
return false;
}
DWORD subkeyCount;
DWORD maxSubkeyLen;
retval = RegQueryInfoKeyW(key, NULL, NULL, NULL, &subkeyCount, &maxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
if (retval != ERROR_SUCCESS) {
mark_failed_with_code(env, "could query registry key", retval, NULL, result);
} else {
wchar_t* keyNameStr = (wchar_t*)malloc(sizeof(wchar_t) * (maxSubkeyLen+1));
for (int i = 0; i < subkeyCount; i++) {
DWORD keyNameLen = maxSubkeyLen + 1;
retval = RegEnumKeyExW(key, i, keyNameStr, &keyNameLen, NULL, NULL, NULL, NULL);
if (retval != ERROR_SUCCESS) {
mark_failed_with_code(env, "could enumerate registry subkey", retval, NULL, result);
break;
}
env->CallVoidMethod(subkeys, method, wchar_to_java(env, keyNameStr, wcslen(keyNameStr), result));
}
free(keyNameStr);
}
RegCloseKey(key);
free(subkeyStr);
return true;
}
#endif

View File

@@ -23,7 +23,7 @@
extern "C" {
#endif
#define NATIVE_VERSION 15
#define NATIVE_VERSION 16
/*
* Marks the given result as failed, using the given error message

View File

@@ -0,0 +1,10 @@
package net.rubygrapefruit.platform;
/**
* Thrown when attempting to query an unknown registry key or value.
*/
public class MissingRegistryEntryException extends NativeException {
public MissingRegistryEntryException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,26 @@
package net.rubygrapefruit.platform;
import java.util.List;
@ThreadSafe
public interface WindowsRegistry extends NativeIntegration {
public enum Key {
HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER
}
/**
* Returns a registry key value as a String.
*
* @throws NativeException On failure.
* @throws MissingRegistryEntryException When the requested key or value does not exist.
*/
String getStringValue(Key key, String subkey, String value) throws NativeException;
/**
* Lists the subkeys of a registry key.
*
* @throws NativeException On failure.
* @throws MissingRegistryEntryException When the requested key does not exist.
*/
List<String> getSubkeys(Key key, String subkey) throws NativeException;
}

View File

@@ -0,0 +1,41 @@
package net.rubygrapefruit.platform.internal;
import net.rubygrapefruit.platform.MissingRegistryEntryException;
import net.rubygrapefruit.platform.NativeException;
import net.rubygrapefruit.platform.WindowsRegistry;
import net.rubygrapefruit.platform.internal.jni.WindowsRegistryFunctions;
import java.util.ArrayList;
import java.util.List;
public class DefaultWindowsRegistry implements WindowsRegistry {
public String getStringValue(Key key, String subkey, String valueName) throws NativeException {
FunctionResult result = new FunctionResult();
String value = WindowsRegistryFunctions.getStringValue(key.ordinal(), subkey, valueName, result);
if (result.isFailed()) {
throw new NativeException(String.format("Could not get value '%s' of registry key '%s\\%s': %s", valueName,
key,
subkey, result.getMessage()));
}
if (value == null) {
throw new MissingRegistryEntryException(String.format(
"Could not get value '%s' of registry key '%s\\%s' as it does not exist.", valueName, key, subkey));
}
return value;
}
public List<String> getSubkeys(Key key, String subkey) throws NativeException {
FunctionResult result = new FunctionResult();
ArrayList<String> subkeys = new ArrayList<String>();
boolean found = WindowsRegistryFunctions.getSubkeys(key.ordinal(), subkey, subkeys, result);
if (result.isFailed()) {
throw new NativeException(String.format("Could not get subkeys of registry key '%s\\%s': %s", key,
subkey, result.getMessage()));
}
if (!found) {
throw new MissingRegistryEntryException(String.format(
"Could not list the subkeys of registry key '%s\\%s' as it does not exist.", key, subkey));
}
return subkeys;
}
}

View File

@@ -114,6 +114,9 @@ public abstract class Platform {
if (type.equals(FileSystems.class)) {
return type.cast(new PosixFileSystems());
}
if (type.equals(WindowsRegistry.class)) {
return type.cast(new DefaultWindowsRegistry());
}
return super.get(type, nativeLibraryLoader);
}
}

View File

@@ -20,7 +20,7 @@ import net.rubygrapefruit.platform.internal.FunctionResult;
import net.rubygrapefruit.platform.internal.MutableSystemInfo;
public class NativeLibraryFunctions {
public static final int VERSION = 15;
public static final int VERSION = 16;
public static native int getVersion();

View File

@@ -0,0 +1,13 @@
package net.rubygrapefruit.platform.internal.jni;
import net.rubygrapefruit.platform.internal.FunctionResult;
import java.util.List;
public class WindowsRegistryFunctions {
// Returns null for unknown key or value
public static native String getStringValue(int key, String subkey, String value, FunctionResult result);
// Returns false for unknown key
public static native boolean getSubkeys(int key, String subkey, List<String> subkeys, FunctionResult result);
}

View File

@@ -0,0 +1,50 @@
package net.rubygrapefruit.platform
import net.rubygrapefruit.platform.internal.Platform
import spock.lang.IgnoreIf
import spock.lang.Specification
@IgnoreIf({!Platform.current().windows})
class WindowsRegistryTest extends Specification {
def windowsRegistry = Native.get(WindowsRegistry)
def "can read string value"() {
expect:
def currentVersion = windowsRegistry.getStringValue(WindowsRegistry.Key.HKEY_LOCAL_MACHINE, /SOFTWARE\Microsoft\Windows NT\CurrentVersion/, "CurrentVersion")
currentVersion.matches("\\d+\\.\\d+")
def path = new File(windowsRegistry.getStringValue(WindowsRegistry.Key.HKEY_CURRENT_USER, "Volatile Environment", "APPDATA"))
path.directory
}
def "cannot read value that does not exist"() {
when:
windowsRegistry.getStringValue(WindowsRegistry.Key.HKEY_LOCAL_MACHINE, /SOFTWARE\Microsoft\Windows NT\CurrentVersion/, "Unknown")
then:
def e = thrown(MissingRegistryEntryException)
e.message == /Could not get value 'Unknown' of registry key 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion' as it does not exist./
}
def "cannot read value of key that does not exist"() {
when:
windowsRegistry.getStringValue(WindowsRegistry.Key.HKEY_LOCAL_MACHINE, /SOFTWARE\Unknown/, "Value")
then:
def e = thrown(MissingRegistryEntryException)
e.message == /Could not get value 'Value' of registry key 'HKEY_LOCAL_MACHINE\SOFTWARE\Unknown' as it does not exist./
}
def "can read subkeys"() {
expect:
windowsRegistry.getSubkeys(WindowsRegistry.Key.HKEY_LOCAL_MACHINE, /SOFTWARE\Microsoft/).flatten().contains("Windows NT")
}
def "cannot read subkeys of key that does not exist"() {
when:
windowsRegistry.getSubkeys(WindowsRegistry.Key.HKEY_LOCAL_MACHINE, /SOFTWARE\Unknown/)
then:
def e = thrown(MissingRegistryEntryException)
e.message == /Could not list the subkeys of registry key 'HKEY_LOCAL_MACHINE\SOFTWARE\Unknown' as it does not exist./
}
}