Tuesday, October 25

Registry Redirection, for 32-bit application in 64-bit Windows OS

Some people might have noticed, and some might not:

In Microsoft's 64-bit operation system, there is one "C:\Program Files\" folder and one "C:\Program Files (x86)" folder. 32-bit applications are placed in the second one. The tricky thing is, when the 32-bit applications internally are trying to visit "C:\Program Files\" folder, they are being redirected to the "C:\Program Files (x86)" folder. This is call "WoW64 File System Redirection". When the 32-bit applications are trying to access Windows\System32\ folder, they are actually accessing Windows\SysWOW64\ folder.

Microsoft use this "WoW64" approach to keep 32-bit applications in the same boxes with 64-bit application, and let the 32-bit applications access 32-bit environment (DLLs), not messing around the 64-bit environment.

Take a wild guess, what is the meaning of "WoW64"?

For registry, we have the same story. For example, there are registry path KEY_LOCAL_MACHINE\SOFTWARE\Microsoft, and HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft. When you run "regedit" in your OS, of course it is 64-bit application, so you can see both paths. When requesting "HKLM\SOFTWARE\Microsoft", a 64-bit application will get the content of first path, but a 32-bit application will get the content of second path.

If a 32-bit application wants to get the content of the first path, in the source code, it will need to open the registry key with extra KEY_WOW64_64KEY option:
RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0, KEY_SET_VALUE|KEY_WOW64_64KEY, &hKey);

Note: Visual Studio, by default, is creating 32-bit applications, even when it is running in 64-bit operating system.

Yesterday I was too lazy to use "RegOpenKeyEx". I just want to call the external regedit.exe to import an existing Ben.reg file, as part of the configuration stage. The registry keys should be in KEY_LOCAL_MACHINE\SOFTWARE\Ben folder. I ran "regedit /s Ben.reg" a thousand times and the content is imported successfully. But when the same command line is called from my application, it reports "imported successfully" but the keys are not in the KEY_LOCAL_MACHINE\SOFTWARE\Ben folder. Of course now you know the keys are in KEY_LOCAL_MACHINE\SOFTWARE\WoW64\Ben folder, since the Visual Studio generated application is a 32-bit application.

After googling thousands of webpages, I found one working solution from Greg Domjan:

Add a class:
class Wow64RedirectOff {
typedef BOOL (WINAPI *FN_Wow64DisableWow64FsRedirection) ( __out PVOID *OldValue );
typedef BOOL (WINAPI *FN_Wow64RevertWow64FsRedirection) ( __in PVOID OldValue );

public:
Wow64RedirectOff() {
LPFN_Disable = (FN_Wow64DisableWow64FsRedirection)GetProcAddress(
GetModuleHandle(TEXT("kernel32")),"Wow64DisableWow64FsRedirection");
if( LPFN_Disable ) {
LPFN_Disable(&OldValue);
}
}

~Wow64RedirectOff() {
if( LPFN_Disable ) {
FN_Wow64RevertWow64FsRedirection LPFN_Revert = (FN_Wow64RevertWow64FsRedirection)GetProcAddress(
GetModuleHandle(TEXT("kernel32")),"Wow64RevertWow64FsRedirection");
if( LPFN_Revert ) {
LPFN_Revert(OldValue);
}
}
}

private:
FN_Wow64DisableWow64FsRedirection LPFN_Disable;
PVOID OldValue;
};

Then in the program, you define Wow64RedirectOff scopedRedirect; before calling the external program "regedit". You can wrap these 2 actions into one bracket so that scopedRedirect is being destructed right after the external program is terminated, and the WoW Redirection is being restored to normal.

Labels: