views:

87

answers:

4

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?

+3  A: 

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...

Dean Harding
urgh! you mean munge all the registry paths and filesystem paths manually... I was really hoping there would be an API for this. For the registrys its fairly straightforward, but I'm pretty sure the SysWow64 directory does not necessarily have to live under the windows dir.
deltanine
@deltanine: I've modified my answer with a few possibilities...
Dean Harding
Thanks for the link, KEY_WOW64_32KEY will work from a 32 or 64 bit process, so that's half my problem solved. I don't think that Wow64EnableWow64FsRedirection will however...
deltanine
@deltanine: yeah, not sure about the filesystem one... the documentation doesn't appear to say.
Dean Harding
A: 

If you want to see the 32-bit registry you can use the KEY_WOW64_32KEY as described here

If you want to access the SysWOW64 directory you can use the GetSystemWow64Directory as described here

jcopenha
how about translating the path on a 64 bit machine so it points to the 32 bit files
deltanine
A: 

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();}
deltanine
A: 

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.

Damien_The_Unbeliever
I did think about that, as our application already does all sorts of COM nastiness with surrogate processes in order to host 32 bit COM objects in 64 bit processes and vice versa. But the only reason we did the 64 bit port was because customers demanded it- the application has no need for 64 bit support, actually. And even tho that C++ code to remap the paths is ugly, its less ugly than going down the COM surrogate route
deltanine