Article ID: 125212
Article Last Modified on 3/7/2005
/*** Function Prototypes ****/ DWORD APIENTRY SynchSpawn( LPCSTR lpszCmdLine, UINT nCmdShow ); /*** Constants for Dispatcher ***/ #define SYNCHSPAWN 1
/*** Main application code ***/
#include <windows.h>
#include "spawn.h"
void main()
{
DWORD dwVersion;
STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
dwVersion = GetVersion();
if( !(dwVersion & 0x80000000) ) // Windows NT
{
si.cb = sizeof(STARTUPINFO);
si.lpReserved = NULL;
si.lpReserved2 = NULL;
si.cbReserved2 = 0;
si.lpDesktop = NULL;
si.dwFlags = 0;
CreateProcess( NULL,
"notepad",
NULL,
NULL,
TRUE,
NORMAL_PRIORITY_CLASS,
NULL,
NULL,
&si,
&pi );
WaitForSingleObject( pi.hProcess, INFINITE );
}
else if( LOBYTE(LOWORD(dwVersion)) < 4 ) // Win32s
{
SynchSpawn( "notepad.exe", SW_SHOWNORMAL );
}
MessageBox( NULL, "Return from SynchSpawn", " ", MB_OK );
}
/*** Code for 32-bit side of thunk ***/
#define W32SUT_32 // Needed for w32sut.h in 32-bit code
#include <windows.h>
#include "w32sut.h"
#include "spawn.h"
typedef BOOL (WINAPI * PUTREGISTER) ( HANDLE hModule,
LPCSTR lpsz16BitDLL,
LPCSTR lpszInitName,
LPCSTR lpszProcName,
UT32PROC * ppfn32Thunk,
FARPROC pfnUT32Callback,
LPVOID lpBuff
);
typedef VOID (WINAPI * PUTUNREGISTER) (HANDLE hModule);
typedef DWORD (APIENTRY *PUT32CBPROC) (LPVOID lpBuff, DWORD dwUserDefined);
UT32PROC pfnUTProc = NULL;
PUTREGISTER pUTRegister = NULL;
PUTUNREGISTER pUTUnRegister = NULL;
PUT32CBPROC pfnUT32CBProc = NULL;
int cProcessesAttached = 0;
BOOL fWin32s = FALSE;
HANDLE hKernel32 = 0;
/********************************************************************\
* Function: BOOL APIENTRY DllMain(HANDLE, DWORD, LPVOID) *
* *
* Purpose: DLL entry point. Establishes thunk. *
\********************************************************************/
BOOL APIENTRY DllMain(HANDLE hInst, DWORD fdwReason, LPVOID lpReserved)
{
DWORD dwVersion;
if ( fdwReason == DLL_PROCESS_ATTACH )
{
/*
* Registration of UT need to be done only once for first
* attaching process. At that time set the fWin32s flag
* to indicate if the DLL is executing under Win32s or not.
*/
if( cProcessesAttached++ )
{
return(TRUE); // Not the first initialization.
}
// Find out if we're running on Win32s
dwVersion = GetVersion();
fWin32s = (BOOL) (!(dwVersion < 0x80000000))
&& (LOBYTE(LOWORD(dwVersion)) < 4);
if( !fWin32s )
return(TRUE); // Win32s - no further initialization needed
hKernel32 = LoadLibrary( "Kernel32.Dll" ); // Get Kernel32.Dll handle
pUTRegister = (PUTREGISTER) GetProcAddress( hKernel32, "UTRegister"
);
if( !pUTRegister )
return(FALSE); // Error- Win32s, but can't find UTRegister
pUTUnRegister = (PUTUNREGISTER) GetProcAddress(hKernel32,
"UTUnRegister");
if( !pUTUnRegister )
return(FALSE); // Error- Win32s, but can't find
UTUnRegister
return (*pUTRegister)( hInst, // Spawn32.DLL module handle
"SPAWN16.DLL", // 16-bit thunk dll
"UTInit", // init routine
"UTProc", // 16-bit dispatch routine
&pfnUTProc, // Receives thunk address
pfnUT32CBProc, // callback function
NULL ); // no shared memroy
}
if((fdwReason==DLL_PROCESS_DETACH)&&(0==--cProcessesAttached)&&fWin32s)
{
(*pUTUnRegister)( hInst );
FreeLibrary( hKernel32 );
}
} // DllMain()
/********************************************************************\
* Function: DWORD APIENTRY SynchSpawn(LPTSTR, UINT) *
* *
* Purpose: Thunk to 16-bit code *
\********************************************************************/
DWORD APIENTRY SynchSpawn( LPCSTR lpszCmdLine, UINT nCmdShow )
{
DWORD Args[2];
PVOID Translist[2];
Args[0] = (DWORD) lpszCmdLine;
Args[1] = (DWORD) nCmdShow;
Translist[0] = &Args[0];
Translist[1] = NULL;
return( (* pfnUTProc)( Args, SYNCHSPAWN, Translist) );
}
/* Code for 16-bit side of thunk. */
/* Requires linking with TOOLHELP.LIB, for ModuleFindHandle(). */
#ifndef APIENTRY
#define APIENTRY
#endif
#define W32SUT_16 // Needed for w32sut.h in 16-bit code
#include <windows.h>
#include <toolhelp.h>
#include <malloc.h>
#include "w32sut.h"
#include "spawn.h"
UT16CBPROC glpfnUT16CallBack;
/********************************************************************\
* Function: LRESULT CALLBACK LibMain(HANDLE, WORD, WORD, LPSTR) *
* *
* Purpose: DLL entry point *
\********************************************************************/
int FAR PASCAL LibMain( HANDLE hLibInst, WORD wDataSeg,
WORD cbHeapSize, LPSTR lpszCmdLine)
{
return (1);
} // LibMain()
/********************************************************************\
* Function: DWORD FAR PASCAL UTInit(UT16CBPROC, LPVOID) *
* *
* Purpose: Universal Thunk initialization procedure *
\********************************************************************/
DWORD FAR PASCAL UTInit( UT16CBPROC lpfnUT16CallBack, LPVOID lpBuf )
{
glpfnUT16CallBack = lpfnUT16CallBack;
return(1); // Return Success
} // UTInit()
/********************************************************************\
* Function: DWORD FAR PASCAL UTProc(LPVOID, DWORD) *
* *
* Purpose: Dispatch routine called by 32-bit UT DLL *
\********************************************************************/
DWORD FAR PASCAL UTProc( LPVOID lpBuf, DWORD dwFunc)
{
switch (dwFunc)
{
case SYNCHSPAWN:
{
HMODULE hMod;
MODULEENTRY FAR *me;
UINT hInst;
LPCSTR lpszCmdLine;
UINT nCmdShow;
MSG msg;
BOOL again=TRUE;
/* Retrieve the command line arguments stored in buffer */
lpszCmdLine = (LPSTR) ((LPDWORD)lpBuf)[0];
nCmdShow = (UINT) ((LPDWORD)lpBuf)[1];
/* Start the application with WinExec() */
hInst = WinExec( lpszCmdLine, nCmdShow );
if( hInst < 32 )
return 0;
/* Loop until the application is terminated. The Toolhelp API
* ModuleFindHandle() returns NULL when the application is
* terminated. NOTE: PeekMessage() is used to yield the
* processor; otherwise, nothing else could execute on the
* system.
* /
hMod = GetModuleHandle( lpszCmdLine );
me = (MODULEENTRY FAR *) _fcalloc( 1, sizeof(MODULEENTRY) );
me->dwSize = sizeof( MODULEENTRY );
while( NULL != ModuleFindHandle( me, hMod ) && again )
{
while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) && again )
{
if(msg.message == WM_QUIT)
{
PostQuitMessage(msg.wParam);
again=FALSE;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 1;
}
} // switch (dwFunc)
return( (DWORD)-1L ); // We should never get here.
} // UTProc()
/********************************************************************\
* Function: int FAR PASCAL _WEP(int) *
* *
* Purpose: Windows exit procedure *
\********************************************************************/
int FAR PASCAL _WEP( int bSystemExit )
{
return (1);
} // WEP()
125213 PRB: Spawn with _P_WAIT Returns Immediately on Win32s
Additional query words: win16 toolhelp
Keywords: kbcode KB125212