diff --git a/app/.classpath b/app/.classpath
index d25e81db1..a5d6c470f 100644
--- a/app/.classpath
+++ b/app/.classpath
@@ -13,5 +13,6 @@
+
diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java
index 74239de61..67fedc459 100644
--- a/app/src/processing/app/Base.java
+++ b/app/src/processing/app/Base.java
@@ -1346,12 +1346,12 @@ public class Base {
}
} else if (isWindows()) {
- // http://support.microsoft.com/kb/242557/en-us
-
// looking for Documents and Settings/blah/My Documents/Processing
// (though using a reg key since it's different on other platforms)
// http://support.microsoft.com/?kbid=221837&sd=RMVP
+ // http://support.microsoft.com/kb/242557/en-us
+
// The path to the My Documents folder is stored in the following
// registry key, where path is the complete path to your storage location
diff --git a/app/src/processing/app/windows/Registry.java b/app/src/processing/app/windows/Registry.java
new file mode 100644
index 000000000..878a9289b
--- /dev/null
+++ b/app/src/processing/app/windows/Registry.java
@@ -0,0 +1,454 @@
+package processing.app.windows;
+
+import com.sun.jna.ptr.ByteByReference;
+import com.sun.jna.ptr.IntByReference;
+import com.sun.jna.ptr.PointerByReference;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+/**
+ * Methods for accessing the Windows Registry. Only String and DWORD values supported at the moment.
+ */
+public class Registry {
+ public static enum REGISTRY_ROOT_KEY{CLASSES_ROOT, CURRENT_USER, LOCAL_MACHINE, USERS};
+ private final static HashMap rootKeyMap = new HashMap();
+
+ static {
+ rootKeyMap.put(REGISTRY_ROOT_KEY.CLASSES_ROOT, WINREG.HKEY_CLASSES_ROOT);
+ rootKeyMap.put(REGISTRY_ROOT_KEY.CURRENT_USER, WINREG.HKEY_CURRENT_USER);
+ rootKeyMap.put(REGISTRY_ROOT_KEY.LOCAL_MACHINE, WINREG.HKEY_LOCAL_MACHINE);
+ rootKeyMap.put(REGISTRY_ROOT_KEY.USERS, WINREG.HKEY_USERS);
+ }
+
+ /**
+ * Testing.
+ *
+ * @param args arguments
+ * @throws java.lang.Exception on error
+ */
+ public static void main(String[] args) throws Exception {
+ }
+
+ /**
+ * Gets one of the root keys.
+ *
+ * @param key key type
+ * @return root key
+ */
+ private static int getRegistryRootKey(REGISTRY_ROOT_KEY key) {
+ Advapi32 advapi32;
+ IntByReference pHandle;
+ int handle = 0;
+
+ advapi32 = Advapi32.INSTANCE;
+ pHandle = new IntByReference();
+
+ if(advapi32.RegOpenKeyEx(rootKeyMap.get(key), null, 0, 0, pHandle) == WINERROR.ERROR_SUCCESS) {
+ handle = pHandle.getValue();
+ }
+ return(handle);
+ }
+
+ /**
+ * Opens a key.
+ *
+ * @param rootKey root key
+ * @param subKeyName name of the key
+ * @param access access mode
+ * @return handle to the key or 0
+ */
+ private static int openKey(REGISTRY_ROOT_KEY rootKey, String subKeyName, int access) {
+ Advapi32 advapi32;
+ IntByReference pHandle;
+ int rootKeyHandle;
+
+ advapi32 = Advapi32.INSTANCE;
+ rootKeyHandle = getRegistryRootKey(rootKey);
+ pHandle = new IntByReference();
+
+ if(advapi32.RegOpenKeyEx(rootKeyHandle, subKeyName, 0, access, pHandle) == WINERROR.ERROR_SUCCESS) {
+ return(pHandle.getValue());
+
+ } else {
+ return(0);
+ }
+ }
+
+ /**
+ * Converts a Windows buffer to a Java String.
+ *
+ * @param buf buffer
+ * @throws java.io.UnsupportedEncodingException on error
+ * @return String
+ */
+ private static String convertBufferToString(byte[] buf) throws UnsupportedEncodingException {
+ return(new String(buf, 0, buf.length - 2, "UTF-16LE"));
+ }
+
+ /**
+ * Converts a Windows buffer to an int.
+ *
+ * @param buf buffer
+ * @return int
+ */
+ private static int convertBufferToInt(byte[] buf) {
+ return(((int)(buf[0] & 0xff)) + (((int)(buf[1] & 0xff)) << 8) + (((int)(buf[2] & 0xff)) << 16) + (((int)(buf[3] & 0xff)) << 24));
+ }
+
+ /**
+ * Read a String value.
+ *
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ * @throws java.io.UnsupportedEncodingException on error
+ * @return String or null
+ */
+ public static String getStringValue(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name) throws UnsupportedEncodingException {
+ Advapi32 advapi32;
+ IntByReference pType, lpcbData;
+ byte[] lpData = new byte[1];
+ int handle = 0;
+ String ret = null;
+
+ advapi32 = Advapi32.INSTANCE;
+ pType = new IntByReference();
+ lpcbData = new IntByReference();
+ handle = openKey(rootKey, subKeyName, WINNT.KEY_READ);
+
+ if(handle != 0) {
+
+ if(advapi32.RegQueryValueEx(handle, name, null, pType, lpData, lpcbData) == WINERROR.ERROR_MORE_DATA) {
+ lpData = new byte[lpcbData.getValue()];
+
+ if(advapi32.RegQueryValueEx(handle, name, null, pType, lpData, lpcbData) == WINERROR.ERROR_SUCCESS) {
+ ret = convertBufferToString(lpData);
+ }
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return(ret);
+ }
+
+ /**
+ * Read an int value.
+ *
+ *
+ * @return int or 0
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ */
+ public static int getIntValue(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name) {
+ Advapi32 advapi32;
+ IntByReference pType, lpcbData;
+ byte[] lpData = new byte[1];
+ int handle = 0;
+ int ret = 0;
+
+ advapi32 = Advapi32.INSTANCE;
+ pType = new IntByReference();
+ lpcbData = new IntByReference();
+ handle = openKey(rootKey, subKeyName, WINNT.KEY_READ);
+
+ if(handle != 0) {
+
+ if(advapi32.RegQueryValueEx(handle, name, null, pType, lpData, lpcbData) == WINERROR.ERROR_MORE_DATA) {
+ lpData = new byte[lpcbData.getValue()];
+
+ if(advapi32.RegQueryValueEx(handle, name, null, pType, lpData, lpcbData) == WINERROR.ERROR_SUCCESS) {
+ ret = convertBufferToInt(lpData);
+ }
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return(ret);
+ }
+
+ /**
+ * Delete a value.
+ *
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ * @return true on success
+ */
+ public static boolean deleteValue(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name) {
+ Advapi32 advapi32;
+ int handle;
+ boolean ret = true;
+
+ advapi32 = Advapi32.INSTANCE;
+
+ handle = openKey(rootKey, subKeyName, WINNT.KEY_READ | WINNT.KEY_WRITE);
+
+ if(handle != 0) {
+ if(advapi32.RegDeleteValue(handle, name) == WINERROR.ERROR_SUCCESS) {
+ ret = true;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return(ret);
+ }
+
+ /**
+ * Writes a String value.
+ *
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ * @param value value
+ * @throws java.io.UnsupportedEncodingException on error
+ * @return true on success
+ */
+ public static boolean setStringValue(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name, String value) throws UnsupportedEncodingException {
+ Advapi32 advapi32;
+ int handle;
+ byte[] data;
+ boolean ret = false;
+
+ data = Arrays.copyOf(value.getBytes("UTF-16LE"), value.length() * 2 + 2);
+ advapi32 = Advapi32.INSTANCE;
+ handle = openKey(rootKey, subKeyName, WINNT.KEY_READ | WINNT.KEY_WRITE);
+
+ if(handle != 0) {
+ if(advapi32.RegSetValueEx(handle, name, 0, WINNT.REG_SZ, data, data.length) == WINERROR.ERROR_SUCCESS) {
+ ret = true;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return(ret);
+ }
+
+ /**
+ * Writes an int value.
+ *
+ *
+ * @return true on success
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ * @param value value
+ */
+ public static boolean setIntValue(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name, int value) {
+ Advapi32 advapi32;
+ int handle;
+ byte[] data;
+ boolean ret = false;
+
+ data = new byte[4];
+ data[0] = (byte)(value & 0xff);
+ data[1] = (byte)((value >> 8) & 0xff);
+ data[2] = (byte)((value >> 16) & 0xff);
+ data[3] = (byte)((value >> 24) & 0xff);
+ advapi32 = Advapi32.INSTANCE;
+ handle = openKey(rootKey, subKeyName, WINNT.KEY_READ | WINNT.KEY_WRITE);
+
+ if(handle != 0) {
+
+ if(advapi32.RegSetValueEx(handle, name, 0, WINNT.REG_DWORD, data, data.length) == WINERROR.ERROR_SUCCESS) {
+ ret = true;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return(ret);
+ }
+
+ /**
+ * Check for existence of a value.
+ *
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ * @return true if exists
+ */
+ public static boolean valueExists(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name) {
+ Advapi32 advapi32;
+ IntByReference pType, lpcbData;
+ byte[] lpData = new byte[1];
+ int handle = 0;
+ boolean ret = false;
+
+ advapi32 = Advapi32.INSTANCE;
+ pType = new IntByReference();
+ lpcbData = new IntByReference();
+ handle = openKey(rootKey, subKeyName, WINNT.KEY_READ);
+
+ if(handle != 0) {
+
+ if(advapi32.RegQueryValueEx(handle, name, null, pType, lpData, lpcbData) != WINERROR.ERROR_FILE_NOT_FOUND) {
+ ret = true;
+
+ } else {
+ ret = false;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return(ret);
+ }
+
+ /**
+ * Create a new key.
+ *
+ * @param rootKey root key
+ * @param parent name of parent key
+ * @param name key name
+ * @return true on success
+ */
+ public static boolean createKey(REGISTRY_ROOT_KEY rootKey, String parent, String name) {
+ Advapi32 advapi32;
+ IntByReference hkResult, dwDisposition;
+ int handle = 0;
+ boolean ret = false;
+
+ advapi32 = Advapi32.INSTANCE;
+ hkResult = new IntByReference();
+ dwDisposition = new IntByReference();
+ handle = openKey(rootKey, parent, WINNT.KEY_READ);
+
+ if(handle != 0) {
+
+ if(advapi32.RegCreateKeyEx(handle, name, 0, null, WINNT.REG_OPTION_NON_VOLATILE, WINNT.KEY_READ, null,
+ hkResult, dwDisposition) == WINERROR.ERROR_SUCCESS) {
+ ret = true;
+ advapi32.RegCloseKey(hkResult.getValue());
+
+ } else {
+ ret = false;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return(ret);
+ }
+
+ /**
+ * Delete a key.
+ *
+ * @param rootKey root key
+ * @param parent name of parent key
+ * @param name key name
+ * @return true on success
+ */
+ public static boolean deleteKey(REGISTRY_ROOT_KEY rootKey, String parent, String name) {
+ Advapi32 advapi32;
+ int handle = 0;
+ boolean ret = false;
+
+ advapi32 = Advapi32.INSTANCE;
+ handle = openKey(rootKey, parent, WINNT.KEY_READ);
+
+ if(handle != 0) {
+
+ if(advapi32.RegDeleteKey(handle, name) == WINERROR.ERROR_SUCCESS) {
+ ret = true;
+
+ } else {
+ ret = false;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return(ret);
+ }
+
+ /**
+ * Get all sub keys of a key.
+ *
+ * @param rootKey root key
+ * @param parent key name
+ * @return array with all sub key names
+ */
+ public static String[] getSubKeys(REGISTRY_ROOT_KEY rootKey, String parent) {
+ Advapi32 advapi32;
+ int handle = 0, dwIndex;
+ char[] lpName;
+ IntByReference lpcName;
+ WINBASE.FILETIME lpftLastWriteTime;
+ TreeSet subKeys = new TreeSet();
+
+ advapi32 = Advapi32.INSTANCE;
+ handle = openKey(rootKey, parent, WINNT.KEY_READ);
+ lpName = new char[256];
+ lpcName = new IntByReference(256);
+ lpftLastWriteTime = new WINBASE.FILETIME();
+
+ if(handle != 0) {
+ dwIndex = 0;
+
+ while(advapi32.RegEnumKeyEx(handle, dwIndex, lpName, lpcName, null,
+ null, null, lpftLastWriteTime) == WINERROR.ERROR_SUCCESS) {
+ subKeys.add(new String(lpName, 0, lpcName.getValue()));
+ lpcName.setValue(256);
+ dwIndex++;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+
+ return(subKeys.toArray(new String[]{}));
+ }
+
+ /**
+ * Get all values under a key.
+ *
+ * @param rootKey root key
+ * @param key jey name
+ * @throws java.io.UnsupportedEncodingException on error
+ * @return TreeMap with name and value pairs
+ */
+ public static TreeMap getValues(REGISTRY_ROOT_KEY rootKey, String key) throws UnsupportedEncodingException {
+ Advapi32 advapi32;
+ int handle = 0, dwIndex, result = 0;
+ char[] lpValueName;
+ byte[] lpData;
+ IntByReference lpcchValueName, lpType, lpcbData;
+ String name;
+ TreeMap values = new TreeMap(String.CASE_INSENSITIVE_ORDER);
+
+ advapi32 = Advapi32.INSTANCE;
+ handle = openKey(rootKey, key, WINNT.KEY_READ);
+ lpValueName = new char[16384];
+ lpcchValueName = new IntByReference(16384);
+ lpType = new IntByReference();
+ lpData = new byte[1];
+ lpcbData = new IntByReference();
+
+ if(handle != 0) {
+ dwIndex = 0;
+
+ do {
+ lpcbData.setValue(0);
+ result = advapi32.RegEnumValue(handle, dwIndex, lpValueName, lpcchValueName, null,
+ lpType, lpData, lpcbData);
+
+ if(result == WINERROR.ERROR_MORE_DATA) {
+ lpData = new byte[lpcbData.getValue()];
+ lpcchValueName = new IntByReference(16384);
+ result = advapi32.RegEnumValue(handle, dwIndex, lpValueName, lpcchValueName, null,
+ lpType, lpData, lpcbData);
+
+ if(result == WINERROR.ERROR_SUCCESS) {
+ name = new String(lpValueName, 0, lpcchValueName.getValue());
+
+ switch(lpType.getValue()) {
+ case WINNT.REG_SZ:
+ values.put(name, convertBufferToString(lpData));
+ break;
+ case WINNT.REG_DWORD:
+ values.put(name, convertBufferToInt(lpData));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ dwIndex++;
+ } while(result == WINERROR.ERROR_SUCCESS);
+
+ advapi32.RegCloseKey(handle);
+ }
+ return(values);
+ }
+}
diff --git a/todo.txt b/todo.txt
index 7d5587674..78cc5212f 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,6 +1,5 @@
0140 pde
-
_ "Target VM failed to initialize: VM initialization failed" when trying to run
_ http://dev.processing.org/bugs/show_bug.cgi?id=796
@@ -16,6 +15,8 @@ _ http://dev.processing.org/bugs/show_bug.cgi?id=775
_ this may just be a macosx (ppc?) bug
further cleanup for simpler building
+_ remove libs from build/shared that are in app/lib
+_ update scripts to copy from app/lib
_ since adding tools.jar, jikes can be removed
_ implement windows registry lookups via reflection
_ http://dev.processing.org/bugs/show_bug.cgi?id=723