Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1800 lines
56 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: wowexec.c
  3. *
  4. * Copyright (c) 1991, Microsoft Corporation
  5. *
  6. * WOWEXEC - 16 Bit Server Task - Does Exec Calls on Behalf of 32 bit CreateProcess
  7. *
  8. *
  9. * History:
  10. * 05-21-91 MattFe Ported to Windows
  11. * mar-20-92 MattFe Added Error Message Boxes (from win 3.1 progman)
  12. * apr-1-92 mattfe added commandline exec and switch to path (from win 3.1 progman)
  13. * jun-1-92 mattfe changed wowgetnextvdmcommand
  14. * 12-Nov-93 DaveHart Multiple WOW support and remove captive
  15. * GetNextVDMCommand thread from WOW32.
  16. * 16-Nov-93 DaveHart Reduce data segment size.
  17. \***************************************************************************/
  18. #include "wowexec.h"
  19. #include "wowinfo.h"
  20. #include "shellapi.h"
  21. #ifndef PULONG
  22. #define PULONG
  23. #endif
  24. #include "vint.h"
  25. #include "dde.h"
  26. /*
  27. * External Prototypes
  28. */
  29. extern WORD FAR PASCAL WOWQueryDebug( void );
  30. extern WORD FAR PASCAL WowWaitForMsgAndEvent( HWND);
  31. extern void FAR PASCAL WowMsgBox(LPSTR szMsg, LPSTR szTitle, DWORD dwOptionalStyle);
  32. extern DWORD FAR PASCAL WowPartyByNumber(DWORD dw, LPSTR psz);
  33. extern DWORD FAR PASCAL WowKillTask(WORD htask);
  34. extern void FAR PASCAL WowShutdownTimer(WORD fEnable);
  35. HWND FaxInit(HINSTANCE hInst);
  36. /*
  37. * Global Variables
  38. */
  39. HANDLE hAppInstance;
  40. HWND ghwndMain = NULL;
  41. HWND ghwndEdit = NULL;
  42. char szOOMExitTitle[32+1];
  43. char szOOMExitMsg[64+1];
  44. char szAppTitleBuffer[32];
  45. LPSTR lpszAppTitle = szAppTitleBuffer;
  46. char szWindowsDirectory[MAXITEMPATHLEN+1];
  47. char szOriginalDirectory[MAXITEMPATHLEN+1];
  48. BOOL gfSharedWOW = FALSE;
  49. BOOL gfInjectedWOW = FALSE;
  50. WORD gwFirstCmdShow;
  51. /*
  52. * Forward declarations.
  53. */
  54. BOOL InitializeApp(LPSTR lpszCommandLine);
  55. LONG FAR PASCAL WndProc(HWND hwnd, WORD message, WORD wParam, LONG lParam);
  56. WORD NEAR PASCAL ExecProgram(PWOWINFO pWowInfo);
  57. BOOL NEAR PASCAL ExecApplication(PWOWINFO pWowInfo);
  58. void NEAR PASCAL MyMessageBox(WORD idTitle, WORD idMessage, LPSTR psz);
  59. PSTR FAR PASCAL GetFilenameFromPath( PSTR szPath );
  60. void NEAR PASCAL GetPathInfo ( PSTR szPath, PSTR *pszFileName, PSTR *pszExt, WORD *pich, BOOL *pfUnc);
  61. BOOL NEAR PASCAL StartRequestedApp(VOID);
  62. #ifdef DEBUG
  63. BOOL FAR PASCAL PartyDialogProc(HWND hDlg, WORD msg, WORD wParam, LONG lParam);
  64. #endif
  65. #define AnsiNext(x) ((x)+1)
  66. typedef struct PARAMETERBLOCK {
  67. WORD wEnvSeg;
  68. LPSTR lpCmdLine;
  69. LPVOID lpCmdShow;
  70. DWORD dwReserved;
  71. } PARAMETERBLOCK, *PPARAMETERBLOCK;
  72. typedef struct CMDSHOW {
  73. WORD two;
  74. WORD nCmdShow;
  75. } CMDSHOW, *PCMDSHOW;
  76. #define CCHMAX 260+13 // MAX_PATH plus 8.3 plus NULL
  77. #define ERROR_ERROR 0
  78. #define ERROR_FILENOTFOUND 2
  79. #define ERROR_PATHNOTFOUND 3
  80. #define ERROR_MANYOPEN 4
  81. #define ERROR_DYNLINKSHARE 5
  82. #define ERROR_LIBTASKDATA 6
  83. #define ERROR_MEMORY 8
  84. #define ERROR_VERSION 10
  85. #define ERROR_BADEXE 11
  86. #define ERROR_OTHEREXE 12
  87. #define ERROR_DOS4EXE 13
  88. #define ERROR_UNKNOWNEXE 14
  89. #define ERROR_RMEXE 15
  90. #define ERROR_MULTDATAINST 16
  91. #define ERROR_PMODEONLY 18
  92. #define ERROR_COMPRESSED 19
  93. #define ERROR_DYNLINKBAD 20
  94. #define ERROR_WIN32 21
  95. /* FindPrevInstanceProc -
  96. * A little enumproc to find any window (EnumWindows) which has a
  97. * matching EXE file path. The desired match EXE pathname is pointed to
  98. * by the lParam. The found window's handle is stored in the
  99. * first word of this buffer.
  100. */
  101. BOOL CALLBACK FindPrevInstanceProc(HWND hWnd, LPSTR lpszParam)
  102. {
  103. char szT[CCHMAX];
  104. HANDLE hInstance;
  105. // Filter out invisible and disabled windows
  106. //
  107. if (!IsWindowEnabled(hWnd) || !IsWindowVisible(hWnd))
  108. return TRUE;
  109. hInstance = GetWindowWord(hWnd, GWW_HINSTANCE);
  110. GetModuleFileName(hInstance, szT, sizeof (szT)-1);
  111. // Make sure that the hWnd belongs to the current VDM process
  112. //
  113. // GetWindowTask returns the wowexec htask16 if the window belongs
  114. // to a different process - thus we filter out windows in
  115. // 'separate VDM' processes.
  116. // - nanduri
  117. if (lstrcmpi(szT, lpszParam) == 0 &&
  118. GetWindowTask(hWnd) != GetWindowTask(ghwndMain)) {
  119. *(LPHANDLE)lpszParam = hWnd;
  120. return FALSE;
  121. }
  122. else {
  123. return TRUE;
  124. }
  125. }
  126. HWND near pascal FindPopupFromExe(LPSTR lpExe)
  127. {
  128. HWND hwnd = (HWND)0;
  129. BOOL b;
  130. b = EnumWindows(FindPrevInstanceProc, (LONG)(LPSTR)lpExe);
  131. if (!b && (hwnd = *(LPHANDLE)(LPSTR)lpExe)) {
  132. // Find a "main" window that is the ancestor of a given window
  133. //
  134. HWND hwndT;
  135. // First go up the parent chain to find the popup window. Then go
  136. // up the owner chain to find the main window
  137. //
  138. while (hwndT = GetParent(hwnd))
  139. hwnd = hwndT;
  140. while (hwndT = GetWindow(hwnd, GW_OWNER))
  141. hwnd = hwndT;
  142. }
  143. return hwnd;
  144. }
  145. WORD ActivatePrevInstance(LPSTR lpszPath)
  146. {
  147. HWND hwnd;
  148. HINSTANCE ret = IDS_MULTIPLEDSMSG;
  149. if (hwnd = FindPopupFromExe(lpszPath)) {
  150. if (IsIconic(hwnd)) {
  151. ShowWindow(hwnd,SW_SHOWNORMAL);
  152. }
  153. else {
  154. HWND hwndT = GetLastActivePopup(hwnd);
  155. BringWindowToTop(hwnd);
  156. if (hwndT && hwnd != hwndT)
  157. BringWindowToTop(hwndT);
  158. }
  159. ret = 0;
  160. }
  161. return (ret);
  162. }
  163. /*--------------------------------------------------------------------------*/
  164. /* */
  165. /* ExecProgram() - */
  166. /* */
  167. /* Taken from Win 3.1 Progman -maf */
  168. /*--------------------------------------------------------------------------*/
  169. /* Returns 0 for success. Otherwise returns a IDS_ string code. */
  170. WORD NEAR PASCAL ExecProgram(PWOWINFO pWowInfo)
  171. {
  172. WORD ret;
  173. PARAMETERBLOCK ParmBlock;
  174. CMDSHOW CmdShow;
  175. char CmdLine[CCHMAX];
  176. ret = 0;
  177. // Don't mess with the mouse state; unless we're on a mouseless system.
  178. if (!GetSystemMetrics(SM_MOUSEPRESENT))
  179. ShowCursor(TRUE);
  180. //
  181. // prepare the dos style cmd line (counted pascal string)
  182. // pWowInfo->lpCmdLine contains the command tail (excluding argv[0])
  183. //
  184. CmdLine[0] = lstrlen(pWowInfo->lpCmdLine) - 2;
  185. lstrcpy( &CmdLine[1], pWowInfo->lpCmdLine);
  186. // We have a WOWINFO structure, then use it to pass the correct environment
  187. ParmBlock.wEnvSeg = HIWORD(pWowInfo->lpEnv);
  188. ParmBlock.lpCmdLine = CmdLine;
  189. ParmBlock.lpCmdShow = &CmdShow;
  190. CmdShow.two = 2;
  191. CmdShow.nCmdShow = pWowInfo->wShowWindow;
  192. ParmBlock.dwReserved = NULL;
  193. ret = LoadModule(pWowInfo->lpAppName,(LPVOID)&ParmBlock) ;
  194. switch (ret)
  195. {
  196. case ERROR_ERROR:
  197. case ERROR_MEMORY:
  198. ret = IDS_NOMEMORYMSG;
  199. break;
  200. case ERROR_FILENOTFOUND:
  201. ret = IDS_FILENOTFOUNDMSG;
  202. break;
  203. case ERROR_PATHNOTFOUND:
  204. ret = IDS_BADPATHMSG;
  205. break;
  206. case ERROR_MANYOPEN:
  207. ret = IDS_MANYOPENFILESMSG;
  208. break;
  209. case ERROR_DYNLINKSHARE:
  210. ret = IDS_ACCESSDENIED;
  211. break;
  212. case ERROR_VERSION:
  213. ret = IDS_NEWWINDOWSMSG;
  214. break;
  215. case ERROR_RMEXE:
  216. /* KERNEL has already put up a messagebox for this one. */
  217. ret = 0;
  218. break;
  219. case ERROR_MULTDATAINST:
  220. ret = ActivatePrevInstance(pWowInfo->lpAppName);
  221. break;
  222. case ERROR_COMPRESSED:
  223. ret = IDS_COMPRESSEDEXE;
  224. break;
  225. case ERROR_DYNLINKBAD:
  226. ret = IDS_INVALIDDLL;
  227. break;
  228. case SE_ERR_SHARE:
  229. ret = IDS_SHAREERROR;
  230. break;
  231. case ERROR_WIN32:
  232. ret = IDS_CANTLOADWIN32DLL;
  233. break;
  234. //
  235. // We shouldn't get any of the following errors,
  236. // so the strings have been removed from the resource
  237. // file. That's why there's the OutputDebugString
  238. // on checked builds only.
  239. //
  240. #ifdef DEBUG
  241. case ERROR_OTHEREXE:
  242. case ERROR_PMODEONLY:
  243. case SE_ERR_ASSOCINCOMPLETE:
  244. case SE_ERR_DDETIMEOUT:
  245. case SE_ERR_DDEFAIL:
  246. case SE_ERR_DDEBUSY:
  247. case SE_ERR_NOASSOC:
  248. {
  249. char szTmp[64];
  250. wsprintf(szTmp, "WOWEXEC: Unexpected error %d executing app, fix that code!\n", (int)ret);
  251. OutputDebugString(szTmp);
  252. }
  253. //
  254. // fall through to default case, so the execution
  255. // is the same as on the free build.
  256. //
  257. #endif
  258. default:
  259. if (ret < 32)
  260. goto EPExit;
  261. ret = 0;
  262. }
  263. EPExit:
  264. if (!GetSystemMetrics(SM_MOUSEPRESENT)) {
  265. /*
  266. * We want to turn the mouse off here on mouseless systems, but
  267. * the mouse will already have been turned off by USER if the
  268. * app has GP'd so make sure everything's kosher.
  269. */
  270. if (ShowCursor(FALSE) != -1)
  271. ShowCursor(TRUE);
  272. }
  273. return(ret);
  274. }
  275. /***************************************************************************\
  276. * ExecApplication
  277. *
  278. * Code Taken From Win 3.1 ExecItem()
  279. *
  280. \***************************************************************************/
  281. #define TDB_PDB_OFFSET 0x60
  282. #define PDB_ENV_OFFSET 0x2C
  283. BOOL NEAR PASCAL ExecApplication(PWOWINFO pWowInfo)
  284. {
  285. WORD ret;
  286. LPSTR szEnv;
  287. LPSTR szEnd;
  288. BYTE bDrive;
  289. WORD wSegEnvSave;
  290. HANDLE hTask;
  291. LPSTR lpTask;
  292. HANDLE hPDB;
  293. LPSTR lpPDB;
  294. HANDLE hNewEnv;
  295. int nLength;
  296. int nNewEnvLength;
  297. LPSTR lpstrEnv;
  298. LPSTR lpstr;
  299. LPSTR lpOriginalEnv;
  300. BOOL bBlanks;
  301. LPSTR szEnvTmp;
  302. if (!pWowInfo) {
  303. return FALSE;
  304. }
  305. //
  306. // Seup the environment from WOWINFO record from getvdmcommand
  307. //
  308. // Figure out who we are (so we can edit our PDB/PSP)
  309. hTask = GetCurrentTask();
  310. lpTask = GlobalLock( hTask );
  311. if ( lpTask == NULL ) {
  312. ret = IDS_NOMEMORYMSG;
  313. goto punt;
  314. }
  315. hPDB = *((LPWORD)(lpTask + TDB_PDB_OFFSET));
  316. lpPDB = GlobalLock( hPDB );
  317. // Save our environment block
  318. wSegEnvSave = *((LPWORD)(lpPDB + PDB_ENV_OFFSET));
  319. // Now determine the length of the original env
  320. lpOriginalEnv = (LPSTR)MAKELONG(0,wSegEnvSave);
  321. do {
  322. nLength = lstrlen(lpOriginalEnv);
  323. lpOriginalEnv += nLength + 1;
  324. } while ( nLength != 0 );
  325. lpOriginalEnv += 2; // Skip over magic word, see comment below
  326. nNewEnvLength = 4 + lstrlen(lpOriginalEnv); // See magic comments below!
  327. // WOW Apps cannot deal with an invalid TEMP=c:\bugusdir directory
  328. // Usually on Win 3.1 the TEMP= is checked in ldboot.asm check_temp
  329. // routine. However on NT since we get a new environment with each
  330. // WOW app it means that we have to check it here. If it is not
  331. // valid then it is edited in the environment.
  332. // - mattfe june 11 93
  333. szEnv = pWowInfo->lpEnv;
  334. szEnd = szEnv + pWowInfo->EnvSize;
  335. szEnd--;
  336. while ( szEnv < szEnd ) {
  337. nLength = lstrlen(szEnv) + 1;
  338. if ( (*szEnv == 'T') &&
  339. (*(szEnv+1) == 'E') &&
  340. (*(szEnv+2) == 'M') &&
  341. (*(szEnv+3) == 'P') &&
  342. (*(szEnv+4) == '=') ) {
  343. // Try to set the current directory to the TEMP= dir
  344. // If it fails then nuke the TEMP= part of the environment
  345. // in the same way check_TEMP does in ldboot.asm
  346. // We also scan for blanks, just like check_TEMP
  347. bBlanks = FALSE;
  348. szEnvTmp = szEnv+5;
  349. while (*szEnvTmp != 0) {
  350. if (*szEnvTmp == ' ') {
  351. bBlanks = TRUE;
  352. break;
  353. }
  354. szEnvTmp++;
  355. }
  356. if (bBlanks || (SetCurrentDirectory(szEnv+5) )) {
  357. while (*szEnv != 0) {
  358. *szEnv = 'x';
  359. szEnv++;
  360. }
  361. }
  362. break;
  363. }
  364. szEnv += nLength;
  365. }
  366. // WOW Apps only have a Single Current Directory
  367. // Find =d:=D:\path where d is the active drive letter
  368. // Note that the drive info doesn have to be at the start
  369. // of the environment.
  370. bDrive = pWowInfo->CurDrive + 'A';
  371. szEnv = pWowInfo->lpEnv;
  372. szEnd = szEnv + pWowInfo->EnvSize;
  373. szEnd--;
  374. while ( szEnv < szEnd ) {
  375. nLength = lstrlen(szEnv) + 1;
  376. if ( *szEnv == '=' ) {
  377. if ( (bDrive == (*(szEnv+1) & 0xdf)) &&
  378. (*(szEnv+2) == ':') && (*(szEnv+3) == '=') ) {
  379. SetCurrentDirectory(szEnv+4);
  380. }
  381. } else {
  382. nNewEnvLength += nLength;
  383. }
  384. szEnv += nLength;
  385. }
  386. // Now allocate and make a personal copy of the Env
  387. hNewEnv = GlobalAlloc( GMEM_MOVEABLE, (DWORD)nNewEnvLength );
  388. if ( hNewEnv == NULL ) {
  389. ret = IDS_NOMEMORYMSG;
  390. goto punt;
  391. }
  392. lpstrEnv = GlobalLock( hNewEnv );
  393. if ( lpstrEnv == NULL ) {
  394. GlobalFree( hNewEnv );
  395. ret = IDS_NOMEMORYMSG;
  396. goto punt;
  397. }
  398. // Copy only the non-current directory env variables
  399. szEnv = pWowInfo->lpEnv;
  400. lpstr = lpstrEnv;
  401. while ( szEnv < szEnd ) {
  402. nLength = lstrlen(szEnv) + 1;
  403. // Copy everything except the drive letters
  404. if ( *szEnv != '=' ) {
  405. lstrcpy( lpstr, szEnv );
  406. lpstr += nLength;
  407. }
  408. szEnv += nLength;
  409. }
  410. *lpstr++ = '\0'; // Extra '\0' on the end
  411. // Magic environment goop!
  412. //
  413. // Windows only supports the passing of environment information
  414. // using the LoadModule API. The WinExec API just causes
  415. // the application to inherit the current DOS PDB's environment.
  416. //
  417. // Also, the environment block has a little gotcha at the end. Just
  418. // after the double-nuls there is a magic WORD value 0x0001 (DOS 3.0
  419. // and later). After the value is a nul terminated string indicating
  420. // the applications executable file name (including PATH).
  421. //
  422. // We copy the value from WOWEXEC's original environment because
  423. // that is what WinExec appears to do.
  424. //
  425. // -BobDay
  426. *lpstr++ = '\1';
  427. *lpstr++ = '\0'; // Magic 0x0001 from DOS
  428. lstrcpy( lpstr, lpOriginalEnv ); // More Magic (see comment above)
  429. // Temporarily update our environment block
  430. *((LPWORD)(lpPDB + PDB_ENV_OFFSET)) = (WORD)hNewEnv | 1;
  431. pWowInfo->lpEnv = lpstrEnv;
  432. //
  433. // Set our current drive & directory as requested.
  434. //
  435. SetCurrentDirectory(pWowInfo->lpCurDir);
  436. ret = ExecProgram(pWowInfo);
  437. // Restore our environment block
  438. *((LPWORD)(lpPDB + PDB_ENV_OFFSET)) = wSegEnvSave;
  439. GlobalUnlock( hPDB );
  440. GlobalUnlock( hTask );
  441. GlobalUnlock( hNewEnv );
  442. GlobalFree( hNewEnv );
  443. punt:
  444. // Change back to the Windows Directory
  445. // So that if we are execing from a NET Drive its
  446. // Not kept Active
  447. SetCurrentDirectory(szWindowsDirectory);
  448. // Always call this when we are done try to start an app.
  449. // It will do nothing if we were successful in starting an
  450. // app, otherwise if we were unsucessful it will signal that
  451. // the app has completed.
  452. WowFailedExec();
  453. // Check for errors.
  454. if (ret) {
  455. MyMessageBox(IDS_EXECERRTITLE, ret, pWowInfo->lpAppName);
  456. if ( ! gfSharedWOW) {
  457. //
  458. // We have just failed to exec the only app we are going to
  459. // try to exec in this separate WOW VDM. We need to end WOW
  460. // here explicitly, otherwise we'll hang around forever because
  461. // the normal path is for kernel to exit the VDM when a task
  462. // exit causes the number of tasks to transition from 2 to 1 --
  463. // in this case the number of tasks never exceeds 1.
  464. //
  465. ExitKernelThunk(0);
  466. }
  467. }
  468. return(ret);
  469. }
  470. /*--------------------------------------------------------------------------*/
  471. /* */
  472. /* MyMessageBox() - */
  473. /* Taken From Win 3.1 Progman - maf */
  474. /*--------------------------------------------------------------------------*/
  475. void NEAR PASCAL MyMessageBox(WORD idTitle, WORD idMessage, LPSTR psz)
  476. {
  477. char szTitle[MAXTITLELEN+1];
  478. char szMessage[MAXMESSAGELEN+1];
  479. char szTempField[MAXMESSAGELEN+1];
  480. if (!LoadString(hAppInstance, idTitle, szTitle, sizeof(szTitle)))
  481. goto MessageBoxOOM;
  482. if (idMessage > IDS_LAST)
  483. {
  484. if (!LoadString(hAppInstance, IDS_UNKNOWNMSG, szTempField, sizeof(szTempField)))
  485. goto MessageBoxOOM;
  486. wsprintf(szMessage, szTempField, idMessage);
  487. }
  488. else
  489. {
  490. if (!LoadString(hAppInstance, idMessage, szTempField, sizeof(szTempField)))
  491. goto MessageBoxOOM;
  492. if (psz)
  493. wsprintf(szMessage, szTempField, (LPSTR)psz);
  494. else
  495. lstrcpy(szMessage, szTempField);
  496. }
  497. WowMsgBox(szMessage, szTitle, MB_ICONEXCLAMATION);
  498. return;
  499. MessageBoxOOM:
  500. WowMsgBox(szOOMExitMsg, szOOMExitTitle, MB_ICONHAND);
  501. return ;
  502. }
  503. /***************************************************************************\
  504. * main
  505. *
  506. *
  507. * History:
  508. * 04-13-91 ScottLu Created - from 32 bit exec app
  509. * 21-mar-92 mattfe significant alterations for WOW
  510. \***************************************************************************/
  511. int PASCAL WinMain(HANDLE hInstance,
  512. HANDLE hPrevInstance, LPSTR lpszCmdLine, int iCmd)
  513. {
  514. int i;
  515. MSG msg;
  516. LPSTR pch,pch1;
  517. WORD ret;
  518. WOWINFO wowinfo;
  519. char aszWOWDEB[CCHMAX];
  520. LPSTR pchWOWDEB;
  521. HANDLE hMMDriver;
  522. char szLoad[CCHMAX];
  523. int iPastSystem32Pos;
  524. char szBuffer[150];
  525. BOOL bFinished;
  526. int iStart;
  527. int iEnd;
  528. #define PATH_32_WHACK "32\\"
  529. hAppInstance = hInstance ;
  530. // Only Want One WOWExec
  531. if (hPrevInstance != NULL) {
  532. return(FALSE);
  533. }
  534. if (!InitializeApp(lpszCmdLine)) {
  535. OutputDebugString("WOWEXEC: InitializeApp failure!\n");
  536. return 0;
  537. }
  538. iPastSystem32Pos = GetSystemDirectory((LPSTR)&szLoad, sizeof(szLoad));
  539. //
  540. // Make sure to have room for 32\filename.ext\0
  541. //
  542. if (iPastSystem32Pos == 0 || iPastSystem32Pos >= CCHMAX-1-3-1-8-1-3-1) {
  543. OutputDebugString("WOWEXEC: Bad system32 directory!\n");
  544. return 0;
  545. }
  546. lstrcpyn( &(szLoad[iPastSystem32Pos]), PATH_32_WHACK, sizeof(PATH_32_WHACK));
  547. iPastSystem32Pos += sizeof(PATH_32_WHACK)-1;
  548. /*
  549. * Look for a drivers= line in the [boot] section of SYSTEM.INI
  550. * If present it is the 16 bit MultiMedia interface, so load it
  551. */
  552. /* Load DDL's from DRIVERS section in system.ini
  553. */
  554. GetPrivateProfileString( (LPSTR)"boot", /* [Boot] section */
  555. (LPSTR)"drivers", /* Drivers= */
  556. (LPSTR)"", /* Default if no match */
  557. szBuffer, /* Return buffer */
  558. sizeof(szBuffer),
  559. (LPSTR)"system.ini" );
  560. if (!*szBuffer) {
  561. goto Done;
  562. }
  563. bFinished = FALSE;
  564. iStart = 0;
  565. while (!bFinished) {
  566. iEnd = iStart;
  567. while (szBuffer[iEnd] && (szBuffer[iEnd] != ' ') &&
  568. (szBuffer[iEnd] != ',')) {
  569. iEnd++;
  570. }
  571. if (szBuffer[iEnd] == NULL) {
  572. bFinished = TRUE;
  573. }
  574. else {
  575. szBuffer[iEnd] = NULL;
  576. }
  577. /* Load and enable the driver.
  578. */
  579. OpenDriver( &(szBuffer[iStart]), NULL, NULL );
  580. iStart = iEnd + 1;
  581. }
  582. Done:
  583. /*
  584. * Look for a debug= line in the [boot] section of SYSTEM.INI
  585. * If present it is the 16 bit MultiMedia interface, so load it
  586. */
  587. if ( !gfInjectedWOW && (WOWQueryDebug() & 0x0001)!=0 ) {
  588. pchWOWDEB = "WOWDEB.EXE";
  589. } else {
  590. pchWOWDEB = "";
  591. }
  592. GetPrivateProfileString((LPSTR)"boot", (LPSTR)"debug",pchWOWDEB, aszWOWDEB, sizeof(aszWOWDEB), (LPSTR)"SYSTEM.INI");
  593. aszWOWDEB[sizeof(aszWOWDEB)-1] = '\0';
  594. if ( lstrlen(pchWOWDEB) != 0 ) {
  595. if (lstrcmp(pchWOWDEB, aszWOWDEB) == 0) {
  596. lstrcpyn(&(szLoad[iPastSystem32Pos]), pchWOWDEB, sizeof("WOWDEB.EXE"));
  597. WinExec((LPSTR)szLoad,SW_SHOW);
  598. } else {
  599. WinExec((LPSTR)aszWOWDEB,SW_SHOW);
  600. }
  601. }
  602. #if 0
  603. /* Preload winspool.exe. Apps will keep loading and freeing it
  604. * which is slow. We might as well load it now so the reference
  605. * count is 1 so it will never be loaded or freed
  606. */
  607. //
  608. // Disabled load of winspool.exe to save 8k. Size vs. speed,
  609. // which one do we care about? Right now, size!
  610. //
  611. LoadLibrary("WINSPOOL.EXE");
  612. #endif
  613. // Always load SHELL.DLL, FileMaker Pro and Lotus Install require it.
  614. lstrcpyn(&(szLoad[iPastSystem32Pos]), "SHELL.DLL", sizeof("SHELL.DLL"));
  615. LoadLibrary(szLoad);
  616. //
  617. // Start any apps pending in basesrv queue
  618. //
  619. while (StartRequestedApp() && gfSharedWOW) {
  620. /* null stmt */ ;
  621. }
  622. while (1) {
  623. WowWaitForMsgAndEvent(ghwndMain);
  624. //
  625. // Always check for messages
  626. //
  627. while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) &&
  628. msg.message != WM_WOWEXECHEARTBEAT )
  629. {
  630. if (msg.message != WM_QUIT) {
  631. TranslateMessage(&msg);
  632. DispatchMessage(&msg);
  633. }
  634. }
  635. }
  636. return 1;
  637. }
  638. /***************************************************************************\
  639. * InitializeApp
  640. *
  641. * History:
  642. * 04-13-91 ScottLu Created.
  643. \***************************************************************************/
  644. BOOL InitializeApp(LPSTR lpszCommandLine)
  645. {
  646. WNDCLASS wc;
  647. int cyExecStart, cxExecStart;
  648. USHORT TitleLen, cbCopy;
  649. HWND hwndFax;
  650. int lResult;
  651. // Remove Real Mode Segment Address
  652. wc.style = 0;
  653. wc.lpfnWndProc = WndProc;
  654. wc.cbClsExtra = 0;
  655. wc.cbWndExtra = 0;
  656. wc.hInstance = hAppInstance;
  657. wc.hIcon = LoadIcon(hAppInstance, MAKEINTRESOURCE(ID_WOWEXEC_ICON));
  658. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  659. wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  660. wc.lpszClassName = "WOWExecClass";
  661. #ifdef DEBUG
  662. wc.lpszMenuName = "MainMenu";
  663. #else
  664. wc.lpszMenuName = NULL;
  665. #endif
  666. if (!RegisterClass(&wc)) {
  667. OutputDebugString("WOWEXEC: RegisterClass failed\n");
  668. return FALSE;
  669. }
  670. /* Load these strings now. If we need them later, we won't be able to load
  671. * them at that time.
  672. */
  673. LoadString(hAppInstance, IDS_OOMEXITTITLE, szOOMExitTitle, sizeof(szOOMExitTitle));
  674. LoadString(hAppInstance, IDS_OOMEXITMSG, szOOMExitMsg, sizeof(szOOMExitMsg));
  675. LoadString(hAppInstance, IDS_APPTITLE, szAppTitleBuffer, sizeof(szAppTitleBuffer));
  676. ghwndMain = CreateWindow("WOWExecClass", lpszAppTitle,
  677. WS_OVERLAPPED | WS_CAPTION | WS_BORDER | WS_THICKFRAME |
  678. WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CLIPCHILDREN |
  679. WS_SYSMENU,
  680. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  681. NULL, NULL, hAppInstance, NULL);
  682. if (ghwndMain == NULL ) {
  683. #ifdef DEBUG
  684. OutputDebugString("WOWEXEC: ghwndMain Null\n");
  685. #endif
  686. return FALSE;
  687. }
  688. hwndFax = FaxInit(hAppInstance);
  689. //
  690. // Give our window handle to BaseSrv, which will post WM_WOWEXECSTARTAPP
  691. // messages when we have commands to pick up. The return value tells
  692. // us if we are the shared WOW VDM or not (a seperate WOW VDM).
  693. // We also pick up the ShowWindow parameter (SW_SHOW, SW_MINIMIZED, etc)
  694. // for the first WOW app here. Subsequent ones we get from BaseSrv.
  695. //
  696. //
  697. // gwFirstCmdShow is no longer used, and is available.
  698. //
  699. lResult = WOWRegisterShellWindowHandle(ghwndMain,
  700. &gwFirstCmdShow,
  701. hwndFax
  702. );
  703. if (lResult < 0) {
  704. gfInjectedWOW=TRUE;
  705. } else if (lResult > 0) {
  706. gfSharedWOW=TRUE;
  707. }
  708. //
  709. // If this isn't the shared WOW, tell the kernel to exit when the
  710. // last app (except WowExec) exits.
  711. //
  712. if (!gfSharedWOW) {
  713. WowSetExitOnLastApp(TRUE);
  714. }
  715. /* Remember the original directory. */
  716. GetCurrentDirectory(NULL, szOriginalDirectory);
  717. GetWindowsDirectory(szWindowsDirectory, MAXITEMPATHLEN+1);
  718. #ifdef DEBUG
  719. ShowWindow(ghwndMain, SW_MINIMIZE);
  720. //
  721. // If this is the shared WOW, change the app title string to
  722. // reflect this and change the window title.
  723. //
  724. if (gfSharedWOW) {
  725. LoadString(hAppInstance, IDS_SHAREDAPPTITLE, szAppTitleBuffer, sizeof(szAppTitleBuffer));
  726. }
  727. SetWindowText(ghwndMain, lpszAppTitle);
  728. UpdateWindow(ghwndMain);
  729. #endif
  730. return TRUE;
  731. }
  732. /***************************************************************************\
  733. * WndProc
  734. *
  735. * History:
  736. * 04-07-91 DarrinM Created.
  737. \***************************************************************************/
  738. LONG FAR PASCAL WndProc(
  739. HWND hwnd,
  740. WORD message,
  741. WORD wParam,
  742. LONG lParam)
  743. {
  744. char chbuf[50];
  745. HICON hIcon;
  746. switch (message) {
  747. case WM_CREATE:
  748. break;
  749. case WM_DESTROY:
  750. // ignore since wowexec must stay around
  751. return 0;
  752. #ifdef DEBUG
  753. case WM_COMMAND:
  754. switch (LOWORD(wParam)) {
  755. case MM_ABOUT:
  756. LoadString(hAppInstance, errTitle, (LPSTR)chbuf, sizeof(chbuf));
  757. hIcon = LoadIcon(hAppInstance, MAKEINTRESOURCE(ID_WOWEXEC_ICON));
  758. ShellAbout(ghwndMain, (LPSTR)chbuf, (LPSTR)lpszAppTitle, hIcon);
  759. break;
  760. case MM_BREAK:
  761. _asm int 3
  762. break;
  763. case MM_FAULT:
  764. _asm mov cs:0,ax
  765. break;
  766. case MM_EXIT:
  767. ExitKernelThunk(0);
  768. break;
  769. case MM_WATSON:
  770. WinExec("drwatson", SW_MINIMIZE );
  771. break;
  772. case MM_PARTY:
  773. {
  774. FARPROC lpPartyDialogProc;
  775. lpPartyDialogProc = MakeProcInstance(PartyDialogProc, hAppInstance);
  776. DialogBox(hAppInstance, MAKEINTRESOURCE(ID_PARTY_DIALOG),
  777. hwnd, lpPartyDialogProc);
  778. FreeProcInstance(lpPartyDialogProc);
  779. }
  780. break;
  781. case MM_GENTHUNK:
  782. {
  783. DWORD FAR PASCAL CallProc32W(DWORD, DWORD, DWORD, DWORD,
  784. DWORD, DWORD, DWORD, DWORD,
  785. DWORD, DWORD, DWORD, DWORD,
  786. DWORD, DWORD, DWORD, DWORD,
  787. DWORD, DWORD, DWORD, DWORD,
  788. DWORD, DWORD, DWORD, DWORD,
  789. DWORD, DWORD, DWORD, DWORD,
  790. DWORD, DWORD, DWORD, DWORD,
  791. DWORD, DWORD, DWORD
  792. );
  793. #define BIT(bitpos) ((DWORD)1 << bitpos)
  794. DWORD hmodKernel32, hmodUser32, hmodWow32;
  795. DWORD pfn32;
  796. DWORD dw16, dw32;
  797. DWORD p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,
  798. p11, p12, p13, p14, p15, p16, p17, p18, p19, p20,
  799. p21, p22, p23, p24, p25, p26, p27, p28, p29, p30,
  800. p31, p32;
  801. char szBuf16[1024], szBuf32[1024];
  802. char *pszErr;
  803. hmodKernel32 = LoadLibraryEx32W("kernel32", 0, 0);
  804. hmodUser32 = LoadLibraryEx32W("user32", 0, 0);
  805. hmodWow32 = LoadLibraryEx32W("wow32", 0, 0);
  806. //
  807. // Simple printf test.
  808. //
  809. pfn32 = GetProcAddress32W(hmodUser32, "wsprintfA");
  810. dw16 = wsprintf(szBuf16, "simple printf %ld", 12345678);
  811. dw32 = CallProc32W( (DWORD)(LPSTR) szBuf32,
  812. (DWORD)(LPSTR) "simple printf %ld",
  813. 12345678,
  814. 0,
  815. 0, 0, 0, 0,
  816. 0, 0, 0, 0,
  817. 0, 0, 0, 0,
  818. 0, 0, 0, 0,
  819. 0, 0, 0, 0,
  820. 0, 0, 0, 0,
  821. 0, 0, 0, 0,
  822. pfn32,
  823. BIT(30) | BIT(31),
  824. CPEX_DEST_CDECL | 32
  825. );
  826. if (dw16 != dw32 || lstrcmp(szBuf16, szBuf32)) {
  827. pszErr = "simple printf comparison failed";
  828. goto ErrorMsg;
  829. }
  830. MessageBox(hwnd, "s1 success", "Genthunk Sanity Test", MB_OK);
  831. dw32 = CallProcEx32W( CPEX_DEST_CDECL | 3,
  832. BIT(0) | BIT(1),
  833. pfn32,
  834. (DWORD)(LPSTR) szBuf32,
  835. (DWORD)(LPSTR) "simple printf %ld",
  836. 12345678 );
  837. if (dw16 != dw32 || lstrcmp(szBuf16, szBuf32)) {
  838. pszErr = "simple printf comparison failed (CallProcEx)";
  839. goto ErrorMsg;
  840. }
  841. MessageBox(hwnd, "s2 success", "Genthunk Sanity Test", MB_OK);
  842. //
  843. // Complex printf test.
  844. //
  845. // pfn32 still points to wsprintfA
  846. // pfn32 = GetProcAddress32W(hmodUser32, "wsprintfA");
  847. #if 0 // this blows out Win16 wsprintf!
  848. dw16 = wsprintf(szBuf16,
  849. "complex printf "
  850. "%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s "
  851. "%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s ",
  852. 12345678,
  853. 0x87654321,
  854. "str",
  855. 12345678,
  856. 0x87654321,
  857. "str",
  858. 12345678,
  859. 0x87654321,
  860. "str",
  861. 12345678,
  862. 0x87654321,
  863. "str",
  864. 12345678,
  865. 0x87654321,
  866. "str",
  867. 12345678,
  868. 0x87654321,
  869. "str",
  870. 12345678,
  871. 0x87654321,
  872. "str",
  873. 12345678,
  874. 0x87654321,
  875. "str",
  876. 12345678,
  877. 0x87654321,
  878. "str",
  879. 12345678,
  880. 0x87654321,
  881. "str"
  882. );
  883. #else
  884. lstrcpy(szBuf16, "complex printf "
  885. "12345678 87654321 str "
  886. "12345678 87654321 str "
  887. "12345678 87654321 str "
  888. "12345678 87654321 str "
  889. "12345678 87654321 str "
  890. "12345678 87654321 str "
  891. "12345678 87654321 str "
  892. "12345678 87654321 str "
  893. "12345678 87654321 str "
  894. "12345678 87654321 str "
  895. );
  896. dw16 = lstrlen(szBuf16);
  897. #endif
  898. dw32 = CallProc32W(
  899. (DWORD)(LPSTR) szBuf32,
  900. (DWORD)(LPSTR) "complex printf "
  901. "%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s "
  902. "%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s ",
  903. 12345678,
  904. 0x87654321,
  905. (DWORD)(LPSTR) "str",
  906. 12345678,
  907. 0x87654321,
  908. (DWORD)(LPSTR) "str",
  909. 12345678,
  910. 0x87654321,
  911. (DWORD)(LPSTR) "str",
  912. 12345678,
  913. 0x87654321,
  914. (DWORD)(LPSTR) "str",
  915. 12345678,
  916. 0x87654321,
  917. (DWORD)(LPSTR) "str",
  918. 12345678,
  919. 0x87654321,
  920. (DWORD)(LPSTR) "str",
  921. 12345678,
  922. 0x87654321,
  923. (DWORD)(LPSTR) "str",
  924. 12345678,
  925. 0x87654321,
  926. (DWORD)(LPSTR) "str",
  927. 12345678,
  928. 0x87654321,
  929. (DWORD)(LPSTR) "str",
  930. 12345678,
  931. 0x87654321,
  932. (DWORD)(LPSTR) "str",
  933. pfn32,
  934. BIT(0) | BIT(3) | BIT(6) | BIT(9) | BIT(12) | BIT(15) |
  935. BIT(18) | BIT(21) | BIT(24) | BIT(27) | BIT(30) | BIT(31),
  936. CPEX_DEST_CDECL | 32
  937. );
  938. if (dw16 != dw32 || lstrcmp(szBuf16, szBuf32)) {
  939. pszErr = "complex printf comparison failed";
  940. goto ErrorMsg;
  941. }
  942. MessageBox(hwnd, "c1 success", "Genthunk Sanity Test", MB_OK);
  943. dw32 = CallProcEx32W( CPEX_DEST_CDECL | 32,
  944. BIT(0) | BIT(1) | BIT(4) | BIT(7) | BIT(10) | BIT(13) |
  945. BIT(16) | BIT(19) | BIT(22) | BIT(25) | BIT(28) | BIT(31),
  946. pfn32,
  947. (DWORD)(LPSTR) szBuf32,
  948. (DWORD)(LPSTR) "complex printf "
  949. "%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s "
  950. "%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s ",
  951. 12345678,
  952. 0x87654321,
  953. (DWORD)(LPSTR) "str",
  954. 12345678,
  955. 0x87654321,
  956. (DWORD)(LPSTR) "str",
  957. 12345678,
  958. 0x87654321,
  959. (DWORD)(LPSTR) "str",
  960. 12345678,
  961. 0x87654321,
  962. (DWORD)(LPSTR) "str",
  963. 12345678,
  964. 0x87654321,
  965. (DWORD)(LPSTR) "str",
  966. 12345678,
  967. 0x87654321,
  968. (DWORD)(LPSTR) "str",
  969. 12345678,
  970. 0x87654321,
  971. (DWORD)(LPSTR) "str",
  972. 12345678,
  973. 0x87654321,
  974. (DWORD)(LPSTR) "str",
  975. 12345678,
  976. 0x87654321,
  977. (DWORD)(LPSTR) "str",
  978. 12345678,
  979. 0x87654321,
  980. (DWORD)(LPSTR) "str"
  981. );
  982. if (dw16 != dw32 || lstrcmp(szBuf16, szBuf32)) {
  983. pszErr = "complex printf comparison failed (CallProcEx)";
  984. goto ErrorMsg;
  985. }
  986. MessageBox(hwnd, "c2 success", "Genthunk Sanity Test", MB_OK);
  987. //
  988. // Simple WINAPI test (GetProcAddress of LoadModule)
  989. //
  990. pfn32 = GetProcAddress32W(hmodKernel32, "GetProcAddress");
  991. dw16 = GetProcAddress32W(hmodKernel32, "LoadModule");
  992. dw32 = CallProc32W( hmodKernel32,
  993. (DWORD)(LPSTR) "LoadModule",
  994. 0, 0,
  995. 0, 0, 0, 0,
  996. 0, 0, 0, 0,
  997. 0, 0, 0, 0,
  998. 0, 0, 0, 0,
  999. 0, 0, 0, 0,
  1000. 0, 0, 0, 0,
  1001. 0, 0, 0, 0,
  1002. pfn32,
  1003. BIT(30),
  1004. CPEX_DEST_STDCALL | 32
  1005. );
  1006. if (dw16 != dw32) {
  1007. pszErr = "GetProcAddress comparison failed";
  1008. goto ErrorMsg;
  1009. }
  1010. MessageBox(hwnd, "w1 success", "Genthunk Sanity Test", MB_OK);
  1011. dw32 = CallProcEx32W( CPEX_DEST_STDCALL | 2,
  1012. BIT(1),
  1013. pfn32,
  1014. hmodKernel32,
  1015. (DWORD)(LPSTR) "LoadModule" );
  1016. wsprintf(szBuf16, "GPA via CP32Ex(LoadModule) == %lx\n", dw32);
  1017. OutputDebugString(szBuf16);
  1018. if (dw16 != dw32) {
  1019. pszErr = "GetProcAddress comparison failed (CallProcEx)";
  1020. goto ErrorMsg;
  1021. }
  1022. MessageBox(hwnd, "w2 success", "Genthunk Sanity Test", MB_OK);
  1023. //
  1024. // Complex WINAPI test WOWStdCall32ArgsTestTarget exists only on
  1025. // checked WOW32.dll
  1026. //
  1027. pfn32 = GetProcAddress32W(hmodWow32, "WOWStdCall32ArgsTestTarget");
  1028. if (!pfn32) {
  1029. MessageBox(hwnd,
  1030. "WOWStdCall32ArgsTestTarget not found, use checked wow32.dll for this test.",
  1031. "Genthunk Quicktest",
  1032. MB_OK
  1033. );
  1034. goto Done;
  1035. }
  1036. p1 = 1;
  1037. p2 = 2;
  1038. p3 = 3;
  1039. p4 = 4;
  1040. p5 = 5;
  1041. p6 = 6;
  1042. p7 = 7;
  1043. p8 = 8;
  1044. p9 = 9;
  1045. p10 = 10;
  1046. p11 = 11;
  1047. p12 = 12;
  1048. p13 = 13;
  1049. p14 = 14;
  1050. p15 = 15;
  1051. p16 = 16;
  1052. p17 = 17;
  1053. p18 = 18;
  1054. p19 = 19;
  1055. p20 = 10;
  1056. p21 = 21;
  1057. p22 = 22;
  1058. p23 = 23;
  1059. p24 = 24;
  1060. p25 = 25;
  1061. p26 = 26;
  1062. p27 = 27;
  1063. p28 = 28;
  1064. p29 = 29;
  1065. p30 = 30;
  1066. p31 = 31;
  1067. p32 = 32;
  1068. dw16 = ((((p1+p2+p3+p4+p5+p6+p7+p8+p9+p10) -
  1069. (p11+p12+p13+p14+p15+p16+p17+p18+p19+p20)) << p21) +
  1070. ((p22+p23+p24+p25+p26) - (p27+p28+p29+p30+p31+p32)));
  1071. dw32 = CallProc32W( p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,
  1072. p11, p12, p13, p14, p15, p16, p17, p18, p19, p20,
  1073. p21, p22,
  1074. (DWORD)(LPDWORD) &p23,
  1075. p24, p25, p26, p27, p28, p29, p30,
  1076. p31,
  1077. (DWORD)(LPDWORD) &p32,
  1078. pfn32,
  1079. BIT(9) | BIT(0),
  1080. CPEX_DEST_STDCALL | 32
  1081. );
  1082. if (dw16 != dw32) {
  1083. pszErr = "WOWStdCall32ArgsTestTarget comparison failed";
  1084. goto ErrorMsg;
  1085. }
  1086. MessageBox(hwnd, "cw1 success", "Genthunk Sanity Test", MB_OK);
  1087. dw32 = CallProcEx32W( CPEX_DEST_STDCALL | 32,
  1088. BIT(22) | BIT(31),
  1089. pfn32,
  1090. p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,
  1091. p11, p12, p13, p14, p15, p16, p17, p18, p19, p20,
  1092. p21, p22,
  1093. (DWORD)(LPDWORD) &p23,
  1094. p24, p25, p26, p27, p28, p29, p30,
  1095. p31,
  1096. (DWORD)(LPDWORD) &p32
  1097. );
  1098. if (dw16 != dw32) {
  1099. pszErr = "WOWStdCall32ArgsTestTarget comparison failed (CallProcEx)";
  1100. goto ErrorMsg;
  1101. ErrorMsg:
  1102. MessageBox(hwnd, pszErr, "Genthunk Sanity Test Failure", MB_OK);
  1103. goto Done;
  1104. }
  1105. wsprintf(szBuf16, "result of odd calc is %lx\n", dw32);
  1106. OutputDebugString(szBuf16);
  1107. MessageBox(hwnd, "Test successful!", "Genthunk Quicktest", MB_OK);
  1108. Done:
  1109. FreeLibrary32W(hmodKernel32);
  1110. FreeLibrary32W(hmodUser32);
  1111. FreeLibrary32W(hmodWow32);
  1112. }
  1113. break;
  1114. }
  1115. break;
  1116. #endif
  1117. case WM_WOWEXECSTARTAPP: // WM_USER+0
  1118. #ifdef DEBUG
  1119. OutputDebugString("WOWEXEC - got WM_WOWEXECSTARTAPP\n");
  1120. #endif
  1121. //
  1122. // Either BaseSrv or Wow32 asked us to go looking for
  1123. // commands to run.
  1124. //
  1125. if (!gfSharedWOW) {
  1126. //
  1127. // We shouldn't get this message unless we are the shared
  1128. // WOW VDM!
  1129. //
  1130. #ifdef DEBUG
  1131. OutputDebugString("WOWEXEC - separate WOW VDM got WM_WOWEXECSTARTAPP!\n");
  1132. _asm int 3;
  1133. #endif
  1134. break;
  1135. }
  1136. //
  1137. // Start requested apps until there are no more to start.
  1138. // This handles the case where several Win16 apps are launched
  1139. // in a row, before BaseSrv has the window handle for WowExec.
  1140. //
  1141. while (StartRequestedApp()) {
  1142. /* Null stmt */ ;
  1143. }
  1144. break;
  1145. case WM_WOWEXEC_START_TASK:
  1146. {
  1147. char sz[512];
  1148. sz[ GlobalGetAtomName(wParam, sz, sizeof sz) ] = 0;
  1149. GlobalDeleteAtom(wParam);
  1150. WinExec(sz, (WORD)lParam);
  1151. }
  1152. case WM_WOWEXECHEARTBEAT:
  1153. // Probably will never get here...
  1154. break;
  1155. case WM_WOWEXECSTARTTIMER:
  1156. WowShutdownTimer(1);
  1157. break;
  1158. case WM_TIMER:
  1159. if (wParam == 1) { // timer ID
  1160. KillTimer(ghwndMain, 1);
  1161. //
  1162. // The shutdown timer has expired, meaning it's time to kill this
  1163. // shared WOW VDM. First we need to let basesrv know not to queue
  1164. // any more apps for us to start.
  1165. //
  1166. if (WOWRegisterShellWindowHandle(NULL,
  1167. &gwFirstCmdShow,
  1168. NULL
  1169. )) {
  1170. //
  1171. // BaseSrv deregistered us successfully after confirming
  1172. // there are no pending commands for us.
  1173. //
  1174. ExitKernelThunk(0);
  1175. } else {
  1176. //
  1177. // There must be pending commands for us. Might as well
  1178. // start them.
  1179. //
  1180. PostMessage(ghwndMain, WM_WOWEXECSTARTAPP, 0, 0);
  1181. }
  1182. }
  1183. break;
  1184. case WM_TIMECHANGE:
  1185. *((DWORD *)(((DWORD)40 << 16) | FIXED_NTVDMSTATE_REL40))
  1186. |= VDM_TIMECHANGE;
  1187. break;
  1188. case WM_DDE_INITIATE:
  1189. {
  1190. // In win31, the Program Manager WindowProc calls peekmessage to filterout
  1191. // otherwindowcreated and otherwindowdestroyed messages (which are atoms in win31)
  1192. // whenever it receives WM_DDE_INITIATE message.
  1193. //
  1194. // This has a side effect - basically when peekmessage is called the app ie program
  1195. // manager effectively yields allowing scheduling of other apps.
  1196. //
  1197. // So we do the side effect thing (simulate win31 behaviour) -
  1198. //
  1199. // The bug: 20221, rumba as/400 can't connect the firsttime to sna server.
  1200. // Scenario: Rumbawsf execs snasrv and blocks on yield, snasrv execs wnap and blocks
  1201. // on yield. Eventually wnap yields and rumbawsf is scheduled which
  1202. // broadcasts a ddeinitiate message. When WOWEXEC receives this message
  1203. // it will peek for nonexistent msg, which allows snasrv to get scheduled
  1204. MSG msg;
  1205. while (PeekMessage(&msg, NULL, 0xFFFF, 0xFFFF, PM_REMOVE))
  1206. DispatchMessage(&msg);
  1207. }
  1208. break;
  1209. case WM_CLOSE:
  1210. #ifdef DEBUG
  1211. ExitKernelThunk(0);
  1212. #else
  1213. // ignore since wowexec must stay around
  1214. return 0;
  1215. #endif // ! DEBUG
  1216. default:
  1217. return DefWindowProc(hwnd, message, wParam, lParam);
  1218. }
  1219. return 1;
  1220. }
  1221. BOOL FAR PASCAL PartyDialogProc(HWND hDlg, WORD msg, WORD wParam, LONG lParam)
  1222. {
  1223. #ifdef DEBUG
  1224. BOOL f;
  1225. DWORD dw;
  1226. char szBuf[255];
  1227. switch (msg) {
  1228. case WM_INITDIALOG:
  1229. SendDlgItemMessage(hDlg, IDD_PARTY_NUMBER, EM_LIMITTEXT, 5, 0L);
  1230. SendDlgItemMessage(hDlg, IDD_PARTY_STRING, EM_LIMITTEXT, sizeof(szBuf)-1, 0L);
  1231. break;
  1232. case WM_COMMAND:
  1233. switch (wParam) {
  1234. case 0xdab /* IDCANCEL */:
  1235. EndDialog(hDlg, FALSE);
  1236. break;
  1237. case 0xdad /* IDOK */:
  1238. dw = GetDlgItemInt(hDlg, IDD_PARTY_NUMBER, &f, FALSE);
  1239. GetDlgItemText(hDlg, IDD_PARTY_STRING, szBuf, sizeof(szBuf));
  1240. WowPartyByNumber(dw, szBuf);
  1241. EndDialog(hDlg, TRUE);
  1242. break;
  1243. default:
  1244. return FALSE;
  1245. }
  1246. break;
  1247. default:
  1248. return FALSE;
  1249. }
  1250. #endif
  1251. return TRUE;
  1252. }
  1253. // Misc File Routines - taken from progman (pmdlg.c) mattfe apr-1 92
  1254. //-------------------------------------------------------------------------
  1255. PSTR FAR PASCAL GetFilenameFromPath
  1256. // Given a full path returns a ptr to the filename bit. Unless it's a UNC style
  1257. // path in which case
  1258. (
  1259. PSTR szPath
  1260. )
  1261. {
  1262. DWORD dummy;
  1263. PSTR pFileName;
  1264. BOOL fUNC;
  1265. GetPathInfo(szPath, &pFileName, (PSTR*) &dummy, (WORD*) &dummy,
  1266. &fUNC);
  1267. // If it's a UNC then the 'filename' part is the whole thing.
  1268. if (fUNC)
  1269. pFileName = szPath;
  1270. return pFileName;
  1271. }
  1272. //-------------------------------------------------------------------------
  1273. void NEAR PASCAL GetPathInfo
  1274. // Get pointers and an index to specific bits of a path.
  1275. // Stops scaning at first space.
  1276. (
  1277. // Uses:
  1278. PSTR szPath, // The path.
  1279. // Returns:
  1280. PSTR *pszFileName, // The start of the filename in the path.
  1281. PSTR *pszExt, // Extension part of path (starting with the dot).
  1282. WORD *pich, // Index (in DBCS characters) of filename part starting at 0.
  1283. BOOL *pfUnc // Contents set to true if it's a UNC style path.
  1284. )
  1285. {
  1286. char *pch; // Temp variable.
  1287. WORD ich = 0; // Temp.
  1288. *pszExt = NULL; // If no extension, return NULL.
  1289. *pszFileName = szPath; // If no seperate filename component, return path.
  1290. *pich = 0;
  1291. *pfUnc = FALSE; // Default to not UNC style.
  1292. // Check for UNC style paths.
  1293. if (*szPath == '\\' && *(szPath+1) == '\\')
  1294. *pfUnc = TRUE;
  1295. // Search forward to find the last backslash or colon in the path.
  1296. // While we're at it, look for the last dot.
  1297. for (pch = szPath; *pch; pch = AnsiNext(pch))
  1298. {
  1299. if (*pch == ' ')
  1300. {
  1301. // Found a space - stop here.
  1302. break;
  1303. }
  1304. if (*pch == '\\' || *pch == ':')
  1305. {
  1306. // Found it, record ptr to it and it's index.
  1307. *pszFileName = pch+1;
  1308. *pich = ich+1;
  1309. }
  1310. if (*pch == '.')
  1311. {
  1312. // Found a dot.
  1313. *pszExt = pch;
  1314. }
  1315. ich++;
  1316. }
  1317. // Check that the last dot is part of the last filename.
  1318. if (*pszExt < *pszFileName)
  1319. *pszExt = NULL;
  1320. }
  1321. //-----------------------------------------------------------------------------
  1322. // StartRequestedApp
  1323. // Calls WIN32 Base GetNextVDMCommand
  1324. // and then starts the application
  1325. //
  1326. //-----------------------------------------------------------------------------
  1327. #define LargeEnvSize() 0x1000 // Size of a large env
  1328. BOOL NEAR PASCAL StartRequestedApp(VOID)
  1329. {
  1330. char achCmdLine[CCHMAX];
  1331. char achAppName[CCHMAX];
  1332. #ifdef DEBUG
  1333. char achAppNamePlusCmdLine[sizeof(achCmdLine) + sizeof(achAppName)];
  1334. int iGetNextVdmCmdLoops = 0;
  1335. #endif
  1336. char achCurDir[CCHMAX];
  1337. WOWINFO wowinfo;
  1338. BOOL b;
  1339. HANDLE hmemEnvironment;
  1340. USHORT usEnvSize;
  1341. achCmdLine[0] = '\0';
  1342. achAppName[0] = '\0';
  1343. // We start by assuming that the app will have an environment that will
  1344. // be less than a large environment size. If not then
  1345. // WowGetNextVdmCommand will fail and we will try again with the
  1346. // enviroment size needed for the app as returned from the failed
  1347. // WowGetNextVdmCommand call. If we detect that WowGetNextVdmCommand fails
  1348. // but that we have plenty of environment space then we know another
  1349. // problem has occured and we give up.
  1350. // We don't worry about wasting memory since the environment will be
  1351. // merged into another buffer and this buffer will be freed below.
  1352. wowinfo.EnvSize = LargeEnvSize();
  1353. hmemEnvironment = NULL;
  1354. do {
  1355. if (hmemEnvironment != NULL) {
  1356. GlobalUnlock(hmemEnvironment);
  1357. GlobalFree(hmemEnvironment);
  1358. }
  1359. // We need to allocate twice the space specified so that international
  1360. // character set conversions can be successful.
  1361. hmemEnvironment = GlobalAlloc(GMEM_MOVEABLE, 2*wowinfo.EnvSize);
  1362. if (hmemEnvironment == NULL) {
  1363. #ifdef DEBUG
  1364. OutputDebugString("WOWEXEC - failed to allocate Environment Memory\n");
  1365. #endif
  1366. MyMessageBox(IDS_EXECERRTITLE, IDS_NOMEMORYMSG, NULL);
  1367. return FALSE;
  1368. }
  1369. wowinfo.lpEnv = GlobalLock(hmemEnvironment);
  1370. #ifdef DEBUG
  1371. if (wowinfo.lpEnv == NULL) {
  1372. OutputDebugString("WOWEXEC ASSERT - GlobalLock failed, fix this!\n");
  1373. _asm { int 3 };
  1374. }
  1375. if (2*wowinfo.EnvSize > GlobalSize(hmemEnvironment)) {
  1376. OutputDebugString("WOWEXEC ASSERT - alloced memory too small, fix this!\n");
  1377. _asm { int 3 };
  1378. }
  1379. #endif
  1380. wowinfo.lpCmdLine = achCmdLine;
  1381. wowinfo.CmdLineSize = CCHMAX;
  1382. wowinfo.lpAppName = achAppName;
  1383. wowinfo.AppNameSize = CCHMAX;
  1384. wowinfo.CurDrive = 0;
  1385. wowinfo.lpCurDir = achCurDir;
  1386. wowinfo.CurDirSize = sizeof(achCurDir);
  1387. wowinfo.iTask = 0;
  1388. usEnvSize = wowinfo.EnvSize;
  1389. #ifdef DEBUG
  1390. if (++iGetNextVdmCmdLoops == 4) {
  1391. OutputDebugString("WOWEXEC ASSERT - Too many calls to GetNextVdmCommand\n");
  1392. _asm { int 3 };
  1393. }
  1394. #endif
  1395. } while (! (b = WowGetNextVdmCommand(&wowinfo)) &&
  1396. (wowinfo.EnvSize > usEnvSize));
  1397. if ( ! b ) {
  1398. #ifdef DEBUG
  1399. OutputDebugString("WOWEXEC - GetNextVdmCommand failed.\n");
  1400. #endif
  1401. MyMessageBox(IDS_EXECERRTITLE, IDS_NOMEMORYMSG, achCmdLine);
  1402. GlobalUnlock( hmemEnvironment );
  1403. GlobalFree( hmemEnvironment );
  1404. return FALSE;
  1405. }
  1406. //
  1407. // If CmdLineSize == 0, no more commands (wowexec was the command)
  1408. // see WK32WowGetNextVdm
  1409. //
  1410. if (! wowinfo.CmdLineSize) {
  1411. GlobalUnlock( hmemEnvironment );
  1412. GlobalFree( hmemEnvironment );
  1413. return FALSE;
  1414. }
  1415. #ifdef DEBUG
  1416. lstrcpy(achAppNamePlusCmdLine, achAppName);
  1417. lstrcat(achAppNamePlusCmdLine, ":");
  1418. lstrcat(achAppNamePlusCmdLine, achCmdLine);
  1419. // Chop off trailing CRLF from command tail.
  1420. achAppNamePlusCmdLine[ lstrlen(achAppNamePlusCmdLine) - 2 ] = '\0';
  1421. OutputDebugString("WOWEXEC: CommandLine = <");
  1422. OutputDebugString(achAppNamePlusCmdLine);
  1423. OutputDebugString(">\n");
  1424. SetWindowText(ghwndMain, achAppNamePlusCmdLine);
  1425. UpdateWindow(ghwndMain);
  1426. #endif
  1427. ExecApplication(&wowinfo);
  1428. #ifdef DEBUG
  1429. if ( ! gfSharedWOW ) {
  1430. //
  1431. // If this is a separate WOW, we have just executed the one and only
  1432. // app we're going to spawn. Change our window title to
  1433. // Command Line - WOWExec so that it's easy to see which WOW this
  1434. // window is associated with. No need to worry about freeing
  1435. // this memory, since when we go away the VDM goes away and
  1436. // vice-versa.
  1437. //
  1438. lpszAppTitle = GlobalLock(
  1439. GlobalAlloc(GMEM_FIXED,
  1440. lstrlen(achAppNamePlusCmdLine) +
  1441. 3 + // for " - "
  1442. lstrlen(szAppTitleBuffer) +
  1443. 1 // for null terminator
  1444. ));
  1445. lstrcpy(lpszAppTitle, achAppNamePlusCmdLine);
  1446. lstrcat(lpszAppTitle, " - ");
  1447. lstrcat(lpszAppTitle, szAppTitleBuffer);
  1448. }
  1449. SetWindowText(ghwndMain, lpszAppTitle);
  1450. UpdateWindow(ghwndMain);
  1451. #endif
  1452. GlobalUnlock(hmemEnvironment);
  1453. GlobalFree(hmemEnvironment);
  1454. return TRUE; // We ran an app.
  1455. }
  1456.