001package com.randomnoun.common;
002
003/* (c) 2013 randomnoun. All Rights Reserved. This work is licensed under a
004 * BSD Simplified License. (http://www.randomnoun.com/bsd-simplified.html)
005 */
006
007/** Java hack to access windows registries. Relies on the sun implementation
008 * of the Preferences class. 
009 * 
010 * <p>Technique stolen from
011 * http://snipplr.com/view/6620/accessing-windows-registry-in-java/
012 * 
013 * <p>Probably better to JNI-wrap this, but hey, who has time for that.
014 * 
015 * 
016 */
017
018import java.lang.reflect.Method;
019import java.util.prefs.Preferences;
020
021public class Registry {
022    
023        // private static final int HKEY_CURRENT_USER = 0x80000001;
024        // private static final int KEY_QUERY_VALUE = 1;
025        // private static final int KEY_SET_VALUE = 2;
026        private static final int KEY_READ = 0x20019;
027
028        private static int initialisationState = 0;
029        
030        // java internals, bit nasty all of this being static
031        private static final Preferences userRoot = Preferences.userRoot();
032        private static final Preferences systemRoot = Preferences.systemRoot();
033        private static final Class<?> clz = userRoot.getClass();
034        private static Method winRegQueryValue;
035        private static Method winRegEnumValue;
036        private static Method winRegQueryInfo;  
037        private static Method openKey;
038        private static Method closeKey;
039        
040        
041        // you'd better hope these methods are threadsafe
042        public static String getSystemValue(String registryKey, String key) {
043                initialise();
044                
045                byte[] valb = null;
046                String vals = null;
047                Integer handle = -1;
048
049                // Query for IE version
050                // key = "SOFTWARE\\Microsoft\\Internet Explorer#Version";
051                try {
052                        handle = (Integer) openKey.invoke(systemRoot, toCstr(registryKey),
053                                        KEY_READ, KEY_READ);
054                        valb = (byte[]) winRegQueryValue.invoke(systemRoot, handle,
055                                        toCstr(key));
056                        vals = (valb != null ? new String(valb).trim() : null);
057                        closeKey.invoke(Preferences.systemRoot(), handle);
058                } catch (Exception e) {
059                        if (handle!=-1) {
060                                try {
061                                        closeKey.invoke(Preferences.systemRoot(), handle);
062                                } catch (Exception e2) {
063                                        throw new IllegalArgumentException("Error reading registry '" + registryKey + "', key '" + key + "'; (and could not close handle " + handle + ": " + e2.getMessage() + ")", e);
064                                }
065                        }
066                        throw new IllegalArgumentException("Error reading registry key '" + registryKey + "', key '" + key + "'", e);
067                }
068                return vals;
069        }
070        
071        public static String getUserValue(String registryKey, String key) {
072                initialise();
073                
074                byte[] valb = null;
075                String vals = null;
076                Integer handle = -1;
077
078                // Query Internet Settings for Proxy
079                //key = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings#ProxyServer";
080                try {
081                        handle = (Integer) openKey.invoke(userRoot, toCstr(registryKey), KEY_READ,
082                                        KEY_READ);
083                        valb = (byte[]) winRegQueryValue.invoke(userRoot,
084                                        handle.intValue(), toCstr(key));
085                        vals = (valb != null ? new String(valb).trim() : null);
086                        closeKey.invoke(Preferences.userRoot(), handle);
087                } catch (Exception e) {
088                        if (handle!=-1) {
089                                try {
090                                        closeKey.invoke(Preferences.systemRoot(), handle);
091                                } catch (Exception e2) {
092                                        throw new IllegalArgumentException("Error reading registry '" + registryKey + "', key '" + key + "'; (and could not close handle " + handle + ": " + e2.getMessage() + ")", e);
093                                }
094                        }
095                        throw new IllegalArgumentException("Error reading registry key '" + registryKey + "', key '" + key + "'", e);
096                }
097                return vals;
098        }
099        
100        private static synchronized void initialise() {
101                if (initialisationState == 2) { 
102                        return; 
103                } else if (initialisationState == 1) {
104                        throw new IllegalStateException("Registry could not be initialised");
105                } else {
106                        try {
107                                openKey = clz.getDeclaredMethod("openKey", byte[].class, int.class, int.class);
108                                openKey.setAccessible(true);
109        
110                                closeKey = clz.getDeclaredMethod("closeKey", int.class);
111                                closeKey.setAccessible(true);
112        
113                                winRegQueryValue = clz.getDeclaredMethod("WindowsRegQueryValueEx", int.class, byte[].class);
114                                winRegQueryValue.setAccessible(true);
115                                winRegEnumValue = clz.getDeclaredMethod("WindowsRegEnumValue1", int.class, int.class, int.class);
116                                winRegEnumValue.setAccessible(true);
117                                winRegQueryInfo = clz.getDeclaredMethod("WindowsRegQueryInfoKey1", int.class);
118                                winRegQueryInfo.setAccessible(true);
119                        } catch (Exception e) {
120                                initialisationState = 1;
121                                throw new IllegalStateException("Cannot access registry", e);
122                        }
123                }
124        }
125        
126        
127        private static byte[] toCstr(String str) {
128                byte[] result = new byte[str.length() + 1];
129                for (int i = 0; i < str.length(); i++) {
130                        result[i] = (byte) str.charAt(i);
131                }
132                result[str.length()] = 0;
133                return result;
134        }
135}