Nov 13, 2016

on Leave a Comment

Access Windows Registry using Java JNA Advapi32 API -- 32-bit and 64-bit Complication


Finally there has a standard and free package to use Java for manipulating Windows registry (read, write, delete).  The Java Native Access (jna) is an once-and-for-all package for accessing OS-specific functionalities that is proven to work.  However, there's a twist for 32-bit and 64-bit Windows.


The story began that I tried to rewrite the Windows Registry part in the my FNDLOADER program. In the last 10+ years, I used these methods for this purpose:



JWinAPI
Probably you can Google it and still able to download it, you need a Jar file (jwinapi.jar) and dll file (JWinAPI.dll) to make it works.  The code is pretty straight forward.  However I dropped this because of Windows 32-bit / 64-bit issue.


import com.JWinAPI.JWinAPI;
import com.JWinAPI.REGConstants;

JWinAPI api = new JWinAPI();
api.doWriteToRegistry(REGConstants.HKEY_LOCAL_MACHINE,
  "SOFTWARE\\MySoftware","UserName", REGConstants.REG_SZ, "Lady Gaga");
String regValue = api.doReadRegistryValueAsString(REGConstants.HKEY_LOCAL_MACHINE,
  "SOFTWARE\\ORACLE\\MySoftware, "UserName", REGConstants.REG_SZ);

Java Preferences API
Basically this is Java's own API comes with JRE itself.  Don't forget that JRE needs to store numerous settings in Windows Registry under HKEA\SOFTWARE\JavaSoft, and there must be some ways that JRE is able to manipulate Windows Registry.  This is java.util.prefs.Preferences package that do this work.  A guy posted a complete set of code for this:

I used to take this API, but not very confident with that since Sun don't encourage people to use. Later I found out JNA, a public free package for this purpose.  Finally this is the one I need.

Java Native Access
The API is pretty well-documented and for Windows Registry the Advapi32Util class is simple and straightforward. However the mixing of 32-bit / 64-bit JRE and Windows OS make thing complicated. 
For example – create registry HKEA\SOFTWARE\MySoftware, String "UserName" with value "Lady Gaga".  This key is used by a 32-bit application.

import com.sun.jna.platform.win32.WinReg;
WinReg.HKEY HKEA = WinReg.HKEY_LOCAL_MACHINE;
String      key = "SOFTWARE\MySoftware";
Advapi32Util.registryCreateKey(HKEA, key);
Advapi32Util.registrySetStringValue(HKEA, key, "UserName", "Lady Gaga");

(CASE 1 – Win 32 + JRE 32)
Under Windows 32-bit environment (obviously the JRE is 32-bit), it will create key likes

(CASE 2 – Win 64 + JREs 32)
If it runs under Windows 64-bit environment with 32-bit JRE, it will create key like

Yes, the key created is "HKEA\SOFTWARE\Wow6432Node\MySoftware", even you do not specify the "Wow6432Node" path in the Registry Key.  Why? It's because 32bit JRE should access Wow6432Node under 64-bit Windows.

(CASE 3 – Win 64 + JRE 64)
If it runs under Window 64-bit environment with 64-bit JRE, it will create key same as in CASE 1.  It's because for 64-bit Windows, the HKEA\SOFTWARE registry is for 64-bit applications, as the JRE is 64-bit.

So the conclusion is that:
32-bit JRE in 32-bit Windows accesses the standard registry.
64-bit JRE in 32-bit Windows – does not work at all
32-bit JRE in 64-bit Windows accesses the "Wow6432Node" part of registry
64-bit JRE in 64-bit Windows accesses the "64-bit" registry, which is the standards place.

(CASE 4 – Win 64 + JRE 64, create Wow6432Node registry)
For this case, you need to explicitly set the registry path "HKEA\SOFTWARE\Wow6432Node\MySoftware" in the API call.

(CASE 5 – Win 64 + JRE 32, create standard registry, i.e. for 64-bit application)
Using Advapi32Util class is not able to achieve this. You need to use Advapi32.INSTANCE API, a more native API call directly mapped to corresponding Advapi32.dll.

How to find out it's 32bit or 64bit JRE and Windows
For JRE, you can use System.getProperty("os.arch").  Yes, this is misleading, but it's correct property to look for.
Possible values: x86 and amd64

For Windows, system variables PROCESSOR_ARCHITECTURE and PROCESSOR_ARCHITEW6432 can be used to determine you're using 32- or 64-bit Windows.

String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432");
String arch = System.getenv("PROCESSOR_ARCHITECTURE");          
String realArch = arch.endsWith("64") || wow64Arch != null && wow64Arch.endsWith("64") ? "64" : "32";   

0 comments: