Get file path from NT/Device Name - windows

I want to convert device path to a file path.
I want to get process name by process id, so I am using this code
PsLookupProcessByProcessId(processId,&pEProcess);
ObOpenObjectByPointer(pEProcess,
OBJ_KERNEL_HANDLE,
NULL,
0,
NULL,
KernelMode,
&hProcess);
ObDereferenceObject (pEProcess);
nts = ZwQueryInformationProcess (hProcess,27,0,0,&ulSize);
But it gives path as \Device\hardDiskVolume1\windows\system32\taskmgr.exe
But I want this as a plain filename C:\windows\system32\taskmgr.exe

There's an article in Dr. Dobb's (NT Handle-to-Path Conversion by Jim Conyngham) that describes a way of getting from a handle to DOS path name: See the listing of GetFileNameFromHandleNT().
In your case, since you already have the device path, you don't need the initial parts of that code that does the handle-to-memory-map-to-get-device-path work.

// From device file name to DOS filename
BOOL GetFsFileName( LPCTSTR lpDeviceFileName, CString& fsFileName )
{
BOOL rc = FALSE;
TCHAR lpDeviceName[0x1000];
TCHAR lpDrive[3] = _T("A:");
// Iterating through the drive letters
for ( TCHAR actDrive = _T('A'); actDrive <= _T('Z'); actDrive++ )
{
lpDrive[0] = actDrive;
// Query the device for the drive letter
if ( QueryDosDevice( lpDrive, lpDeviceName, 0x1000 ) != 0 )
{
// Network drive?
if ( _tcsnicmp( _T("\\Device\\LanmanRedirector\\"), lpDeviceName, 25 ) == 0 )
{
//Mapped network drive
char cDriveLetter;
DWORD dwParam;
TCHAR lpSharedName[0x1000];
if ( _stscanf( lpDeviceName,
_T("\\Device\\LanmanRedirector\\;%c:%d\\%s"),
&cDriveLetter,
&dwParam,
lpSharedName ) != 3 )
continue;
_tcscpy( lpDeviceName, _T("\\Device\\LanmanRedirector\\") );
_tcscat( lpDeviceName, lpSharedName );
}
// Is this the drive letter we are looking for?
if ( _tcsnicmp( lpDeviceName, lpDeviceFileName, _tcslen( lpDeviceName ) ) == 0 )
{
fsFileName = lpDrive;
fsFileName += (LPCTSTR)( lpDeviceFileName + _tcslen( lpDeviceName ) );
rc = TRUE;
break;
}
}
}
return rc;
}

Related

Where are positions of desktop shortcuts stored?

Where are the positions of Windows desktop shortcuts stored?
I am asking about the screen positions of the icons not the actual icons themselves. I know the icons themselves are stored in various DLLs, EXEs etc. The positions are clearly stored in some non-volatile store because they persists through re-boots.
My end goal is to write an app to display, and optionally re-arrange icons on my desktop.
I know this is possible because many available apps do this (e.g., "WinTidy").
I find much talk about "Windows Shell Bags". An interesting article about these are in http://williballethin.com.forensics/shellbags, but that only addresses directories not shortcuts. These are in the registry at various places including
`HKEY_CURRENT_USER/Software/Microsoft/Windows/Shell/Bags/1/Desktop`
`HKEY_USERS/.DEFAULT/Software/Microsoft/Windows/Shell/Bags/1/Desktop`
I wrote a program to extract these but the format of the key values is incomprehensible.
Any body know where and how they are stored?
UPDATE 6/3/20
++++++++++++++++++++++++++++++++++++++
I just switched over to a Win10 64-bit machine and find the solution below no longer works. I believe because of a change in the desktop internals. I figured out how to do this. See "WIN10 ADDENDUM" at the end of this answer.
++++++++++++++++++++++++++++++++++++++
I finally figured out how to do what I want (display and re-arrange desktop icons). My original question concerned locating, reading and writing to the file where the icon info is stored, but this is not a useful approach. Here is what I learned:
Explorer.exe displays desktop items in a giant ListView covering the whole desktop with ListView items corresponding to each visible icon. At startup, Explorer reads info from some arcane file and populates the ListView. On exit, it re-writes that file from the ListView. So modifying the file would not help because it would be overwritten on exit.
The right way to manipulate desktop items is to directly manipulate items in the ListView. Any changes are immediately visible on change, and are saved on exit. To access the items, we can use several Windows messages: LVM_GETITEM, LVM_GETITEMCOUNT, LVM_GETITEMPOSITION and LVM_SETITEMPOSITION. These messages are fairly simple to use with one complication: some require pointers to parameter structures. These structures must be in Explorer's address space not my app's, so some trickery is needed. Here's how to do it. I use LVM_GETITEMPOSITION as an example, which requires a pointer to a POINT structure.
Declare a POINT structure in your app.
Allocate a mirror structure in Explorer's address space using API VirtualAllocEx().
Send LVM_GETITEMPOSITION to Explorer specifying a pointer to this structure.
Read back the result into your app's POINT using API ReadProcessMemory(). This function can read memory across different address spaces.
I have prototyped these operations and they work as I wanted. My code is quite long but I will post excerpts as soon as I clean it up.
UPDATE 10/4/2019 ------------------------------------
CODE EXCERPTS
A set of commonly used utility functions was created to make code more compact and readable. These are named "exp*()" and are included at the end. A reference can be found at http://ramrodtechnology.com/explorer. Much of the basic technique herein was shamelessly stolen from https://www.codeproject.com/Articles/5570/Stealing-Program-s-Memory
Setup
// COMMONLY USED VARS
HANDLE hProcess; // explorer process handle
HWND hWndLV; // explorer main window
// SET UP CONVENIENCE VARS
hProcess = expGetProcessHandle(); // get explorer process handle
if( !hProcess ) exit( 1 );
hWndLV = expGetListView(); // get main ListView of Desktop
if( !hWndLV ) exit( 1 );
Function to Print All Item Names
//# Process a list view window and print item names
int
printAllNames()
{
int ok,icount,indx;
LVITEM item; // point in app space
LVITEM *_pitem; // point in exp space
char text[512];
char *_ptext;
int nr,nwrite; // count of bytes read/written
printf( "\n" );
// ALLOC ITEMS IN EXP SPACE
_pitem = expAlloc( sizeof(LVITEM) );
_ptext = expAlloc( sizeof(text ) );
printf( " NAME\n" );
printf( " ==================================\n" );
icount = expGetItemCount();
for( indx=0; indx<icount; indx++ ) { // for each item in LV
// SETUP ITEM IN EXP SPACE
memset( &item, 0, sizeof(LVITEM) ); // preclear
item.iItem = indx; // index of item to read
item.iSubItem = 0; // sub index (always 0)
item.mask = LVIF_TEXT; // component to read
item.pszText = _ptext; // buffer to recv text
item.cchTextMax = sizeof(text); // size of buffer
// WRITE ITEM REQ TO EXP SPACE
ok = WriteProcessMemory( hProcess, _pitem, &item, sizeof(LVITEM), &nwrite );
// SEND MESSAGE TO GET ITEM INTO EXP SPACE
ok = SendMessage( hWndLV, LVM_GETITEM, indx, (LPARAM)_pitem );
// READ EXP TEXT INTO APP SPACE
memset( &item, 0, sizeof(LVITEM) );
ok = ReadProcessMemory( hProcess, _pitem, &item, sizeof(POINT), &nr );
ok = ReadProcessMemory( hProcess, _ptext, &text, sizeof(text), &nr );
// PRINT RESULT
printf( " %s\n", text );
}
ok = expFree( _pitem );
ok = expFree( _ptext );
return( TRUE );
//r Returns TRUE on success, FALSE on error
}
Function To Print All Item Positions
//# Process a list view window and print position
int
printAllPositions()
{
int ok,icount,indx,nr;
POINT pt; // point in app space
POINT *_ppt; // point in exp space
icount = expGetItemCount();
_ppt = expAlloc( sizeof(POINT) );
if( !_ppt ) return( FALSE );
printf( " X Y\n" );
printf( "---- ----\n" );
for( indx=0; indx<icount; indx++ ) { // for each item in LV
ok = SendMessage( hWndLV, LVM_GETITEMPOSITION, indx, (LPARAM)_ppt );
ok = ReadProcessMemory( hProcess, _ppt, &pt, sizeof(POINT), &nr );
printf( "%4d %4d\n", pt.x, pt.y );
}
ok = expFree( _ppt );
return( TRUE );
//r Returns TRUE on success
}
Function To Move Item
See 'expSetItemPosition' below. UPDATED 10/6/19
Explorer Utility Functions
// EXPLORER UTILITY FUNCTIONS
//# Allocate a block of memory in explorer space
void *
expAlloc(
int size) // size of block
{
void *p;
p = VirtualAllocEx(
hProcess,
NULL,
size,
MEM_COMMIT,
PAGE_READWRITE );
return( p );
//r Returns addr of memory in EXPLORER space or NULL on error
}
//# Free virtual memory in EXPLORER space
int
expFree(
void *p) // pointer to free
{
int ok;
ok = VirtualFreeEx( hProcess, p, 0, MEM_RELEASE );
return( ok );
//r Returns TRUE on success, else FALSE
}
static int aBiggest; // biggest area so far
static HWND hWndBiggest; // hWnd with biggest area
//# Find main list view of explorer
HWND
expGetListView()
{
//n Approach: Enumerate all child windows of desktop and find largest.
//n This will be the main explorer window.
HWND hWndDesktop;
hWndDesktop = GetDesktopWindow();
if( !hWndDesktop ) return( NULL );
aBiggest = -1; // init
hWndBiggest = NULL; // init
EnumChildWindows( hWndDesktop, CallbackDesktopChild, 0 );
return( hWndBiggest );
//r Returns hWnd of largest explorer list view
}
//# Callback for EnumChildWindows
BOOL CALLBACK CallbackDesktopChild(
HWND hWnd,
LPARAM dwUser)
{
//n Get size of child. If biggest, save hWnd.
int i,w,h,a;
char classname[MAXPATH+1];
RECT rect;
i = GetClassName( hWnd, classname, MAXPATH ); // get class
if( stricmp( classname, "SysListView32" ) ) { // not a list view?
return( TRUE ); // skip it
}
// CALC SIZE
i = GetWindowRect( hWnd, &rect );
w = rect.right - rect.left;
h = rect.bottom - rect.top;
// CHECK IF BIGGEST
a = w * h;
if( a > aBiggest ) { // is biggest?
aBiggest = a;
hWndBiggest = hWnd;
}
return( TRUE ); // TRUE to continue enumeration
}
//# Get process handle of explorer.exe
HANDLE
expGetProcessHandle()
{
//n Approach: take process snapshot and loop through to find "explorer.exe"
//n Needs tlhelp32.h and comctl32.lib
int i,stat;
PROCESSENTRY32 pe;
HANDLE hSnapshot;
char *name;
HANDLE h;
// TAKE A SNAPSHOT
hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( !hSnapshot ) return( NULL );
// LOOP THROUGH PROCESSES AND FIND "explorer.exe"
for( i=0;;i++ ) {
pe.dwSize = sizeof( PROCESSENTRY32 );
if( i == 0 ) stat = Process32First( hSnapshot, &pe );
else stat = Process32Next ( hSnapshot, &pe );
if( !stat ) break; // done or error?
name = pe.szExeFile;
if( !stricmp( name, "explorer.exe" ) ) { // matches?
h = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID );
return( h );
}
}
return( NULL );
//r Returns explorer process handle or NULL on error
}
//# Get count of items in explorer list view
int
expGetItemCount()
{
int count;
count = SendMessage( hWndLV, LVM_GETITEMCOUNT, 0, 0 );
return( count );
//r Returns count of item
}
//# Get position of list view icon by index
int
expGetItemPosition(
int indx, // index of item
int *x, // ptr to int to recv x
int *y) // ptr to int to recv y
{
int i,ok,icount;
char classname[MAXPATH+1];
POINT pt; // point in app space
POINT *_ppt; // point in exp space
int nr; // count of bytes read
//int w,h;
i = GetClassName( hWndLV, classname, MAXPATH );
// GET COUNT OF ITEMS IN LIST VIEW
icount = expGetItemCount();
if( indx < 0 || indx >= icount ) return( FALSE );
// ALLOC POINT IN EXP SPACE
_ppt = expAlloc( sizeof(POINT) );
if( !_ppt ) return( FALSE );
// SEND MESSAGE TO GET POS INTO EXP SPACE POINT
ok = SendMessage( hWndLV, LVM_GETITEMPOSITION, indx, (LPARAM)_ppt );
if( !ok ) return( FALSE );
// READ EXP SPACE POINT INTO APP SPACE POINT
ok = ReadProcessMemory( hProcess, _ppt, &pt, sizeof(POINT), &nr );
if( !ok ) return( FALSE );
ok = expFree( _ppt );
if( !ok ) return( FALSE );
if( x ) *x = pt.x;
if( y ) *y = pt.y;
//r Returns TRUE on success
return( TRUE );
}
//# Move item
int
expSetItemPosition(
char *name, // icon name
int x, // new x coord
int y) // new y coord
{
int ok,indx;
LPARAM lParam;
indx = expGetItemIndex( name );
if( indx < 0 ) return( FALSE );
lParam = MAKELPARAM( x, y );
ok = SendMessage( hWndLV, LVM_SETITEMPOSITION, indx, lParam );
if( !ok ) return( FALSE );
return( TRUE );
//r Returns TRUE on success
}
WIN10 ADDENDUM
6/19/20
++++++++++++++++++++++++++++++++++
Under Win10, the solution is much more complicated. You must use various COM objects and interfaces, e.g. IShellWindows, etc. (God, I hate COM). I did not create a library but rather offer a complete working program below. I compiled this using MSVC 2019. Error checking has been omitted for clarity (but you should do it).
// icons.cpp - Display (and optionally move) desktop icons
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <ShlObj.h>
#include <atlbase.h>
int
main(int argc,char** argv)
{
CComPtr<IShellWindows> spShellWindows;
CComPtr<IShellBrowser> spBrowser;
CComPtr<IDispatch> spDispatch;
CComPtr<IShellView> spShellView;
CComPtr<IFolderView> spView;
CComPtr<IShellFolder> spFolder;
CComPtr<IEnumIDList> spEnum;
CComHeapPtr<ITEMID_CHILD> spidl;
CComVariant vtLoc(CLSID_ShellWindows);
CComVariant vtEmpty;
STRRET str;
int count=0;
HRESULT hr;
long lhWnd;
// INITIALIZE COM
CoInitialize(NULL);
// GET ShellWindows INTERFACE
hr = spShellWindows.CoCreateInstance(CLSID_ShellWindows);
// FIND WINDOW
hr = spShellWindows->FindWindowSW(
&vtLoc, &vtEmpty, SWC_DESKTOP, &lhWnd, SWFO_NEEDDISPATCH, &spDispatch);
// GET DISPATCH INTERFACE
CComQIPtr<IServiceProvider>(spDispatch)->
QueryService(SID_STopLevelBrowser, IID_PPV_ARGS(&spBrowser));
spBrowser->QueryActiveShellView(&spShellView);
spShellView->QueryInterface(IID_PPV_ARGS(&spView) );
hr = spView->GetFolder(IID_PPV_ARGS(&spFolder));
// GET ENUMERATOR
spView->Items(SVGIO_ALLVIEW, IID_PPV_ARGS(&spEnum)); // get enumerator
// ENUMERATE ALL DESKTOP ITEMS
for (; spEnum->Next(1, &spidl, nullptr) == S_OK; spidl.Free()) {
// GET/PRINT ICON NAME AND POSITION
char* name;
POINT pt;
spFolder->GetDisplayNameOf(spidl, SHGDN_NORMAL, &str);
StrRetToStr(&str, spidl, &name);
spView->GetItemPosition(spidl, &pt);
printf("%5d %5d \"%s\"\n", pt.x, pt.y, name);
#define MOVE_ICON
#ifdef MOVE_ICON
// OPTIONAL: MOVE *SINGLE* SELECTED ITEM
{
if( !_stricmp(name, "ICON_NAME_TO_MOVE") ) {
PCITEMID_CHILD apidl[1] = { spidl };
int numitems = 1;
// SET pt TO NEW POSITION HERE
hr = spView->SelectAndPositionItems(numitems, apidl, &pt, 0);
}
}
#endif
count++;
}
CoUninitialize(); // release COM
fprintf(stderr, "enumerated %d desktop icons\n", count);
fprintf(stderr, "Press any key to exit...\n");
_getch();
exit(0 );
}

