1797 lines
54 KiB
C
1797 lines
54 KiB
C
/****************************** Module Header ******************************\
|
||
* Module Name: wowexec.c
|
||
*
|
||
* Copyright (c) 1991, Microsoft Corporation
|
||
*
|
||
* WOWEXEC - 16 Bit Server Task - Does Exec Calls on Behalf of 32 bit CreateProcess
|
||
*
|
||
*
|
||
* History:
|
||
* 05-21-91 MattFe Ported to Windows
|
||
* mar-20-92 MattFe Added Error Message Boxes (from win 3.1 progman)
|
||
* apr-1-92 mattfe added commandline exec and switch to path (from win 3.1 progman)
|
||
* jun-1-92 mattfe changed wowgetnextvdmcommand
|
||
* 12-Nov-93 DaveHart Multiple WOW support and remove captive
|
||
* GetNextVDMCommand thread from WOW32.
|
||
* 16-Nov-93 DaveHart Reduce data segment size.
|
||
\***************************************************************************/
|
||
#include "wowexec.h"
|
||
#include "wowinfo.h"
|
||
#include "shellapi.h"
|
||
#ifndef PULONG
|
||
#define PULONG
|
||
#endif
|
||
#include "vint.h"
|
||
#include "dde.h"
|
||
|
||
|
||
/*
|
||
* External Prototypes
|
||
*/
|
||
extern WORD FAR PASCAL WOWQueryDebug( void );
|
||
extern WORD FAR PASCAL WowWaitForMsgAndEvent( HWND);
|
||
extern void FAR PASCAL WowMsgBox(LPSTR szMsg, LPSTR szTitle, DWORD dwOptionalStyle);
|
||
extern DWORD FAR PASCAL WowPartyByNumber(DWORD dw, LPSTR psz);
|
||
extern DWORD FAR PASCAL WowKillTask(WORD htask);
|
||
extern void FAR PASCAL WowShutdownTimer(WORD fEnable);
|
||
HWND FaxInit(HINSTANCE hInst);
|
||
|
||
/*
|
||
* Global Variables
|
||
*/
|
||
HANDLE hAppInstance;
|
||
HWND ghwndMain = NULL;
|
||
HWND ghwndEdit = NULL;
|
||
char szOOMExitTitle[32+1];
|
||
char szOOMExitMsg[64+1];
|
||
char szAppTitleBuffer[32];
|
||
LPSTR lpszAppTitle = szAppTitleBuffer;
|
||
char szWindowsDirectory[MAXITEMPATHLEN+1];
|
||
char szOriginalDirectory[MAXITEMPATHLEN+1];
|
||
BOOL gfSharedWOW = FALSE;
|
||
BOOL gfMeow = FALSE;
|
||
WORD gwFirstCmdShow;
|
||
|
||
|
||
|
||
/*
|
||
* Forward declarations.
|
||
*/
|
||
BOOL InitializeApp(LPSTR lpszCommandLine);
|
||
LONG FAR PASCAL WndProc(HWND hwnd, WORD message, WORD wParam, LONG lParam);
|
||
WORD NEAR PASCAL ExecProgram(PWOWINFO pWowInfo);
|
||
BOOL NEAR PASCAL ExecApplication(PWOWINFO pWowInfo);
|
||
void NEAR PASCAL MyMessageBox(WORD idTitle, WORD idMessage, LPSTR psz);
|
||
PSTR FAR PASCAL GetFilenameFromPath( PSTR szPath );
|
||
void NEAR PASCAL GetPathInfo ( PSTR szPath, PSTR *pszFileName, PSTR *pszExt, WORD *pich, BOOL *pfUnc);
|
||
BOOL NEAR PASCAL StartRequestedApp(VOID);
|
||
#ifdef DEBUG
|
||
BOOL FAR PASCAL PartyDialogProc(HWND hDlg, WORD msg, WORD wParam, LONG lParam);
|
||
#endif
|
||
|
||
#define AnsiNext(x) ((x)+1)
|
||
|
||
typedef struct PARAMETERBLOCK {
|
||
WORD wEnvSeg;
|
||
LPSTR lpCmdLine;
|
||
LPVOID lpCmdShow;
|
||
DWORD dwReserved;
|
||
} PARAMETERBLOCK, *PPARAMETERBLOCK;
|
||
|
||
typedef struct CMDSHOW {
|
||
WORD two;
|
||
WORD nCmdShow;
|
||
} CMDSHOW, *PCMDSHOW;
|
||
|
||
#define CCHMAX 256+13 // MAX_PATH plus 8.3 plus NULL
|
||
|
||
#define ERROR_ERROR 0
|
||
#define ERROR_FILENOTFOUND 2
|
||
#define ERROR_PATHNOTFOUND 3
|
||
#define ERROR_MANYOPEN 4
|
||
#define ERROR_DYNLINKSHARE 5
|
||
#define ERROR_LIBTASKDATA 6
|
||
#define ERROR_MEMORY 8
|
||
#define ERROR_VERSION 10
|
||
#define ERROR_BADEXE 11
|
||
#define ERROR_OTHEREXE 12
|
||
#define ERROR_DOS4EXE 13
|
||
#define ERROR_UNKNOWNEXE 14
|
||
#define ERROR_RMEXE 15
|
||
#define ERROR_MULTDATAINST 16
|
||
#define ERROR_PMODEONLY 18
|
||
#define ERROR_COMPRESSED 19
|
||
#define ERROR_DYNLINKBAD 20
|
||
#define ERROR_WIN32 21
|
||
|
||
|
||
/* FindPrevInstanceProc -
|
||
* A little enumproc to find any window (EnumWindows) which has a
|
||
* matching EXE file path. The desired match EXE pathname is pointed to
|
||
* by the lParam. The found window's handle is stored in the
|
||
* first word of this buffer.
|
||
*/
|
||
|
||
BOOL CALLBACK FindPrevInstanceProc(HWND hWnd, LPSTR lpszParam)
|
||
{
|
||
char szT[260];
|
||
HANDLE hInstance;
|
||
|
||
// Filter out invisible and disabled windows
|
||
//
|
||
|
||
if (!IsWindowEnabled(hWnd) || !IsWindowVisible(hWnd))
|
||
return TRUE;
|
||
|
||
hInstance = GetWindowWord(hWnd, GWW_HINSTANCE);
|
||
GetModuleFileName(hInstance, szT, sizeof (szT)-1);
|
||
|
||
// Make sure that the hWnd belongs to the current VDM process
|
||
//
|
||
// GetWindowTask returns the wowexec htask16 if the window belongs
|
||
// to a different process - thus we filter out windows in
|
||
// 'separate VDM' processes.
|
||
// - nanduri
|
||
|
||
if (lstrcmpi(szT, lpszParam) == 0 &&
|
||
GetWindowTask(hWnd) != GetWindowTask(ghwndMain)) {
|
||
*(LPHANDLE)lpszParam = hWnd;
|
||
return FALSE;
|
||
}
|
||
else {
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
HWND near pascal FindPopupFromExe(LPSTR lpExe)
|
||
{
|
||
HWND hwnd = (HWND)0;
|
||
BOOL b;
|
||
|
||
b = EnumWindows(FindPrevInstanceProc, (LONG)(LPSTR)lpExe);
|
||
if (!b && (hwnd = *(LPHANDLE)(LPSTR)lpExe)) {
|
||
// Find a "main" window that is the ancestor of a given window
|
||
//
|
||
|
||
HWND hwndT;
|
||
|
||
// First go up the parent chain to find the popup window. Then go
|
||
// up the owner chain to find the main window
|
||
//
|
||
|
||
while (hwndT = GetParent(hwnd))
|
||
hwnd = hwndT;
|
||
|
||
while (hwndT = GetWindow(hwnd, GW_OWNER))
|
||
hwnd = hwndT;
|
||
}
|
||
|
||
return hwnd;
|
||
}
|
||
|
||
WORD ActivatePrevInstance(LPSTR lpszPath)
|
||
{
|
||
HWND hwnd;
|
||
HINSTANCE ret = IDS_MULTIPLEDSMSG;
|
||
|
||
if (hwnd = FindPopupFromExe(lpszPath)) {
|
||
if (IsIconic(hwnd)) {
|
||
ShowWindow(hwnd,SW_SHOWNORMAL);
|
||
}
|
||
else {
|
||
HWND hwndT = GetLastActivePopup(hwnd);
|
||
BringWindowToTop(hwnd);
|
||
if (hwndT && hwnd != hwndT)
|
||
BringWindowToTop(hwndT);
|
||
}
|
||
ret = 0;
|
||
}
|
||
|
||
return (ret);
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------*/
|
||
/* */
|
||
/* ExecProgram() - */
|
||
/* */
|
||
/* Taken from Win 3.1 Progman -maf */
|
||
/*--------------------------------------------------------------------------*/
|
||
|
||
/* Returns 0 for success. Otherwise returns a IDS_ string code. */
|
||
|
||
WORD NEAR PASCAL ExecProgram(PWOWINFO pWowInfo)
|
||
{
|
||
WORD ret;
|
||
PARAMETERBLOCK ParmBlock;
|
||
CMDSHOW CmdShow;
|
||
char CmdLine[CCHMAX];
|
||
|
||
ret = 0;
|
||
|
||
// Don't mess with the mouse state; unless we're on a mouseless system.
|
||
if (!GetSystemMetrics(SM_MOUSEPRESENT))
|
||
ShowCursor(TRUE);
|
||
|
||
//
|
||
// prepare the dos style cmd line (counted pascal string)
|
||
// pWowInfo->lpCmdLine contains the command tail (excluding argv[0])
|
||
//
|
||
CmdLine[0] = lstrlen(pWowInfo->lpCmdLine) - 2;
|
||
lstrcpy( &CmdLine[1], pWowInfo->lpCmdLine);
|
||
|
||
// We have a WOWINFO structure, then use it to pass the correct environment
|
||
|
||
ParmBlock.wEnvSeg = HIWORD(pWowInfo->lpEnv);
|
||
ParmBlock.lpCmdLine = CmdLine;
|
||
ParmBlock.lpCmdShow = &CmdShow;
|
||
CmdShow.two = 2;
|
||
CmdShow.nCmdShow = pWowInfo->wShowWindow;
|
||
|
||
ParmBlock.dwReserved = NULL;
|
||
|
||
ret = LoadModule(pWowInfo->lpAppName,(LPVOID)&ParmBlock) ;
|
||
|
||
switch (ret)
|
||
{
|
||
case ERROR_ERROR:
|
||
case ERROR_MEMORY:
|
||
ret = IDS_NOMEMORYMSG;
|
||
break;
|
||
|
||
case ERROR_FILENOTFOUND:
|
||
ret = IDS_FILENOTFOUNDMSG;
|
||
break;
|
||
|
||
case ERROR_PATHNOTFOUND:
|
||
ret = IDS_BADPATHMSG;
|
||
break;
|
||
|
||
case ERROR_MANYOPEN:
|
||
ret = IDS_MANYOPENFILESMSG;
|
||
break;
|
||
|
||
case ERROR_DYNLINKSHARE:
|
||
ret = IDS_ACCESSDENIED;
|
||
break;
|
||
|
||
case ERROR_VERSION:
|
||
ret = IDS_NEWWINDOWSMSG;
|
||
break;
|
||
|
||
case ERROR_RMEXE:
|
||
/* KERNEL has already put up a messagebox for this one. */
|
||
ret = 0;
|
||
break;
|
||
|
||
case ERROR_MULTDATAINST:
|
||
ret = ActivatePrevInstance(pWowInfo->lpAppName);
|
||
break;
|
||
|
||
case ERROR_COMPRESSED:
|
||
ret = IDS_COMPRESSEDEXE;
|
||
break;
|
||
|
||
case ERROR_DYNLINKBAD:
|
||
ret = IDS_INVALIDDLL;
|
||
break;
|
||
|
||
case SE_ERR_SHARE:
|
||
ret = IDS_SHAREERROR;
|
||
break;
|
||
|
||
case ERROR_WIN32:
|
||
ret = IDS_CANTLOADWIN32DLL;
|
||
break;
|
||
|
||
//
|
||
// We shouldn't get any of the following errors,
|
||
// so the strings have been removed from the resource
|
||
// file. That's why there's the OutputDebugString
|
||
// on checked builds only.
|
||
//
|
||
|
||
#ifdef DEBUG
|
||
case ERROR_OTHEREXE:
|
||
case ERROR_PMODEONLY:
|
||
case SE_ERR_ASSOCINCOMPLETE:
|
||
case SE_ERR_DDETIMEOUT:
|
||
case SE_ERR_DDEFAIL:
|
||
case SE_ERR_DDEBUSY:
|
||
case SE_ERR_NOASSOC:
|
||
{
|
||
char szTmp[64];
|
||
wsprintf(szTmp, "WOWEXEC: Unexpected error %d executing app, fix that code!\n", (int)ret);
|
||
OutputDebugString(szTmp);
|
||
}
|
||
//
|
||
// fall through to default case, so the execution
|
||
// is the same as on the free build.
|
||
//
|
||
#endif
|
||
|
||
default:
|
||
if (ret < 32)
|
||
goto EPExit;
|
||
ret = 0;
|
||
}
|
||
|
||
EPExit:
|
||
|
||
if (!GetSystemMetrics(SM_MOUSEPRESENT)) {
|
||
/*
|
||
* We want to turn the mouse off here on mouseless systems, but
|
||
* the mouse will already have been turned off by USER if the
|
||
* app has GP'd so make sure everything's kosher.
|
||
*/
|
||
if (ShowCursor(FALSE) != -1)
|
||
ShowCursor(TRUE);
|
||
}
|
||
|
||
return(ret);
|
||
}
|
||
|
||
/***************************************************************************\
|
||
* ExecApplication
|
||
*
|
||
* Code Taken From Win 3.1 ExecItem()
|
||
*
|
||
\***************************************************************************/
|
||
|
||
#define TDB_PDB_OFFSET 0x60
|
||
#define PDB_ENV_OFFSET 0x2C
|
||
|
||
BOOL NEAR PASCAL ExecApplication(PWOWINFO pWowInfo)
|
||
{
|
||
|
||
WORD ret;
|
||
LPSTR szEnv;
|
||
LPSTR szEnd;
|
||
BYTE bDrive;
|
||
WORD wSegEnvSave;
|
||
HANDLE hTask;
|
||
LPSTR lpTask;
|
||
HANDLE hPDB;
|
||
LPSTR lpPDB;
|
||
HANDLE hNewEnv;
|
||
|
||
int nLength;
|
||
int nNewEnvLength;
|
||
LPSTR lpstrEnv;
|
||
LPSTR lpstr;
|
||
LPSTR lpOriginalEnv;
|
||
BOOL bBlanks;
|
||
LPSTR szEnvTmp;
|
||
|
||
|
||
if (!pWowInfo) {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Seup the environment from WOWINFO record from getvdmcommand
|
||
//
|
||
|
||
|
||
// Figure out who we are (so we can edit our PDB/PSP)
|
||
|
||
hTask = GetCurrentTask();
|
||
lpTask = GlobalLock( hTask );
|
||
if ( lpTask == NULL ) {
|
||
ret = IDS_NOMEMORYMSG;
|
||
goto punt;
|
||
}
|
||
|
||
hPDB = *((LPWORD)(lpTask + TDB_PDB_OFFSET));
|
||
lpPDB = GlobalLock( hPDB );
|
||
|
||
// Save our environment block
|
||
wSegEnvSave = *((LPWORD)(lpPDB + PDB_ENV_OFFSET));
|
||
|
||
|
||
// Now determine the length of the original env
|
||
|
||
lpOriginalEnv = (LPSTR)MAKELONG(0,wSegEnvSave);
|
||
|
||
do {
|
||
nLength = lstrlen(lpOriginalEnv);
|
||
lpOriginalEnv += nLength + 1;
|
||
} while ( nLength != 0 );
|
||
|
||
lpOriginalEnv += 2; // Skip over magic word, see comment below
|
||
|
||
nNewEnvLength = 4 + lstrlen(lpOriginalEnv); // See magic comments below!
|
||
|
||
// WOW Apps cannot deal with an invalid TEMP=c:\bugusdir directory
|
||
// Usually on Win 3.1 the TEMP= is checked in ldboot.asm check_temp
|
||
// routine. However on NT since we get a new environment with each
|
||
// WOW app it means that we have to check it here. If it is not
|
||
// valid then it is edited in the environment.
|
||
// - mattfe june 11 93
|
||
|
||
szEnv = pWowInfo->lpEnv;
|
||
szEnd = szEnv + pWowInfo->EnvSize;
|
||
szEnd--;
|
||
|
||
while ( szEnv < szEnd ) {
|
||
|
||
nLength = lstrlen(szEnv) + 1;
|
||
|
||
if ( (*szEnv == 'T') &&
|
||
(*(szEnv+1) == 'E') &&
|
||
(*(szEnv+2) == 'M') &&
|
||
(*(szEnv+3) == 'P') &&
|
||
(*(szEnv+4) == '=') ) {
|
||
|
||
// Try to set the current directory to the TEMP= dir
|
||
// If it fails then nuke the TEMP= part of the environment
|
||
// in the same way check_TEMP does in ldboot.asm
|
||
// We also scan for blanks, just like check_TEMP
|
||
|
||
bBlanks = FALSE;
|
||
szEnvTmp = szEnv+5;
|
||
while (*szEnvTmp != 0) {
|
||
if (*szEnvTmp == ' ') {
|
||
bBlanks = TRUE;
|
||
break;
|
||
}
|
||
szEnvTmp++;
|
||
}
|
||
|
||
if (bBlanks || (SetCurrentDirectory(szEnv+5) )) {
|
||
while (*szEnv != 0) {
|
||
*szEnv = 'x';
|
||
szEnv++;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
szEnv += nLength;
|
||
}
|
||
|
||
// WOW Apps only have a Single Current Directory
|
||
// Find =d:=D:\path where d is the active drive letter
|
||
// Note that the drive info doesn have to be at the start
|
||
// of the environment.
|
||
|
||
bDrive = pWowInfo->CurDrive + 'A';
|
||
szEnv = pWowInfo->lpEnv;
|
||
szEnd = szEnv + pWowInfo->EnvSize;
|
||
szEnd--;
|
||
|
||
while ( szEnv < szEnd ) {
|
||
|
||
nLength = lstrlen(szEnv) + 1;
|
||
if ( *szEnv == '=' ) {
|
||
if ( (bDrive == (*(szEnv+1) & 0xdf)) &&
|
||
(*(szEnv+2) == ':') && (*(szEnv+3) == '=') ) {
|
||
SetCurrentDirectory(szEnv+4);
|
||
}
|
||
} else {
|
||
nNewEnvLength += nLength;
|
||
}
|
||
szEnv += nLength;
|
||
}
|
||
|
||
// Now allocate and make a personal copy of the Env
|
||
|
||
hNewEnv = GlobalAlloc( GMEM_MOVEABLE, (DWORD)nNewEnvLength );
|
||
if ( hNewEnv == NULL ) {
|
||
ret = IDS_NOMEMORYMSG;
|
||
goto punt;
|
||
}
|
||
lpstrEnv = GlobalLock( hNewEnv );
|
||
if ( lpstrEnv == NULL ) {
|
||
GlobalFree( hNewEnv );
|
||
ret = IDS_NOMEMORYMSG;
|
||
goto punt;
|
||
}
|
||
|
||
// Copy only the non-current directory env variables
|
||
|
||
szEnv = pWowInfo->lpEnv;
|
||
lpstr = lpstrEnv;
|
||
|
||
while ( szEnv < szEnd ) {
|
||
nLength = lstrlen(szEnv) + 1;
|
||
|
||
// Copy everything except the drive letters
|
||
|
||
if ( *szEnv != '=' ) {
|
||
lstrcpy( lpstr, szEnv );
|
||
lpstr += nLength;
|
||
}
|
||
szEnv += nLength;
|
||
}
|
||
*lpstr++ = '\0'; // Extra '\0' on the end
|
||
|
||
// Magic environment goop!
|
||
//
|
||
// Windows only supports the passing of environment information
|
||
// using the LoadModule API. The WinExec API just causes
|
||
// the application to inherit the current DOS PDB's environment.
|
||
//
|
||
// Also, the environment block has a little gotcha at the end. Just
|
||
// after the double-nuls there is a magic WORD value 0x0001 (DOS 3.0
|
||
// and later). After the value is a nul terminated string indicating
|
||
// the applications executable file name (including PATH).
|
||
//
|
||
// We copy the value from WOWEXEC's original environment because
|
||
// that is what WinExec appears to do.
|
||
//
|
||
// -BobDay
|
||
|
||
*lpstr++ = '\1';
|
||
*lpstr++ = '\0'; // Magic 0x0001 from DOS
|
||
|
||
lstrcpy( lpstr, lpOriginalEnv ); // More Magic (see comment above)
|
||
|
||
// Temporarily update our environment block
|
||
|
||
*((LPWORD)(lpPDB + PDB_ENV_OFFSET)) = (WORD)hNewEnv | 1;
|
||
|
||
pWowInfo->lpEnv = lpstrEnv;
|
||
|
||
|
||
//
|
||
// Set our current drive & directory as requested.
|
||
//
|
||
|
||
SetCurrentDirectory(pWowInfo->lpCurDir);
|
||
|
||
ret = ExecProgram(pWowInfo);
|
||
|
||
// Restore our environment block
|
||
|
||
*((LPWORD)(lpPDB + PDB_ENV_OFFSET)) = wSegEnvSave;
|
||
|
||
GlobalUnlock( hPDB );
|
||
GlobalUnlock( hTask );
|
||
GlobalUnlock( hNewEnv );
|
||
GlobalFree( hNewEnv );
|
||
|
||
|
||
punt:
|
||
|
||
// Change back to the Windows Directory
|
||
// So that if we are execing from a NET Drive its
|
||
// Not kept Active
|
||
|
||
SetCurrentDirectory(szWindowsDirectory);
|
||
|
||
// Always call this when we are done try to start an app.
|
||
// It will do nothing if we were successful in starting an
|
||
// app, otherwise if we were unsucessful it will signal that
|
||
// the app has completed.
|
||
WowFailedExec();
|
||
|
||
// Check for errors.
|
||
if (ret) {
|
||
MyMessageBox(IDS_EXECERRTITLE, ret, pWowInfo->lpAppName);
|
||
|
||
if ( ! gfSharedWOW) {
|
||
|
||
//
|
||
// We have just failed to exec the only app we are going to
|
||
// try to exec in this separate WOW VDM. We need to end WOW
|
||
// here explicitly, otherwise we'll hang around forever because
|
||
// the normal path is for kernel to exit the VDM when a task
|
||
// exit causes the number of tasks to transition from 2 to 1 --
|
||
// in this case the number of tasks never exceeds 1.
|
||
//
|
||
|
||
ExitKernelThunk(0);
|
||
|
||
}
|
||
}
|
||
|
||
return(ret);
|
||
}
|
||
|
||
|
||
/*--------------------------------------------------------------------------*/
|
||
/* */
|
||
/* MyMessageBox() - */
|
||
/* Taken From Win 3.1 Progman - maf */
|
||
/*--------------------------------------------------------------------------*/
|
||
|
||
void NEAR PASCAL MyMessageBox(WORD idTitle, WORD idMessage, LPSTR psz)
|
||
{
|
||
char szTitle[MAXTITLELEN+1];
|
||
char szMessage[MAXMESSAGELEN+1];
|
||
char szTempField[MAXMESSAGELEN+1];
|
||
|
||
|
||
if (!LoadString(hAppInstance, idTitle, szTitle, sizeof(szTitle)))
|
||
goto MessageBoxOOM;
|
||
|
||
if (idMessage > IDS_LAST)
|
||
{
|
||
if (!LoadString(hAppInstance, IDS_UNKNOWNMSG, szTempField, sizeof(szTempField)))
|
||
goto MessageBoxOOM;
|
||
wsprintf(szMessage, szTempField, idMessage);
|
||
}
|
||
else
|
||
{
|
||
if (!LoadString(hAppInstance, idMessage, szTempField, sizeof(szTempField)))
|
||
goto MessageBoxOOM;
|
||
|
||
if (psz)
|
||
wsprintf(szMessage, szTempField, (LPSTR)psz);
|
||
else
|
||
lstrcpy(szMessage, szTempField);
|
||
}
|
||
|
||
WowMsgBox(szMessage, szTitle, MB_ICONEXCLAMATION);
|
||
return;
|
||
|
||
|
||
MessageBoxOOM:
|
||
WowMsgBox(szOOMExitMsg, szOOMExitTitle, MB_ICONHAND);
|
||
|
||
return ;
|
||
}
|
||
|
||
|
||
|
||
/***************************************************************************\
|
||
* main
|
||
*
|
||
*
|
||
* History:
|
||
* 04-13-91 ScottLu Created - from 32 bit exec app
|
||
* 21-mar-92 mattfe significant alterations for WOW
|
||
\***************************************************************************/
|
||
|
||
int PASCAL WinMain(HANDLE hInstance,
|
||
HANDLE hPrevInstance, LPSTR lpszCmdLine, int iCmd)
|
||
|
||
{
|
||
int i;
|
||
MSG msg;
|
||
LPSTR pch,pch1;
|
||
WORD ret;
|
||
WOWINFO wowinfo;
|
||
char aszWOWDEB[CCHMAX];
|
||
LPSTR pchWOWDEB;
|
||
HANDLE hMMDriver;
|
||
|
||
|
||
char szBuffer[150];
|
||
BOOL bFinished;
|
||
int iStart;
|
||
int iEnd;
|
||
|
||
|
||
hAppInstance = hInstance ;
|
||
|
||
// Only Want One WOWExec
|
||
if (hPrevInstance != NULL) {
|
||
return(FALSE);
|
||
}
|
||
|
||
if (!InitializeApp(lpszCmdLine)) {
|
||
OutputDebugString("WOWEXEC: InitializeApp failure!\n");
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* Look for a drivers= line in the [boot] section of SYSTEM.INI
|
||
* If present it is the 16 bit MultiMedia interface, so load it
|
||
*/
|
||
|
||
#ifdef OLD_MMSYSTEM_LOAD
|
||
if (GetPrivateProfileString((LPSTR)"boot", (LPSTR)"drivers",(LPSTR)"", aszMMDriver, sizeof(aszMMDriver), (LPSTR)"SYSTEM.INI")) {
|
||
/*
|
||
* We have now discovered an app that rewrites the "drivers" entry with
|
||
* multiple drivers - so the existing load method fails. As a temporary fix
|
||
* while we decide what the "proper" fix is I will always load MMSYSTEM and
|
||
* ONLY MMSYSTEM.
|
||
*
|
||
* aszMMDriver[sizeof(aszMMDriver)-1] = '\0';
|
||
* hMMDriver = LoadLibrary((LPSTR)aszMMDriver);
|
||
* #ifdef DEBUG
|
||
* if (hMMDriver < 32) {
|
||
* OutputDebugString("WOWEXEC: Load of MultiMedia driver failed\n");
|
||
* }
|
||
* #endif
|
||
*/
|
||
LoadLibrary("MMSYSTEM.DLL");
|
||
}
|
||
#else
|
||
/* Load DDL's from DRIVERS section in system.ini
|
||
*/
|
||
GetPrivateProfileString( (LPSTR)"boot", /* [Boot] section */
|
||
(LPSTR)"drivers", /* Drivers= */
|
||
(LPSTR)"", /* Default if no match */
|
||
szBuffer, /* Return buffer */
|
||
sizeof(szBuffer),
|
||
(LPSTR)"system.ini" );
|
||
|
||
if (!*szBuffer) {
|
||
goto Done;
|
||
}
|
||
|
||
bFinished = FALSE;
|
||
iStart = 0;
|
||
|
||
while (!bFinished) {
|
||
iEnd = iStart;
|
||
|
||
while (szBuffer[iEnd] && (szBuffer[iEnd] != ' ') &&
|
||
(szBuffer[iEnd] != ',')) {
|
||
iEnd++;
|
||
}
|
||
|
||
if (szBuffer[iEnd] == NULL) {
|
||
bFinished = TRUE;
|
||
}
|
||
else {
|
||
szBuffer[iEnd] = NULL;
|
||
}
|
||
|
||
/* Load and enable the driver.
|
||
*/
|
||
OpenDriver( &(szBuffer[iStart]), NULL, NULL );
|
||
iStart = iEnd + 1;
|
||
}
|
||
|
||
Done:
|
||
|
||
#endif
|
||
|
||
/*
|
||
* Look for a debug= line in the [boot] section of SYSTEM.INI
|
||
* If present it is the 16 bit MultiMedia interface, so load it
|
||
*/
|
||
|
||
if ( !gfMeow && (WOWQueryDebug() & 0x0001)!=0 ) {
|
||
pchWOWDEB = "WOWDEB.EXE";
|
||
} else {
|
||
pchWOWDEB = "";
|
||
}
|
||
|
||
GetPrivateProfileString((LPSTR)"boot", (LPSTR)"debug",pchWOWDEB, aszWOWDEB, sizeof(aszWOWDEB), (LPSTR)"SYSTEM.INI");
|
||
aszWOWDEB[sizeof(aszWOWDEB)-1] = '\0';
|
||
|
||
if ( lstrlen(pchWOWDEB) != 0 ) {
|
||
WinExec((LPSTR)aszWOWDEB,SW_SHOW);
|
||
}
|
||
|
||
#if 0
|
||
/* Preload winspool.exe. Apps will keep loading and freeing it
|
||
* which is slow. We might as well load it now so the reference
|
||
* count is 1 so it will never be loaded or freed
|
||
*/
|
||
//
|
||
// Disabled load of winspool.exe to save 8k. Size vs. speed,
|
||
// which one do we care about? Right now, size!
|
||
//
|
||
LoadLibrary("WINSPOOL.EXE");
|
||
#endif
|
||
|
||
// Always load SHELL.DLL, FileMaker Pro and Lotus Install require it.
|
||
|
||
LoadLibrary("SHELL.DLL");
|
||
|
||
//
|
||
// Start any apps pending in basesrv queue
|
||
//
|
||
|
||
while (StartRequestedApp() && gfSharedWOW) {
|
||
/* null stmt */ ;
|
||
}
|
||
|
||
|
||
while (1) {
|
||
if (!WowWaitForMsgAndEvent(ghwndMain) &&
|
||
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) &&
|
||
msg.message != WM_WOWEXECHEARTBEAT )
|
||
{
|
||
if (msg.message != WM_QUIT) {
|
||
TranslateMessage(&msg);
|
||
DispatchMessage(&msg);
|
||
}
|
||
}
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
|
||
/***************************************************************************\
|
||
* InitializeApp
|
||
*
|
||
* History:
|
||
* 04-13-91 ScottLu Created.
|
||
\***************************************************************************/
|
||
|
||
BOOL InitializeApp(LPSTR lpszCommandLine)
|
||
{
|
||
WNDCLASS wc;
|
||
int cyExecStart, cxExecStart;
|
||
USHORT TitleLen, cbCopy;
|
||
HWND hwndFax;
|
||
int lResult;
|
||
|
||
|
||
// Remove Real Mode Segment Address
|
||
|
||
wc.style = 0;
|
||
wc.lpfnWndProc = WndProc;
|
||
wc.cbClsExtra = 0;
|
||
wc.cbWndExtra = 0;
|
||
wc.hInstance = hAppInstance;
|
||
wc.hIcon = LoadIcon(hAppInstance, MAKEINTRESOURCE(ID_WOWEXEC_ICON));
|
||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
|
||
wc.lpszClassName = "WOWExecClass";
|
||
#ifdef DEBUG
|
||
wc.lpszMenuName = "MainMenu";
|
||
#else
|
||
wc.lpszMenuName = NULL;
|
||
#endif
|
||
|
||
if (!RegisterClass(&wc)) {
|
||
OutputDebugString("WOWEXEC: RegisterClass failed\n");
|
||
return FALSE;
|
||
}
|
||
|
||
/* Load these strings now. If we need them later, we won't be able to load
|
||
* them at that time.
|
||
*/
|
||
LoadString(hAppInstance, IDS_OOMEXITTITLE, szOOMExitTitle, sizeof(szOOMExitTitle));
|
||
LoadString(hAppInstance, IDS_OOMEXITMSG, szOOMExitMsg, sizeof(szOOMExitMsg));
|
||
LoadString(hAppInstance, IDS_APPTITLE, szAppTitleBuffer, sizeof(szAppTitleBuffer));
|
||
|
||
ghwndMain = CreateWindow("WOWExecClass", lpszAppTitle,
|
||
WS_OVERLAPPED | WS_CAPTION | WS_BORDER | WS_THICKFRAME |
|
||
WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CLIPCHILDREN |
|
||
WS_SYSMENU,
|
||
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
||
NULL, NULL, hAppInstance, NULL);
|
||
|
||
if (ghwndMain == NULL ) {
|
||
#ifdef DEBUG
|
||
OutputDebugString("WOWEXEC: ghwndMain Null\n");
|
||
#endif
|
||
return FALSE;
|
||
}
|
||
|
||
hwndFax = FaxInit(hAppInstance);
|
||
|
||
//
|
||
// Give our window handle to BaseSrv, which will post WM_WOWEXECSTARTAPP
|
||
// messages when we have commands to pick up. The return value tells
|
||
// us if we are the shared WOW VDM or not (a seperate WOW VDM).
|
||
// We also pick up the ShowWindow parameter (SW_SHOW, SW_MINIMIZED, etc)
|
||
// for the first WOW app here. Subsequent ones we get from BaseSrv.
|
||
//
|
||
|
||
//
|
||
// gwFirstCmdShow is no longer used, and is available.
|
||
//
|
||
|
||
lResult = WOWRegisterShellWindowHandle(ghwndMain,
|
||
&gwFirstCmdShow,
|
||
hwndFax
|
||
);
|
||
|
||
if (lResult < 0) {
|
||
gfMeow=TRUE;
|
||
} else if (lResult > 0) {
|
||
gfSharedWOW=TRUE;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// If this isn't the shared WOW, tell the kernel to exit when the
|
||
// last app (except WowExec) exits.
|
||
//
|
||
|
||
if (!gfSharedWOW) {
|
||
WowSetExitOnLastApp(TRUE);
|
||
}
|
||
|
||
/* Remember the original directory. */
|
||
GetCurrentDirectory(NULL, szOriginalDirectory);
|
||
GetWindowsDirectory(szWindowsDirectory, MAXITEMPATHLEN+1);
|
||
|
||
#ifdef DEBUG
|
||
|
||
ShowWindow(ghwndMain, SW_MINIMIZE);
|
||
|
||
//
|
||
// If this is the shared WOW, change the app title string to
|
||
// reflect this and change the window title.
|
||
//
|
||
|
||
if (gfSharedWOW) {
|
||
|
||
LoadString(hAppInstance, IDS_SHAREDAPPTITLE, szAppTitleBuffer, sizeof(szAppTitleBuffer));
|
||
|
||
}
|
||
|
||
SetWindowText(ghwndMain, lpszAppTitle);
|
||
UpdateWindow(ghwndMain);
|
||
|
||
#endif
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
/***************************************************************************\
|
||
* WndProc
|
||
*
|
||
* History:
|
||
* 04-07-91 DarrinM Created.
|
||
\***************************************************************************/
|
||
|
||
LONG FAR PASCAL WndProc(
|
||
HWND hwnd,
|
||
WORD message,
|
||
WORD wParam,
|
||
LONG lParam)
|
||
{
|
||
char chbuf[50];
|
||
HICON hIcon;
|
||
|
||
switch (message) {
|
||
case WM_CREATE:
|
||
break;
|
||
|
||
case WM_DESTROY:
|
||
// ignore since wowexec must stay around
|
||
return 0;
|
||
|
||
#ifdef DEBUG
|
||
case WM_COMMAND:
|
||
switch (LOWORD(wParam)) {
|
||
case MM_ABOUT:
|
||
LoadString(hAppInstance, errTitle, (LPSTR)chbuf, sizeof(chbuf));
|
||
hIcon = LoadIcon(hAppInstance, MAKEINTRESOURCE(ID_WOWEXEC_ICON));
|
||
ShellAbout(ghwndMain, (LPSTR)chbuf, (LPSTR)lpszAppTitle, hIcon);
|
||
break;
|
||
|
||
case MM_BREAK:
|
||
_asm int 3
|
||
break;
|
||
|
||
case MM_FAULT:
|
||
_asm mov cs:0,ax
|
||
break;
|
||
|
||
case MM_EXIT:
|
||
ExitKernelThunk(0);
|
||
break;
|
||
|
||
case MM_WATSON:
|
||
WinExec("drwatson", SW_MINIMIZE );
|
||
break;
|
||
|
||
case MM_PARTY:
|
||
{
|
||
FARPROC lpPartyDialogProc;
|
||
|
||
lpPartyDialogProc = MakeProcInstance(PartyDialogProc, hAppInstance);
|
||
|
||
DialogBox(hAppInstance, MAKEINTRESOURCE(ID_PARTY_DIALOG),
|
||
hwnd, lpPartyDialogProc);
|
||
|
||
FreeProcInstance(lpPartyDialogProc);
|
||
}
|
||
break;
|
||
|
||
case MM_GENTHUNK:
|
||
{
|
||
DWORD FAR PASCAL CallProc32W(DWORD, DWORD, DWORD, DWORD,
|
||
DWORD, DWORD, DWORD, DWORD,
|
||
DWORD, DWORD, DWORD, DWORD,
|
||
DWORD, DWORD, DWORD, DWORD,
|
||
DWORD, DWORD, DWORD, DWORD,
|
||
DWORD, DWORD, DWORD, DWORD,
|
||
DWORD, DWORD, DWORD, DWORD,
|
||
DWORD, DWORD, DWORD, DWORD,
|
||
DWORD, DWORD, DWORD
|
||
);
|
||
|
||
#define BIT(bitpos) ((DWORD)1 << bitpos)
|
||
|
||
DWORD hmodKernel32, hmodUser32, hmodWow32;
|
||
DWORD pfn32;
|
||
DWORD dw16, dw32;
|
||
DWORD p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,
|
||
p11, p12, p13, p14, p15, p16, p17, p18, p19, p20,
|
||
p21, p22, p23, p24, p25, p26, p27, p28, p29, p30,
|
||
p31, p32;
|
||
char szBuf16[1024], szBuf32[1024];
|
||
char *pszErr;
|
||
|
||
hmodKernel32 = LoadLibraryEx32W("kernel32", 0, 0);
|
||
hmodUser32 = LoadLibraryEx32W("user32", 0, 0);
|
||
hmodWow32 = LoadLibraryEx32W("wow32", 0, 0);
|
||
|
||
|
||
//
|
||
// Simple printf test.
|
||
//
|
||
|
||
pfn32 = GetProcAddress32W(hmodUser32, "wsprintfA");
|
||
|
||
dw16 = wsprintf(szBuf16, "simple printf %ld", 12345678);
|
||
|
||
dw32 = CallProc32W( (DWORD)(LPSTR) szBuf32,
|
||
(DWORD)(LPSTR) "simple printf %ld",
|
||
12345678,
|
||
0,
|
||
0, 0, 0, 0,
|
||
0, 0, 0, 0,
|
||
0, 0, 0, 0,
|
||
0, 0, 0, 0,
|
||
0, 0, 0, 0,
|
||
0, 0, 0, 0,
|
||
0, 0, 0, 0,
|
||
pfn32,
|
||
BIT(30) | BIT(31),
|
||
CPEX_DEST_CDECL | 32
|
||
);
|
||
|
||
if (dw16 != dw32 || lstrcmp(szBuf16, szBuf32)) {
|
||
pszErr = "simple printf comparison failed";
|
||
goto ErrorMsg;
|
||
}
|
||
|
||
MessageBox(hwnd, "s1 success", "Genthunk Sanity Test", MB_OK);
|
||
|
||
|
||
dw32 = CallProcEx32W( CPEX_DEST_CDECL | 3,
|
||
BIT(0) | BIT(1),
|
||
pfn32,
|
||
(DWORD)(LPSTR) szBuf32,
|
||
(DWORD)(LPSTR) "simple printf %ld",
|
||
12345678 );
|
||
|
||
if (dw16 != dw32 || lstrcmp(szBuf16, szBuf32)) {
|
||
pszErr = "simple printf comparison failed (CallProcEx)";
|
||
goto ErrorMsg;
|
||
}
|
||
|
||
MessageBox(hwnd, "s2 success", "Genthunk Sanity Test", MB_OK);
|
||
|
||
//
|
||
// Complex printf test.
|
||
//
|
||
|
||
// pfn32 still points to wsprintfA
|
||
// pfn32 = GetProcAddress32W(hmodUser32, "wsprintfA");
|
||
|
||
|
||
#if 0 // this blows out Win16 wsprintf!
|
||
dw16 = wsprintf(szBuf16,
|
||
"complex printf "
|
||
"%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s "
|
||
"%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s ",
|
||
12345678,
|
||
0x87654321,
|
||
"str",
|
||
12345678,
|
||
0x87654321,
|
||
"str",
|
||
12345678,
|
||
0x87654321,
|
||
"str",
|
||
12345678,
|
||
0x87654321,
|
||
"str",
|
||
12345678,
|
||
0x87654321,
|
||
"str",
|
||
12345678,
|
||
0x87654321,
|
||
"str",
|
||
12345678,
|
||
0x87654321,
|
||
"str",
|
||
12345678,
|
||
0x87654321,
|
||
"str",
|
||
12345678,
|
||
0x87654321,
|
||
"str",
|
||
12345678,
|
||
0x87654321,
|
||
"str"
|
||
);
|
||
#else
|
||
lstrcpy(szBuf16, "complex printf "
|
||
"12345678 87654321 str "
|
||
"12345678 87654321 str "
|
||
"12345678 87654321 str "
|
||
"12345678 87654321 str "
|
||
"12345678 87654321 str "
|
||
"12345678 87654321 str "
|
||
"12345678 87654321 str "
|
||
"12345678 87654321 str "
|
||
"12345678 87654321 str "
|
||
"12345678 87654321 str "
|
||
);
|
||
dw16 = lstrlen(szBuf16);
|
||
#endif
|
||
|
||
dw32 = CallProc32W(
|
||
(DWORD)(LPSTR) szBuf32,
|
||
(DWORD)(LPSTR) "complex printf "
|
||
"%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s "
|
||
"%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s ",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
pfn32,
|
||
BIT(0) | BIT(3) | BIT(6) | BIT(9) | BIT(12) | BIT(15) |
|
||
BIT(18) | BIT(21) | BIT(24) | BIT(27) | BIT(30) | BIT(31),
|
||
CPEX_DEST_CDECL | 32
|
||
);
|
||
|
||
if (dw16 != dw32 || lstrcmp(szBuf16, szBuf32)) {
|
||
pszErr = "complex printf comparison failed";
|
||
goto ErrorMsg;
|
||
}
|
||
|
||
MessageBox(hwnd, "c1 success", "Genthunk Sanity Test", MB_OK);
|
||
|
||
dw32 = CallProcEx32W( CPEX_DEST_CDECL | 32,
|
||
BIT(0) | BIT(1) | BIT(4) | BIT(7) | BIT(10) | BIT(13) |
|
||
BIT(16) | BIT(19) | BIT(22) | BIT(25) | BIT(28) | BIT(31),
|
||
pfn32,
|
||
(DWORD)(LPSTR) szBuf32,
|
||
(DWORD)(LPSTR) "complex printf "
|
||
"%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s "
|
||
"%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s ",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str",
|
||
12345678,
|
||
0x87654321,
|
||
(DWORD)(LPSTR) "str"
|
||
);
|
||
|
||
|
||
if (dw16 != dw32 || lstrcmp(szBuf16, szBuf32)) {
|
||
pszErr = "complex printf comparison failed (CallProcEx)";
|
||
goto ErrorMsg;
|
||
}
|
||
|
||
MessageBox(hwnd, "c2 success", "Genthunk Sanity Test", MB_OK);
|
||
|
||
//
|
||
// Simple WINAPI test (GetProcAddress of LoadModule)
|
||
//
|
||
|
||
pfn32 = GetProcAddress32W(hmodKernel32, "GetProcAddress");
|
||
|
||
dw16 = GetProcAddress32W(hmodKernel32, "LoadModule");
|
||
|
||
dw32 = CallProc32W( hmodKernel32,
|
||
(DWORD)(LPSTR) "LoadModule",
|
||
0, 0,
|
||
0, 0, 0, 0,
|
||
0, 0, 0, 0,
|
||
0, 0, 0, 0,
|
||
0, 0, 0, 0,
|
||
0, 0, 0, 0,
|
||
0, 0, 0, 0,
|
||
0, 0, 0, 0,
|
||
pfn32,
|
||
BIT(30),
|
||
CPEX_DEST_STDCALL | 32
|
||
);
|
||
|
||
if (dw16 != dw32) {
|
||
pszErr = "GetProcAddress comparison failed";
|
||
goto ErrorMsg;
|
||
}
|
||
|
||
MessageBox(hwnd, "w1 success", "Genthunk Sanity Test", MB_OK);
|
||
|
||
dw32 = CallProcEx32W( CPEX_DEST_STDCALL | 2,
|
||
BIT(1),
|
||
pfn32,
|
||
hmodKernel32,
|
||
(DWORD)(LPSTR) "LoadModule" );
|
||
|
||
wsprintf(szBuf16, "GPA via CP32Ex(LoadModule) == %lx\n", dw32);
|
||
OutputDebugString(szBuf16);
|
||
if (dw16 != dw32) {
|
||
pszErr = "GetProcAddress comparison failed (CallProcEx)";
|
||
goto ErrorMsg;
|
||
}
|
||
|
||
MessageBox(hwnd, "w2 success", "Genthunk Sanity Test", MB_OK);
|
||
|
||
//
|
||
// Complex WINAPI test WOWStdCall32ArgsTestTarget exists only on
|
||
// checked WOW32.dll
|
||
//
|
||
|
||
pfn32 = GetProcAddress32W(hmodWow32, "WOWStdCall32ArgsTestTarget");
|
||
|
||
if (!pfn32) {
|
||
MessageBox(hwnd,
|
||
"WOWStdCall32ArgsTestTarget not found, use checked wow32.dll for this test.",
|
||
"Genthunk Quicktest",
|
||
MB_OK
|
||
);
|
||
goto Done;
|
||
}
|
||
|
||
p1 = 1;
|
||
p2 = 2;
|
||
p3 = 3;
|
||
p4 = 4;
|
||
p5 = 5;
|
||
p6 = 6;
|
||
p7 = 7;
|
||
p8 = 8;
|
||
p9 = 9;
|
||
p10 = 10;
|
||
p11 = 11;
|
||
p12 = 12;
|
||
p13 = 13;
|
||
p14 = 14;
|
||
p15 = 15;
|
||
p16 = 16;
|
||
p17 = 17;
|
||
p18 = 18;
|
||
p19 = 19;
|
||
p20 = 10;
|
||
p21 = 21;
|
||
p22 = 22;
|
||
p23 = 23;
|
||
p24 = 24;
|
||
p25 = 25;
|
||
p26 = 26;
|
||
p27 = 27;
|
||
p28 = 28;
|
||
p29 = 29;
|
||
p30 = 30;
|
||
p31 = 31;
|
||
p32 = 32;
|
||
|
||
dw16 = ((((p1+p2+p3+p4+p5+p6+p7+p8+p9+p10) -
|
||
(p11+p12+p13+p14+p15+p16+p17+p18+p19+p20)) << p21) +
|
||
((p22+p23+p24+p25+p26) - (p27+p28+p29+p30+p31+p32)));
|
||
|
||
dw32 = CallProc32W( p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,
|
||
p11, p12, p13, p14, p15, p16, p17, p18, p19, p20,
|
||
p21, p22,
|
||
(DWORD)(LPDWORD) &p23,
|
||
p24, p25, p26, p27, p28, p29, p30,
|
||
p31,
|
||
(DWORD)(LPDWORD) &p32,
|
||
pfn32,
|
||
BIT(9) | BIT(0),
|
||
CPEX_DEST_STDCALL | 32
|
||
);
|
||
|
||
if (dw16 != dw32) {
|
||
pszErr = "WOWStdCall32ArgsTestTarget comparison failed";
|
||
goto ErrorMsg;
|
||
}
|
||
|
||
MessageBox(hwnd, "cw1 success", "Genthunk Sanity Test", MB_OK);
|
||
|
||
dw32 = CallProcEx32W( CPEX_DEST_STDCALL | 32,
|
||
BIT(22) | BIT(31),
|
||
pfn32,
|
||
p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,
|
||
p11, p12, p13, p14, p15, p16, p17, p18, p19, p20,
|
||
p21, p22,
|
||
(DWORD)(LPDWORD) &p23,
|
||
p24, p25, p26, p27, p28, p29, p30,
|
||
p31,
|
||
(DWORD)(LPDWORD) &p32
|
||
);
|
||
|
||
if (dw16 != dw32) {
|
||
pszErr = "WOWStdCall32ArgsTestTarget comparison failed (CallProcEx)";
|
||
goto ErrorMsg;
|
||
|
||
ErrorMsg:
|
||
MessageBox(hwnd, pszErr, "Genthunk Sanity Test Failure", MB_OK);
|
||
goto Done;
|
||
}
|
||
|
||
wsprintf(szBuf16, "result of odd calc is %lx\n", dw32);
|
||
OutputDebugString(szBuf16);
|
||
|
||
MessageBox(hwnd, "Test successful!", "Genthunk Quicktest", MB_OK);
|
||
|
||
Done:
|
||
FreeLibrary32W(hmodKernel32);
|
||
FreeLibrary32W(hmodUser32);
|
||
FreeLibrary32W(hmodWow32);
|
||
}
|
||
break;
|
||
|
||
}
|
||
break;
|
||
#endif
|
||
|
||
case WM_WOWEXECSTARTAPP: // WM_USER+0
|
||
|
||
#ifdef DEBUG
|
||
OutputDebugString("WOWEXEC - got WM_WOWEXECSTARTAPP\n");
|
||
#endif
|
||
|
||
//
|
||
// Either BaseSrv or Wow32 asked us to go looking for
|
||
// commands to run.
|
||
//
|
||
|
||
if (!gfSharedWOW) {
|
||
|
||
//
|
||
// We shouldn't get this message unless we are the shared
|
||
// WOW VDM!
|
||
//
|
||
|
||
#ifdef DEBUG
|
||
OutputDebugString("WOWEXEC - separate WOW VDM got WM_WOWEXECSTARTAPP!\n");
|
||
_asm int 3;
|
||
#endif
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Start requested apps until there are no more to start.
|
||
// This handles the case where several Win16 apps are launched
|
||
// in a row, before BaseSrv has the window handle for WowExec.
|
||
//
|
||
|
||
while (StartRequestedApp()) {
|
||
/* Null stmt */ ;
|
||
}
|
||
|
||
break;
|
||
|
||
case WM_WOWEXEC_START_TASK:
|
||
{
|
||
char sz[512];
|
||
|
||
sz[ GlobalGetAtomName(wParam, sz, sizeof sz) ] = 0;
|
||
GlobalDeleteAtom(wParam);
|
||
WinExec(sz, (WORD)lParam);
|
||
}
|
||
|
||
case WM_WOWEXECHEARTBEAT:
|
||
// Probably will never get here...
|
||
break;
|
||
|
||
case WM_WOWEXECSTARTTIMER:
|
||
WowShutdownTimer(1);
|
||
break;
|
||
|
||
case WM_TIMER:
|
||
if (wParam == 1) { // timer ID
|
||
|
||
KillTimer(ghwndMain, 1);
|
||
|
||
//
|
||
// The shutdown timer has expired, meaning it's time to kill this
|
||
// shared WOW VDM. First we need to let basesrv know not to queue
|
||
// any more apps for us to start.
|
||
//
|
||
|
||
if (WOWRegisterShellWindowHandle(NULL,
|
||
&gwFirstCmdShow,
|
||
NULL
|
||
)) {
|
||
|
||
//
|
||
// BaseSrv deregistered us successfully after confirming
|
||
// there are no pending commands for us.
|
||
//
|
||
|
||
ExitKernelThunk(0);
|
||
} else {
|
||
|
||
//
|
||
// There must be pending commands for us. Might as well
|
||
// start them.
|
||
//
|
||
|
||
PostMessage(ghwndMain, WM_WOWEXECSTARTAPP, 0, 0);
|
||
}
|
||
|
||
}
|
||
|
||
break;
|
||
|
||
case WM_TIMECHANGE:
|
||
*((DWORD *)(((DWORD)40 << 16) | FIXED_NTVDMSTATE_REL40))
|
||
|= VDM_TIMECHANGE;
|
||
break;
|
||
|
||
case WM_DDE_INITIATE:
|
||
{
|
||
// In win31, the Program Manager WindowProc calls peekmessage to filterout
|
||
// otherwindowcreated and otherwindowdestroyed messages (which are atoms in win31)
|
||
// whenever it receives WM_DDE_INITIATE message.
|
||
//
|
||
// This has a side effect - basically when peekmessage is called the app ie program
|
||
// manager effectively yields allowing scheduling of other apps.
|
||
//
|
||
// So we do the side effect thing (simulate win31 behaviour) -
|
||
//
|
||
// The bug: 20221, rumba as/400 can't connect the firsttime to sna server.
|
||
// Scenario: Rumbawsf execs snasrv and blocks on yield, snasrv execs wnap and blocks
|
||
// on yield. Eventually wnap yields and rumbawsf is scheduled which
|
||
// broadcasts a ddeinitiate message. When WOWEXEC receives this message
|
||
// it will peek for nonexistent msg, which allows snasrv to get scheduled
|
||
|
||
MSG msg;
|
||
while (PeekMessage(&msg, NULL, 0xFFFF, 0xFFFF, PM_REMOVE))
|
||
DispatchMessage(&msg);
|
||
}
|
||
break;
|
||
|
||
|
||
|
||
case WM_CLOSE:
|
||
#ifdef DEBUG
|
||
ExitKernelThunk(0);
|
||
#else
|
||
// ignore since wowexec must stay around
|
||
return 0;
|
||
#endif // ! DEBUG
|
||
|
||
|
||
default:
|
||
return DefWindowProc(hwnd, message, wParam, lParam);
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
BOOL FAR PASCAL PartyDialogProc(HWND hDlg, WORD msg, WORD wParam, LONG lParam)
|
||
{
|
||
#ifdef DEBUG
|
||
BOOL f;
|
||
DWORD dw;
|
||
char szBuf[255];
|
||
|
||
switch (msg) {
|
||
|
||
case WM_INITDIALOG:
|
||
SendDlgItemMessage(hDlg, IDD_PARTY_NUMBER, EM_LIMITTEXT, 5, 0L);
|
||
SendDlgItemMessage(hDlg, IDD_PARTY_STRING, EM_LIMITTEXT, sizeof(szBuf)-1, 0L);
|
||
break;
|
||
|
||
case WM_COMMAND:
|
||
switch (wParam) {
|
||
|
||
case 0xdab /* IDCANCEL */:
|
||
EndDialog(hDlg, FALSE);
|
||
break;
|
||
|
||
case 0xdad /* IDOK */:
|
||
dw = GetDlgItemInt(hDlg, IDD_PARTY_NUMBER, &f, FALSE);
|
||
GetDlgItemText(hDlg, IDD_PARTY_STRING, szBuf, sizeof(szBuf));
|
||
WowPartyByNumber(dw, szBuf);
|
||
EndDialog(hDlg, TRUE);
|
||
break;
|
||
|
||
default:
|
||
return FALSE;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
return FALSE;
|
||
}
|
||
#endif
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
// Misc File Routines - taken from progman (pmdlg.c) mattfe apr-1 92
|
||
|
||
//-------------------------------------------------------------------------
|
||
PSTR FAR PASCAL GetFilenameFromPath
|
||
// Given a full path returns a ptr to the filename bit. Unless it's a UNC style
|
||
// path in which case
|
||
(
|
||
PSTR szPath
|
||
)
|
||
{
|
||
DWORD dummy;
|
||
PSTR pFileName;
|
||
BOOL fUNC;
|
||
|
||
|
||
GetPathInfo(szPath, &pFileName, (PSTR*) &dummy, (WORD*) &dummy,
|
||
&fUNC);
|
||
|
||
// If it's a UNC then the 'filename' part is the whole thing.
|
||
if (fUNC)
|
||
pFileName = szPath;
|
||
|
||
return pFileName;
|
||
}
|
||
|
||
|
||
//-------------------------------------------------------------------------
|
||
void NEAR PASCAL GetPathInfo
|
||
// Get pointers and an index to specific bits of a path.
|
||
// Stops scaning at first space.
|
||
(
|
||
// Uses:
|
||
PSTR szPath, // The path.
|
||
|
||
// Returns:
|
||
PSTR *pszFileName, // The start of the filename in the path.
|
||
PSTR *pszExt, // Extension part of path (starting with the dot).
|
||
WORD *pich, // Index (in DBCS characters) of filename part starting at 0.
|
||
BOOL *pfUnc // Contents set to true if it's a UNC style path.
|
||
)
|
||
{
|
||
char *pch; // Temp variable.
|
||
WORD ich = 0; // Temp.
|
||
|
||
*pszExt = NULL; // If no extension, return NULL.
|
||
*pszFileName = szPath; // If no seperate filename component, return path.
|
||
*pich = 0;
|
||
*pfUnc = FALSE; // Default to not UNC style.
|
||
|
||
// Check for UNC style paths.
|
||
if (*szPath == '\\' && *(szPath+1) == '\\')
|
||
*pfUnc = TRUE;
|
||
|
||
// Search forward to find the last backslash or colon in the path.
|
||
// While we're at it, look for the last dot.
|
||
for (pch = szPath; *pch; pch = AnsiNext(pch))
|
||
{
|
||
if (*pch == ' ')
|
||
{
|
||
// Found a space - stop here.
|
||
break;
|
||
}
|
||
if (*pch == '\\' || *pch == ':')
|
||
{
|
||
// Found it, record ptr to it and it's index.
|
||
*pszFileName = pch+1;
|
||
*pich = ich+1;
|
||
}
|
||
if (*pch == '.')
|
||
{
|
||
// Found a dot.
|
||
*pszExt = pch;
|
||
}
|
||
ich++;
|
||
}
|
||
|
||
// Check that the last dot is part of the last filename.
|
||
if (*pszExt < *pszFileName)
|
||
*pszExt = NULL;
|
||
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// StartRequestedApp
|
||
// Calls WIN32 Base GetNextVDMCommand
|
||
// and then starts the application
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
#define LargeEnvSize() 0x1000 // Size of a large env
|
||
|
||
BOOL NEAR PASCAL StartRequestedApp(VOID)
|
||
{
|
||
char achCmdLine[CCHMAX];
|
||
char achAppName[CCHMAX];
|
||
#ifdef DEBUG
|
||
char achAppNamePlusCmdLine[sizeof(achCmdLine) + sizeof(achAppName)];
|
||
int iGetNextVdmCmdLoops = 0;
|
||
#endif
|
||
char achCurDir[CCHMAX];
|
||
WOWINFO wowinfo;
|
||
BOOL b;
|
||
HANDLE hmemEnvironment;
|
||
USHORT usEnvSize;
|
||
|
||
achCmdLine[0] = '\0';
|
||
achAppName[0] = '\0';
|
||
|
||
// We start by assuming that the app will have an environment that will
|
||
// be less than a large environment size. If not then
|
||
// WowGetNextVdmCommand will fail and we will try again with the
|
||
// enviroment size needed for the app as returned from the failed
|
||
// WowGetNextVdmCommand call. If we detect that WowGetNextVdmCommand fails
|
||
// but that we have plenty of environment space then we know another
|
||
// problem has occured and we give up.
|
||
|
||
// We don't worry about wasting memory since the environment will be
|
||
// merged into another buffer and this buffer will be freed below.
|
||
|
||
wowinfo.EnvSize = LargeEnvSize();
|
||
hmemEnvironment = NULL;
|
||
|
||
do {
|
||
if (hmemEnvironment != NULL) {
|
||
GlobalUnlock(hmemEnvironment);
|
||
GlobalFree(hmemEnvironment);
|
||
}
|
||
|
||
// We need to allocate twice the space specified so that international
|
||
// character set conversions can be successful.
|
||
hmemEnvironment = GlobalAlloc(GMEM_MOVEABLE, 2*wowinfo.EnvSize);
|
||
if (hmemEnvironment == NULL) {
|
||
#ifdef DEBUG
|
||
OutputDebugString("WOWEXEC - failed to allocate Environment Memory\n");
|
||
#endif
|
||
MyMessageBox(IDS_EXECERRTITLE, IDS_NOMEMORYMSG, NULL);
|
||
return FALSE;
|
||
}
|
||
|
||
wowinfo.lpEnv = GlobalLock(hmemEnvironment);
|
||
#ifdef DEBUG
|
||
if (wowinfo.lpEnv == NULL) {
|
||
OutputDebugString("WOWEXEC ASSERT - GlobalLock failed, fix this!\n");
|
||
_asm { int 3 };
|
||
}
|
||
|
||
if (2*wowinfo.EnvSize > GlobalSize(hmemEnvironment)) {
|
||
OutputDebugString("WOWEXEC ASSERT - alloced memory too small, fix this!\n");
|
||
_asm { int 3 };
|
||
}
|
||
#endif
|
||
wowinfo.lpCmdLine = achCmdLine;
|
||
wowinfo.CmdLineSize = CCHMAX;
|
||
wowinfo.lpAppName = achAppName;
|
||
wowinfo.AppNameSize = CCHMAX;
|
||
wowinfo.CurDrive = 0;
|
||
wowinfo.lpCurDir = achCurDir;
|
||
wowinfo.CurDirSize = sizeof(achCurDir);
|
||
wowinfo.iTask = 0;
|
||
|
||
usEnvSize = wowinfo.EnvSize;
|
||
|
||
#ifdef DEBUG
|
||
if (++iGetNextVdmCmdLoops == 4) {
|
||
OutputDebugString("WOWEXEC ASSERT - Too many calls to GetNextVdmCommand\n");
|
||
_asm { int 3 };
|
||
}
|
||
#endif
|
||
} while (! (b = WowGetNextVdmCommand(&wowinfo)) &&
|
||
(wowinfo.EnvSize > usEnvSize));
|
||
|
||
if ( ! b ) {
|
||
#ifdef DEBUG
|
||
OutputDebugString("WOWEXEC - GetNextVdmCommand failed.\n");
|
||
#endif
|
||
MyMessageBox(IDS_EXECERRTITLE, IDS_NOMEMORYMSG, achCmdLine);
|
||
GlobalUnlock( hmemEnvironment );
|
||
GlobalFree( hmemEnvironment );
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// If CmdLineSize == 0, no more commands (wowexec was the command)
|
||
// see WK32WowGetNextVdm
|
||
//
|
||
if (! wowinfo.CmdLineSize) {
|
||
GlobalUnlock( hmemEnvironment );
|
||
GlobalFree( hmemEnvironment );
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
#ifdef DEBUG
|
||
lstrcpy(achAppNamePlusCmdLine, achAppName);
|
||
lstrcat(achAppNamePlusCmdLine, ":");
|
||
lstrcat(achAppNamePlusCmdLine, achCmdLine);
|
||
// Chop off trailing CRLF from command tail.
|
||
achAppNamePlusCmdLine[ lstrlen(achAppNamePlusCmdLine) - 2 ] = '\0';
|
||
|
||
OutputDebugString("WOWEXEC: CommandLine = <");
|
||
OutputDebugString(achAppNamePlusCmdLine);
|
||
OutputDebugString(">\n");
|
||
|
||
SetWindowText(ghwndMain, achAppNamePlusCmdLine);
|
||
UpdateWindow(ghwndMain);
|
||
#endif
|
||
|
||
ExecApplication(&wowinfo);
|
||
|
||
#ifdef DEBUG
|
||
|
||
if ( ! gfSharedWOW ) {
|
||
|
||
//
|
||
// If this is a separate WOW, we have just executed the one and only
|
||
// app we're going to spawn. Change our window title to
|
||
// Command Line - WOWExec so that it's easy to see which WOW this
|
||
// window is associated with. No need to worry about freeing
|
||
// this memory, since when we go away the VDM goes away and
|
||
// vice-versa.
|
||
//
|
||
|
||
lpszAppTitle = GlobalLock(
|
||
GlobalAlloc(GMEM_FIXED,
|
||
lstrlen(achAppNamePlusCmdLine) +
|
||
3 + // for " - "
|
||
lstrlen(szAppTitleBuffer) +
|
||
1 // for null terminator
|
||
));
|
||
|
||
lstrcpy(lpszAppTitle, achAppNamePlusCmdLine);
|
||
lstrcat(lpszAppTitle, " - ");
|
||
lstrcat(lpszAppTitle, szAppTitleBuffer);
|
||
}
|
||
|
||
|
||
SetWindowText(ghwndMain, lpszAppTitle);
|
||
UpdateWindow(ghwndMain);
|
||
#endif
|
||
|
||
GlobalUnlock(hmemEnvironment);
|
||
GlobalFree(hmemEnvironment);
|
||
|
||
return TRUE; // We ran an app.
|
||
}
|
||
|
||
|