Saturday, May 31, 2008

Access Windows Registry using 'pure' Java

(rehash of my old post since all those wonderful blog post drafts I was planning to publish are unfortunately out-dated or irrelevant)

One can use the private code of Sun's Preferences API to access values of type REG_SZ in the Windows Registry. Stupid hack. Maybe I should make a library out of this. I have used this soooo many times.

The java.util.prefs.WindowsPreferences is the concrete implementation of AbstractPreferences in the Windows platform. This class provides methods like WindowsRegQueryValueEx, etc. Using Reflection, one can use the methods in this class to query string values under HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER


Given below is a code-snippet that demonstrates how to get the ProxyServer setting on Windows (this is what IE uses/sets) and the Internet Explorer version


import java.lang.reflect.Method;
import java.util.prefs.Preferences;

public class JavaRegistryHack {

private static final int HKEY_CURRENT_USER = 0x80000001;
private static final int KEY_QUERY_VALUE = 1;
private static final int KEY_SET_VALUE = 2;
private static final int KEY_READ = 0x20019;

public static void main(String args[]) {
final Preferences userRoot = Preferences.userRoot();
final Preferences systemRoot = Preferences.systemRoot();
final Class clz = userRoot.getClass();
try {
final Method openKey = clz.getDeclaredMethod("openKey",
byte[].class, int.class, int.class);
openKey.setAccessible(true);

final Method closeKey = clz.getDeclaredMethod("closeKey",
int.class);
closeKey.setAccessible(true);

final Method winRegQueryValue = clz.getDeclaredMethod(
"WindowsRegQueryValueEx", int.class, byte[].class);
winRegQueryValue.setAccessible(true);
final Method winRegEnumValue = clz.getDeclaredMethod(
"WindowsRegEnumValue1", int.class, int.class, int.class);
winRegEnumValue.setAccessible(true);
final Method winRegQueryInfo = clz.getDeclaredMethod(
"WindowsRegQueryInfoKey1", int.class);
winRegQueryInfo.setAccessible(true);


byte[] valb = null;
String vals = null;
String key = null;
Integer handle = -1;

//Query Internet Settings for Proxy
key = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
handle = (Integer) openKey.invoke(userRoot, toCstr(key), KEY_READ, KEY_READ);
valb = (byte[]) winRegQueryValue.invoke(userRoot, handle.intValue(),
toCstr("ProxyServer"));
vals = (valb != null ? new String(valb).trim() : null);
System.out.println("Proxy Server = " + vals);
closeKey.invoke(Preferences.userRoot(), handle);

// Query for IE version
key = "SOFTWARE\\Microsoft\\Internet Explorer";
handle = (Integer) openKey.invoke(systemRoot, toCstr(key), KEY_READ, KEY_READ);
valb = (byte[]) winRegQueryValue.invoke(systemRoot, handle, toCstr("Version"));
vals = (valb != null ? new String(valb).trim() : null);
System.out.println("Internet Explorer Version = " + vals);
closeKey.invoke(Preferences.systemRoot(), handle);

} catch (Exception e) {
e.printStackTrace();
}
}


private static byte[] toCstr(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;
}

13 comments:

Anonymous said...

Nice one

Borys said...

I've tried this method to read value from HKEY_LOCAL_MACHINE tree. To do that you need another method:
final Method openKey2 = clz.getDeclaredMethod("openKey", int.class, byte[].class, int.class, int.class);

and as first argument use:
final int HKEY_LOCAL_MACHINE = 0x80000002;

No problem reading Strings but I can't read DWORD values. Have you had any success with DWORDs?

Shashikanth said...

Hi , Very nice way to hack. I want to get the default mail client details from HKEYCLASSESROOT\mailto\shell\open\command, to invoke the mail client Kindly let me know if possible by mail , solution for above key

Anonymous said...

Is this code free to use in any app, does it require a credit?

<b>Tarun Ramakrishna Elankath</b> said...

No credits required at all.

Mail client are possbile. dword's was done once..will check up confirm.

I am just not a blog writer..too lazy to respond to even comments. :(

<b>Tarun Ramakrishna Elankath</b> said...

I'll post the snippets for the other requests tomorrow..

PLUS: If you are doing lost of win32 integration you should really look at jna.dev.java.net and com4j.dev.java.net. Those are the 'proper' solutions. This is just nothing but a stupid hack.

mathew said...

Hi tarun,
Good work here.

I have a question...

How can I get a list of subkeys under a key? For example in under HKLM\Software\JavaSoft, I would like to get the list of subkeys (Java Development Kit, Java Runtime Environment etc). Can
this be done using the library?
Thanks

Karandeep Malik said...

This wont work for dwords for sure This method works only for strings.

thE_29 said...

Hello!

Well my project (founded 30 november 2006) do the same like yours!

http://sourceforge.net/projects/java-registry/

Maybe next time search in sourceforge too, so you dont need to create a new solution for the same thing!

Best regards, Joerg

Anonymous said...

What is the way to load DWord Entrys?

Sunny. said...

Impressive digging. I knew that the preferences API peered to the registry on windows, but I wasn't aware that you could use that capability to get access to arbitrary keys.
I have looked at jna.dev.java.net and com4j.dev.java.net.
So Thanks.... keep the work!!
Registry Easy

TECO said...

Is that possible to read windows registry via html page (or via applet) using your code?

Tariq said...

Dear Friend, i have to get the installed path of OpenOffice from Windows registry on the run time. Can you plz help me out.My email id is tariq.javed@live.com.
Please help me, i couldn't understand that example code from ur bloget.

regards,
tariq from Sweden