Windows NamedPipe on 2012 limits the data read to 64k

I have 2 process communicating via named pipes using overlapped i/o . On Window 2012 r2 it has been observed that the the data read at the reading end of the file is limited to 64k. If the client process runs on a Windows 7 64 bit, client is able to get the data even if more than 64k.
while( TRUE )
{
// Read from the pipe.
BOOL fSuccess ;
DWORD cbRead ;
OVERLAPPED osRx ;
memset( &osRx, 0, sizeof( osRx ) ) ;
osRx.hEvent = m_hRxEvent ;
// create a new message object
m_pMsg = new CInMsg( 64*1024 ) ; // This is the message size and can be changed via registry
fSuccess = ReadFile(
m_hPipe, // pipe handle
m_pMsg->GetDataPtr(), // buffer to receive reply
m_pMsg->GetBuffLength(), // size of buffer
&cbRead, // number of bytes read
&osRx // overlapped
);
if(!fSuccess)
{
dwError = GetLastError() ;
if( ERROR_IO_PENDING == dwError )
{
fSuccess = GetOverlappedResult(
m_hPipe, // handle to pipe
&osRx, // OVERLAPPED structure
&cbRead, // bytes transferred
INFINITE // wait
) ;
if(!fSuccess)
{
dwError = GetLastError() ;
}
}
}
if( !fSuccess )
{
while( ERROR_MORE_DATA == dwError )
{
DWORD dwBytesLeft ;
// find out how much left
PeekNamedPipe(
m_hPipe,
NULL,
0,
NULL,
NULL,
&dwBytesLeft
) ;
if( 0 == dwBytesLeft )
{
// break out as no data left
fSuccess = TRUE ;
break ;
}
// Use the dwBytesLeft and create a new CInMsg (pTempTmsMsg)
// Copy data from old to new Object
//delete old message
OVERLAPPED osTmpRx ;
memset( &osTmpRx, 0, sizeof( osTmpRx ) ) ;
osTmpRx.hEvent = m_hRxEvent ;
DWORD cbTmpRead ;
// now do another read
dwError = NO_ERROR ;
fSuccess = ReadFile(
m_hPipe,
m_pMsg->GetAppendBuffer(),
m_pMsg->GetAppendLength(),
&cbTmpRead,
&osTmpRx
);
if(!fSuccess)
{
dwError = GetLastError() ;
if( ERROR_IO_PENDING == dwError )
{
fSuccess = GetOverlappedResult(
m_hPipe,
&osTmpRx,
&cbTmpRead,
INFINITE
) ;
if(!fSuccess)
{
dwError = GetLastError() ;
}
}
}
m_pMsg->SetMsgLength( m_pMsg->GetMsgLength() + cbTmpRead ) ;
// set message size
cbRead += cbTmpRead ;
}
}
This is the main loop of the client.
The Pipe is created in Message Mode and the overlapped flag is also setup.
The applications are compiled using Visual Studio 2008 and both processes are 32 bit.
Is there any limits that needs to be set up from Windows Server 2012 r2?Same behaviour is observed on Win Server 2016.
Thanks

Checking the environment variable without using GetLastError() == ERROR_ENVVAR_NOT_FOUND in VC++

Here is my code
#include<iostream>
#include<Windows.h>
using namespace std;
#define BUFSIZE 4602
#define VARNAME TEXT("zzz")
int main()
{
TCHAR chNewEnv[BUFSIZE];
GetEnvironmentVariable(VARNAME, chNewEnv, BUFSIZE);
if(GetLastError()==ERROR_ENVVAR_NOT_FOUND)
{
cout<<"Hello";
}
else
{
cout<<"Bye";
}
return 0;
}
I am checking whether zzz environment variable is available or not. I need to do the same without using if(GetLastError()==ERROR_ENVVAR_NOT_FOUND). Is there any way?
I am doing the same program using C# in which I don't use GetLastError(). I need to make these two programs similar that is why I am asking without the use of GetLastError(). Here is my C# snippet
string abc =Environment.GetEnvironmentVariable("zzz");
if (abc == null || abc.ToUpper() == "NULL" || abc.ToUpper() == "NUL")
You have to use GetLastError, as you may encounter cases where a variable is defined with no value.
Such cases can be emulated with:
SetEnvironmentVariable( "foo", "" );
When GetEnvironmentVariable return 0, it may be that the variable doesn't exist, or that is exists with an empty content. In the later case, GetLastError returns 0.
If you don't care (that is: a nonexistent variable or an empty one is the same for you), then don't bother with GetLastError.
Side note. You should always make a first call with a NULL nSize argument, as the documentation states:
If lpBuffer is not large enough to hold the data, the return value is
the buffer size, in characters, required to hold the string and its
terminating null character and the contents of lpBuffer are undefined.
And, I just tested (Windows 7), in such case GetLastError returns 0 (awkward, if you ask me)
Edit: On Windows 7, when I set an user variable to "null", the value retrieved by GetEnvironmentVariable (MBCS) is a 5 bytes string 'n', 'u', 'l', 'l', '\0'
Code (UNICODE build):
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <Windows.h>
#define BUFSIZE 4602
#define VARNAME L"zzz"
const wchar_t * MyGetEnv( const wchar_t * pszVarName, wchar_t * pszVarValue,
size_t cbValue ) {
DWORD dwCopied = GetEnvironmentVariable( pszVarName, pszVarValue, cbValue );
// The line bellow MAY BE COMMENTED OUT IF YOU REALLY
// DON'T LIKE GETLASTERROR, AS cbCopied WILL BE ZERO FOR
// NON-EXISTENT VARIABLE
if ( GetLastError() != NO_ERROR ) return NULL; // doesn't exist, or error
if ( dwCopied == 0 ) return NULL; // var is empty
return pszVarValue;
}
int main() {
wchar_t szVarValue[ BUFSIZE ];
const wchar_t * pszVarValue = MyGetEnv( VARNAME, szVarValue,
_countof( szVarValue ) );
if ( pszVarValue == NULL ) {
printf( "No variable or empty value\n" );
} else if ( ( _wcsicmp( pszVarValue, L"null" ) == 0 ) ||
( _wcsicmp( pszVarValue, L"nul" ) == 0 ) ) {
printf( "Special 'null' or 'nul' value\n" );
} else {
wprintf( L"Value is %s\n", szVarValue );
}
return 0;
}

GetFileAttributes on (locked) system file

Calling GetFileAttributes for a file such as C:/pagefile.sys returns INVALID_FILE_ATTRIBUTES, and GetLastError returns ERROR_SHARING_VIOLATION. Yet it should definitely be possible to retrieve information about system files - e.g. being able to tell if it is a file or a directory. Is there a workaround?
Using FindFirstFile you can get information of pagefile.sys file. You can get the file's other information from ffd.
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile( "C:\\pagefile.sys", &ffd );
if ( INVALID_HANDLE_VALUE == hFind )
{
return 0;
}
if ( !( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
{
_int64 filesize = ffd.nFileSizeHigh;
filesize <<= 32;
filesize |= ffd.nFileSizeLow;
printf( "%s is %I64u bytes", ffd.cFileName, filesize );
}
FindClose( hFind );

How can a 64-bit process have a 32-bit view of file system and registry?

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?
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...
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();}
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
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.

Resources