Source code of Windows XP (NT5)
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.

1796 lines
54 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 gfMeow = 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 256+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[260];
  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 szBuffer[150];
  523. BOOL bFinished;
  524. int iStart;
  525. int iEnd;
  526. hAppInstance = hInstance ;
  527. // Only Want One WOWExec
  528. if (hPrevInstance != NULL) {
  529. return(FALSE);
  530. }
  531. if (!InitializeApp(lpszCmdLine)) {
  532. OutputDebugString("WOWEXEC: InitializeApp failure!\n");
  533. return 0;
  534. }
  535. /*
  536. * Look for a drivers= line in the [boot] section of SYSTEM.INI
  537. * If present it is the 16 bit MultiMedia interface, so load it
  538. */
  539. #ifdef OLD_MMSYSTEM_LOAD
  540. if (GetPrivateProfileString((LPSTR)"boot", (LPSTR)"drivers",(LPSTR)"", aszMMDriver, sizeof(aszMMDriver), (LPSTR)"SYSTEM.INI")) {
  541. /*
  542. * We have now discovered an app that rewrites the "drivers" entry with
  543. * multiple drivers - so the existing load method fails. As a temporary fix
  544. * while we decide what the "proper" fix is I will always load MMSYSTEM and
  545. * ONLY MMSYSTEM.
  546. *
  547. * aszMMDriver[sizeof(aszMMDriver)-1] = '\0';
  548. * hMMDriver = LoadLibrary((LPSTR)aszMMDriver);
  549. * #ifdef DEBUG
  550. * if (hMMDriver < 32) {
  551. * OutputDebugString("WOWEXEC: Load of MultiMedia driver failed\n");
  552. * }
  553. * #endif
  554. */
  555. LoadLibrary("MMSYSTEM.DLL");
  556. }
  557. #else
  558. /* Load DDL's from DRIVERS section in system.ini
  559. */
  560. GetPrivateProfileString( (LPSTR)"boot", /* [Boot] section */
  561. (LPSTR)"drivers", /* Drivers= */
  562. (LPSTR)"", /* Default if no match */
  563. szBuffer, /* Return buffer */
  564. sizeof(szBuffer),
  565. (LPSTR)"system.ini" );
  566. if (!*szBuffer) {
  567. goto Done;
  568. }
  569. bFinished = FALSE;
  570. iStart = 0;
  571. while (!bFinished) {
  572. iEnd = iStart;
  573. while (szBuffer[iEnd] && (szBuffer[iEnd] != ' ') &&
  574. (szBuffer[iEnd] != ',')) {
  575. iEnd++;
  576. }
  577. if (szBuffer[iEnd] == NULL) {
  578. bFinished = TRUE;
  579. }
  580. else {
  581. szBuffer[iEnd] = NULL;
  582. }
  583. /* Load and enable the driver.
  584. */
  585. OpenDriver( &(szBuffer[iStart]), NULL, NULL );
  586. iStart = iEnd + 1;
  587. }
  588. Done:
  589. #endif
  590. /*
  591. * Look for a debug= line in the [boot] section of SYSTEM.INI
  592. * If present it is the 16 bit MultiMedia interface, so load it
  593. */
  594. if ( !gfMeow && (WOWQueryDebug() & 0x0001)!=0 ) {
  595. pchWOWDEB = "WOWDEB.EXE";
  596. } else {
  597. pchWOWDEB = "";
  598. }
  599. GetPrivateProfileString((LPSTR)"boot", (LPSTR)"debug",pchWOWDEB, aszWOWDEB, sizeof(aszWOWDEB), (LPSTR)"SYSTEM.INI");
  600. aszWOWDEB[sizeof(aszWOWDEB)-1] = '\0';
  601. if ( lstrlen(pchWOWDEB) != 0 ) {
  602. WinExec((LPSTR)aszWOWDEB,SW_SHOW);
  603. }
  604. #if 0
  605. /* Preload winspool.exe. Apps will keep loading and freeing it
  606. * which is slow. We might as well load it now so the reference
  607. * count is 1 so it will never be loaded or freed
  608. */
  609. //
  610. // Disabled load of winspool.exe to save 8k. Size vs. speed,
  611. // which one do we care about? Right now, size!
  612. //
  613. LoadLibrary("WINSPOOL.EXE");
  614. #endif
  615. // Always load SHELL.DLL, FileMaker Pro and Lotus Install require it.
  616. LoadLibrary("SHELL.DLL");
  617. //
  618. // Start any apps pending in basesrv queue
  619. //
  620. while (StartRequestedApp() && gfSharedWOW) {
  621. /* null stmt */ ;
  622. }
  623. while (1) {
  624. if (!WowWaitForMsgAndEvent(ghwndMain) &&
  625. PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) &&
  626. msg.message != WM_WOWEXECHEARTBEAT )
  627. {
  628. if (msg.message != WM_QUIT) {
  629. TranslateMessage(&msg);
  630. DispatchMessage(&msg);
  631. }
  632. }
  633. }
  634. return 1;
  635. }
  636. /***************************************************************************\
  637. * InitializeApp
  638. *
  639. * History:
  640. * 04-13-91 ScottLu Created.
  641. \***************************************************************************/
  642. BOOL InitializeApp(LPSTR lpszCommandLine)
  643. {
  644. WNDCLASS wc;
  645. int cyExecStart, cxExecStart;
  646. USHORT TitleLen, cbCopy;
  647. HWND hwndFax;
  648. int lResult;
  649. // Remove Real Mode Segment Address
  650. wc.style = 0;
  651. wc.lpfnWndProc = WndProc;
  652. wc.cbClsExtra = 0;
  653. wc.cbWndExtra = 0;
  654. wc.hInstance = hAppInstance;
  655. wc.hIcon = LoadIcon(hAppInstance, MAKEINTRESOURCE(ID_WOWEXEC_ICON));
  656. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  657. wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  658. wc.lpszClassName = "WOWExecClass";
  659. #ifdef DEBUG
  660. wc.lpszMenuName = "MainMenu";
  661. #else
  662. wc.lpszMenuName = NULL;
  663. #endif
  664. if (!RegisterClass(&wc)) {
  665. OutputDebugString("WOWEXEC: RegisterClass failed\n");
  666. return FALSE;
  667. }
  668. /* Load these strings now. If we need them later, we won't be able to load
  669. * them at that time.
  670. */
  671. LoadString(hAppInstance, IDS_OOMEXITTITLE, szOOMExitTitle, sizeof(szOOMExitTitle));
  672. LoadString(hAppInstance, IDS_OOMEXITMSG, szOOMExitMsg, sizeof(szOOMExitMsg));
  673. LoadString(hAppInstance, IDS_APPTITLE, szAppTitleBuffer, sizeof(szAppTitleBuffer));
  674. ghwndMain = CreateWindow("WOWExecClass", lpszAppTitle,
  675. WS_OVERLAPPED | WS_CAPTION | WS_BORDER | WS_THICKFRAME |
  676. WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CLIPCHILDREN |
  677. WS_SYSMENU,
  678. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  679. NULL, NULL, hAppInstance, NULL);
  680. if (ghwndMain == NULL ) {
  681. #ifdef DEBUG
  682. OutputDebugString("WOWEXEC: ghwndMain Null\n");
  683. #endif
  684. return FALSE;
  685. }
  686. hwndFax = FaxInit(hAppInstance);
  687. //
  688. // Give our window handle to BaseSrv, which will post WM_WOWEXECSTARTAPP
  689. // messages when we have commands to pick up. The return value tells
  690. // us if we are the shared WOW VDM or not (a seperate WOW VDM).
  691. // We also pick up the ShowWindow parameter (SW_SHOW, SW_MINIMIZED, etc)
  692. // for the first WOW app here. Subsequent ones we get from BaseSrv.
  693. //
  694. //
  695. // gwFirstCmdShow is no longer used, and is available.
  696. //
  697. lResult = WOWRegisterShellWindowHandle(ghwndMain,
  698. &gwFirstCmdShow,
  699. hwndFax
  700. );
  701. if (lResult < 0) {
  702. gfMeow=TRUE;
  703. } else if (lResult > 0) {
  704. gfSharedWOW=TRUE;
  705. }
  706. //
  707. // If this isn't the shared WOW, tell the kernel to exit when the
  708. // last app (except WowExec) exits.
  709. //
  710. if (!gfSharedWOW) {
  711. WowSetExitOnLastApp(TRUE);
  712. }
  713. /* Remember the original directory. */
  714. GetCurrentDirectory(NULL, szOriginalDirectory);
  715. GetWindowsDirectory(szWindowsDirectory, MAXITEMPATHLEN+1);
  716. #ifdef DEBUG
  717. ShowWindow(ghwndMain, SW_MINIMIZE);
  718. //
  719. // If this is the shared WOW, change the app title string to
  720. // reflect this and change the window title.
  721. //
  722. if (gfSharedWOW) {
  723. LoadString(hAppInstance, IDS_SHAREDAPPTITLE, szAppTitleBuffer, sizeof(szAppTitleBuffer));
  724. }
  725. SetWindowText(ghwndMain, lpszAppTitle);
  726. UpdateWindow(ghwndMain);
  727. #endif
  728. return TRUE;
  729. }
  730. /***************************************************************************\
  731. * WndProc
  732. *
  733. * History:
  734. * 04-07-91 DarrinM Created.
  735. \***************************************************************************/
  736. LONG FAR PASCAL WndProc(
  737. HWND hwnd,
  738. WORD message,
  739. WORD wParam,
  740. LONG lParam)
  741. {
  742. char chbuf[50];
  743. HICON hIcon;
  744. switch (message) {
  745. case WM_CREATE:
  746. break;
  747. case WM_DESTROY:
  748. // ignore since wowexec must stay around
  749. return 0;
  750. #ifdef DEBUG
  751. case WM_COMMAND:
  752. switch (LOWORD(wParam)) {
  753. case MM_ABOUT:
  754. LoadString(hAppInstance, errTitle, (LPSTR)chbuf, sizeof(chbuf));
  755. hIcon = LoadIcon(hAppInstance, MAKEINTRESOURCE(ID_WOWEXEC_ICON));
  756. ShellAbout(ghwndMain, (LPSTR)chbuf, (LPSTR)lpszAppTitle, hIcon);
  757. break;
  758. case MM_BREAK:
  759. _asm int 3
  760. break;
  761. case MM_FAULT:
  762. _asm mov cs:0,ax
  763. break;
  764. case MM_EXIT:
  765. ExitKernelThunk(0);
  766. break;
  767. case MM_WATSON:
  768. WinExec("drwatson", SW_MINIMIZE );
  769. break;
  770. case MM_PARTY:
  771. {
  772. FARPROC lpPartyDialogProc;
  773. lpPartyDialogProc = MakeProcInstance(PartyDialogProc, hAppInstance);
  774. DialogBox(hAppInstance, MAKEINTRESOURCE(ID_PARTY_DIALOG),
  775. hwnd, lpPartyDialogProc);
  776. FreeProcInstance(lpPartyDialogProc);
  777. }
  778. break;
  779. case MM_GENTHUNK:
  780. {
  781. DWORD FAR PASCAL CallProc32W(DWORD, DWORD, DWORD, DWORD,
  782. DWORD, DWORD, DWORD, DWORD,
  783. 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
  790. );
  791. #define BIT(bitpos) ((DWORD)1 << bitpos)
  792. DWORD hmodKernel32, hmodUser32, hmodWow32;
  793. DWORD pfn32;
  794. DWORD dw16, dw32;
  795. DWORD p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,
  796. p11, p12, p13, p14, p15, p16, p17, p18, p19, p20,
  797. p21, p22, p23, p24, p25, p26, p27, p28, p29, p30,
  798. p31, p32;
  799. char szBuf16[1024], szBuf32[1024];
  800. char *pszErr;
  801. hmodKernel32 = LoadLibraryEx32W("kernel32", 0, 0);
  802. hmodUser32 = LoadLibraryEx32W("user32", 0, 0);
  803. hmodWow32 = LoadLibraryEx32W("wow32", 0, 0);
  804. //
  805. // Simple printf test.
  806. //
  807. pfn32 = GetProcAddress32W(hmodUser32, "wsprintfA");
  808. dw16 = wsprintf(szBuf16, "simple printf %ld", 12345678);
  809. dw32 = CallProc32W( (DWORD)(LPSTR) szBuf32,
  810. (DWORD)(LPSTR) "simple printf %ld",
  811. 12345678,
  812. 0,
  813. 0, 0, 0, 0,
  814. 0, 0, 0, 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. pfn32,
  821. BIT(30) | BIT(31),
  822. CPEX_DEST_CDECL | 32
  823. );
  824. if (dw16 != dw32 || lstrcmp(szBuf16, szBuf32)) {
  825. pszErr = "simple printf comparison failed";
  826. goto ErrorMsg;
  827. }
  828. MessageBox(hwnd, "s1 success", "Genthunk Sanity Test", MB_OK);
  829. dw32 = CallProcEx32W( CPEX_DEST_CDECL | 3,
  830. BIT(0) | BIT(1),
  831. pfn32,
  832. (DWORD)(LPSTR) szBuf32,
  833. (DWORD)(LPSTR) "simple printf %ld",
  834. 12345678 );
  835. if (dw16 != dw32 || lstrcmp(szBuf16, szBuf32)) {
  836. pszErr = "simple printf comparison failed (CallProcEx)";
  837. goto ErrorMsg;
  838. }
  839. MessageBox(hwnd, "s2 success", "Genthunk Sanity Test", MB_OK);
  840. //
  841. // Complex printf test.
  842. //
  843. // pfn32 still points to wsprintfA
  844. // pfn32 = GetProcAddress32W(hmodUser32, "wsprintfA");
  845. #if 0 // this blows out Win16 wsprintf!
  846. dw16 = wsprintf(szBuf16,
  847. "complex printf "
  848. "%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s "
  849. "%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s ",
  850. 12345678,
  851. 0x87654321,
  852. "str",
  853. 12345678,
  854. 0x87654321,
  855. "str",
  856. 12345678,
  857. 0x87654321,
  858. "str",
  859. 12345678,
  860. 0x87654321,
  861. "str",
  862. 12345678,
  863. 0x87654321,
  864. "str",
  865. 12345678,
  866. 0x87654321,
  867. "str",
  868. 12345678,
  869. 0x87654321,
  870. "str",
  871. 12345678,
  872. 0x87654321,
  873. "str",
  874. 12345678,
  875. 0x87654321,
  876. "str",
  877. 12345678,
  878. 0x87654321,
  879. "str"
  880. );
  881. #else
  882. lstrcpy(szBuf16, "complex printf "
  883. "12345678 87654321 str "
  884. "12345678 87654321 str "
  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. );
  894. dw16 = lstrlen(szBuf16);
  895. #endif
  896. dw32 = CallProc32W(
  897. (DWORD)(LPSTR) szBuf32,
  898. (DWORD)(LPSTR) "complex printf "
  899. "%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s "
  900. "%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s ",
  901. 12345678,
  902. 0x87654321,
  903. (DWORD)(LPSTR) "str",
  904. 12345678,
  905. 0x87654321,
  906. (DWORD)(LPSTR) "str",
  907. 12345678,
  908. 0x87654321,
  909. (DWORD)(LPSTR) "str",
  910. 12345678,
  911. 0x87654321,
  912. (DWORD)(LPSTR) "str",
  913. 12345678,
  914. 0x87654321,
  915. (DWORD)(LPSTR) "str",
  916. 12345678,
  917. 0x87654321,
  918. (DWORD)(LPSTR) "str",
  919. 12345678,
  920. 0x87654321,
  921. (DWORD)(LPSTR) "str",
  922. 12345678,
  923. 0x87654321,
  924. (DWORD)(LPSTR) "str",
  925. 12345678,
  926. 0x87654321,
  927. (DWORD)(LPSTR) "str",
  928. 12345678,
  929. 0x87654321,
  930. (DWORD)(LPSTR) "str",
  931. pfn32,
  932. BIT(0) | BIT(3) | BIT(6) | BIT(9) | BIT(12) | BIT(15) |
  933. BIT(18) | BIT(21) | BIT(24) | BIT(27) | BIT(30) | BIT(31),
  934. CPEX_DEST_CDECL | 32
  935. );
  936. if (dw16 != dw32 || lstrcmp(szBuf16, szBuf32)) {
  937. pszErr = "complex printf comparison failed";
  938. goto ErrorMsg;
  939. }
  940. MessageBox(hwnd, "c1 success", "Genthunk Sanity Test", MB_OK);
  941. dw32 = CallProcEx32W( CPEX_DEST_CDECL | 32,
  942. BIT(0) | BIT(1) | BIT(4) | BIT(7) | BIT(10) | BIT(13) |
  943. BIT(16) | BIT(19) | BIT(22) | BIT(25) | BIT(28) | BIT(31),
  944. pfn32,
  945. (DWORD)(LPSTR) szBuf32,
  946. (DWORD)(LPSTR) "complex printf "
  947. "%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s "
  948. "%ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s %ld %lx %s ",
  949. 12345678,
  950. 0x87654321,
  951. (DWORD)(LPSTR) "str",
  952. 12345678,
  953. 0x87654321,
  954. (DWORD)(LPSTR) "str",
  955. 12345678,
  956. 0x87654321,
  957. (DWORD)(LPSTR) "str",
  958. 12345678,
  959. 0x87654321,
  960. (DWORD)(LPSTR) "str",
  961. 12345678,
  962. 0x87654321,
  963. (DWORD)(LPSTR) "str",
  964. 12345678,
  965. 0x87654321,
  966. (DWORD)(LPSTR) "str",
  967. 12345678,
  968. 0x87654321,
  969. (DWORD)(LPSTR) "str",
  970. 12345678,
  971. 0x87654321,
  972. (DWORD)(LPSTR) "str",
  973. 12345678,
  974. 0x87654321,
  975. (DWORD)(LPSTR) "str",
  976. 12345678,
  977. 0x87654321,
  978. (DWORD)(LPSTR) "str"
  979. );
  980. if (dw16 != dw32 || lstrcmp(szBuf16, szBuf32)) {
  981. pszErr = "complex printf comparison failed (CallProcEx)";
  982. goto ErrorMsg;
  983. }
  984. MessageBox(hwnd, "c2 success", "Genthunk Sanity Test", MB_OK);
  985. //
  986. // Simple WINAPI test (GetProcAddress of LoadModule)
  987. //
  988. pfn32 = GetProcAddress32W(hmodKernel32, "GetProcAddress");
  989. dw16 = GetProcAddress32W(hmodKernel32, "LoadModule");
  990. dw32 = CallProc32W( hmodKernel32,
  991. (DWORD)(LPSTR) "LoadModule",
  992. 0, 0,
  993. 0, 0, 0, 0,
  994. 0, 0, 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. pfn32,
  1001. BIT(30),
  1002. CPEX_DEST_STDCALL | 32
  1003. );
  1004. if (dw16 != dw32) {
  1005. pszErr = "GetProcAddress comparison failed";
  1006. goto ErrorMsg;
  1007. }
  1008. MessageBox(hwnd, "w1 success", "Genthunk Sanity Test", MB_OK);
  1009. dw32 = CallProcEx32W( CPEX_DEST_STDCALL | 2,
  1010. BIT(1),
  1011. pfn32,
  1012. hmodKernel32,
  1013. (DWORD)(LPSTR) "LoadModule" );
  1014. wsprintf(szBuf16, "GPA via CP32Ex(LoadModule) == %lx\n", dw32);
  1015. OutputDebugString(szBuf16);
  1016. if (dw16 != dw32) {
  1017. pszErr = "GetProcAddress comparison failed (CallProcEx)";
  1018. goto ErrorMsg;
  1019. }
  1020. MessageBox(hwnd, "w2 success", "Genthunk Sanity Test", MB_OK);
  1021. //
  1022. // Complex WINAPI test WOWStdCall32ArgsTestTarget exists only on
  1023. // checked WOW32.dll
  1024. //
  1025. pfn32 = GetProcAddress32W(hmodWow32, "WOWStdCall32ArgsTestTarget");
  1026. if (!pfn32) {
  1027. MessageBox(hwnd,
  1028. "WOWStdCall32ArgsTestTarget not found, use checked wow32.dll for this test.",
  1029. "Genthunk Quicktest",
  1030. MB_OK
  1031. );
  1032. goto Done;
  1033. }
  1034. p1 = 1;
  1035. p2 = 2;
  1036. p3 = 3;
  1037. p4 = 4;
  1038. p5 = 5;
  1039. p6 = 6;
  1040. p7 = 7;
  1041. p8 = 8;
  1042. p9 = 9;
  1043. p10 = 10;
  1044. p11 = 11;
  1045. p12 = 12;
  1046. p13 = 13;
  1047. p14 = 14;
  1048. p15 = 15;
  1049. p16 = 16;
  1050. p17 = 17;
  1051. p18 = 18;
  1052. p19 = 19;
  1053. p20 = 10;
  1054. p21 = 21;
  1055. p22 = 22;
  1056. p23 = 23;
  1057. p24 = 24;
  1058. p25 = 25;
  1059. p26 = 26;
  1060. p27 = 27;
  1061. p28 = 28;
  1062. p29 = 29;
  1063. p30 = 30;
  1064. p31 = 31;
  1065. p32 = 32;
  1066. dw16 = ((((p1+p2+p3+p4+p5+p6+p7+p8+p9+p10) -
  1067. (p11+p12+p13+p14+p15+p16+p17+p18+p19+p20)) << p21) +
  1068. ((p22+p23+p24+p25+p26) - (p27+p28+p29+p30+p31+p32)));
  1069. dw32 = CallProc32W( p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,
  1070. p11, p12, p13, p14, p15, p16, p17, p18, p19, p20,
  1071. p21, p22,
  1072. (DWORD)(LPDWORD) &p23,
  1073. p24, p25, p26, p27, p28, p29, p30,
  1074. p31,
  1075. (DWORD)(LPDWORD) &p32,
  1076. pfn32,
  1077. BIT(9) | BIT(0),
  1078. CPEX_DEST_STDCALL | 32
  1079. );
  1080. if (dw16 != dw32) {
  1081. pszErr = "WOWStdCall32ArgsTestTarget comparison failed";
  1082. goto ErrorMsg;
  1083. }
  1084. MessageBox(hwnd, "cw1 success", "Genthunk Sanity Test", MB_OK);
  1085. dw32 = CallProcEx32W( CPEX_DEST_STDCALL | 32,
  1086. BIT(22) | BIT(31),
  1087. pfn32,
  1088. p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,
  1089. p11, p12, p13, p14, p15, p16, p17, p18, p19, p20,
  1090. p21, p22,
  1091. (DWORD)(LPDWORD) &p23,
  1092. p24, p25, p26, p27, p28, p29, p30,
  1093. p31,
  1094. (DWORD)(LPDWORD) &p32
  1095. );
  1096. if (dw16 != dw32) {
  1097. pszErr = "WOWStdCall32ArgsTestTarget comparison failed (CallProcEx)";
  1098. goto ErrorMsg;
  1099. ErrorMsg:
  1100. MessageBox(hwnd, pszErr, "Genthunk Sanity Test Failure", MB_OK);
  1101. goto Done;
  1102. }
  1103. wsprintf(szBuf16, "result of odd calc is %lx\n", dw32);
  1104. OutputDebugString(szBuf16);
  1105. MessageBox(hwnd, "Test successful!", "Genthunk Quicktest", MB_OK);
  1106. Done:
  1107. FreeLibrary32W(hmodKernel32);
  1108. FreeLibrary32W(hmodUser32);
  1109. FreeLibrary32W(hmodWow32);
  1110. }
  1111. break;
  1112. }
  1113. break;
  1114. #endif
  1115. case WM_WOWEXECSTARTAPP: // WM_USER+0
  1116. #ifdef DEBUG
  1117. OutputDebugString("WOWEXEC - got WM_WOWEXECSTARTAPP\n");
  1118. #endif
  1119. //
  1120. // Either BaseSrv or Wow32 asked us to go looking for
  1121. // commands to run.
  1122. //
  1123. if (!gfSharedWOW) {
  1124. //
  1125. // We shouldn't get this message unless we are the shared
  1126. // WOW VDM!
  1127. //
  1128. #ifdef DEBUG
  1129. OutputDebugString("WOWEXEC - separate WOW VDM got WM_WOWEXECSTARTAPP!\n");
  1130. _asm int 3;
  1131. #endif
  1132. break;
  1133. }
  1134. //
  1135. // Start requested apps until there are no more to start.
  1136. // This handles the case where several Win16 apps are launched
  1137. // in a row, before BaseSrv has the window handle for WowExec.
  1138. //
  1139. while (StartRequestedApp()) {
  1140. /* Null stmt */ ;
  1141. }
  1142. break;
  1143. case WM_WOWEXEC_START_TASK:
  1144. {
  1145. char sz[512];
  1146. sz[ GlobalGetAtomName(wParam, sz, sizeof sz) ] = 0;
  1147. GlobalDeleteAtom(wParam);
  1148. WinExec(sz, (WORD)lParam);
  1149. }
  1150. case WM_WOWEXECHEARTBEAT:
  1151. // Probably will never get here...
  1152. break;
  1153. case WM_WOWEXECSTARTTIMER:
  1154. WowShutdownTimer(1);
  1155. break;
  1156. case WM_TIMER:
  1157. if (wParam == 1) { // timer ID
  1158. KillTimer(ghwndMain, 1);
  1159. //
  1160. // The shutdown timer has expired, meaning it's time to kill this
  1161. // shared WOW VDM. First we need to let basesrv know not to queue
  1162. // any more apps for us to start.
  1163. //
  1164. if (WOWRegisterShellWindowHandle(NULL,
  1165. &gwFirstCmdShow,
  1166. NULL
  1167. )) {
  1168. //
  1169. // BaseSrv deregistered us successfully after confirming
  1170. // there are no pending commands for us.
  1171. //
  1172. ExitKernelThunk(0);
  1173. } else {
  1174. //
  1175. // There must be pending commands for us. Might as well
  1176. // start them.
  1177. //
  1178. PostMessage(ghwndMain, WM_WOWEXECSTARTAPP, 0, 0);
  1179. }
  1180. }
  1181. break;
  1182. case WM_TIMECHANGE:
  1183. *((DWORD *)(((DWORD)40 << 16) | FIXED_NTVDMSTATE_REL40))
  1184. |= VDM_TIMECHANGE;
  1185. break;
  1186. case WM_DDE_INITIATE:
  1187. {
  1188. // In win31, the Program Manager WindowProc calls peekmessage to filterout
  1189. // otherwindowcreated and otherwindowdestroyed messages (which are atoms in win31)
  1190. // whenever it receives WM_DDE_INITIATE message.
  1191. //
  1192. // This has a side effect - basically when peekmessage is called the app ie program
  1193. // manager effectively yields allowing scheduling of other apps.
  1194. //
  1195. // So we do the side effect thing (simulate win31 behaviour) -
  1196. //
  1197. // The bug: 20221, rumba as/400 can't connect the firsttime to sna server.
  1198. // Scenario: Rumbawsf execs snasrv and blocks on yield, snasrv execs wnap and blocks
  1199. // on yield. Eventually wnap yields and rumbawsf is scheduled which
  1200. // broadcasts a ddeinitiate message. When WOWEXEC receives this message
  1201. // it will peek for nonexistent msg, which allows snasrv to get scheduled
  1202. MSG msg;
  1203. while (PeekMessage(&msg, NULL, 0xFFFF, 0xFFFF, PM_REMOVE))
  1204. DispatchMessage(&msg);
  1205. }
  1206. break;
  1207. case WM_CLOSE:
  1208. #ifdef DEBUG
  1209. ExitKernelThunk(0);
  1210. #else
  1211. // ignore since wowexec must stay around
  1212. return 0;
  1213. #endif // ! DEBUG
  1214. default:
  1215. return DefWindowProc(hwnd, message, wParam, lParam);
  1216. }
  1217. return 1;
  1218. }
  1219. BOOL FAR PASCAL PartyDialogProc(HWND hDlg, WORD msg, WORD wParam, LONG lParam)
  1220. {
  1221. #ifdef DEBUG
  1222. BOOL f;
  1223. DWORD dw;
  1224. char szBuf[255];
  1225. switch (msg) {
  1226. case WM_INITDIALOG:
  1227. SendDlgItemMessage(hDlg, IDD_PARTY_NUMBER, EM_LIMITTEXT, 5, 0L);
  1228. SendDlgItemMessage(hDlg, IDD_PARTY_STRING, EM_LIMITTEXT, sizeof(szBuf)-1, 0L);
  1229. break;
  1230. case WM_COMMAND:
  1231. switch (wParam) {
  1232. case 0xdab /* IDCANCEL */:
  1233. EndDialog(hDlg, FALSE);
  1234. break;
  1235. case 0xdad /* IDOK */:
  1236. dw = GetDlgItemInt(hDlg, IDD_PARTY_NUMBER, &f, FALSE);
  1237. GetDlgItemText(hDlg, IDD_PARTY_STRING, szBuf, sizeof(szBuf));
  1238. WowPartyByNumber(dw, szBuf);
  1239. EndDialog(hDlg, TRUE);
  1240. break;
  1241. default:
  1242. return FALSE;
  1243. }
  1244. break;
  1245. default:
  1246. return FALSE;
  1247. }
  1248. #endif
  1249. return TRUE;
  1250. }
  1251. // Misc File Routines - taken from progman (pmdlg.c) mattfe apr-1 92
  1252. //-------------------------------------------------------------------------
  1253. PSTR FAR PASCAL GetFilenameFromPath
  1254. // Given a full path returns a ptr to the filename bit. Unless it's a UNC style
  1255. // path in which case
  1256. (
  1257. PSTR szPath
  1258. )
  1259. {
  1260. DWORD dummy;
  1261. PSTR pFileName;
  1262. BOOL fUNC;
  1263. GetPathInfo(szPath, &pFileName, (PSTR*) &dummy, (WORD*) &dummy,
  1264. &fUNC);
  1265. // If it's a UNC then the 'filename' part is the whole thing.
  1266. if (fUNC)
  1267. pFileName = szPath;
  1268. return pFileName;
  1269. }
  1270. //-------------------------------------------------------------------------
  1271. void NEAR PASCAL GetPathInfo
  1272. // Get pointers and an index to specific bits of a path.
  1273. // Stops scaning at first space.
  1274. (
  1275. // Uses:
  1276. PSTR szPath, // The path.
  1277. // Returns:
  1278. PSTR *pszFileName, // The start of the filename in the path.
  1279. PSTR *pszExt, // Extension part of path (starting with the dot).
  1280. WORD *pich, // Index (in DBCS characters) of filename part starting at 0.
  1281. BOOL *pfUnc // Contents set to true if it's a UNC style path.
  1282. )
  1283. {
  1284. char *pch; // Temp variable.
  1285. WORD ich = 0; // Temp.
  1286. *pszExt = NULL; // If no extension, return NULL.
  1287. *pszFileName = szPath; // If no seperate filename component, return path.
  1288. *pich = 0;
  1289. *pfUnc = FALSE; // Default to not UNC style.
  1290. // Check for UNC style paths.
  1291. if (*szPath == '\\' && *(szPath+1) == '\\')
  1292. *pfUnc = TRUE;
  1293. // Search forward to find the last backslash or colon in the path.
  1294. // While we're at it, look for the last dot.
  1295. for (pch = szPath; *pch; pch = AnsiNext(pch))
  1296. {
  1297. if (*pch == ' ')
  1298. {
  1299. // Found a space - stop here.
  1300. break;
  1301. }
  1302. if (*pch == '\\' || *pch == ':')
  1303. {
  1304. // Found it, record ptr to it and it's index.
  1305. *pszFileName = pch+1;
  1306. *pich = ich+1;
  1307. }
  1308. if (*pch == '.')
  1309. {
  1310. // Found a dot.
  1311. *pszExt = pch;
  1312. }
  1313. ich++;
  1314. }
  1315. // Check that the last dot is part of the last filename.
  1316. if (*pszExt < *pszFileName)
  1317. *pszExt = NULL;
  1318. }
  1319. //-----------------------------------------------------------------------------
  1320. // StartRequestedApp
  1321. // Calls WIN32 Base GetNextVDMCommand
  1322. // and then starts the application
  1323. //
  1324. //-----------------------------------------------------------------------------
  1325. #define LargeEnvSize() 0x1000 // Size of a large env
  1326. BOOL NEAR PASCAL StartRequestedApp(VOID)
  1327. {
  1328. char achCmdLine[CCHMAX];
  1329. char achAppName[CCHMAX];
  1330. #ifdef DEBUG
  1331. char achAppNamePlusCmdLine[sizeof(achCmdLine) + sizeof(achAppName)];
  1332. int iGetNextVdmCmdLoops = 0;
  1333. #endif
  1334. char achCurDir[CCHMAX];
  1335. WOWINFO wowinfo;
  1336. BOOL b;
  1337. HANDLE hmemEnvironment;
  1338. USHORT usEnvSize;
  1339. achCmdLine[0] = '\0';
  1340. achAppName[0] = '\0';
  1341. // We start by assuming that the app will have an environment that will
  1342. // be less than a large environment size. If not then
  1343. // WowGetNextVdmCommand will fail and we will try again with the
  1344. // enviroment size needed for the app as returned from the failed
  1345. // WowGetNextVdmCommand call. If we detect that WowGetNextVdmCommand fails
  1346. // but that we have plenty of environment space then we know another
  1347. // problem has occured and we give up.
  1348. // We don't worry about wasting memory since the environment will be
  1349. // merged into another buffer and this buffer will be freed below.
  1350. wowinfo.EnvSize = LargeEnvSize();
  1351. hmemEnvironment = NULL;
  1352. do {
  1353. if (hmemEnvironment != NULL) {
  1354. GlobalUnlock(hmemEnvironment);
  1355. GlobalFree(hmemEnvironment);
  1356. }
  1357. // We need to allocate twice the space specified so that international
  1358. // character set conversions can be successful.
  1359. hmemEnvironment = GlobalAlloc(GMEM_MOVEABLE, 2*wowinfo.EnvSize);
  1360. if (hmemEnvironment == NULL) {
  1361. #ifdef DEBUG
  1362. OutputDebugString("WOWEXEC - failed to allocate Environment Memory\n");
  1363. #endif
  1364. MyMessageBox(IDS_EXECERRTITLE, IDS_NOMEMORYMSG, NULL);
  1365. return FALSE;
  1366. }
  1367. wowinfo.lpEnv = GlobalLock(hmemEnvironment);
  1368. #ifdef DEBUG
  1369. if (wowinfo.lpEnv == NULL) {
  1370. OutputDebugString("WOWEXEC ASSERT - GlobalLock failed, fix this!\n");
  1371. _asm { int 3 };
  1372. }
  1373. if (2*wowinfo.EnvSize > GlobalSize(hmemEnvironment)) {
  1374. OutputDebugString("WOWEXEC ASSERT - alloced memory too small, fix this!\n");
  1375. _asm { int 3 };
  1376. }
  1377. #endif
  1378. wowinfo.lpCmdLine = achCmdLine;
  1379. wowinfo.CmdLineSize = CCHMAX;
  1380. wowinfo.lpAppName = achAppName;
  1381. wowinfo.AppNameSize = CCHMAX;
  1382. wowinfo.CurDrive = 0;
  1383. wowinfo.lpCurDir = achCurDir;
  1384. wowinfo.CurDirSize = sizeof(achCurDir);
  1385. wowinfo.iTask = 0;
  1386. usEnvSize = wowinfo.EnvSize;
  1387. #ifdef DEBUG
  1388. if (++iGetNextVdmCmdLoops == 4) {
  1389. OutputDebugString("WOWEXEC ASSERT - Too many calls to GetNextVdmCommand\n");
  1390. _asm { int 3 };
  1391. }
  1392. #endif
  1393. } while (! (b = WowGetNextVdmCommand(&wowinfo)) &&
  1394. (wowinfo.EnvSize > usEnvSize));
  1395. if ( ! b ) {
  1396. #ifdef DEBUG
  1397. OutputDebugString("WOWEXEC - GetNextVdmCommand failed.\n");
  1398. #endif
  1399. MyMessageBox(IDS_EXECERRTITLE, IDS_NOMEMORYMSG, achCmdLine);
  1400. GlobalUnlock( hmemEnvironment );
  1401. GlobalFree( hmemEnvironment );
  1402. return FALSE;
  1403. }
  1404. //
  1405. // If CmdLineSize == 0, no more commands (wowexec was the command)
  1406. // see WK32WowGetNextVdm
  1407. //
  1408. if (! wowinfo.CmdLineSize) {
  1409. GlobalUnlock( hmemEnvironment );
  1410. GlobalFree( hmemEnvironment );
  1411. return FALSE;
  1412. }
  1413. #ifdef DEBUG
  1414. lstrcpy(achAppNamePlusCmdLine, achAppName);
  1415. lstrcat(achAppNamePlusCmdLine, ":");
  1416. lstrcat(achAppNamePlusCmdLine, achCmdLine);
  1417. // Chop off trailing CRLF from command tail.
  1418. achAppNamePlusCmdLine[ lstrlen(achAppNamePlusCmdLine) - 2 ] = '\0';
  1419. OutputDebugString("WOWEXEC: CommandLine = <");
  1420. OutputDebugString(achAppNamePlusCmdLine);
  1421. OutputDebugString(">\n");
  1422. SetWindowText(ghwndMain, achAppNamePlusCmdLine);
  1423. UpdateWindow(ghwndMain);
  1424. #endif
  1425. ExecApplication(&wowinfo);
  1426. #ifdef DEBUG
  1427. if ( ! gfSharedWOW ) {
  1428. //
  1429. // If this is a separate WOW, we have just executed the one and only
  1430. // app we're going to spawn. Change our window title to
  1431. // Command Line - WOWExec so that it's easy to see which WOW this
  1432. // window is associated with. No need to worry about freeing
  1433. // this memory, since when we go away the VDM goes away and
  1434. // vice-versa.
  1435. //
  1436. lpszAppTitle = GlobalLock(
  1437. GlobalAlloc(GMEM_FIXED,
  1438. lstrlen(achAppNamePlusCmdLine) +
  1439. 3 + // for " - "
  1440. lstrlen(szAppTitleBuffer) +
  1441. 1 // for null terminator
  1442. ));
  1443. lstrcpy(lpszAppTitle, achAppNamePlusCmdLine);
  1444. lstrcat(lpszAppTitle, " - ");
  1445. lstrcat(lpszAppTitle, szAppTitleBuffer);
  1446. }
  1447. SetWindowText(ghwndMain, lpszAppTitle);
  1448. UpdateWindow(ghwndMain);
  1449. #endif
  1450. GlobalUnlock(hmemEnvironment);
  1451. GlobalFree(hmemEnvironment);
  1452. return TRUE; // We ran an app.
  1453. }
  1454.