Accessing the Windows registry through the preferences API

On Windows, the preferences API makes use of a DLL to access program-specific properties in the Windows Registry. The following example uses reflection to access private native methods in the preferences API and allows you to get REG_SZ values from the Windows Registry.

For example, to get the IE start page on my machine, I executed:

C:registrytest> c:jdk1.4binjava Main "HKEY_CURRENT_USER\Softw --
are\Microsoft\Internet Explorer\Main" "start page"

http://www.google.com/

It’s a demonstration and works only with JDK1.4. Use at your own risk.

Main.java:

import java.lang.reflect.*;
import java.util.prefs.*;
import java.util.*;
import java.io.*;
 
public class Main
{
   /* Windows security masks */
   private final static int KEY_QUERY_VALUE = 1;
 
   /* Constants used to interpret returns of native functions    */
   private final static int NATIVE_HANDLE = 0;
   private final static int ERROR_CODE = 1;
 
   /*  Windows error codes. */
   private final static int ERROR_SUCCESS = 0;
 
   public static void main(String[] args) {
      if (args.length != 2) {
         System.out.println("Usage: java Main path key");
         System.out.print("  eg.: java Main "HKEY_CURRENT_USER\");
         System.out.print("\Software\\Microsoft\\Internet Explorer\\Main"");
         System.out.println(" "start page"");
         System.exit(1);
      }
 
      try {
         int hkey = getHKEY(args[0]);
         byte[] WINDOWS_ROOT_PATH = stripHKEY(args[0]);
         String key = args[1];
         System.out.println(getValue(hkey, WINDOWS_ROOT_PATH, key));
      }
      catch(Exception e) {
         System.out.println(e.getMessage());
      }
   }
 
   public static int getHKEY(String path) throws Exception {
      if (path.startsWith("HKEY_CURRENT_USER")) {
         return 0x80000001;
      }
      else if (path.startsWith("HKEY_LOCAL_MACHINE")) {
         return 0x80000002;
      }
      else {
         throw new Exception("Path should start with HKEY_CURRENT_USER " + 
                                                 "or HKEY_LOCAL_MACHINE");
      }
   }
 
   public static byte[] stripHKEY(String path) {
      int beginIndex = path.indexOf("\\");
      return stringToByteArray(path.substring(beginIndex+2));
   }
 
   public static String getValue(int hkey, byte[] WINDOWS_ROOT_PATH, String key) 
                                             throws Exception {
      Class theClass = Class.forName("java.util.prefs.WindowsPreferences");
 
      int[] result = openKey1(hkey, windowsAbsolutePath(WINDOWS_ROOT_PATH),
                              KEY_QUERY_VALUE);
      if (result[ERROR_CODE] != ERROR_SUCCESS) {
         throw new Exception("Path not found!");
      }
      int nativeHandle = result[NATIVE_HANDLE];
 
      Method m = theClass.getDeclaredMethod("WindowsRegQueryValueEx",
                                            new Class[]{int.class, byte[].class});
      m.setAccessible(true);
      byte[] windowsName = toWindowsName(key);
      Object value = m.invoke(null, new Object[]{new Integer(nativeHandle), windowsName});
      WindowsRegCloseKey(nativeHandle);
      if (value == null) {
         throw new Exception("Path found.  Key not found.");
      }
 
      byte[] origBuffer = (byte[]) value;
      byte[] destBuffer = new byte[origBuffer.length - 1];
      System.arraycopy(origBuffer, 0, destBuffer, 0, origBuffer.length - 1);
 
      return new String(destBuffer);
   }
 
   public static int WindowsRegCloseKey(int nativeHandle) 
                                         throws Exception {
      Class theClass = Class.forName("java.util.prefs.WindowsPreferences");
      Method m = theClass.getDeclaredMethod("WindowsRegCloseKey", new Class[]{int.class});
      m.setAccessible(true);
      Object ret = m.invoke(null, new Object[]{new Integer(nativeHandle)});
      return ((Integer) ret).intValue();
   }
 
   public static int openKey(byte[] windowsAbsolutePath, int securityMask) 
                                         throws Exception {
      Class theClass = Class.forName("java.util.prefs.WindowsPreferences");
      Method m = theClass.getDeclaredMethod("openKey", new Class[]{byte[].class, int.class});
      m.setAccessible(true);
      Object ret = m.invoke(null, new Object[]{windowsAbsolutePath, new Integer(securityMask)});
      return ((Integer) ret).intValue();
   }
 
   public static int[] openKey1(int hkey, byte[] windowsAbsolutePath, int securityMask) 
                                         throws Exception {
      Class theClass = Class.forName("java.util.prefs.WindowsPreferences");
      Method m = theClass.getDeclaredMethod("WindowsRegOpenKey", new Class[]{int.class, 
                                                                             byte[].class, 
                                                                             int.class});
      m.setAccessible(true);
      Object ret = m.invoke(null, new Object[]{new Integer(hkey), 
                                               windowsAbsolutePath, 
                                               new Integer(securityMask)});
      return (int[]) ret;
   }
 
   private static byte[] stringToByteArray(String str) {
      byte[] result = new byte[str.length() + 1];
      for (int i = 0; i < str.length(); i++) {
         result[i] = (byte) str.charAt(i);
      }
      result[str.length()] = 0;
      return result;
   } 
 
   private static byte[] windowsAbsolutePath(byte[] WINDOWS_ROOT_PATH) {
      ByteArrayOutputStream bstream = new ByteArrayOutputStream();
      bstream.write(WINDOWS_ROOT_PATH, 0, WINDOWS_ROOT_PATH.length - 1);
      StringTokenizer tokenizer = new StringTokenizer(absolutePath(), "/");
      while (tokenizer.hasMoreTokens()) {
         bstream.write((byte) '\');
         String nextName = tokenizer.nextToken();
         byte[] windowsNextName = toWindowsName(nextName);
         bstream.write(windowsNextName, 0, windowsNextName.length - 1);
      }
      bstream.write(0);
      return bstream.toByteArray();
   }
 
   private static String absolutePath() {
      return "/";
   }
 
   private static byte[] toWindowsName(String javaName) {
      StringBuffer windowsName = new StringBuffer();
      for (int i = 0; i < javaName.length(); i++) {
         char ch = javaName.charAt(i);
         if ((ch < 0x0020) || (ch > 0x007f)) {
            throw new RuntimeException("Unable to convert to Windows name");
         }
         if (ch == '\') {
            windowsName.append("//");
         } else if (ch == '/') {
            windowsName.append('\');
         } else if ((ch >= 'A') && (ch <= 'Z')) {
            windowsName.append("/" + ch);
         } else {
            windowsName.append(ch);
         }
      }
      return stringToByteArray(windowsName.toString());
   }
 
   private static String toJavaValueString(byte[] windowsNameArray) {
      // Use modified native2ascii algorithm
      String windowsName = byteArrayToString(windowsNameArray);
      StringBuffer javaName = new StringBuffer();
      char ch;
      for (int i = 0; i < windowsName.length(); i++) {
         if ((ch = windowsName.charAt(i)) == '/') {
            char next = ' ';
 
            if (windowsName.length() > i + 1 &&
                  (next = windowsName.charAt(i + 1)) == 'u') {
               if (windowsName.length() < i + 6) {
                  break;
               } else {
                  ch = (char) Integer.parseInt
                        (windowsName.substring(i + 2, i + 6), 16);
                  i += 5;
               }
            } else
                  if ((windowsName.length() > i + 1) &&
                  ((windowsName.charAt(i + 1)) >= 'A') && (next <= 'Z')) {
               ch = next;
               i++;
            } else if ((windowsName.length() > i + 1) &&
                  (next == '/')) {
               ch = '\';
               i++;
            }
         } else if (ch == '\') {
            ch = '/';
         }
         javaName.append(ch);
      }
      return javaName.toString();
   }
 
   private static String byteArrayToString(byte[] array) {
      StringBuffer result = new StringBuffer();
      for (int i = 0; i < array.length - 1; i++) {
         result.append((char) array[i]);
      }
      return result.toString();
   }
}