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