How can a 64-bit process have a 32-bit view of file system and registry?
Question
For backwards compatibility, my 64 process needs to see the the 32-bit view of the file system and registry.
I know how to make a 32-bit process see a 64-bit view of the file system and registry (using Wow64DisableWow64FsRedirection and Wow64RevertWow64FsRedirection)
But how do I make a 64 bit process have a 32 bit view of the file system and registry?
Solution 4
KEY_WOW64_32KEY works for 64 bit and 32 bit processes.
From experiment, Wow64EnableWow64FsRedirection/Wow64DisableWow64FsRedirection doesn't seem to work in a 64 bit process - and the name suggests it only seems to work in an WOW64 process.
So in order to have a 32 bit "view" of the file system from a 64 bit process the paths will need to be be altered to point to the correct locations
This is really ugly, but here is a c++ code sample of how to perform the file system redirection according to Microsoft. Requires Boost.
#include"boost/filesystem.hpp"
#include"wstring"
#include"shfolder.h"
#include"Shlobj.h"
bool redirectPathRoot( boost::filesystem::wpath pathFromRoot, boost::filesystem::wpath pathToRoot, boost::filesystem::wpath & pathToRedirect )
{
bool bPathWasRedirected = false;
boost::filesystem::wpath theNewPath;
boost::filesystem::wpath::iterator iPathToRedirect = pathToRedirect.begin();
boost::filesystem::wpath::iterator iFromRoot = pathFromRoot.begin();
bool bMatch = true;
while( iPathToRedirect != pathToRedirect.end() && iFromRoot != pathFromRoot.end() && bMatch )
{
//
// see if the root of the path we are checking matches
//
bMatch = ( std::wstring(*iPathToRedirect++) == std::wstring(*iFromRoot++) );
}
if( bMatch && iFromRoot == pathFromRoot.end() )
{
theNewPath = pathToRoot;
//
// these guys need to be redirected
//
while( iPathToRedirect != pathToRedirect.end() )
{
theNewPath /= *iPathToRedirect++;
}
bPathWasRedirected = true;
pathToRedirect = theNewPath;
}
return bPathWasRedirected;
}
std::wstring adjustPathFor32BitOn64BitProcess( LPCWSTR thePath )
{
std::wstring strPath(thePath);
boost::to_lower(strPath);
//
// default to the original path
//
boost::filesystem::wpath theNewPath(strPath.c_str());
theNewPath.normalize();
//
// init the supplied path
//
boost::filesystem::wpath pathToCheck( strPath.c_str() );
pathToCheck.normalize();
//
// get the path for the 32 bit folder on a 64 bit system
//
wchar_t strTemp[MAX_PATH] = L"\0";
GetSystemWow64Directory( strTemp, MAX_PATH );
std::wstring strSysWow64 = strTemp;
boost::to_lower( strSysWow64 );
boost::filesystem::wpath pathSysWow64( strSysWow64.c_str() );
pathSysWow64.normalize();
//
// get the path for the system directory
//
GetSystemDirectory( strTemp, MAX_PATH );
std::wstring strSys = strTemp;
boost::to_lower( strSys );
boost::filesystem::wpath pathSys( strSys.c_str() );
pathSys.normalize();
//
// get the path for the Program Files directory
//
SHGetFolderPath( NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_DEFAULT, strTemp);
std::wstring strPrograms = strTemp;
boost::to_lower( strPrograms );
boost::filesystem::wpath pathPrograms( strPrograms.c_str() );
pathPrograms.normalize();
//
// get the path for the Program Files x86 directory
//
SHGetFolderPath( NULL, CSIDL_PROGRAM_FILESX86, NULL, SHGFP_TYPE_DEFAULT, strTemp);
std::wstring strProgramsX86 = strTemp;
boost::to_lower( strProgramsX86 );
boost::filesystem::wpath pathProgramsX86( strProgramsX86.c_str() );
pathProgramsX86.normalize();
//
// get the path for the Windows\lastgood\system32 directory
//
SHGetFolderPath( NULL, CSIDL_WINDOWS, NULL, SHGFP_TYPE_DEFAULT, strTemp);
std::wstring strWindows = strTemp;
boost::to_lower( strWindows );
boost::filesystem::wpath pathWindows( strWindows.c_str() );
pathWindows.normalize();
boost::filesystem::wpath pathWindowsLastGoodSystem32( strWindows.c_str() );
pathWindowsLastGoodSystem32 /= L"lastgood";
pathWindowsLastGoodSystem32 /= L"system32";
pathWindowsLastGoodSystem32.normalize();
boost::filesystem::wpath pathWindowsLastGoodSysWOW64( strWindows.c_str() );
pathWindowsLastGoodSysWOW64 /= L"lastgood";
pathWindowsLastGoodSysWOW64 /= L"syswow64";
pathWindowsLastGoodSysWOW64.normalize();
//
// finally, regedit...
//
boost::filesystem::wpath pathRegedit( strWindows.c_str() );
pathRegedit /= L"regedit.exe";
pathRegedit.normalize();
boost::filesystem::wpath pathRegeditSysWOW64( pathSysWow64 );
pathRegeditSysWOW64 /= L"regedit.exe";
pathRegeditSysWOW64.normalize();
//
// now see if the supplied path matches system directoy
//
boost::filesystem::wpath::iterator iPathToCheck = pathToCheck.begin();
boost::filesystem::wpath::iterator iSys = pathSys.begin();
bool bMatch = true;
while( iPathToCheck != pathToCheck.end() && iSys != pathSys.end() && bMatch )
{
//
// see if the beginning of the path we are checking matches the system path
//
bMatch = ( std::wstring(*iPathToCheck++) == std::wstring(*iSys++) );
}
if( bMatch && iSys == pathSys.end() )
{
//
// the supplied path matches at least as far as the system dir...
//
if( iPathToCheck == pathToCheck.end() )
{
//
// ...actually its an exact match, so redirect it
//
theNewPath = pathSysWow64;
}
else
{
//
// ...however, there are a few exceptions....
//
boost::filesystem::wpath::iterator iTemp = iPathToCheck;
if(
!(
std::wstring(*iTemp) == L"drivers" &&
(
(++iTemp) != pathToCheck.end() &&
std::wstring(*(iTemp)) == L"etc"
)
)
&&
(std::wstring(*iPathToCheck) != L"catroot") &&
(std::wstring(*iPathToCheck) != L"catroot2") &&
(std::wstring(*iPathToCheck) != L"logfiles") &&
(std::wstring(*iPathToCheck) != L"spool")
)
{
//
// all but the above dirs should be redirected
//
theNewPath = pathSysWow64;
while( iPathToCheck != pathToCheck.end() )
{
theNewPath /= *iPathToCheck++;
}
}
}
}
else
{
//
// didn't match the system dir... see if it matches the Program Files dir
//
if(!redirectPathRoot( pathPrograms, pathProgramsX86, theNewPath ))
{
//
// now try %windir%/lastgood/system32
//
if(!redirectPathRoot( pathWindowsLastGoodSystem32, pathWindowsLastGoodSysWOW64, theNewPath ))
{
//
// finally, regedit
//
redirectPathRoot( pathRegedit, pathRegeditSysWOW64, theNewPath );
}
}
}
return theNewPath.file_string();}
OTHER TIPS
You need to explicitly look in the "WOW64" keys/directories. There is actually no "64-bit" registry, there's just "the registry" and the Wow64 redirection stuff simply redirects a 32-bit process to a different subkey. So when a 32-bit process asks for "HKLM\Software\foo" the registry API actually says, "hang on, you're 32-bit so I'm going to pretend you asked for 'HKLM\Software\Wow6432Node\foo' instead".
So with that in mind, there is no way to have a 64-bit process look in the "32-bit" registry, because there is no such thing as a "32-bit registry". Instead, you'll just have to do what the Wow64 redirection logic does automatically.
EDIT
For the registry, there's actually the KEY_WOW64_32KEY
key which you can specify in various method calls.
For the filesystem, you might be able to try Wow64EnableWow64FsRedirection, but I'm not sure whether it'll work or not...
Bit late to the party, but could you not create a small 32-bit process that does your 32-bit work? Then all of the built in goodness of WOW64 will work.
Not sure what your development language/runtime is like, so not able to offer further suggestions on what the inter-process communication would look like.