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.

6638 lines
193 KiB

  1. /*++
  2. *
  3. * WOW v1.0
  4. *
  5. * Copyright (c) 1991, Microsoft Corporation
  6. *
  7. * WKMAN.C
  8. * WOW32 16-bit Kernel API support (manually-coded thunks)
  9. *
  10. * History:
  11. * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
  12. * 20-Apr-91 Matt Felton (mattfe) Added WK32CheckLoadModuleDrv
  13. * 28-Jan-92 Matt Felton (mattfe) Added Wk32GetNextVdmCommand + MIPS build
  14. * 10-Feb-92 Matt Felton (mattfe) Removed WK32CheckLoadModuleDRV
  15. * 10-Feb-92 Matt Felton (mattfe) cleanup and task creation
  16. * 4-mar-92 mattfe add killprocess
  17. * 11-mar-92 mattfe added W32NotifyThread
  18. * 12-mar-92 mattfe added WowRegisterShellWindowHandle
  19. * 17-apr-92 daveh changed to use host_CreateThread and host_ExitThread
  20. * 11-jun-92 mattfe hung app support W32HungAppNotifyThread, W32EndTask
  21. *
  22. --*/
  23. #include "precomp.h"
  24. #pragma hdrstop
  25. #include <ntexapi.h>
  26. #include <vdmdbg.h>
  27. #include <ntseapi.h>
  28. #include <wingdip.h> // GACF_ app compat flags
  29. #include <shlobj.h> // CSIDL_COMMON_STARTMENU etc
  30. #include <userenv.h> // GetAllUsersProfilesDirectory and etc
  31. #include "wowfax.h"
  32. #include "demexp.h"
  33. extern void UnloadNetworkFonts( UINT id );
  34. MODNAME(wkman.c);
  35. extern void FreeTaskFormFeedHacks(HAND16 h16);
  36. BOOL WOWSortEnvironmentStrings(PSZ pszEnv);
  37. void WOWStripDownTheEnvironment(WORD segEnv);
  38. DWORD WOW32GetEnvironmentPtrs(IN PSZ pEnv,
  39. OUT PSZ *pGoo,
  40. OUT PSZ *pSig,
  41. OUT PDWORD pdw);
  42. extern PFAMILY_TABLE *pgDpmWowFamTbls;
  43. void WK32ChangeDisplayMode(DWORD dmBitsPerPel);
  44. void WK32RevertDisplayMode(void);
  45. // Global DATA
  46. //
  47. // The 5 variables below are used to hold STARTUPINFO fields between
  48. // WowExec's GetNextVdmComand call and the InitTask call of the new
  49. // app. We pass them on to user32's InitTask.
  50. //
  51. DWORD dwLastHotkey;
  52. DWORD dwLastX = (DWORD) CW_USEDEFAULT;
  53. DWORD dwLastY = (DWORD) CW_USEDEFAULT;
  54. DWORD dwLastXSize = (DWORD) CW_USEDEFAULT;
  55. DWORD dwLastYSize = (DWORD) CW_USEDEFAULT;
  56. HWND ghwndShell; // WOWEXEC Window Handle
  57. HANDLE ghInstanceUser32;
  58. HAND16 ghShellTDB; // WOWEXEC TDB
  59. HANDLE ghevWowExecMsgWait;
  60. HANDLE ghevWaitHungAppNotifyThread = (HANDLE)-1; // Syncronize App Termination to Hung App NotifyThread
  61. HANDLE ghNotifyThread = (HANDLE)-1; // Notification Thread Handle
  62. HANDLE ghHungAppNotifyThread = (HANDLE)-1; // HungAppNotification ThreadHandle
  63. PTD gptdTaskHead; // Linked List of TDs
  64. CRITICAL_SECTION gcsWOW; // WOW Critical Section used when updating task linked list
  65. CRITICAL_SECTION gcsHungApp; // HungApp Critical Section used when VDM_WOWHUNGAPP bit
  66. HMODCACHE ghModCache[CHMODCACHE]; // avoid callbacks to get 16-bit hMods
  67. volatile HANDLE ghTaskCreation; // hThread from task creation (see WK32SyncTask)
  68. // touched by parent and child threads during task init
  69. HANDLE ghTaskAppHelp; // hProcess from apphelp
  70. BOOL gfTaskContinue; // indicates whether child thread should continue without waiting for apphelp
  71. VPVOID vpnum_tasks; // Pointer to KDATA variables (KDATA.ASM)
  72. PWORD16 pCurTDB; // Pointer to KDATA variables
  73. PWORD16 pCurDirOwner; // Pointer to KDATA variables
  74. VPVOID vpDebugWOW = 0; // Pointer to KDATA variables
  75. VPVOID vpLockTDB; // Pointer to KDATA variables
  76. VPVOID vptopPDB = 0; // KRNL PDB
  77. DOSWOWDATA DosWowData; // structure that keeps linear pointer to
  78. // DOS internal variables.
  79. //
  80. // List of known DLLs used by WK32WowIsKnownDLL, called by 16-bit LoadModule.
  81. // This causes known DLLs to be forced to load from the 32-bit system
  82. // directory, since these are "special" binaries that should not be
  83. // overwritten by unwitting 16-bit setup programs.
  84. //
  85. // This list is initialized from the registry value
  86. // ...\CurrentControlSet\Control\WOW\KnownDLLs REG_SZ (space separated list)
  87. //
  88. #define MAX_KNOWN_DLLS 64
  89. PSZ apszKnownDLL[MAX_KNOWN_DLLS];
  90. //
  91. // Fully-qualified path to %windir%\control.exe for PM5 setup fix.
  92. // Setup by WK32InitWowIsKnownDll, used by WK32WowIsKnownDll.
  93. //
  94. CHAR szBackslashControlExe[] = "\\control.exe";
  95. PSZ pszControlExeWinDirPath; // "c:\winnt\control.exe"
  96. PSZ pszControlExeSysDirPath; // "c:\winnt\system32\control.exe"
  97. CHAR szBackslashProgmanExe[] = "\\progman.exe";
  98. PSZ pszProgmanExeWinDirPath; // "c:\winnt\progman.exe"
  99. PSZ pszProgmanExeSysDirPath; // "c:\winnt\system32\progman.exe"
  100. char szWOAWOW32[] = "-WoAWoW32";
  101. // spells WS.. in db dumps (non-printable 0x01's won't be in any env strings)
  102. #define WOW_ENV_SIG 0x01014557
  103. //
  104. // WOW GDI/CSR batching limit.
  105. //
  106. DWORD dwWOWBatchLimit = 0;
  107. UINT GetWOWTaskId(void);
  108. #define TOOLONGLIMIT _MAX_PATH
  109. #define WARNINGMSGLENGTH 255
  110. static char szCaption[TOOLONGLIMIT + WARNINGMSGLENGTH];
  111. static char szMsgBoxText[TOOLONGLIMIT + WARNINGMSGLENGTH];
  112. extern HANDLE hmodWOW32;
  113. /*
  114. * These are used to clean up DelayFree arrray
  115. *
  116. */
  117. extern LPVOID glpvDelayFree[];
  118. extern DWORD gdwDelayFree;
  119. /*
  120. * This function is living inside dpmi32/i386 and is used when we need to force dpmi linear memory allocation
  121. * via the compat flag
  122. *
  123. */
  124. extern VOID DpmiSetIncrementalAlloc(BOOL);
  125. /* WK32WaitEvent - First API called by app, courtesy the C runtimes
  126. *
  127. * ENTRY
  128. *
  129. * EXIT
  130. * Returns TRUE to indicate that a reschedule occurred
  131. *
  132. *
  133. */
  134. ULONG FASTCALL WK32WaitEvent(PVDMFRAME pFrame)
  135. {
  136. UNREFERENCED_PARAMETER(pFrame);
  137. return TRUE;
  138. }
  139. /* WK32KernelTrace - Trace 16Bit Kernel API Calls
  140. *
  141. * ENTRY
  142. *
  143. * EXIT
  144. *
  145. *
  146. */
  147. ULONG FASTCALL WK32WOWKernelTrace(PVDMFRAME pFrame)
  148. {
  149. #ifdef DEBUG
  150. PBYTE pb1;
  151. PBYTE pb2;
  152. register PWOWKERNELTRACE16 parg16;
  153. // Check Filtering - Trace Correct TaskID and Kernel Tracing Enabled
  154. if (((WORD)(pFrame->wTDB & fLogTaskFilter) == pFrame->wTDB) &&
  155. ((fLogFilter & FILTER_KERNEL16) != 0 )) {
  156. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  157. GETVDMPTR(parg16->lpRoutineName, 50, pb1);
  158. GETVDMPTR(parg16->lpUserArgs, parg16->cParms, pb2);
  159. if ((fLogFilter & FILTER_VERBOSE) == 0 ) {
  160. LOGDEBUG(12, ("%s(", pb1));
  161. } else {
  162. LOGDEBUG(12, ("%04X %08X %04X %s:%s(",pFrame->wTDB, pb2, pFrame->wAppDS, (LPSZ)"Kernel16", pb1));
  163. }
  164. pb2 += 2*sizeof(WORD); // point past callers CS:IP
  165. pb2 += parg16->cParms;
  166. while (parg16->cParms > 0) {
  167. pb2 -= sizeof(WORD);
  168. parg16->cParms -= sizeof(WORD);
  169. LOGDEBUG(12,( "%04x", *(PWORD)pb2));
  170. if (parg16->cParms > 0) {
  171. LOGDEBUG(12,( ","));
  172. }
  173. }
  174. LOGDEBUG(12,( ")\n"));
  175. if (fDebugWait != 0) {
  176. DbgPrint("WOWSingle Step\n");
  177. DbgBreakPoint();
  178. }
  179. FREEVDMPTR(pb1);
  180. FREEVDMPTR(pb2);
  181. FREEARGPTR(parg16);
  182. }
  183. #else
  184. UNREFERENCED_PARAMETER(pFrame);
  185. #endif
  186. return TRUE;
  187. }
  188. DWORD ParseHotkeyReserved(
  189. CHAR *pchReserved)
  190. {
  191. ULONG dw;
  192. CHAR *pch;
  193. if (!pchReserved || !*pchReserved)
  194. return 0;
  195. dw = 0;
  196. if ((pch = WOW32_strstr(pchReserved, "hotkey")) != NULL) {
  197. pch += strlen("hotkey");
  198. pch++;
  199. dw = atoi(pch);
  200. }
  201. return dw;
  202. }
  203. /* WK32WowGetNextVdmCommand - Get Next App Name to Exec
  204. *
  205. *
  206. * Entry - lpReturnedString - Pointer to String Buffer
  207. * nSize - Size of Buffer
  208. *
  209. * Exit
  210. * SUCCESS
  211. * if (!pWowInfo->CmdLineSize) {
  212. * // no apps queued
  213. * } else {
  214. * Buffer Has Next App Name to Exec
  215. * and new environment
  216. * }
  217. *
  218. * FAILURE
  219. * Buffer Size too Small or Environment is too small
  220. * pWowInfo->EnvSize - required size
  221. * pWowInfo->CmdLineSize - required size
  222. *
  223. *
  224. */
  225. // these two functions are imported from ntvdm.exe and housed in
  226. // dos\\command\\cmdenv.c
  227. //
  228. extern VOID cmdCheckTempInit(VOID);
  229. extern LPSTR cmdCheckTemp(LPSTR lpszzEnv);
  230. CHAR szProcessHistoryVar[] = "__PROCESS_HISTORY";
  231. CHAR szCompatLayerVar [] = "__COMPAT_LAYER";
  232. CHAR szShimFileLogVar [] = "SHIM_FILE_LOG";
  233. ULONG FASTCALL WK32WowGetNextVdmCommand (PVDMFRAME pFrame)
  234. {
  235. ULONG ul;
  236. PSZ pszEnv16, pszEnv, pszCurDir, pszCmd, pszAppName, pszEnv32, pszTemp;
  237. register PWOWGETNEXTVDMCOMMAND16 parg16;
  238. PWOWINFO pWowInfo;
  239. VDMINFO VDMInfo;
  240. PCHAR pTemp;
  241. WORD w;
  242. CHAR szSiReservedBuf[128];
  243. GETARGPTR(pFrame, sizeof(WOWGETNEXTVDMCOMMAND16), parg16);
  244. GETVDMPTR(parg16->lpWowInfo, sizeof(WOWINFO), pWowInfo);
  245. GETVDMPTR(pWowInfo->lpCmdLine, pWowInfo->CmdLineSize, pszCmd);
  246. GETVDMPTR(pWowInfo->lpAppName, pWowInfo->AppNameSize, pszAppName);
  247. GETVDMPTR(pWowInfo->lpEnv, pWowInfo->EnvSize, pszEnv);
  248. GETVDMPTR(pWowInfo->lpCurDir, pWowInfo->CurDirSize, pszCurDir);
  249. pszEnv16 = pszEnv;
  250. // if we have a real environment pointer and size then
  251. // malloc a 32 bit buffer. Note that the 16 bit buffer should
  252. // be twice the size.
  253. VDMInfo.Enviornment = pszEnv;
  254. pszEnv32 = NULL;
  255. if (pWowInfo->EnvSize != 0) {
  256. if (pszEnv32 = malloc_w(pWowInfo->EnvSize)) {
  257. VDMInfo.Enviornment = pszEnv32;
  258. }
  259. }
  260. SkipWowExec:
  261. VDMInfo.CmdLine = pszCmd;
  262. VDMInfo.CmdSize = pWowInfo->CmdLineSize;
  263. VDMInfo.AppName = pszAppName;
  264. VDMInfo.AppLen = pWowInfo->AppNameSize;
  265. VDMInfo.PifFile = NULL;
  266. VDMInfo.PifLen = 0;
  267. VDMInfo.CurDrive = 0;
  268. VDMInfo.EnviornmentSize = pWowInfo->EnvSize;
  269. VDMInfo.ErrorCode = TRUE;
  270. VDMInfo.VDMState = fSeparateWow ? ASKING_FOR_SEPWOW_BINARY : ASKING_FOR_WOW_BINARY;
  271. VDMInfo.iTask = 0;
  272. VDMInfo.StdIn = 0;
  273. VDMInfo.StdOut = 0;
  274. VDMInfo.StdErr = 0;
  275. VDMInfo.CodePage = 0;
  276. VDMInfo.TitleLen = 0;
  277. VDMInfo.DesktopLen = 0;
  278. VDMInfo.CurDirectory = pszCurDir;
  279. VDMInfo.CurDirectoryLen = pWowInfo->CurDirSize;
  280. VDMInfo.Reserved = szSiReservedBuf;
  281. VDMInfo.ReservedLen = sizeof(szSiReservedBuf);
  282. ul = GetNextVDMCommand (&VDMInfo);
  283. if (ul) {
  284. //
  285. // BaseSrv will return TRUE with CmdSize == 0 if no more commands
  286. //
  287. if (VDMInfo.CmdSize == 0) {
  288. pWowInfo->CmdLineSize = 0;
  289. goto CleanUp;
  290. }
  291. //
  292. // If wowexec is the appname then we don't want to pass it back to
  293. // the existing instance of wowexec in a shared VDM since it will
  294. // basically do nothing but load and exit. Since it is not run we
  295. // need call ExitVDM to cleanup. Next we go back to look for more
  296. // commands.
  297. //
  298. if ((! fSeparateWow) && WOW32_strstr(VDMInfo.AppName, "wowexec.exe")) {
  299. ExitVDM(WOWVDM, VDMInfo.iTask);
  300. goto SkipWowExec;
  301. }
  302. }
  303. //
  304. // WOWEXEC will initially call with a guess of the correct environment
  305. // size. If he did not allocate enough then we will return the appropriate
  306. // size so that he can try again. WOWEXEC knows that we will require a
  307. // buffer twice the size specified. The environment can be up to 64k since
  308. // 16 bit LoadModule can only take a selector pointer to the environment.
  309. //
  310. if ( VDMInfo.EnviornmentSize > pWowInfo->EnvSize ||
  311. VDMInfo.CmdSize > (USHORT)pWowInfo->CmdLineSize ||
  312. VDMInfo.AppLen > (USHORT)pWowInfo->AppNameSize ||
  313. VDMInfo.CurDirectoryLen > (ULONG)pWowInfo->CurDirSize )
  314. {
  315. // We return the size specified, but assume that WOWEXEC will double
  316. // it when allocating memory to allow for the string conversion/
  317. // expansion that might happen for international versions of NT.
  318. // See below where we uppercase and convert to OEM characters.
  319. w = 2*(WORD)VDMInfo.EnviornmentSize;
  320. if ( (DWORD)w == 2*(VDMInfo.EnviornmentSize) ) {
  321. // Fit in a Word!
  322. pWowInfo->EnvSize = (WORD)VDMInfo.EnviornmentSize;
  323. } else {
  324. // Make it the max size (see 16 bit globalrealloc)
  325. pWowInfo->EnvSize = (65536-17)/2;
  326. }
  327. // Pass back other correct sizes required
  328. pWowInfo->CmdLineSize = VDMInfo.CmdSize;
  329. pWowInfo->AppNameSize = VDMInfo.AppLen;
  330. pWowInfo->CurDirSize = (USHORT)VDMInfo.CurDirectoryLen;
  331. ul = FALSE;
  332. }
  333. if ( ul ) {
  334. //
  335. // Boost the hour glass
  336. //
  337. ShowStartGlass (10000);
  338. //
  339. // Save away wShowWindow, hotkey and startup window position from
  340. // the STARTUPINFO structure. We'll pass them over to UserSrv during
  341. // the new app's InitTask call. The assumption here is that this
  342. // will be the last GetNextVDMCommand call before the call to InitTask
  343. // by the newly-created task.
  344. //
  345. dwLastHotkey = ParseHotkeyReserved(VDMInfo.Reserved);
  346. if (VDMInfo.StartupInfo.dwFlags & STARTF_USESHOWWINDOW) {
  347. pWowInfo->wShowWindow =
  348. (VDMInfo.StartupInfo.wShowWindow == SW_SHOWDEFAULT)
  349. ? SW_SHOW : VDMInfo.StartupInfo.wShowWindow ;
  350. } else {
  351. pWowInfo->wShowWindow = SW_SHOW;
  352. }
  353. if (VDMInfo.StartupInfo.dwFlags & STARTF_USEPOSITION) {
  354. dwLastX = VDMInfo.StartupInfo.dwX;
  355. dwLastY = VDMInfo.StartupInfo.dwY;
  356. } else {
  357. dwLastX = dwLastY = (DWORD) CW_USEDEFAULT;
  358. }
  359. if (VDMInfo.StartupInfo.dwFlags & STARTF_USESIZE) {
  360. dwLastXSize = VDMInfo.StartupInfo.dwXSize;
  361. dwLastYSize = VDMInfo.StartupInfo.dwYSize;
  362. } else {
  363. dwLastXSize = dwLastYSize = (DWORD) CW_USEDEFAULT;
  364. }
  365. LOGDEBUG(4, ("WK32WowGetNextVdmCommand: HotKey: %u\n"
  366. " Window Pos: (%u,%u)\n"
  367. " Window Size: (%u,%u)\n",
  368. dwLastHotkey, dwLastX, dwLastY, dwLastXSize, dwLastYSize));
  369. // 20-Jan-1994 sudeepb
  370. // Following callout is for inheriting the directories for the new
  371. // task. After this we mark the CDS's to be invalid which will force
  372. // new directories to be pickedup on need basis. See bug#1995 for
  373. // details.
  374. W32RefreshCurrentDirectories (pszEnv32);
  375. // Save iTask
  376. // When Server16 does the Exec Call we can put this Id into task
  377. // Structure. When the WOW app dies we can notify Win32 using this
  378. // taskid so if any apps are waiting they will get notified.
  379. iW32ExecTaskId = VDMInfo.iTask;
  380. //
  381. // krnl expects ANSI strings!
  382. //
  383. #pragma prefast(suppress:56, src ptr == dst ptr (PREfast bug 526))
  384. OemToChar(pszCmd, pszCmd);
  385. #pragma prefast(suppress:56, src ptr == dst ptr (PREfast bug 526))
  386. OemToChar(pszAppName, pszAppName);
  387. //
  388. // So should the current directory be OEM or Ansi?
  389. //
  390. pWowInfo->iTask = VDMInfo.iTask;
  391. pWowInfo->CurDrive = VDMInfo.CurDrive;
  392. pWowInfo->EnvSize = (USHORT)VDMInfo.EnviornmentSize;
  393. // Uppercase the Environment KeyNames but leave the environment
  394. // variables in mixed case - to be compatible with MS-DOS
  395. // Also convert environment to OEM character set
  396. // another thing that we do here is a fixup to temp/tmp variables
  397. // which occurs via the provided ntvdm functions
  398. if (pszEnv32) {
  399. cmdCheckTempInit();
  400. for (pszTemp = pszEnv32;*pszTemp;pszTemp += (strlen(pszTemp) + 1)) {
  401. PSZ pEnv;
  402. // The MS-DOS Environment is OEM
  403. if (NULL == (pEnv = cmdCheckTemp(pszTemp))) {
  404. pEnv = pszTemp;
  405. }
  406. CharToOem(pEnv,pszEnv);
  407. // Ignore the NT specific Environment variables that start ==
  408. if (*pszEnv != '=') {
  409. if (pTemp = WOW32_strchr(pszEnv,'=')) {
  410. *pTemp = '\0';
  411. // don't uppercase "windir" as it is lowercase for
  412. // Win 3.1 and MS-DOS apps.
  413. if (pTemp-pszEnv != 6 || WOW32_strncmp(pszEnv, "windir", 6))
  414. WOW32_strupr(pszEnv);
  415. *pTemp = '=';
  416. }
  417. }
  418. pszEnv += (strlen(pszEnv) + 1);
  419. }
  420. // Environment is Double NULL terminated
  421. *pszEnv = '\0';
  422. }
  423. }
  424. CleanUp:
  425. if (pszEnv32) {
  426. free_w(pszEnv32);
  427. }
  428. FLUSHVDMPTR(parg16->lpWowInfo, sizeof(WOWINFO), pWowInfo);
  429. FLUSHVDMPTR((ULONG)pWowInfo->lpCmdLine, pWowInfo->CmdLineSize, pszCmd);
  430. FREEVDMPTR(pszCmd);
  431. FREEVDMPTR(pszEnv);
  432. FREEVDMPTR(pszCurDir);
  433. FREEVDMPTR(pWowInfo);
  434. FREEARGPTR(parg16);
  435. RETURN(ul);
  436. }
  437. #if 0
  438. // this version inserts process history
  439. ULONG FASTCALL WK32WowGetNextVdmCommand (PVDMFRAME pFrame)
  440. {
  441. ULONG ul;
  442. PSZ pszEnv16, pszEnv, pszCurDir, pszCmd, pszAppName, pszEnv32, pszTemp;
  443. register PWOWGETNEXTVDMCOMMAND16 parg16;
  444. PWOWINFO pWowInfo;
  445. VDMINFO VDMInfo;
  446. PCHAR pTemp;
  447. CHAR szSiReservedBuf[128];
  448. GETARGPTR(pFrame, sizeof(WOWGETNEXTVDMCOMMAND16), parg16);
  449. GETVDMPTR(parg16->lpWowInfo, sizeof(WOWINFO), pWowInfo);
  450. GETVDMPTR(pWowInfo->lpCmdLine, pWowInfo->CmdLineSize, pszCmd);
  451. GETVDMPTR(pWowInfo->lpAppName, pWowInfo->AppNameSize, pszAppName);
  452. GETVDMPTR(pWowInfo->lpEnv, pWowInfo->EnvSize, pszEnv);
  453. GETVDMPTR(pWowInfo->lpCurDir, pWowInfo->CurDirSize, pszCurDir);
  454. pszEnv16 = pszEnv;
  455. // if we have a real environment pointer and size then
  456. // malloc a 32 bit buffer. Note that the 16 bit buffer should
  457. // be twice the size.
  458. VDMInfo.Enviornment = pszEnv;
  459. pszEnv32 = NULL;
  460. if (pWowInfo->EnvSize != 0) {
  461. if (pszEnv32 = malloc_w(pWowInfo->EnvSize)) {
  462. VDMInfo.Enviornment = pszEnv32;
  463. }
  464. }
  465. SkipWowExec:
  466. VDMInfo.CmdLine = pszCmd;
  467. VDMInfo.CmdSize = pWowInfo->CmdLineSize;
  468. VDMInfo.AppName = pszAppName;
  469. VDMInfo.AppLen = pWowInfo->AppNameSize;
  470. VDMInfo.PifFile = NULL;
  471. VDMInfo.PifLen = 0;
  472. VDMInfo.CurDrive = 0;
  473. VDMInfo.EnviornmentSize = pWowInfo->EnvSize;
  474. VDMInfo.ErrorCode = TRUE;
  475. VDMInfo.VDMState = fSeparateWow ? ASKING_FOR_SEPWOW_BINARY : ASKING_FOR_WOW_BINARY;
  476. VDMInfo.iTask = 0;
  477. VDMInfo.StdIn = 0;
  478. VDMInfo.StdOut = 0;
  479. VDMInfo.StdErr = 0;
  480. VDMInfo.CodePage = 0;
  481. VDMInfo.TitleLen = 0;
  482. VDMInfo.DesktopLen = 0;
  483. VDMInfo.CurDirectory = pszCurDir;
  484. VDMInfo.CurDirectoryLen = pWowInfo->CurDirSize;
  485. VDMInfo.Reserved = szSiReservedBuf;
  486. VDMInfo.ReservedLen = sizeof(szSiReservedBuf);
  487. ul = GetNextVDMCommand (&VDMInfo);
  488. if (ul) {
  489. //
  490. // BaseSrv will return TRUE with CmdSize == 0 if no more commands
  491. //
  492. if (VDMInfo.CmdSize == 0) {
  493. pWowInfo->CmdLineSize = 0;
  494. goto CleanUp;
  495. }
  496. //
  497. // If wowexec is the appname then we don't want to pass it back to
  498. // the existing instance of wowexec in a shared VDM since it will
  499. // basically do nothing but load and exit. Since it is not run we
  500. // need call ExitVDM to cleanup. Next we go back to look for more
  501. // commands.
  502. //
  503. if ((! fSeparateWow) && WOW32_strstr(VDMInfo.AppName, "wowexec.exe")) {
  504. ExitVDM(WOWVDM, VDMInfo.iTask);
  505. goto SkipWowExec;
  506. }
  507. }
  508. //
  509. // WOWEXEC will initially call with a guess of the correct environment
  510. // size. If he did not allocate enough then we will return the appropriate
  511. // size so that he can try again. WOWEXEC knows that we will require a
  512. // buffer twice the size specified. The environment can be up to 64k since
  513. // 16 bit LoadModule can only take a selector pointer to the environment.
  514. //
  515. if ( VDMInfo.EnviornmentSize > pWowInfo->EnvSize ||
  516. VDMInfo.CmdSize > (USHORT)pWowInfo->CmdLineSize ||
  517. VDMInfo.AppLen > (USHORT)pWowInfo->AppNameSize ||
  518. VDMInfo.CurDirectoryLen > (ULONG)pWowInfo->CurDirSize )
  519. {
  520. // We return the size specified, but assume that WOWEXEC will double
  521. // it when allocating memory to allow for the string conversion/
  522. // expansion that might happen for international versions of NT.
  523. // See below where we uppercase and convert to OEM characters.
  524. DWORD dwEnvSize = 2 * (VDMInfo.EnviornmentSize +
  525. VDMInfo.AppLen +
  526. strlen(szProcessHistoryVar) + 2);
  527. if (0 == HIWORD(dwEnvSize)) {
  528. // Fit in a Word!
  529. pWowInfo->EnvSize = (WORD)(dwEnvSize / 2);
  530. } else {
  531. // Make it the max size (see 16 bit globalrealloc)
  532. pWowInfo->EnvSize = (65536-17)/2;
  533. }
  534. // Pass back other correct sizes required
  535. pWowInfo->CmdLineSize = VDMInfo.CmdSize;
  536. pWowInfo->AppNameSize = VDMInfo.AppLen;
  537. pWowInfo->CurDirSize = (USHORT)VDMInfo.CurDirectoryLen;
  538. ul = FALSE;
  539. }
  540. if ( ul ) {
  541. //
  542. // Boost the hour glass
  543. //
  544. ShowStartGlass (10000);
  545. //
  546. // Save away wShowWindow, hotkey and startup window position from
  547. // the STARTUPINFO structure. We'll pass them over to UserSrv during
  548. // the new app's InitTask call. The assumption here is that this
  549. // will be the last GetNextVDMCommand call before the call to InitTask
  550. // by the newly-created task.
  551. //
  552. dwLastHotkey = ParseHotkeyReserved(VDMInfo.Reserved);
  553. if (VDMInfo.StartupInfo.dwFlags & STARTF_USESHOWWINDOW) {
  554. pWowInfo->wShowWindow =
  555. (VDMInfo.StartupInfo.wShowWindow == SW_SHOWDEFAULT)
  556. ? SW_SHOW : VDMInfo.StartupInfo.wShowWindow ;
  557. } else {
  558. pWowInfo->wShowWindow = SW_SHOW;
  559. }
  560. if (VDMInfo.StartupInfo.dwFlags & STARTF_USEPOSITION) {
  561. dwLastX = VDMInfo.StartupInfo.dwX;
  562. dwLastY = VDMInfo.StartupInfo.dwY;
  563. } else {
  564. dwLastX = dwLastY = (DWORD) CW_USEDEFAULT;
  565. }
  566. if (VDMInfo.StartupInfo.dwFlags & STARTF_USESIZE) {
  567. dwLastXSize = VDMInfo.StartupInfo.dwXSize;
  568. dwLastYSize = VDMInfo.StartupInfo.dwYSize;
  569. } else {
  570. dwLastXSize = dwLastYSize = (DWORD) CW_USEDEFAULT;
  571. }
  572. LOGDEBUG(4, ("WK32WowGetNextVdmCommand: HotKey: %u\n"
  573. " Window Pos: (%u,%u)\n"
  574. " Window Size: (%u,%u)\n",
  575. dwLastHotkey, dwLastX, dwLastY, dwLastXSize, dwLastYSize));
  576. // 20-Jan-1994 sudeepb
  577. // Following callout is for inheriting the directories for the new
  578. // task. After this we mark the CDS's to be invalid which will force
  579. // new directories to be pickedup on need basis. See bug#1995 for
  580. // details.
  581. W32RefreshCurrentDirectories (pszEnv32);
  582. // Save iTask
  583. // When Server16 does the Exec Call we can put this Id into task
  584. // Structure. When the WOW app dies we can notify Win32 using this
  585. // taskid so if any apps are waiting they will get notified.
  586. iW32ExecTaskId = VDMInfo.iTask;
  587. //
  588. // krnl expects ANSI strings!
  589. //
  590. OemToChar(pszCmd, pszCmd);
  591. OemToChar(pszAppName, pszAppName);
  592. //
  593. // So should the current directory be OEM or Ansi?
  594. //
  595. pWowInfo->iTask = VDMInfo.iTask;
  596. pWowInfo->CurDrive = VDMInfo.CurDrive;
  597. pWowInfo->EnvSize = (USHORT)VDMInfo.EnviornmentSize;
  598. // Uppercase the Environment KeyNames but leave the environment
  599. // variables in mixed case - to be compatible with MS-DOS
  600. // Also convert environment to OEM character set
  601. // another thing that we do here is a fixup to temp/tmp variables
  602. // which occurs via the provided ntvdm functions
  603. if (pszEnv32) {
  604. LPSTR pszProcessHistory = NULL; // null at first
  605. int nProcessHistoryVarLen = strlen(szProcessHistoryVar);
  606. cmdCheckTempInit();
  607. for (pszTemp = pszEnv32;*pszTemp;pszTemp += (strlen(pszTemp) + 1)) {
  608. PSZ pEnv;
  609. // The MS-DOS Environment is OEM
  610. if (NULL == (pEnv = cmdCheckTemp(pszTemp))) {
  611. pEnv = pszTemp;
  612. }
  613. //
  614. // check for process history variable
  615. //
  616. if (szProcessHistoryVar[0] == *pszTemp) { // quick check first
  617. //
  618. // might be a __process_history
  619. //
  620. if (NULL != (pTemp = WOW32_strchr(pszTemp, '=')) &&
  621. (int)(pTemp - pszTemp) == nProcessHistoryVarLen &&
  622. !WOW32_strnicmp(pszTemp, szProcessHistoryVar, nProcessHistoryVarLen)) {
  623. pszProcessHistory = pszTemp;
  624. // now skip the rest for this item and go to
  625. // the next one. This var will be added later
  626. // since we do not touch pszEnv we won't be
  627. // adding this env var at this time
  628. continue; // go all the way back and resume for loop
  629. }
  630. }
  631. CharToOem(pEnv,pszEnv);
  632. // Ignore the NT specific Environment variables that start ==
  633. if (*pszEnv != '=') {
  634. if (pTemp = WOW32_strchr(pszEnv,'=')) {
  635. *pTemp = '\0';
  636. // don't uppercase "windir" as it is lowercase for
  637. // Win 3.1 and MS-DOS apps.
  638. if (pTemp-pszEnv != 6 || WOW32_strncmp(pszEnv, "windir", 6))
  639. WOW32_strupr(pszEnv);
  640. *pTemp = '=';
  641. }
  642. }
  643. pszEnv += (strlen(pszEnv) + 1);
  644. }
  645. // now add in the process history var
  646. // we have a pointer to it in the pszProcessHistory space
  647. if (NULL != pszProcessHistory) {
  648. // copy the variable
  649. CharToOem(pszProcessHistory, pszEnv);
  650. // advance the pointer
  651. pszEnv += strlen(pszEnv);
  652. // add semicolon
  653. *pszEnv++ = ';';
  654. }
  655. else {
  656. CharToOem(szProcessHistoryVar, pszEnv);
  657. pszEnv += strlen(pszEnv); // skip over the name
  658. // put in an equal sign
  659. *pszEnv++ = '=';
  660. }
  661. // copy app name if there
  662. CharToOem(pszAppName, pszEnv);
  663. pszEnv += strlen(pszEnv) + 1;
  664. // Environment is Double NULL terminated
  665. *pszEnv = '\0';
  666. // now sort it
  667. WOWSortEnvironmentStrings(pszEnv16);
  668. }
  669. }
  670. CleanUp:
  671. if (pszEnv32) {
  672. free_w(pszEnv32);
  673. }
  674. FLUSHVDMPTR(parg16->lpWowInfo, sizeof(WOWINFO), pWowInfo);
  675. FLUSHVDMPTR((ULONG)pWowInfo->lpCmdLine, pWowInfo->CmdLineSize, pszCmd);
  676. FREEVDMPTR(pszCmd);
  677. FREEVDMPTR(pszEnv);
  678. FREEVDMPTR(pszCurDir);
  679. FREEVDMPTR(pWowInfo);
  680. FREEARGPTR(parg16);
  681. RETURN(ul);
  682. }
  683. #endif
  684. /*++
  685. WK32WOWInitTask - API Used to Create a New Task + Thread
  686. Routine Description:
  687. All the 16 bit initialization is completed, the app is loaded in memory and ready to go
  688. we come here to create a thread for this task.
  689. The current thread impersonates the new task, its running on the new tasks stack and it
  690. has its wTDB, this makes it easy for us to get a pointer to the new tasks stack and for it
  691. to have the correct 16 bit stack frame. In order for the creator to continue correctly
  692. we set RET_TASKSTARTED on the stack. Kernel16 will then not return to the new task
  693. but will know to restart the creator and put his thread ID and stack back.
  694. We ResetEvent so we can wait for the new thread to get going, this is important since
  695. we want the first YIELD call from the creator to yield to the newly created task.
  696. Special Case During Boot
  697. During the boot process the kernel will load the first app into memory on the main thread
  698. using the regular LoadModule. We don't want the first app to start running until the kernel
  699. boot is completed so we can reuse the first thread.
  700. Arguments:
  701. pFrame - Points to the New Tasks Stack Frame
  702. Return Value:
  703. TRUE - Successfully Created a Thread
  704. FALSE - Failed to Create a New Task
  705. --*/
  706. ULONG FASTCALL WK32WOWInitTask(PVDMFRAME pFrame)
  707. {
  708. VPVOID vpStack;
  709. DWORD dwThreadId;
  710. HANDLE hThread;
  711. vpStack = VDMSTACK();
  712. pFrame->wRetID = RET_TASKSTARTED;
  713. /*
  714. * Suspend the timer thread on the startup of every task
  715. * To allow resyncing of the dos time to the system time.
  716. * When wowexec is the only task running the timer thread
  717. * will remain suspended. When the new task actually intializes
  718. * it will resume the timer thread, provided it is not wowexec.
  719. */
  720. if (nWOWTasks != 1)
  721. SuspendTimerThread(); // turns timer thread off
  722. if (fBoot) {
  723. W32Thread((LPVOID)vpStack); // SHOULD NEVER RETURN
  724. WOW32ASSERTMSG(FALSE, "\nWOW32: WK32WOWInitTask ERROR - Main Thread Returning - Contact DaveHart\n");
  725. ExitVDM(WOWVDM, ALL_TASKS);
  726. ExitProcess(EXIT_FAILURE);
  727. }
  728. //
  729. // VadimB: remember parent's TDB
  730. //
  731. hThread = host_CreateThread(NULL,
  732. 8192,
  733. W32Thread,
  734. (LPVOID)vpStack,
  735. CREATE_SUSPENDED,
  736. &dwThreadId);
  737. ((PTDB)SEGPTR(pFrame->wTDB,0))->TDB_hThread = (DWORD) hThread;
  738. ((PTDB)SEGPTR(pFrame->wTDB,0))->TDB_ThreadID = dwThreadId;
  739. if ( hThread ) {
  740. WOW32VERIFY(DuplicateHandle(
  741. GetCurrentProcess(),
  742. hThread,
  743. GetCurrentProcess(),
  744. (HANDLE *) &ghTaskCreation,
  745. 0,
  746. FALSE,
  747. DUPLICATE_SAME_ACCESS
  748. ));
  749. }
  750. #ifdef DEBUG
  751. {
  752. char szModName[9];
  753. RtlCopyMemory(szModName, ((PTDB)SEGPTR(pFrame->wTDB,0))->TDB_ModName, 8);
  754. szModName[8] = 0;
  755. LOGDEBUG( hThread ? LOG_IMPORTANT : LOG_ALWAYS,
  756. ("\nWK32WOWInitTask: %s task %04x %s\n",
  757. hThread ? "created" : "ERROR failed to create",
  758. pFrame->wTDB,
  759. szModName
  760. ));
  761. }
  762. #endif
  763. return hThread ? TRUE : FALSE;
  764. }
  765. /*++
  766. WK32YIELD - Yield to the Next Task
  767. Routine Description:
  768. Normal Case - A 16 bit task is running and wants to give up the CPU to any higher priority
  769. task that might want to run. Since we are running with a non-preemptive scheduler apps
  770. have to cooperate.
  771. ENTRY
  772. pFrame - Not used
  773. EXIT
  774. Nothing
  775. --*/
  776. ULONG FASTCALL WK32Yield(PVDMFRAME pFrame)
  777. {
  778. //
  779. // WARNING: wkgthunk.c's WOWYield16 export (part of the Generic Thunk
  780. // interface) calls this thunk with a NULL pFrame. If you
  781. // change this function to use pFrame change WOWYield16 as
  782. // well.
  783. //
  784. UNREFERENCED_PARAMETER(pFrame);
  785. BlockWOWIdle(TRUE);
  786. (pfnOut.pfnYieldTask)();
  787. BlockWOWIdle(FALSE);
  788. RETURN(0);
  789. }
  790. /*++
  791. WK32WowSyncNewTask -
  792. Routine Description:
  793. Sync parent and child thread with apphelp (child thread
  794. could potentially be blocked by apphelp)
  795. EXIT
  796. for parent thread nothing
  797. for child thread
  798. 0 - continue running the app
  799. 1 - wait in a loop
  800. -1 - exit the thread, user selected not to run this app
  801. , app is hard blocked
  802. --*/
  803. ULONG FASTCALL WK32WowSyncTask(PVDMFRAME pFrame)
  804. {
  805. PTDB ptdb;
  806. //
  807. // Parent task (thread) comes here from loader
  808. // -ghTaskCreation is set to child thread handle
  809. // in Wk32WowInitTask, so it is guaranteed to be non NULL.
  810. // -when child task (thread) signals it from W32Thread and
  811. // parent returns immediately "never" going to the second
  812. // part of this function
  813. if (ghTaskCreation) {
  814. DWORD dw;
  815. HANDLE ThreadEvents[2];
  816. ThreadEvents[0] = ghevWaitCreatorThread;
  817. ThreadEvents[1] = ghTaskCreation;
  818. ghTaskCreation = NULL;
  819. WOW32VERIFY( ResumeThread(ThreadEvents[1]) != (DWORD)-1 ); // ghTaskCreation
  820. dw = WaitForMultipleObjects(2, ThreadEvents, FALSE, INFINITE);
  821. if (dw != WAIT_OBJECT_0) {
  822. WOW32ASSERTMSGF(FALSE,
  823. ("\nWK32SyncNewTask: ERROR WaitInitTask %d gle %d\n\n", dw, GetLastError())
  824. );
  825. ResetEvent(ghevWaitCreatorThread);
  826. }
  827. CloseHandle(ThreadEvents[1]); // ghTaskCreation
  828. WK32Yield(pFrame);
  829. return 0;
  830. }
  831. //
  832. // Child task (thread) comes here from StartWowTask
  833. // - ghTaskCreation is NULL, so it skips the first part
  834. // of this function.
  835. // -ghTaskAppHelp if set (in CheckAppHelpInfo) means wait for user input
  836. if (ghTaskAppHelp) {
  837. DWORD dwResult;
  838. // if the app wasn't hardblocked
  839. // wait for the user input.
  840. if(gfTaskContinue) {
  841. dwResult = WaitForSingleObject(ghTaskAppHelp,10);
  842. // -if WaitForSingleObject timed out, return to 16bit to process hardware interrupts
  843. // then come back try again, apphelp is still waiting for user input
  844. if (WAIT_TIMEOUT == dwResult) {
  845. return 1; // back to 16-bit to loop and try again
  846. }
  847. gfTaskContinue = FALSE;
  848. if (WAIT_OBJECT_0 == dwResult &&
  849. GetExitCodeProcess(ghTaskAppHelp,&dwResult) &&
  850. 0 != dwResult)
  851. {
  852. gfTaskContinue = TRUE;
  853. }
  854. }
  855. CloseHandle(ghTaskAppHelp);
  856. ghTaskAppHelp = NULL;
  857. }
  858. //
  859. // gfTaskContinue is FALSE if
  860. // 1) user decided to abort the app
  861. // 2) app was hardblocked
  862. // 3) zzzInitTask failed.
  863. //
  864. if (!gfTaskContinue) {
  865. return -1;
  866. }
  867. //
  868. // App is ready to run
  869. // if this app requires 256 color display mode, set it now
  870. //
  871. ptdb = (PTDB)SEGPTR(pFrame->wTDB,0);
  872. if (ptdb->TDB_WOWCompatFlagsEx & WOWCFEX_DISPMODE256){
  873. WK32ChangeDisplayMode(8);
  874. }
  875. //
  876. // Some apps need to start from the exe file's directory
  877. // Whistler bug 281759
  878. if (CURRENTPTD()->dwWOWCompatFlags2 & WOWCF2_RESETCURDIR) {
  879. CURRENTPTD()->dwWOWCompatFlags2 &= ~WOWCF2_RESETCURDIR;
  880. DosWowSetCurrentDirectory((LPSTR)ptdb->TDB_Directory);
  881. }
  882. return 0;
  883. }
  884. ULONG FASTCALL WK32OldYield(PVDMFRAME pFrame)
  885. {
  886. UNREFERENCED_PARAMETER(pFrame);
  887. BlockWOWIdle(TRUE);
  888. (pfnOut.pfnDirectedYield)(DY_OLDYIELD);
  889. BlockWOWIdle(FALSE);
  890. RETURN(0);
  891. }
  892. /*++
  893. WK32ForegroundIdleHook - Supply WMU_FOREGROUNDIDLE message when system
  894. (foreground "task") goes idle; support for int 2f
  895. Routine Description:
  896. This is the hook procedure for idle detection. When the
  897. foregorund task goes idle, if the int 2f is hooked, then
  898. we will get control here and we call Wow16 to issue
  899. the int 2f:1689 to signal the idle condition to the hooker.
  900. ENTRY
  901. normal hook parameters: ignored
  902. EXIT
  903. Nothing
  904. --*/
  905. LRESULT CALLBACK WK32ForegroundIdleHook(int code, WPARAM wParam, LPARAM lParam)
  906. {
  907. PARM16 Parm16;
  908. UNREFERENCED_PARAMETER(code);
  909. UNREFERENCED_PARAMETER(wParam);
  910. UNREFERENCED_PARAMETER(lParam);
  911. CallBack16(RET_FOREGROUNDIDLE, &Parm16, 0, 0);
  912. RETURN(0);
  913. }
  914. /*++
  915. WK32WowSetIdleHook - Set the hook so we will get notified when the
  916. (foreground "task") goes idle; support for int 2f
  917. Routine Description:
  918. This sets the hook procedure for idle detection. When the
  919. foregorund task goes idle, if the int 2f is hooked, then
  920. we will get control above and send a message to WOW so it can issue
  921. the int 2f:1689 to signal the idle condition to the hooker.
  922. ENTRY
  923. pFrame - not used
  924. EXIT
  925. The hook is set and it's handle is placed in to the per thread
  926. data ptd->hIdleHook. 0 is returned. On
  927. failure, the hook is just not set (sorry), but a debug call is
  928. made.
  929. --*/
  930. ULONG FASTCALL WK32WowSetIdleHook(PVDMFRAME pFrame)
  931. {
  932. PTD ptd;
  933. UNREFERENCED_PARAMETER(pFrame);
  934. ptd = CURRENTPTD();
  935. if (ptd->hIdleHook == NULL) {
  936. // If there is no hook already set then set a GlobalHook
  937. // It is important to set a GlobalHook otherwise we will not
  938. // Get accurate timing results with a LocalHook.
  939. ptd->hIdleHook = SetWindowsHookEx(WH_FOREGROUNDIDLE,
  940. WK32ForegroundIdleHook,
  941. hmodWOW32,
  942. 0);
  943. WOW32ASSERTMSG(ptd->hIdleHook, "\nWK32WowSetIdleHook : ERROR failed to Set Idle Hook Proc\n\n");
  944. }
  945. RETURN(0);
  946. }
  947. /*++
  948. W32Thread - New Thread Starts Here
  949. Routine Description:
  950. A newly created thread starts here. We Allocated the Per Task Data from
  951. the Threads Stack and point NtCurrentTeb()->WOW32Reserved at it, so that
  952. we can find it quickly when we dispatch an api or recieve a message from
  953. Win 32.
  954. NOTE - The Call to Win32 InitTask() does NOT return until we are in sync
  955. with the other 16 bit tasks in the non-preemptive scheduler.
  956. Once We have everything initialized we SetEvent to wake our Creator thread
  957. and then call Win32 to get in sync with the other tasks running in the
  958. non-preemptive scheduler.
  959. Special Case - BOOT
  960. We return (host_simulate) to the caller - kernel16, so he can complete
  961. his initialization and then reuse the same thread to start the first app
  962. (usually wowexec the wow shell).
  963. The second host_simulate call doesn't return until the app exits
  964. (see tasking.asm - ExitSchedule) at which point we tidy up the task and
  965. then kill this thread. Win32 Non-Preemptive Scheduler will detect the
  966. thread going away and will then schedule another task.
  967. ENTRY
  968. 16:16 to New Task Stack
  969. EXIT
  970. NEVER RETURNS - Thread Exits
  971. --*/
  972. DWORD W32Thread(LPVOID vpInitialSSSP)
  973. {
  974. TD td;
  975. UNICODE_STRING uImageName;
  976. WCHAR wcImageName[MAX_VDMFILENAME];
  977. RTL_PERTHREAD_CURDIR rptc;
  978. PVDMFRAME pFrame;
  979. PWOWINITTASK16 pArg16;
  980. PTDB ptdb;
  981. USHORT SaveIp;
  982. RtlZeroMemory(&td, sizeof(TD));
  983. InitializeCriticalSection(&td.csTD);
  984. if (gptdShell == NULL) {
  985. //
  986. // This is the initial thread, free the temporary TD we used during
  987. // boot.
  988. //
  989. DeleteCriticalSection(&CURRENTPTD()->csTD);
  990. free_w( (PVOID) CURRENTPTD() );
  991. gptdShell = &td;
  992. } else if (pptdWOA) {
  993. //
  994. // See WK32WOWLoadModule32
  995. //
  996. *pptdWOA = &td;
  997. pptdWOA = NULL;
  998. }
  999. CURRENTPTD() = &td;
  1000. if (fBoot) {
  1001. td.htask16 = 0;
  1002. td.hInst16 = 0;
  1003. td.hMod16 = 0;
  1004. {
  1005. VPVOID vpStack;
  1006. vpStack = VDMSTACK();
  1007. GETFRAMEPTR(vpStack, pFrame);
  1008. pFrame->wAX = 1;
  1009. }
  1010. SaveIp = getIP();
  1011. host_simulate();
  1012. setIP(SaveIp);
  1013. }
  1014. // Init the task with the WOW global DPM tables
  1015. DPMFAMTBLS() = pgDpmWowFamTbls;
  1016. //
  1017. // Initialize Per Task Data
  1018. //
  1019. GETFRAMEPTR((VPVOID)vpInitialSSSP, pFrame);
  1020. td.htask16 = pFrame->wTDB;
  1021. ptdb = (PTDB)SEGPTR(td.htask16,0);
  1022. td.VDMInfoiTaskID = iW32ExecTaskId;
  1023. iW32ExecTaskId = (UINT)-1;
  1024. td.vpStack = (VPVOID)vpInitialSSSP;
  1025. td.dwThreadID = GetCurrentThreadId();
  1026. if (THREADID32(td.htask16) == 0) {
  1027. ptdb->TDB_ThreadID = td.dwThreadID;
  1028. }
  1029. EnterCriticalSection(&gcsWOW);
  1030. td.ptdNext = gptdTaskHead;
  1031. gptdTaskHead = &td;
  1032. LeaveCriticalSection(&gcsWOW);
  1033. td.hrgnClip = (HRGN)NULL;
  1034. td.ulLastDesktophDC = 0;
  1035. td.pWOAList = NULL;
  1036. //
  1037. // NOTE - Add YOUR Per Task Init Code HERE
  1038. //
  1039. td.hIdleHook = NULL;
  1040. //
  1041. // Set the CSR batching limit to whatever was specified in
  1042. // win.ini [WOW] BatchLimit= line, which we read into
  1043. // dwWOWBatchLimit during WOW startup in W32Init.
  1044. //
  1045. // This code allows the performance people to benchmark
  1046. // WOW on an API for API basis without having to use
  1047. // a private CSRSRV.DLL with a hardcoded batch limit of 1.
  1048. //
  1049. // Note: This is a per-thread attribute, so we must call
  1050. // ==== GdiSetBatchLimit during the initialization of
  1051. // each thread that could call GDI on behalf of
  1052. // 16-bit code.
  1053. //
  1054. if (dwWOWBatchLimit) {
  1055. DWORD dwOldBatchLimit;
  1056. dwOldBatchLimit = GdiSetBatchLimit(dwWOWBatchLimit);
  1057. LOGDEBUG(LOG_ALWAYS,("WOW W32Thread: Changed thread %d GDI batch limit from %u to %u.\n",
  1058. nWOWTasks+1, dwOldBatchLimit, dwWOWBatchLimit));
  1059. }
  1060. nWOWTasks++;
  1061. //
  1062. // Inittask: requires ExpWinVer and Modulename
  1063. //
  1064. {
  1065. DWORD dwExpWinVer;
  1066. DWORD dwCompatFlags;
  1067. BYTE szModName[9]; // modname = 8bytes + nullchar
  1068. BYTE szBaseFileName[9]; // 8.3 filename minus .3
  1069. LPSTR pszBaseName;
  1070. CHAR szFilePath[256];
  1071. LPBYTE lpModule;
  1072. PWOWINITTASK16 pArgIT16;
  1073. PTDB ptdb2;
  1074. WORD wPathOffset;
  1075. BYTE bImageNameLength;
  1076. ULONG ulLength;
  1077. BOOL fRet;
  1078. DWORD dw;
  1079. HANDLE hThread;
  1080. GETARGPTR(pFrame, sizeof(WOWINITTASK16), pArgIT16);
  1081. ptdb2 = (PTDB)SEGPTR(td.htask16,0);
  1082. td.hInst16 = ptdb2->TDB_Module;
  1083. td.hMod16 = ptdb2->TDB_pModule;
  1084. hThread = (HANDLE)ptdb2->TDB_hThread;
  1085. dwExpWinVer = FETCHDWORD(pArgIT16->dwExpWinVer);
  1086. RtlCopyMemory(szModName, ptdb2->TDB_ModName, 8);
  1087. dwCompatFlags = *((DWORD *)&ptdb2->TDB_CompatFlags);
  1088. szModName[8] = (BYTE)0;
  1089. #define NE_PATHOFFSET 10 // Offset to file path stuff
  1090. dw = MAKELONG(0,td.hMod16);
  1091. GETMISCPTR( dw, lpModule );
  1092. wPathOffset = *((LPWORD)(lpModule+NE_PATHOFFSET));
  1093. bImageNameLength = *(lpModule+wPathOffset);
  1094. bImageNameLength -= 8; // 7 bytes of trash at the start
  1095. wPathOffset += 8;
  1096. RtlCopyMemory(szFilePath, lpModule + wPathOffset, bImageNameLength);
  1097. szFilePath[bImageNameLength] = 0;
  1098. RtlMultiByteToUnicodeN( wcImageName,
  1099. sizeof(wcImageName),
  1100. &ulLength,
  1101. szFilePath,
  1102. bImageNameLength );
  1103. wcImageName[bImageNameLength] = L'\0';
  1104. RtlInitUnicodeString(&uImageName, wcImageName);
  1105. LOGDEBUG(2,("WOW W32Thread: setting image name to %ws\n",
  1106. wcImageName));
  1107. RtlAssociatePerThreadCurdir( &rptc, NULL, &uImageName, NULL );
  1108. FREEMISCPTR( lpModule );
  1109. //
  1110. // Add this task to the list of 16-bit tasks
  1111. //
  1112. AddTaskSharedList( &td, szModName, szFilePath);
  1113. //
  1114. // Get the base part of the filename, no path or extension,
  1115. // for InitTask to use looking for setup program names.
  1116. // Often this is the same as the module name, to shortcut
  1117. // redundant checks we only pass the base filename if it
  1118. // differs from the module name.
  1119. //
  1120. if (!(pszBaseName = WOW32_strrchr(szFilePath, '\\'))) {
  1121. WOW32ASSERTMSG(FALSE, "W32Thread assumed path was fully qualified, no '\\'.\n");
  1122. }
  1123. pszBaseName++; // skip over backslash to point at start of base filename.
  1124. RtlCopyMemory(szBaseFileName, pszBaseName, sizeof(szBaseFileName) - 1);
  1125. szBaseFileName[sizeof(szBaseFileName) - 1] = 0;
  1126. if (pszBaseName = WOW32_strchr(szBaseFileName, '.')) {
  1127. *pszBaseName = 0;
  1128. }
  1129. if (!WOW32_strcmp(szBaseFileName, szModName)) {
  1130. pszBaseName = NULL;
  1131. } else {
  1132. pszBaseName = szBaseFileName;
  1133. }
  1134. //
  1135. // Initialize WOW compatibility flags from the database
  1136. //
  1137. //
  1138. gfTaskContinue = CheckAppHelpInfo(&td,szFilePath,szModName);
  1139. //
  1140. // We now inherit the WOW compatibility flags from the parent's TDB. Right
  1141. // now We are only interested in inheriting the WOWCF_UNIQUEHDCHWND flag
  1142. // in order to really fix a bug with MS Publisher. Each Wizard and Cue Cards
  1143. // that ship with mspub is its own task and would require MANY new
  1144. // compatibility flag entries in the registry. This mechanism allows anything
  1145. // spawned from an app that has WOWCF_UNIQUEHDCHWND to have
  1146. // WOWCF_UNIQUEHDCHWND.
  1147. if (ptdb2->TDB_WOWCompatFlags & LOWORD(WOWCF_UNIQUEHDCHWND)) {
  1148. td.dwWOWCompatFlags |= LOWORD(WOWCF_UNIQUEHDCHWND);
  1149. }
  1150. // Exchange setup and Return of Arcade module names conflict (bootstrp)
  1151. // so set GACF_HACKWINFLAGS if it is specified in WOWCF2_
  1152. // Whistler bug 384201
  1153. if (td.dwWOWCompatFlags2 & WOWCF2_HACKWINFLAGS) {
  1154. ptdb2->TDB_CompatFlags |= LOWORD(GACF_HACKWINFLAGS);
  1155. }
  1156. if (td.dwWOWCompatFlagsEx & WOWCFEX_WIN31VERSIONLIE) {
  1157. ptdb2->TDB_CompatFlags2 |= HIWORD(GACF_WINVER31);
  1158. }
  1159. //
  1160. // Some apps need to start from the exe file's directory
  1161. // Whistler bug 281759 (check wowsynctask also)
  1162. if(td.dwWOWCompatFlags2 & WOWCF2_RESETCURDIR) {
  1163. if (pszBaseName = WOW32_strrchr(szFilePath, '\\')) {
  1164. *pszBaseName = 0;
  1165. WOW32_strncpy(ptdb2->TDB_Directory,szFilePath,TDB_DIR_SIZE);
  1166. }
  1167. ptdb2->TDB_Directory[TDB_DIR_SIZE]='\0';
  1168. }
  1169. if(td.dwWOWCompatFlags2 & WOWCF2_USEMINIMALENVIRONMENT) {
  1170. WOWStripDownTheEnvironment(ptdb2->TDB_PDB);
  1171. }
  1172. ptdb2->TDB_WOWCompatFlags = LOWORD(td.dwWOWCompatFlags);
  1173. ptdb2->TDB_WOWCompatFlags2 = HIWORD(td.dwWOWCompatFlags);
  1174. ptdb2->TDB_WOWCompatFlagsEx = LOWORD(td.dwWOWCompatFlagsEx);
  1175. ptdb2->TDB_WOWCompatFlagsEx2 = HIWORD(td.dwWOWCompatFlagsEx);
  1176. #ifdef FE_SB
  1177. ptdb2->TDB_WOWCompatFlagsJPN = LOWORD(td.dwWOWCompatFlagsFE);
  1178. ptdb2->TDB_WOWCompatFlagsJPN2 = HIWORD(td.dwWOWCompatFlagsFE);
  1179. #endif // FE_SB
  1180. // Enable the special VDMAllocateVirtualMemory strategy in NTVDM.
  1181. if (td.dwWOWCompatFlagsEx & WOWCFEX_FORCEINCDPMI) {
  1182. #ifdef i386
  1183. DpmiSetIncrementalAlloc(TRUE);
  1184. #else
  1185. SetWOWforceIncrAlloc(TRUE);
  1186. #endif
  1187. }
  1188. FREEVDMPTR(ptdb2);
  1189. // Init task forces us to the active task in USER
  1190. // and does ShowStartGlass, so new app gets focus correctly
  1191. dw = 0;
  1192. do {
  1193. if (dw) {
  1194. Sleep(dw * 50);
  1195. }
  1196. fRet = (pfnOut.pfnInitTask)(dwExpWinVer,
  1197. dwCompatFlags,
  1198. td.dwUserWOWCompatFlags,
  1199. szModName,
  1200. pszBaseName,
  1201. td.htask16 | HTW_IS16BIT,
  1202. dwLastHotkey,
  1203. fSeparateWow ? 0 : td.VDMInfoiTaskID,
  1204. dwLastX,
  1205. dwLastY,
  1206. dwLastXSize,
  1207. dwLastYSize
  1208. );
  1209. } while (dw++ < 6 && !fRet);
  1210. if (!fRet) {
  1211. LOGDEBUG(LOG_ALWAYS,
  1212. ("\n%04X task, PTD address %08X InitTaskFailed\n",
  1213. td.htask16,
  1214. &td)
  1215. );
  1216. if(ghTaskAppHelp) {
  1217. CloseHandle(ghTaskAppHelp);
  1218. ghTaskAppHelp = NULL;
  1219. gfTaskContinue = FALSE;
  1220. }
  1221. }
  1222. dwLastHotkey = 0;
  1223. dwLastX = dwLastY = dwLastXSize = dwLastYSize = (DWORD) CW_USEDEFAULT;
  1224. if (fBoot) {
  1225. fBoot = FALSE;
  1226. //
  1227. // This call needs to happen after WOWExec's InitTask call so that
  1228. // USER sees us as expecting Windows version 3.10 -- otherwise they
  1229. // will fail some of the LoadCursor calls.
  1230. //
  1231. InitStdCursorIconAlias();
  1232. } else {
  1233. //
  1234. // Syncronize the new thread with the creator thread.
  1235. // Wake our creator thread
  1236. //
  1237. WOW32VERIFY(SetEvent(ghevWaitCreatorThread));
  1238. }
  1239. td.hThread = hThread;
  1240. LOGDEBUG(2,("WOW W32Thread: New thread ready for execution\n"));
  1241. // turn the timer thread on if its not for the first task
  1242. // which we presume to be wowexec
  1243. if (nWOWTasks != 1) {
  1244. ResumeTimerThread();
  1245. }
  1246. FREEARGPTR(pArgIT16);
  1247. }
  1248. FREEVDMPTR(pFrame);
  1249. GETFRAMEPTR((VPVOID)vpInitialSSSP, pFrame);
  1250. WOW32ASSERT(pFrame->wTDB == td.htask16);
  1251. SETVDMSTACK(vpInitialSSSP);
  1252. pFrame->wRetID = RET_RETURN;
  1253. //
  1254. // Let user set breakpoints before Starting App
  1255. //
  1256. if ( IsDebuggerAttached() ) {
  1257. GETARGPTR(pFrame, sizeof(WOWINITTASK16), pArg16);
  1258. DBGNotifyNewTask((LPVOID)pArg16, OFFSETOF(VDMFRAME,bArgs) );
  1259. FREEARGPTR(pArg16);
  1260. if (flOptions & OPT_BREAKONNEWTASK) {
  1261. LOGDEBUG(
  1262. LOG_ALWAYS,
  1263. ("\n%04X %08X task is starting, PTD address %08X, type g to continue\n\n",
  1264. td.htask16,
  1265. pFrame->vpCSIP,
  1266. &td));
  1267. DebugBreak();
  1268. }
  1269. }
  1270. //
  1271. // Start APP
  1272. //
  1273. BlockWOWIdle(FALSE);
  1274. #ifdef DEBUG
  1275. // BUGBUG: HACK ALERT
  1276. // This code has been added to aid in debugging a problem that only
  1277. // seems to occur on MIPS chk
  1278. // What appears to be happening is that the SS:SP is set correctly
  1279. // above, but sometime later, perhaps during the "BlockWOWIdle" call,
  1280. // the emulator's flat stack pointer ends up getting reset to WOWEXEC's
  1281. // stack. The SETVDMSTACK call below will reset the values we want so
  1282. // that the user can continue normally.
  1283. WOW32ASSERTMSG(LOWORD(vpInitialSSSP)==getSP(), "WOW32: W32Thread Error - SP is invalid!\n");
  1284. SETVDMSTACK(vpInitialSSSP);
  1285. #endif
  1286. SaveIp = getIP();
  1287. host_simulate();
  1288. setIP(SaveIp);
  1289. //
  1290. // We should Never Come Here, an app should get terminated via calling wk32killtask thunk
  1291. // not by doing an unsimulate call.
  1292. //
  1293. #ifdef DEBUG
  1294. WOW32ASSERTMSG(FALSE, "WOW32: W32Thread Error - Too many unsimulate calls\n");
  1295. #else
  1296. if (IsDebuggerAttached() && (flOptions & OPT_DEBUG)) {
  1297. DbgBreakPoint();
  1298. }
  1299. #endif
  1300. W32DestroyTask(&td);
  1301. host_ExitThread(EXIT_SUCCESS);
  1302. return 0;
  1303. }
  1304. /* WK32KillTask - Force the Distruction of the Current Thread
  1305. *
  1306. * Called When App Does an Exit
  1307. * If there is another active Win16 app then USER32 will schedule another
  1308. * task.
  1309. *
  1310. * ENTRY
  1311. *
  1312. * EXIT
  1313. * Never Returns - We kill the process
  1314. *
  1315. */
  1316. ULONG FASTCALL WK32WOWKillTask(PVDMFRAME pFrame)
  1317. {
  1318. UNREFERENCED_PARAMETER(pFrame);
  1319. CURRENTPTD()->dwFlags &= ~TDF_FORCETASKEXIT;
  1320. W32DestroyTask(CURRENTPTD());
  1321. host_ExitThread(EXIT_SUCCESS);
  1322. return 0; // to quiet compiler, never executed.
  1323. }
  1324. /*++
  1325. W32RemoteThread - New Remote Thread Starts Here
  1326. Routine Description:
  1327. The debugger needs to be able to call back into 16-bit code to
  1328. execute some toolhelp functions. This function is provided as a remote
  1329. interface to calling 16-bit functions.
  1330. ENTRY
  1331. 16:16 to New Task Stack
  1332. EXIT
  1333. NEVER RETURNS - Thread Exits
  1334. --*/
  1335. VDMCONTEXT vcRemote;
  1336. VDMCONTEXT vcSave;
  1337. VPVOID vpRemoteBlock = (DWORD)0;
  1338. WORD wPrevTDB = 0;
  1339. DWORD dwPrevEBP = 0;
  1340. DWORD W32RemoteThread(VOID)
  1341. {
  1342. TD td;
  1343. PVDMFRAME pFrame;
  1344. HANDLE hThread;
  1345. NTSTATUS Status;
  1346. THREAD_BASIC_INFORMATION ThreadInfo;
  1347. OBJECT_ATTRIBUTES obja;
  1348. VPVOID vpStack;
  1349. RtlZeroMemory(&td, sizeof(TD));
  1350. // turn the timer thread off to resync dos time
  1351. if (nWOWTasks != 1)
  1352. SuspendTimerThread();
  1353. Status = NtQueryInformationThread(
  1354. NtCurrentThread(),
  1355. ThreadBasicInformation,
  1356. (PVOID)&ThreadInfo,
  1357. sizeof(THREAD_BASIC_INFORMATION),
  1358. NULL
  1359. );
  1360. if ( !NT_SUCCESS(Status) ) {
  1361. #if DBG
  1362. DbgPrint("NTVDM: Could not get thread information\n");
  1363. DbgBreakPoint();
  1364. #endif
  1365. return( 0 );
  1366. }
  1367. InitializeObjectAttributes(
  1368. &obja,
  1369. NULL,
  1370. 0,
  1371. NULL,
  1372. 0 );
  1373. Status = NtOpenThread(
  1374. &hThread,
  1375. THREAD_SET_CONTEXT
  1376. | THREAD_GET_CONTEXT
  1377. | THREAD_QUERY_INFORMATION,
  1378. &obja,
  1379. &ThreadInfo.ClientId );
  1380. if ( !NT_SUCCESS(Status) ) {
  1381. #if DBG
  1382. DbgPrint("NTVDM: Could not get open thread handle\n");
  1383. DbgBreakPoint();
  1384. #endif
  1385. return( 0 );
  1386. }
  1387. cpu_createthread( hThread, NULL );
  1388. Status = NtClose( hThread );
  1389. if ( !NT_SUCCESS(Status) ) {
  1390. #if DBG
  1391. DbgPrint("NTVDM: Could not close thread handle\n");
  1392. DbgBreakPoint();
  1393. #endif
  1394. return( 0 );
  1395. }
  1396. InitializeCriticalSection(&td.csTD);
  1397. CURRENTPTD() = &td;
  1398. //
  1399. // Save the current state (for future callbacks)
  1400. //
  1401. vcSave.SegSs = getSS();
  1402. vcSave.SegCs = getCS();
  1403. vcSave.SegDs = getDS();
  1404. vcSave.SegEs = getES();
  1405. vcSave.Eax = getAX();
  1406. vcSave.Ebx = getBX();
  1407. vcSave.Ecx = getCX();
  1408. vcSave.Edx = getDX();
  1409. vcSave.Esi = getSI();
  1410. vcSave.Edi = getDI();
  1411. vcSave.Ebp = getBP();
  1412. vcSave.Eip = getIP();
  1413. vcSave.Esp = getSP();
  1414. wPrevTDB = *pCurTDB;
  1415. //
  1416. // Now prepare for the callback. Set the registers such that it looks
  1417. // like we are returning from the WOWKillRemoteTask call.
  1418. //
  1419. setDS( (WORD)vcRemote.SegDs );
  1420. setES( (WORD)vcRemote.SegEs );
  1421. setAX( (WORD)vcRemote.Eax );
  1422. setBX( (WORD)vcRemote.Ebx );
  1423. setCX( (WORD)vcRemote.Ecx );
  1424. setDX( (WORD)vcRemote.Edx );
  1425. setSI( (WORD)vcRemote.Esi );
  1426. setDI( (WORD)vcRemote.Edi );
  1427. setBP( (WORD)vcRemote.Ebp );
  1428. setIP( (WORD)vcRemote.Eip );
  1429. setSP( (WORD)vcRemote.Esp );
  1430. setSS( (WORD)vcRemote.SegSs );
  1431. setCS( (WORD)vcRemote.SegCs );
  1432. vpStack = VDMSTACK();
  1433. //
  1434. // Initialize Per Task Data
  1435. //
  1436. GETFRAMEPTR(vpStack, pFrame);
  1437. td.htask16 = pFrame->wTDB;
  1438. td.VDMInfoiTaskID = -1;
  1439. td.vpStack = vpStack;
  1440. td.pWOAList = NULL;
  1441. //
  1442. // NOTE - Add YOUR Per Task Init Code HERE
  1443. //
  1444. nWOWTasks++;
  1445. // turn the timer thread on
  1446. if (nWOWTasks != 1)
  1447. ResumeTimerThread();
  1448. pFrame->wRetID = RET_RETURN;
  1449. pFrame->wAX = (WORD)TRUE;
  1450. pFrame->wDX = (WORD)0;
  1451. //
  1452. // Start Callback
  1453. //
  1454. host_simulate();
  1455. setIP((WORD)vcSave.Eip);
  1456. //
  1457. // We should Never Come Here, an app should get terminated via calling wk32wowkilltask thunk
  1458. // not by doing an unsimulate call.
  1459. //
  1460. #ifdef DEBUG
  1461. WOW32ASSERTMSG(FALSE, "WOW32: W32RemoteThread Error - Too many unsimulate calls");
  1462. #else
  1463. if (IsDebuggerAttached() && (flOptions & OPT_DEBUG)) {
  1464. DbgBreakPoint();
  1465. }
  1466. #endif
  1467. W32DestroyTask(&td);
  1468. host_ExitThread(EXIT_SUCCESS);
  1469. return 0;
  1470. }
  1471. //
  1472. // lives in dos/dem/demlfn.c
  1473. //
  1474. extern VOID demLFNCleanup(VOID);
  1475. /* W32FreeTask - Per Task Cleanup
  1476. *
  1477. * Put any 16-bit task clean-up code here. The remote thread for debugging
  1478. * is a 16-bit task, but has no real 32-bit thread associated with it, until
  1479. * the debugger creates it. Then it is created and destroyed in special
  1480. * ways, see W32RemoteThread and W32KillRemoteThread.
  1481. *
  1482. * ENTRY
  1483. * Per Task Pointer
  1484. *
  1485. * EXIT
  1486. * None
  1487. *
  1488. */
  1489. VOID W32FreeTask( PTD ptd )
  1490. {
  1491. PWOAINST pWOA, pWOANext;
  1492. if(ptd->dwWOWCompatFlags2 & WOWCF2_DPM_PATCHES) {
  1493. FreeTaskDpmSupport(DPMFAMTBLS(),
  1494. NUM_WOW_FAMILIES_HOOKED,
  1495. pgDpmWowFamTbls);
  1496. }
  1497. nWOWTasks--;
  1498. if (nWOWTasks < 2)
  1499. SuspendTimerThread();
  1500. // Disable the special VDMAllocateVirtualMemory strategy in NTVDM.
  1501. if (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_FORCEINCDPMI) {
  1502. #ifdef i386
  1503. DpmiSetIncrementalAlloc(FALSE);
  1504. #else
  1505. SetWOWforceIncrAlloc(FALSE);
  1506. #endif
  1507. }
  1508. // Free compat flag parameters if any
  1509. if(ptd->pWOWCompatFlagsEx_Info) {
  1510. FreeFlagInfo(ptd->pWOWCompatFlagsEx_Info);
  1511. }
  1512. if(ptd->pWOWCompatFlags2_Info) {
  1513. FreeFlagInfo(ptd->pWOWCompatFlags2_Info);
  1514. }
  1515. // Free all DCs owned by the current task
  1516. FreeCachedDCs(ptd->htask16);
  1517. // If wowexec is the only task running now, we might as well clean up any
  1518. // GDI handle leaks and rebuild our mapping tables.
  1519. if(nWOWTasks < 2) {
  1520. RebuildGdiHandleMappingTables();
  1521. }
  1522. // Unload network fonts
  1523. if( CURRENTPTD()->dwWOWCompatFlags & WOWCF_UNLOADNETFONTS )
  1524. {
  1525. UnloadNetworkFonts( (UINT)CURRENTPTD() );
  1526. }
  1527. // Free all timers owned by the current task
  1528. DestroyTimers16(ptd->htask16);
  1529. // clean up comm support
  1530. FreeCommSupportResources(ptd->dwThreadID);
  1531. // remove the hacks for this task from the FormFeedHackList (see wgdi.c)
  1532. FreeTaskFormFeedHacks(ptd->htask16);
  1533. // Cleanup WinSock support.
  1534. if (WWS32IsThreadInitialized) {
  1535. WWS32TaskCleanup();
  1536. }
  1537. // Free all local resource info owned by the current task
  1538. DestroyRes16(ptd->htask16);
  1539. // Unhook all hooks and reset their state.
  1540. W32FreeOwnedHooks(ptd->htask16);
  1541. // Free all the resources of this task
  1542. FreeCursorIconAlias(ptd->htask16,CIALIAS_HTASK | CIALIAS_TASKISGONE);
  1543. // Free accelerator aliases
  1544. DestroyAccelAlias(ptd->htask16);
  1545. // Remove idle hook, if any has been installed.
  1546. if (ptd->hIdleHook != NULL) {
  1547. UnhookWindowsHookEx(ptd->hIdleHook);
  1548. ptd->hIdleHook = NULL;
  1549. }
  1550. // Free Special thunking list for this task (wparam.c)
  1551. FreeParamMap(ptd->htask16);
  1552. // cleanup lfn search handles and other lfn-related stuff
  1553. demLFNCleanup();
  1554. // Free WinOldAp tracking structures for this thread.
  1555. EnterCriticalSection(&ptd->csTD);
  1556. if (pWOA = ptd->pWOAList) {
  1557. ptd->pWOAList = NULL;
  1558. while (pWOA) {
  1559. pWOANext = pWOA->pNext;
  1560. free_w(pWOA);
  1561. pWOA = pWOANext;
  1562. }
  1563. }
  1564. LeaveCriticalSection(&ptd->csTD);
  1565. }
  1566. /* WK32KillRemoteTask - Force the Distruction of the Current Thread
  1567. *
  1568. * Called When App Does an Exit
  1569. * If there is another active Win16 app then USER32 will schedule another
  1570. * task.
  1571. *
  1572. * ENTRY
  1573. *
  1574. * EXIT
  1575. * Never Returns - We kill the process
  1576. *
  1577. */
  1578. ULONG FASTCALL WK32KillRemoteTask(PVDMFRAME pFrame)
  1579. {
  1580. PWOWKILLREMOTETASK16 pArg16;
  1581. WORD wSavedTDB;
  1582. PTD ptd = CURRENTPTD();
  1583. LPBYTE lpNum_Tasks;
  1584. //
  1585. // Save the current state (for future callbacks)
  1586. //
  1587. vcRemote.SegDs = getDS();
  1588. vcRemote.SegEs = getES();
  1589. vcRemote.Eax = getAX();
  1590. vcRemote.Ebx = getBX();
  1591. vcRemote.Ecx = getCX();
  1592. vcRemote.Edx = getDX();
  1593. vcRemote.Esi = getSI();
  1594. vcRemote.Edi = getDI();
  1595. vcRemote.Ebp = getBP();
  1596. vcRemote.Eip = getIP();
  1597. vcRemote.Esp = getSP();
  1598. vcRemote.SegSs = getSS();
  1599. vcRemote.SegCs = getCS();
  1600. W32FreeTask(CURRENTPTD());
  1601. if ( vpRemoteBlock ) {
  1602. wSavedTDB = ptd->htask16;
  1603. ptd->htask16 = wPrevTDB;
  1604. pFrame->wTDB = wPrevTDB;
  1605. // This is a nop callback just to make sure that we switch tasks
  1606. // back for the one we were on originally.
  1607. GlobalUnlockFree16( 0 );
  1608. GETFRAMEPTR(ptd->vpStack, pFrame);
  1609. pFrame->wTDB = ptd->htask16 = wSavedTDB;
  1610. //
  1611. // We must be returning from a callback, restore the previous
  1612. // context info. Don't worry about flags, they aren't needed.
  1613. //
  1614. setSS( (WORD)vcSave.SegSs );
  1615. setCS( (WORD)vcSave.SegCs );
  1616. setDS( (WORD)vcSave.SegDs );
  1617. setES( (WORD)vcSave.SegEs );
  1618. setAX( (WORD)vcSave.Eax );
  1619. setBX( (WORD)vcSave.Ebx );
  1620. setCX( (WORD)vcSave.Ecx );
  1621. setDX( (WORD)vcSave.Edx );
  1622. setSI( (WORD)vcSave.Esi );
  1623. setDI( (WORD)vcSave.Edi );
  1624. setBP( (WORD)vcSave.Ebp );
  1625. setIP( (WORD)vcSave.Eip );
  1626. setSP( (WORD)vcSave.Esp );
  1627. } else {
  1628. //
  1629. // Decrement the count of 16-bit tasks so that the last one,
  1630. // excluding the remote handler (WOWDEB.EXE) will remember to
  1631. // call ExitKernel when done.
  1632. //
  1633. GETVDMPTR(vpnum_tasks, 1, lpNum_Tasks);
  1634. *lpNum_Tasks -= 1;
  1635. FREEVDMPTR(lpNum_Tasks);
  1636. //
  1637. // Remove this 32-bit thread from the list of tasks as well.
  1638. //
  1639. WK32DeleteTask( CURRENTPTD() );
  1640. //
  1641. // first instance of wowdeb has a valid thread handle, close it to prevent
  1642. // leaking it.
  1643. if (ptd->hThread) {
  1644. CloseHandle( ptd->hThread );
  1645. }
  1646. }
  1647. GETARGPTR(pFrame, sizeof(WOWKILLREMOTETASK16), pArg16);
  1648. //
  1649. // Save the current state (for future callbacks)
  1650. //
  1651. vpRemoteBlock = FETCHDWORD(pArg16->lpBuffer);
  1652. // Notify DBG that we have a remote thread address
  1653. DBGNotifyRemoteThreadAddress( W32RemoteThread, vpRemoteBlock );
  1654. FREEARGPTR(pArg16);
  1655. DeleteCriticalSection(&CURRENTPTD()->csTD);
  1656. host_ExitThread(EXIT_SUCCESS);
  1657. return 0; // never executed, keep compiler happy.
  1658. }
  1659. /* W32DestroyTask - Per Task Cleanup
  1660. *
  1661. * Task destruction code here. Put any 32-bit task cleanup code here
  1662. *
  1663. * ENTRY
  1664. * Per Task Pointer
  1665. *
  1666. * EXIT
  1667. * None
  1668. *
  1669. */
  1670. VOID W32DestroyTask( PTD ptd)
  1671. {
  1672. LOGDEBUG(LOG_IMPORTANT,("W32DestroyTask: destroying task %04X\n", ptd->htask16));
  1673. // Inform Hung App Support
  1674. SetEvent(ghevWaitHungAppNotifyThread);
  1675. // Free all information pertinant to this 32-bit thread
  1676. W32FreeTask( ptd );
  1677. // delete the cliprgn used by GetClipRgn if it exists
  1678. if (ptd->hrgnClip != NULL)
  1679. {
  1680. DeleteObject(ptd->hrgnClip);
  1681. ptd->hrgnClip = NULL;
  1682. }
  1683. // Report task termination to Win32 - in case someone is waiting for us
  1684. // LATER - fix Win32 so we don't have to report it.
  1685. if (nWOWTasks == 0) { // If we're the last one out, turn out the lights & tell Win32 WOWVDM is history.
  1686. ptd->VDMInfoiTaskID = -1;
  1687. ExitVDM(WOWVDM, ALL_TASKS); // Tell Win32 All Tasks are gone.
  1688. }
  1689. else if (ptd->VDMInfoiTaskID != -1 ) { // If 32 bit app is waiting for us - then signal we are done
  1690. ExitVDM(WOWVDM, ptd->VDMInfoiTaskID);
  1691. }
  1692. ptd->dwFlags &= ~TDF_IGNOREINPUT;
  1693. if (!(ptd->dwFlags & TDF_TASKCLEANUPDONE)) {
  1694. (pfnOut.pfnWOWCleanup)(HINSTRES32(ptd->hInst16), (DWORD) ptd->htask16);
  1695. }
  1696. // Remove this task from the linked list of tasks
  1697. WK32DeleteTask(ptd);
  1698. // Close This Apps Thread Handle
  1699. if (ptd->hThread) {
  1700. CloseHandle( ptd->hThread );
  1701. }
  1702. DeleteCriticalSection(&ptd->csTD);
  1703. }
  1704. /***************************************************************************\
  1705. * WK32DeleteTask
  1706. *
  1707. * This function removes a task from the task list.
  1708. *
  1709. * History:
  1710. * Borrowed From User32 taskman.c - mattfe aug 5 92
  1711. \***************************************************************************/
  1712. void WK32DeleteTask(
  1713. PTD ptdDelete)
  1714. {
  1715. PTD ptd, ptdPrev;
  1716. int i;
  1717. EnterCriticalSection(&gcsWOW);
  1718. ptd = gptdTaskHead;
  1719. ptdPrev = NULL;
  1720. /*
  1721. * If this app changed display settings revert back
  1722. *
  1723. */
  1724. if(ptdDelete->dwWOWCompatFlagsEx & WOWCFEX_DISPMODE256){
  1725. WK32RevertDisplayMode();
  1726. }
  1727. /*
  1728. * If cleanup environment data
  1729. *
  1730. */
  1731. if (ptdDelete->pWowEnvData != NULL) {
  1732. free_w(ptdDelete->pWowEnvData);
  1733. }
  1734. if (ptdDelete->pWowEnvDataChild != NULL) {
  1735. free_w(ptdDelete->pWowEnvDataChild);
  1736. }
  1737. /*
  1738. * Find the task to delete
  1739. */
  1740. while ((ptd != NULL) && (ptd != ptdDelete)) {
  1741. ptdPrev = ptd;
  1742. ptd = ptd->ptdNext;
  1743. }
  1744. /*
  1745. * Error if we didn't find it. If we did find it, remove it
  1746. * from the chain. If this was the head of the list, set it
  1747. * to point to our next guy.
  1748. */
  1749. if (ptd == NULL) {
  1750. LOGDEBUG(LOG_ALWAYS,("WK32DeleteTask:Task not found.\n"));
  1751. } else if (ptdPrev != NULL) {
  1752. ptdPrev->ptdNext = ptd->ptdNext;
  1753. } else {
  1754. gptdTaskHead = ptd->ptdNext;
  1755. }
  1756. /*
  1757. * Clean up DelayFree array in wkmem.c wk32virtualfree
  1758. *
  1759. */
  1760. for (i=0; i < 4 ;i++) {
  1761. if( NULL != glpvDelayFree[i]) {
  1762. VirtualFree(glpvDelayFree[i],
  1763. 0,
  1764. MEM_RELEASE);
  1765. glpvDelayFree[i] = NULL;
  1766. }
  1767. }
  1768. LeaveCriticalSection(&gcsWOW);
  1769. }
  1770. /*++
  1771. WK32RegisterShellWindowHandle - 16 Bit Shell Registers is Hanle
  1772. Routine Description:
  1773. This routines saves the 32 bit hwnd for the 16 bit shell
  1774. When WOWEXEC (16 bit shell) has sucessfully created its window it calls us to
  1775. register its window handle. If this is the shared WOW VDM, we register the
  1776. handle with BaseSrv, which posts WM_WOWEXECSTARTAPP messages when Win16 apps
  1777. are started.
  1778. ENTRY
  1779. pFrame -> hwndShell, 16 bit hwnd for shell (WOWEXEC)
  1780. EXIT
  1781. TRUE - This is the shared WOW VDM
  1782. FALSE - This is a separate WOW VDM
  1783. --*/
  1784. ULONG FASTCALL WK32RegisterShellWindowHandle(PVDMFRAME pFrame)
  1785. {
  1786. register PWOWREGISTERSHELLWINDOWHANDLE16 parg16;
  1787. WNDCLASS wc;
  1788. NTSTATUS Status;
  1789. GETARGPTR(pFrame, sizeof(WOWREGISTERSHELLWINDOWHANDLE16), parg16);
  1790. // gwFirstCmdShow is no longer used, and is available.
  1791. #if 0
  1792. GETVDMPTR(parg16->lpwCmdShow, sizeof(WORD), pwCmdShow);
  1793. #endif
  1794. if (ghwndShell) {
  1795. //
  1796. // The shared WOW is calling to deregister right before it
  1797. // shuts down.
  1798. //
  1799. WOW32ASSERT( !fSeparateWow );
  1800. WOW32ASSERT( !parg16->hwndShell );
  1801. Status = RegisterWowExec(NULL);
  1802. return NT_SUCCESS(Status);
  1803. }
  1804. ghwndShell = HWND32(parg16->hwndShell);
  1805. ghShellTDB = pFrame->wTDB;
  1806. //
  1807. // Save away the hInstance for User32
  1808. //
  1809. GetClassInfo(0, (LPCSTR)0x8000, &wc);
  1810. ghInstanceUser32 = wc.hInstance;
  1811. // Fritz, when you get called about this it means that the GetClassInfo()
  1812. // call above is returning with lpWC->hInstance == 0 instead of hModuser32.
  1813. WOW32ASSERTMSGF((ghInstanceUser32),
  1814. ("WOW Error ghInstanceUser32 == NULL! Contact user folks\n"));
  1815. //
  1816. // If this is the shared WOW VDM, register the WowExec window handle
  1817. // with BaseSrv so it can post WM_WOWEXECSTARTAPP messages.
  1818. //
  1819. if (!fSeparateWow) {
  1820. RegisterWowExec(ghwndShell);
  1821. }
  1822. WOW32FaxHandler(WM_DDRV_SUBCLASS, (LPSTR)(HWND32(parg16->hwndFax)));
  1823. FREEARGPTR(parg16);
  1824. //
  1825. // Return value is TRUE if this is the shared WOW VDM,
  1826. // FALSE if this is a separate WOW VDM.
  1827. //
  1828. return fSeparateWow ? FALSE : TRUE;
  1829. }
  1830. //
  1831. // Worker routine for WK32WOWLoadModule32
  1832. //
  1833. VOID FASTCALL CleanupWOAList(HANDLE hProcess)
  1834. {
  1835. PTD ptd;
  1836. PWOAINST *ppWOA, pWOAToFree;
  1837. EnterCriticalSection(&gcsWOW);
  1838. ptd = gptdTaskHead;
  1839. while (ptd) {
  1840. EnterCriticalSection(&ptd->csTD);
  1841. ppWOA = &(ptd->pWOAList);
  1842. while (*ppWOA && (*ppWOA)->hChildProcess != hProcess) {
  1843. ppWOA = &( (*ppWOA)->pNext );
  1844. }
  1845. if (*ppWOA) {
  1846. //
  1847. // We found the WOAINST structure to clean up.
  1848. //
  1849. pWOAToFree = *ppWOA;
  1850. //
  1851. // Remove this entry from the list
  1852. //
  1853. *ppWOA = pWOAToFree->pNext;
  1854. free_w(pWOAToFree);
  1855. LeaveCriticalSection(&ptd->csTD);
  1856. break; // no need to look at other tasks.
  1857. }
  1858. LeaveCriticalSection(&ptd->csTD);
  1859. ptd = ptd->ptdNext;
  1860. }
  1861. LeaveCriticalSection(&gcsWOW);
  1862. }
  1863. // finds the environment variable pszName in environment block
  1864. // pointed to by pszEnv, *ppszVal receives the pointer to the value
  1865. // of the variable, if ppszVal is not NULL
  1866. PSZ WOWFindEnvironmentVar(PSZ pszName, PSZ pszEnv, PSZ* ppszVal)
  1867. {
  1868. int nNameLen = strlen(pszName);
  1869. PSZ pTemp; // ptr to '='
  1870. if (NULL != pszEnv) {
  1871. while ('\0' != *pszEnv) {
  1872. // check the first char to be speedy
  1873. if (*pszName == *pszEnv) {
  1874. // compare the rest
  1875. if (NULL != (pTemp = WOW32_strchr(pszEnv, '=')) &&
  1876. (int)(pTemp - pszEnv) == nNameLen &&
  1877. !WOW32_strnicmp(pszEnv, pszName, nNameLen)) {
  1878. // found it
  1879. if (NULL != ppszVal) {
  1880. *ppszVal = pTemp + 1; // next char
  1881. }
  1882. return(pszEnv);
  1883. }
  1884. }
  1885. pszEnv += strlen(pszEnv) + 1;
  1886. }
  1887. }
  1888. return(NULL); // not found
  1889. }
  1890. //
  1891. // returns size in characters
  1892. // of an env block
  1893. // pStrCount receives the number of env strings
  1894. //
  1895. DWORD WOWGetEnvironmentSize(PSZ pszEnv, LPDWORD pStrCount)
  1896. {
  1897. PSZ pTemp = pszEnv;
  1898. DWORD dwCount = 0;
  1899. while ('\0' != *pTemp) {
  1900. ++dwCount;
  1901. pTemp += strlen(pTemp) + 1;
  1902. }
  1903. ++pTemp;
  1904. if (NULL != pStrCount) {
  1905. *pStrCount = dwCount;
  1906. }
  1907. return(DWORD)(pTemp - pszEnv);
  1908. }
  1909. BOOL WOWSortEnvironmentStrings(PSZ pszEnv)
  1910. {
  1911. // we sort the strings as needed for CreateProcess
  1912. // we implement bubble-sort which is an in-place sort using pointers
  1913. DWORD dwStrCount;
  1914. DWORD dwEnvSize = WOWGetEnvironmentSize(pszEnv, &dwStrCount);
  1915. PSZ* rgpEnv; // array of env ptrs
  1916. INT* rgLen; // length
  1917. int i, nLen;
  1918. PSZ pTemp, pEnv;
  1919. PSZ pEnd;
  1920. BOOL fSwap;
  1921. // now we have the size and string count, allocate array of ptrs
  1922. rgpEnv = (PSZ*)malloc_w(sizeof(PSZ) * dwStrCount);
  1923. if (NULL == rgpEnv) {
  1924. return(FALSE);
  1925. }
  1926. rgLen = (INT*)malloc_w(sizeof(INT) * dwStrCount);
  1927. if (NULL == rgLen) {
  1928. free_w(rgpEnv);
  1929. return(FALSE);
  1930. }
  1931. pEnv = (PSZ)malloc_w(dwEnvSize);
  1932. if (NULL == pEnv) {
  1933. free_w(rgpEnv);
  1934. free_w(rgLen);
  1935. return(FALSE);
  1936. }
  1937. // setup the pointers
  1938. for (pTemp = pszEnv, i = 0; '\0' != *pTemp; pTemp += strlen(pTemp) + 1, ++i) {
  1939. rgpEnv[i] = pTemp;
  1940. pEnd = WOW32_strchr(pTemp, '=');
  1941. rgLen[i] = (NULL == pEnd) ? strlen(pTemp) : (INT)(pEnd - pTemp);
  1942. }
  1943. // bubble - sort the strings using the pointers
  1944. do {
  1945. fSwap = FALSE;
  1946. for (i = 0; i < (int)dwStrCount - 1; ++i) {
  1947. // compare length, if no match use the longer string
  1948. nLen = __max(rgLen[i], rgLen[i+1]);
  1949. if (WOW32_strncmp(rgpEnv[i], rgpEnv[i+1], nLen) > 0) {
  1950. fSwap = TRUE;
  1951. pTemp = rgpEnv[i+1];
  1952. rgpEnv[i+1] = rgpEnv[i];
  1953. rgpEnv[i] = pTemp;
  1954. nLen = rgLen[i+1];
  1955. rgLen[i+1] = rgLen[i];
  1956. rgLen[i] = nLen;
  1957. }
  1958. }
  1959. } while (fSwap);
  1960. //
  1961. // now we have sorted the strings, have them rewritten in the buffer --
  1962. //
  1963. for (pTemp = pEnv, i = 0; i < (INT)dwStrCount; ++i) {
  1964. strcpy(pTemp, rgpEnv[i]);
  1965. pTemp += strlen(pTemp) + 1;
  1966. }
  1967. *pTemp = '\0';
  1968. // now copy the env whole
  1969. RtlCopyMemory(pszEnv, pEnv, dwEnvSize);
  1970. // we are done now
  1971. free_w(pEnv);
  1972. free_w(rgLen);
  1973. free_w(rgpEnv);
  1974. return(TRUE);
  1975. }
  1976. BOOL WOWIsEnvVar(PSZ pszEnv, PSZ pszVarName, INT nNameLen)
  1977. {
  1978. return !WOW32_strnicmp(pszEnv, pszVarName, nNameLen) && (*(pszEnv + nNameLen) == '=');
  1979. }
  1980. //
  1981. // Inherit parent environment, sanitizing it for all the "interesting" things
  1982. //
  1983. PSZ WOWCreateEnvBlock(PSZ pszParentEnv)
  1984. {
  1985. LPSTR pszProcessHistory = WOWFindEnvironmentVar(szProcessHistoryVar, pszParentEnv, NULL);
  1986. LPSTR pszCompatLayer = WOWFindEnvironmentVar(szCompatLayerVar, pszParentEnv, NULL);
  1987. LPSTR pszShimFileLog = WOWFindEnvironmentVar(szShimFileLogVar, pszParentEnv, NULL);
  1988. INT nLenCompatLayer = strlen(szCompatLayerVar);
  1989. INT nLenProcessHistory = strlen(szProcessHistoryVar);
  1990. INT nLenShimFileLog = strlen(szShimFileLogVar);
  1991. INT nLen;
  1992. PSZ pszNewEnv;
  1993. PSZ pTemp, pNew;
  1994. DWORD dwSize;
  1995. dwSize = WOWGetEnvironmentSize(pszParentEnv, NULL);
  1996. if (NULL != pszProcessHistory) {
  1997. dwSize -= strlen(pszProcessHistory) + 1;
  1998. }
  1999. if (NULL != pszCompatLayer) {
  2000. dwSize -= strlen(pszCompatLayer) + 1;
  2001. }
  2002. if (NULL != pszShimFileLog) {
  2003. dwSize -= strlen(pszShimFileLog) + 1;
  2004. }
  2005. //
  2006. // allocate env block
  2007. // filter out all the existing process_history and compat layer vars
  2008. //
  2009. pNew =
  2010. pszNewEnv = (PSZ)malloc_w(dwSize);
  2011. if (NULL == pszNewEnv) {
  2012. return NULL;
  2013. }
  2014. // copy the env
  2015. for (pTemp = pszParentEnv; '\0' != *pTemp; ) {
  2016. nLen = strlen(pTemp);
  2017. if (!WOWIsEnvVar(pTemp, szProcessHistoryVar, nLenProcessHistory) &&
  2018. !WOWIsEnvVar(pTemp, szCompatLayerVar, nLenCompatLayer) &&
  2019. !WOWIsEnvVar(pTemp, szShimFileLogVar, nLenShimFileLog)) {
  2020. //
  2021. // copy variable
  2022. //
  2023. strcpy(pNew, pTemp);
  2024. pNew += nLen + 1;
  2025. }
  2026. pTemp += nLen + 1;
  2027. }
  2028. *pNew = '\0'; // done
  2029. return pszNewEnv;
  2030. }
  2031. #if 0
  2032. //
  2033. // fn to create environment -- code to filter certain environment variables
  2034. // is located here, currently not used
  2035. //
  2036. // pszEnv - this is where most of the vars come from, except if ProcessHistory
  2037. // var is specified separately
  2038. // pszEnvWowApp -- this is where compat_layer and such come from
  2039. //
  2040. PSZ WOWCreateEnvBlock(PSZ pszEnvWowApp, PSZ pszEnv, PSZ pszProcessHistoryVal)
  2041. {
  2042. // this will :
  2043. // retrieve __PROCESS_HISTORY
  2044. // __COMPAT_LAYER
  2045. // SHIM_FILE_LOG
  2046. // carry those over into the environment and insert them at the
  2047. // appropriate place
  2048. LPSTR pszProcessHistory = (NULL == pszProcessHistoryVal) ?
  2049. WOWFindEnvironmentVar(szProcessHistoryVar, pszEnvWowApp, NULL) :
  2050. pszProcessHistoryVal;
  2051. LPSTR pszCompatLayer = WOWFindEnvironmentVar(szCompatLayerVar, pszEnvWowApp, NULL);
  2052. LPSTR pszShimFileLog = WOWFindEnvironmentVar(szShimFileLogVar, pszEnvWowApp, NULL);
  2053. //
  2054. // get env size first
  2055. //
  2056. DWORD dwSize = WOWGetEnvironmentSize(pszEnv, NULL); // size that we might need to expand
  2057. DWORD dwNewSize = dwSize;
  2058. PSZ pszNewEnv;
  2059. PSZ pTemp, pNew;
  2060. INT nLen;
  2061. INT nLenCompatLayer = strlen(szCompatLayerVar);
  2062. INT nLenProcessHistory = strlen(szProcessHistoryVar);
  2063. INT nLenShimFileLog = strlen(szShimFileLogVar);
  2064. INT nLenCompatLayerVar = 0;
  2065. INT nLenProcessHistoryVar = 0;
  2066. INT nLenShimFileLogVar = 0;
  2067. CHAR szCompatLayer[MAX_PATH + sizeof(szCompatLayerVar) + 1]; // buffer space for the compat layer + length of varname
  2068. //
  2069. // so we have the environment
  2070. // expand it -- be safe here, allocate extra just in case
  2071. //
  2072. if (NULL != pszProcessHistory) {
  2073. nLenProcessHistoryVar = strlen(pszProcessHistory);
  2074. dwNewSize += nLenProcessHistoryVar + 1;
  2075. }
  2076. if (NULL == pszCompatLayer && fSeparateWow) { // if separate wow and no appcompat layer in child --
  2077. nLen = wsprintf(szCompatLayer, "%s=", szCompatLayerVar);
  2078. nLenCompatLayerVar = (INT)GetEnvironmentVariable(szCompatLayerVar,
  2079. szCompatLayer + nLen,
  2080. MAX_PATH);
  2081. if (nLenCompatLayerVar && nLenCompatLayerVar <= MAX_PATH) {
  2082. pszCompatLayer = szCompatLayer;
  2083. }
  2084. }
  2085. if (NULL != pszCompatLayer) {
  2086. nLenCompatLayerVar = strlen(pszCompatLayer);
  2087. dwNewSize += nLenCompatLayerVar + 1;
  2088. }
  2089. if (NULL != pszShimFileLog) {
  2090. nLenShimFileLogVar = strlen(pszShimFileLog);
  2091. dwNewSize += nLenShimFileLogVar + 1;
  2092. }
  2093. // allocate env block
  2094. // filter out all the existing process_history and compat layer vars
  2095. pNew =
  2096. pszNewEnv = (PSZ)malloc_w(dwNewSize);
  2097. if (NULL == pszNewEnv) {
  2098. return(NULL);
  2099. }
  2100. // copy the env
  2101. for (pTemp = pszEnv; '\0' != *pTemp; ) {
  2102. nLen = strlen(pTemp);
  2103. if (WOW32_strnicmp(pTemp, szProcessHistoryVar, nLenProcessHistory) &&
  2104. WOW32_strnicmp(pTemp, szCompatLayerVar, nLenCompatLayer) &&
  2105. WOW32_strnicmp(pTemp, szShimFileLogVar, nLenShimFileLog)
  2106. ) {
  2107. // copy variable
  2108. strcpy(pNew, pTemp);
  2109. pNew += nLen + 1;
  2110. }
  2111. pTemp += nLen + 1;
  2112. }
  2113. // now copy vars
  2114. if (NULL != pszProcessHistory) {
  2115. strcpy(pNew, pszProcessHistory);
  2116. pNew += nLenProcessHistoryVar + 1;
  2117. }
  2118. if (NULL != pszCompatLayer) {
  2119. strcpy(pNew, pszCompatLayer);
  2120. pNew += nLenCompatLayerVar + 1;
  2121. }
  2122. if (NULL != pszShimFileLog) {
  2123. strcpy(pNew, pszShimFileLog);
  2124. pNew += nLenShimFileLogVar + 1;
  2125. }
  2126. *pNew = '\0'; // final touch
  2127. if (!WOWSortEnvironmentStrings(pszNewEnv)) {
  2128. free_w(pszNewEnv);
  2129. return(NULL);
  2130. }
  2131. return(pszNewEnv);
  2132. }
  2133. #endif // 0
  2134. ULONG FASTCALL WK32WowPassEnvironment(PVDMFRAME pFrame)
  2135. {
  2136. PWOWPASSENVIRONMENT16 parg16;
  2137. PDOSEXECBLOCK pParmBlk; // exec param block
  2138. PBYTE pExe; // parameter, passed from 16-bit
  2139. PDOSPDB pDosPDB;
  2140. PSZ pszEnvParentTask = NULL; // parent task env, the one that has __process_history
  2141. PSZ pszEnvParent = NULL; // parent env -- the one that has everything else
  2142. PSZ pszEnv; // "forged" environment, 32-bit
  2143. PSZ pszEnvTask; // pointer to 16-bit task env -- the one that is passed back
  2144. WORD wExeFlags; // exe flags wow16\inc\newexe.inc
  2145. WORD wExe16; // selector for exe header
  2146. BYTE TDB_Flags = 0; // tdb flags for the parent task
  2147. DWORD dwEnvSize; // new environment size
  2148. DWORD dwSize; // 16-bit memory block size
  2149. HMEM16 hMemEnv; // 16-bit memory selector
  2150. PSZ pCmdLine = NULL; // command line tail
  2151. PSZ pModuleFileName; // module filename, obtained from wExe16
  2152. PSZ pProcessHistoryVar = NULL; // process history, obtained from pszEnvParentTask
  2153. PSZ pProcessHistory = NULL; // process history, working ptr
  2154. PSZ pTemp; // temp var, used while writing to the env
  2155. DWORD nSizeModuleFileName; // module file name variable size
  2156. DWORD nSizeCmdLine = 0; // command line tail size
  2157. BOOL fFreeEnv = TRUE; // free temp env flag (in case of failure, we use parent env)
  2158. USHORT uCmdLineStart = 0; // return value, offset of the command tail
  2159. BOOL fCopy2 = TRUE; // copy mod filename twice
  2160. // get arg ptr
  2161. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  2162. // retrieve arguments from 16-bit land
  2163. wExe16 = FETCHWORD(parg16->pExe);
  2164. pExe = (PBYTE)SEGPTR(wExe16, 0);
  2165. GETVDMPTR(FETCHDWORD(parg16->pParmBlk), sizeof(DOSEXECBLOCK), pParmBlk);
  2166. GETPSZPTR(FETCHDWORD(pParmBlk->lpcmdline), pCmdLine); // pointer
  2167. pDosPDB = SEGPTR(FETCHWORD(parg16->cur_DOS_PDB), 0);
  2168. if (*pCurTDB) { // extract Parent task environment info
  2169. PTDB pTDB;
  2170. pTDB = (PTDB)SEGPTR(*pCurTDB, 0); // tdb in windows
  2171. if (NULL != pTDB && TDB_SIGNATURE == pTDB->TDB_sig) {
  2172. // valid tdb, retrieve env ptr
  2173. #if 0
  2174. pPSP = (PDOSPDB)SEGPTR(pTDB->TDB_PDB, 0); // psp
  2175. if (NULL != pPSP) {
  2176. pszEnvParentTask = (PSZ)SEGPTR(pPSP->PDB_environ, 0);
  2177. }
  2178. #endif
  2179. TDB_Flags = pTDB->TDB_flags; // flags
  2180. }
  2181. }
  2182. /* // dump various helpful info
  2183. if (NULL != pszEnv) {
  2184. LOGDEBUG(0, ("pszEnv = %lx\n", pszEnv));
  2185. }
  2186. LOGDEBUG(0, ("pExe = %lx\n", pExe));
  2187. LOGDEBUG(0, ("pParmBlk = %lx\n", pParmBlk));
  2188. LOGDEBUG(0, ("pDosPDB = %lx\n", pDosPDB));
  2189. LOGDEBUG(0, ("pWinPDB = %lx\n", pWinPDB));
  2190. */
  2191. // determine which environment segment we will use as a template
  2192. if (0 != pParmBlk->envseg) {
  2193. // aha - envseg is passed from above
  2194. pszEnvParent = SEGPTR(pParmBlk->envseg, 0);
  2195. }
  2196. else {
  2197. // no env seg -- use default one from kernel
  2198. pszEnvParent = SEGPTR(pDosPDB->PDB_environ, 0);
  2199. }
  2200. //
  2201. // get module filename from the exe header
  2202. //
  2203. pModuleFileName = SEGPTR(wExe16, (*(WORD *)SEGPTR(wExe16, 10)) + 8);
  2204. nSizeModuleFileName = strlen(pModuleFileName) + 1;
  2205. //
  2206. // Create Child environment cookies using our own cookies and some other hints
  2207. //
  2208. CreateWowChildEnvInformation(pszEnvParent);
  2209. //
  2210. // form the environment block
  2211. //
  2212. pszEnv = WOWCreateEnvBlock(pszEnvParent);
  2213. // now see if we're out of memory
  2214. if (NULL == pszEnv) {
  2215. pszEnv = pszEnvParent; // no worse than before, use parent
  2216. fFreeEnv = FALSE;
  2217. }
  2218. // now pszEnv is the right "merged" environment
  2219. // measure how big it is
  2220. dwSize =
  2221. dwEnvSize = WOWGetEnvironmentSize(pszEnv, NULL);
  2222. // now let us deal with command line
  2223. wExeFlags = *(PUSHORT)(pExe+NE_FLAGS_OFFSET);
  2224. if (wExeFlags & NEPROT) {
  2225. if (TDB_Flags & TDBF_OS2APP) {
  2226. // now measure both strings
  2227. nSizeCmdLine = strlen(pCmdLine) + 1;
  2228. nSizeCmdLine += strlen(pCmdLine + nSizeCmdLine) + 1;
  2229. dwSize += nSizeCmdLine + 1;
  2230. fCopy2 = FALSE;
  2231. }
  2232. else {
  2233. // dos app executed this
  2234. nSizeCmdLine = *pCmdLine++; // move to the next char
  2235. // also update original value
  2236. ++pParmBlk->lpcmdline;
  2237. dwSize += nSizeCmdLine + 1;
  2238. }
  2239. }
  2240. else {
  2241. dwSize += 3; // room for magic word and nul
  2242. fCopy2 = FALSE;
  2243. }
  2244. dwSize += nSizeModuleFileName * 2; // we need to have that twice
  2245. dwSize += 4; // add WOW_ENV_SIG at the end to help us find end of the goo
  2246. dwSize += 4; // add 4 NULLS to end it all
  2247. // allocate memory
  2248. hMemEnv = WOWGlobalAlloc16(GMEM_FIXED, dwSize);
  2249. if (!hMemEnv) {
  2250. // we are dead!
  2251. goto exit_passenv;
  2252. }
  2253. pTemp =
  2254. pszEnvTask = SEGPTR(hMemEnv, 0); // fixed memory
  2255. RtlCopyMemory (pTemp, pszEnv, dwEnvSize); // done with env
  2256. pTemp += dwEnvSize; // adjust
  2257. // env is followed by
  2258. if (!(wExeFlags & NEPROT)) {
  2259. // we store 1 \0
  2260. *pTemp++ = '\x1';
  2261. *pTemp++ = '\0';
  2262. }
  2263. // copy stuff
  2264. RtlCopyMemory(pTemp, pModuleFileName, nSizeModuleFileName);
  2265. pTemp += nSizeModuleFileName;
  2266. // see where cmd line should start
  2267. uCmdLineStart = (USHORT)(pTemp - pszEnvTask);
  2268. // second copy of the same
  2269. if (fCopy2) {
  2270. RtlCopyMemory(pTemp, pModuleFileName, nSizeModuleFileName);
  2271. pTemp += nSizeModuleFileName;
  2272. }
  2273. RtlCopyMemory(pTemp, pCmdLine, nSizeCmdLine);
  2274. *(pTemp + nSizeCmdLine + 1) = '\0';
  2275. // add the stuff needed by WOWStripDownTheEnvironment()
  2276. dwEnvSize = WOW_ENV_SIG;
  2277. RtlCopyMemory(pTemp, &dwEnvSize, sizeof(DWORD));
  2278. pTemp += sizeof(DWORD);
  2279. dwEnvSize = (DWORD)NULL;
  2280. RtlCopyMemory(pTemp, &dwEnvSize, sizeof(DWORD));
  2281. exit_passenv:
  2282. if (fFreeEnv) {
  2283. free_w(pszEnv);
  2284. }
  2285. FREEARGPTR(parg16);
  2286. return(MAKELONG(hMemEnv, uCmdLineStart));
  2287. }
  2288. /*++
  2289. WK32WOWLoadModule32
  2290. Routine Description:
  2291. Exec a 32 bit Process
  2292. This routine is called by the 16 bit kernel when it fails to load a 16 bit task
  2293. with error codes 11 - invalid exe, 12 - os2, 13 - DOS 4.0, 14 - Unknown.
  2294. ENTRY
  2295. pFrame -> lpCmdLine Input\output buffer for winoldapp cmd line
  2296. pFrame -> lpParameterBlock (see win 3.x apis) Parameter Block if NULL
  2297. winoldap calling
  2298. pFrame -> lpModuleName (see win 3.x apis) App Name
  2299. EXIT
  2300. 32 - Sucess
  2301. Error code
  2302. History:
  2303. rewrote to call CreateProcess() instead of LoadModule - barryb 29sep92
  2304. --*/
  2305. ULONG FASTCALL WK32WOWLoadModule32(PVDMFRAME pFrame)
  2306. {
  2307. static PSZ pszExplorerFullPathUpper = NULL; // "C:\WINNT\EXPLORER.EXE"
  2308. ULONG ulRet;
  2309. int i, len = 0;
  2310. char *pch, *pSrc;
  2311. PSZ pszModuleName;
  2312. PSZ pszWinOldAppCmd;
  2313. PBYTE pbCmdLine;
  2314. BOOL CreateProcessStatus;
  2315. PPARAMETERBLOCK16 pParmBlock16;
  2316. PWORD16 pCmdShow = NULL;
  2317. BOOL fProgman = FALSE;
  2318. PROCESS_INFORMATION ProcessInformation;
  2319. STARTUPINFO StartupInfo;
  2320. char CmdLine[2*MAX_PATH];
  2321. char szOut[2*MAX_PATH];
  2322. char szMsgBoxTxt[4*MAX_PATH];
  2323. register PWOWLOADMODULE16 parg16;
  2324. PTD ptd;
  2325. PSZ pszEnv = NULL; // environment ptr for new process
  2326. WCHAR* pwszEnv = NULL; // environment ptr, unicode
  2327. GETARGPTR(pFrame, sizeof(WOWLOADMODULE16), parg16);
  2328. GETPSZPTR(parg16->lpWinOldAppCmd, pszWinOldAppCmd);
  2329. if (parg16->lpParameterBlock) {
  2330. GETVDMPTR(parg16->lpParameterBlock,sizeof(PARAMETERBLOCK16), pParmBlock16);
  2331. GETPSZPTR(pParmBlock16->lpCmdLine, pbCmdLine);
  2332. } else {
  2333. pParmBlock16 = NULL;
  2334. pbCmdLine = NULL;
  2335. }
  2336. UpdateDosCurrentDirectory(DIR_DOS_TO_NT); // update current dir
  2337. /*
  2338. * if ModuleName == NULL, called by winoldap, or LM_NTLOADMODULE
  2339. * to deal with the process handle.
  2340. *
  2341. * if lpParameterBlock == NULL
  2342. * winoldap calling to wait on the process handle
  2343. * else
  2344. * LM_NTLoadModule calling to clean up process handle
  2345. * because an error ocurred loading winoldap.
  2346. */
  2347. if (!parg16->lpModuleName) {
  2348. HANDLE hProcess;
  2349. MSG msg;
  2350. pszModuleName = NULL;
  2351. if (pszWinOldAppCmd &&
  2352. *pszWinOldAppCmd &&
  2353. RtlEqualMemory(pszWinOldAppCmd, szWOAWOW32, sizeof(szWOAWOW32)-1))
  2354. {
  2355. hProcess = (HANDLE)strtoul(pszWinOldAppCmd + sizeof(szWOAWOW32) - 1,
  2356. NULL,
  2357. 16
  2358. );
  2359. if (hProcess == (HANDLE)-1) { // ULONG_MAX
  2360. hProcess = NULL;
  2361. }
  2362. if (parg16->lpParameterBlock && hProcess) {
  2363. //
  2364. // Error loading winoldap.mod
  2365. //
  2366. pptdWOA = NULL;
  2367. CleanupWOAList(hProcess);
  2368. CloseHandle(hProcess);
  2369. hProcess = NULL;
  2370. }
  2371. } else {
  2372. hProcess = NULL;
  2373. }
  2374. BlockWOWIdle(TRUE);
  2375. if (hProcess) {
  2376. while (MsgWaitForMultipleObjects(1, &hProcess, FALSE, INFINITE, QS_ALLINPUT)
  2377. == WAIT_OBJECT_0 + 1)
  2378. {
  2379. PeekMessage(&msg, NULL, 0,0, PM_NOREMOVE);
  2380. }
  2381. if (!GetExitCodeProcess(hProcess, &ulRet)) {
  2382. ulRet = 0;
  2383. }
  2384. CleanupWOAList(hProcess);
  2385. CloseHandle(hProcess);
  2386. } else {
  2387. (pfnOut.pfnYieldTask)();
  2388. ulRet = 0;
  2389. }
  2390. BlockWOWIdle(FALSE);
  2391. goto lm32Exit;
  2392. /*
  2393. * if ModuleName == -1, uses traditional style winoldap cmdline
  2394. * and is called to spawn a non win16 app.
  2395. *
  2396. * "<cbWord><CmdLineParameters>CR<ModulePathName>LF"
  2397. *
  2398. * Extract the ModuleName from the command line
  2399. *
  2400. */
  2401. } else if (parg16->lpModuleName == -1) {
  2402. pszModuleName = NULL;
  2403. pSrc = pbCmdLine + 2;
  2404. pch = WOW32_strchr(pSrc, '\r');
  2405. if (!pch || (i = pch - pSrc) >= MAX_PATH) {
  2406. ulRet = 23;
  2407. goto lm32Exit;
  2408. }
  2409. pSrc = pch + 1;
  2410. pch = WOW32_strchr(pSrc, '\n');
  2411. if (!pch || (i = pch - pSrc) >= MAX_PATH) {
  2412. ulRet = 23;
  2413. goto lm32Exit;
  2414. }
  2415. pch = CmdLine;
  2416. while (*pSrc != '\n' && *pSrc) {
  2417. *pch++ = *pSrc++;
  2418. }
  2419. *pch++ = ' ';
  2420. pSrc = pbCmdLine + 2;
  2421. while (*pSrc != '\r' && *pSrc) {
  2422. *pch++ = *pSrc++;
  2423. }
  2424. *pch = '\0';
  2425. /*
  2426. * lpModuleName contains Application Path Name
  2427. * pbCmdLIne contains Command Tail
  2428. */
  2429. } else {
  2430. GETPSZPTR(parg16->lpModuleName, pszModuleName);
  2431. if (pszModuleName) {
  2432. //
  2433. // 2nd part of control.exe/progman.exe implemented here. In the
  2434. // first part, in WK32WowIsKnownDll, forced the 16-bit loader to
  2435. // load c:\winnt\system32\control.exe(progman.exe) if the app
  2436. // tries to load c:\winnt\control.exe(progman.exe). 16-bit
  2437. // LoadModule tries and eventually discovers its a PE module
  2438. // and returns LME_PE, which causes this function to get called.
  2439. // Unfortunately, the scope of the WK32WowIsKnownDLL modified
  2440. // path is LMLoadExeFile, so by the time we get here, the path is
  2441. // once again c:\winnt\control.exe(progman.exe). Fix that.
  2442. //
  2443. if (!WOW32_stricmp(pszModuleName, pszControlExeWinDirPath) ||
  2444. (fProgman = TRUE,
  2445. !WOW32_stricmp(pszModuleName, pszProgmanExeWinDirPath))) {
  2446. if(fProgman) {
  2447. len = strlen(pszProgmanExeSysDirPath);
  2448. } else {
  2449. len = strlen(pszControlExeSysDirPath);
  2450. }
  2451. len = min(sizeof(CmdLine)-1, len);
  2452. strncpy(CmdLine,
  2453. fProgman ?
  2454. pszProgmanExeSysDirPath : pszControlExeSysDirPath,
  2455. len);
  2456. } else {
  2457. len = strlen(pszModuleName);
  2458. len = min(sizeof(CmdLine)-1, len);
  2459. strncpy(CmdLine, pszModuleName, len);
  2460. }
  2461. CmdLine[len] = '\0';
  2462. FREEPSZPTR(pszModuleName);
  2463. }
  2464. else {
  2465. ulRet = 2; // LME_FNF
  2466. goto lm32Exit;
  2467. }
  2468. pch = CmdLine + strlen(CmdLine);
  2469. *pch++ = ' ';
  2470. //
  2471. // The cmdline is a Pascal-style string: a count byte followed by
  2472. // characters followed by a terminating CR character. If this string is
  2473. // not well formed we will still try to reconstruct the command line in
  2474. // a similar manner that the c startup code does so using the following
  2475. // assumptions:
  2476. //
  2477. // 1. The command line can be no greater that 128 characters including
  2478. // the length byte and the terminator.
  2479. //
  2480. // 2. The valid terminators for a command line are CR or 0.
  2481. //
  2482. //
  2483. i = 0;
  2484. pSrc = pbCmdLine+1;
  2485. while (*pSrc != '\r' && *pSrc && i < 0x80 - 2) {
  2486. *pch++ = *pSrc++;
  2487. }
  2488. *pch = '\0';
  2489. }
  2490. RtlZeroMemory((PVOID)&StartupInfo, (DWORD)sizeof(StartupInfo));
  2491. StartupInfo.cb = sizeof(StartupInfo);
  2492. StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
  2493. //
  2494. // pCmdShow is documented as a pointer to an array of two WORDs,
  2495. // the first of which must be 2, and the second of which is
  2496. // the nCmdShow to use. It turns out that Win3.1 ignores
  2497. // the second word (uses SW_NORMAL) if the first word isn't 2.
  2498. // Pixie 2.0 passes an array of 2 zeros, which on Win 3.1 works
  2499. // because the nCmdShow of 0 (== SW_HIDE) is ignored since the
  2500. // first word isn't 2.
  2501. //
  2502. // Our logic, then, is to use SW_NORMAL unless pCmdShow is
  2503. // valid and points to a WORD value 2, in which case we use
  2504. // the next word as nCmdShow.
  2505. //
  2506. // DaveHart 27 June 1993.
  2507. //
  2508. GETVDMPTR(pParmBlock16->lpCmdShow, 4, pCmdShow);
  2509. if (pCmdShow && 2 == pCmdShow[0]) {
  2510. StartupInfo.wShowWindow = pCmdShow[1];
  2511. } else {
  2512. StartupInfo.wShowWindow = SW_NORMAL;
  2513. }
  2514. if (pCmdShow)
  2515. FREEVDMPTR(pCmdShow);
  2516. // we have a problem here -- we need to pass on our environment
  2517. // which is in tdb -- get a pointer to it now
  2518. if (*pCurTDB) {
  2519. PTDB pTDB = (PTDB)SEGPTR(*pCurTDB, 0); // tdb in windows
  2520. PDOSPDB pPSP; // psp pointer
  2521. if (NULL != pTDB && TDB_SIGNATURE == pTDB->TDB_sig) {
  2522. // valid tdb, retrieve env ptr
  2523. pPSP = (PDOSPDB)SEGPTR(pTDB->TDB_PDB, 0); // psp
  2524. if (NULL != pPSP) {
  2525. pszEnv = (PSZ)SEGPTR(pPSP->PDB_environ, 0);
  2526. }
  2527. }
  2528. }
  2529. pwszEnv = WOWForgeUnicodeEnvironment(pszEnv, CURRENTPTD()->pWowEnvData);
  2530. CreateProcessStatus = CreateProcess(
  2531. NULL,
  2532. CmdLine,
  2533. NULL, // security
  2534. NULL, // security
  2535. FALSE, // inherit handles
  2536. CREATE_UNICODE_ENVIRONMENT |
  2537. CREATE_NEW_CONSOLE |
  2538. CREATE_DEFAULT_ERROR_MODE,
  2539. pwszEnv, // environment strings
  2540. NULL, // current directory
  2541. &StartupInfo,
  2542. &ProcessInformation
  2543. );
  2544. if (NULL != pwszEnv) {
  2545. WOWFreeUnicodeEnvironment(pwszEnv);
  2546. }
  2547. if (CreateProcessStatus) {
  2548. DWORD WaitStatus;
  2549. if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_SYNCHRONOUSDOSAPP) {
  2550. LPBYTE lpT;
  2551. // This is for supporting BeyondMail installation. It uses
  2552. // 40:72 as shared memory when it execs DOS programs. The windows
  2553. // part of installation program loops till the byte at 40:72 is
  2554. // non-zero. The DOS program ORs in 0x80 into this location which
  2555. // effectively signals the completion of the DOS task. On NT
  2556. // Windows and Dos programs are different processes and thus this
  2557. // 'sharing' business doesn't work. Hence this compatibility stuff.
  2558. // - nanduri
  2559. WaitStatus = WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
  2560. lpT = GetRModeVDMPointer(0x400072);
  2561. *lpT |= 0x80;
  2562. }
  2563. else if (!(CURRENTPTD()->dwWOWCompatFlags & WOWCF_NOWAITFORINPUTIDLE)) {
  2564. DWORD dw;
  2565. int ii = 20;
  2566. //
  2567. // Wait for the started process to go idle.
  2568. //
  2569. do {
  2570. dw = WaitForInputIdle(ProcessInformation.hProcess, 5000);
  2571. WaitStatus = WaitForSingleObject(ProcessInformation.hProcess, 0);
  2572. } while (dw == WAIT_TIMEOUT && WaitStatus == WAIT_TIMEOUT && ii--);
  2573. }
  2574. CloseHandle(ProcessInformation.hThread);
  2575. if (ProcessInformation.hProcess) {
  2576. PWOAINST pWOAInst;
  2577. DWORD cb;
  2578. //
  2579. // We're returning a process handle to winoldap, so
  2580. // build up a WOAINST structure add add it to this
  2581. // task's list of child WinOldAp instances.
  2582. //
  2583. if (parg16->lpModuleName && -1 != parg16->lpModuleName) {
  2584. GETPSZPTR(parg16->lpModuleName, pszModuleName);
  2585. cb = strlen(pszModuleName)+1;
  2586. } else {
  2587. cb = 1; // null terminator
  2588. pszModuleName = NULL;
  2589. }
  2590. //
  2591. // WOAINST includes one byte of szModuleName in its
  2592. // size, allocate enough room for the full string.
  2593. //
  2594. pWOAInst = malloc_w( (sizeof *pWOAInst) + cb - 1 );
  2595. WOW32ASSERT(pWOAInst);
  2596. if (pWOAInst) {
  2597. ptd = CURRENTPTD();
  2598. EnterCriticalSection(&ptd->csTD);
  2599. pWOAInst->pNext = ptd->pWOAList;
  2600. ptd->pWOAList = pWOAInst;
  2601. pWOAInst->dwChildProcessID = ProcessInformation.dwProcessId;
  2602. pWOAInst->hChildProcess = ProcessInformation.hProcess;
  2603. //
  2604. // point pptdWOA at pWOAInst->ptdWOA so that
  2605. // W32Thread can fill in the pointer to the
  2606. // WinOldAp TD.
  2607. //
  2608. pWOAInst->ptdWOA = NULL;
  2609. pptdWOA = &(pWOAInst->ptdWOA);
  2610. if (pszModuleName == NULL) {
  2611. pWOAInst->szModuleName[0] = 0;
  2612. } else {
  2613. RtlCopyMemory(
  2614. pWOAInst->szModuleName,
  2615. pszModuleName,
  2616. cb
  2617. );
  2618. //
  2619. // We are storing pszModuleName for comparison
  2620. // later in WowGetModuleHandle, called by
  2621. // Win16 GetModuleHandle. The latter always
  2622. // uppercases the paths involved, so we do
  2623. // as well so that we can do a case-insensitive
  2624. // comparison.
  2625. //
  2626. WOW32_strupr(pWOAInst->szModuleName);
  2627. //
  2628. // HACK -- PackRat can't run Explorer in one
  2629. // of its "Application Windows", because the
  2630. // spawned explorer.exe process goes away
  2631. // after asking the existing explorer to put
  2632. // up a window.
  2633. //
  2634. // If we're starting Explorer, close the
  2635. // process handle find the "real" shell
  2636. // explorer.exe process and put its handle
  2637. // and ID in this WOAINST structure. This
  2638. // fixes PackRat, but means that the
  2639. // winoldap task never goes away because
  2640. // the shell never goes away.
  2641. //
  2642. if (! pszExplorerFullPathUpper) {
  2643. int nLenWin = strlen(pszWindowsDirectory);
  2644. int nLenExpl = strlen(szExplorerDotExe);
  2645. //
  2646. // pszExplorerFullPathUpper looks like "C:\WINNT\EXPLORER.EXE"
  2647. //
  2648. pszExplorerFullPathUpper =
  2649. malloc_w(nLenWin + // strlen(pszWindowsDirectory)
  2650. 1 + // backslash
  2651. nLenExpl + // strlen("explorer.exe")
  2652. 1 // null terminator
  2653. );
  2654. if (pszExplorerFullPathUpper) {
  2655. RtlCopyMemory(pszExplorerFullPathUpper, pszWindowsDirectory, nLenWin);
  2656. pszExplorerFullPathUpper[nLenWin] = '\\';
  2657. RtlCopyMemory(&pszExplorerFullPathUpper[nLenWin+1], szExplorerDotExe, nLenExpl+1);
  2658. WOW32_strupr(pszExplorerFullPathUpper);
  2659. }
  2660. }
  2661. if (pszExplorerFullPathUpper &&
  2662. ! WOW32_strcmp(pWOAInst->szModuleName, pszExplorerFullPathUpper)) {
  2663. GetWindowThreadProcessId(
  2664. GetShellWindow(),
  2665. &pWOAInst->dwChildProcessID
  2666. );
  2667. CloseHandle(pWOAInst->hChildProcess);
  2668. pWOAInst->hChildProcess = ProcessInformation.hProcess =
  2669. OpenProcess(
  2670. PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
  2671. FALSE,
  2672. pWOAInst->dwChildProcessID
  2673. );
  2674. }
  2675. }
  2676. LeaveCriticalSection(&ptd->csTD);
  2677. }
  2678. if (pszModuleName) {
  2679. FREEPSZPTR(pszModuleName);
  2680. }
  2681. }
  2682. ulRet = 33;
  2683. pch = pszWinOldAppCmd + 2;
  2684. sprintf(pch, "%s%x\r", szWOAWOW32, ProcessInformation.hProcess);
  2685. *pszWinOldAppCmd = (char) strlen(pch);
  2686. *(pszWinOldAppCmd+1) = '\0';
  2687. } else {
  2688. //
  2689. // CreateProcess failed, map the most common error codes
  2690. //
  2691. switch (GetLastError()) {
  2692. case ERROR_FILE_NOT_FOUND:
  2693. ulRet = 2;
  2694. break;
  2695. case ERROR_PATH_NOT_FOUND:
  2696. ulRet = 3;
  2697. break;
  2698. case ERROR_BAD_EXE_FORMAT:
  2699. ulRet = 11;
  2700. break;
  2701. // put up warning that they're trying to load a binary intended for
  2702. // a different platform
  2703. case ERROR_EXE_MACHINE_TYPE_MISMATCH:
  2704. // attempt to find the end of the module name path
  2705. pch = CmdLine;
  2706. while((*pch != ' ') && (*pch != '//') && (*pch != '\0')) {
  2707. pch++;
  2708. }
  2709. *pch = '\0';
  2710. LoadString(hmodWOW32,
  2711. iszMisMatchedBinary,
  2712. szMsgBoxTxt,
  2713. sizeof szMsgBoxTxt);
  2714. sprintf(szOut, szMsgBoxTxt, CmdLine);
  2715. LoadString(hmodWOW32,
  2716. iszMisMatchedBinaryTitle,
  2717. szMsgBoxTxt,
  2718. sizeof szMsgBoxTxt);
  2719. MessageBox(NULL,
  2720. szOut,
  2721. szMsgBoxTxt,
  2722. MB_OK | MB_ICONEXCLAMATION);
  2723. // fall through to default case
  2724. default:
  2725. ulRet = 0; // no memory
  2726. break;
  2727. }
  2728. }
  2729. lm32Exit:
  2730. FREEARGPTR(parg16);
  2731. FREEPSZPTR(pbCmdLine);
  2732. FREEPSZPTR(pszWinOldAppCmd);
  2733. if (pParmBlock16)
  2734. FREEVDMPTR(pParmBlock16);
  2735. RETURN(ulRet);
  2736. }
  2737. /*++
  2738. WK32WOWQueryPerformanceCounter
  2739. Routine Description:
  2740. Calls NTQueryPerformanceCounter
  2741. Implemented for Performance Group
  2742. ENTRY
  2743. pFrame -> lpPerformanceFrequency points to location for storing Frequency
  2744. pFrame -> lpPerformanceCounter points to location for storing Counter
  2745. EXIT
  2746. NTStatus Code
  2747. --*/
  2748. ULONG FASTCALL WK32WOWQueryPerformanceCounter(PVDMFRAME pFrame)
  2749. {
  2750. PLARGE_INTEGER pPerfCount16;
  2751. PLARGE_INTEGER pPerfFreq16;
  2752. LARGE_INTEGER PerformanceCounter;
  2753. LARGE_INTEGER PerformanceFrequency;
  2754. register PWOWQUERYPERFORMANCECOUNTER16 parg16;
  2755. GETARGPTR(pFrame, sizeof(WOWQUERYPERFORMANCECOUNTER16), parg16);
  2756. if (parg16->lpPerformanceCounter != 0) {
  2757. GETVDMPTR(parg16->lpPerformanceCounter, 8, pPerfCount16);
  2758. }
  2759. if (parg16->lpPerformanceFrequency != 0) {
  2760. GETVDMPTR(parg16->lpPerformanceFrequency, 8, pPerfFreq16);
  2761. }
  2762. NtQueryPerformanceCounter ( &PerformanceCounter, &PerformanceFrequency );
  2763. if (parg16->lpPerformanceCounter != 0) {
  2764. STOREDWORD(pPerfCount16->LowPart,PerformanceCounter.LowPart);
  2765. STOREDWORD(pPerfCount16->HighPart,PerformanceCounter.HighPart);
  2766. }
  2767. if (parg16->lpPerformanceFrequency != 0) {
  2768. STOREDWORD(pPerfFreq16->LowPart,PerformanceFrequency.LowPart);
  2769. STOREDWORD(pPerfFreq16->HighPart,PerformanceFrequency.HighPart);
  2770. }
  2771. FREEVDMPTR(pPerfCount16);
  2772. FREEVDMPTR(pPerfFreq16);
  2773. FREEARGPTR(parg16);
  2774. RETURN(TRUE);
  2775. }
  2776. /*++
  2777. WK32WOWOutputDebugString - Write a String to the debugger
  2778. The 16 bit kernel OutputDebugString calls this thunk to actually output the string to the
  2779. debugger. The 16 bit kernel routine does all the parameter validation etc before calling
  2780. this routine. Note also that all 16 bit kernel trace output also uses this routine, so
  2781. it not just the app which calls this function.
  2782. If this is a checked build the the output is send via LOGDEBUG so that it gets mingled with
  2783. the WOW trace information, this is useful when running the 16 bit logger tool.
  2784. Entry
  2785. pFrame->vpString Pointer to NULL terminated string to output to the debugger.
  2786. EXIT
  2787. ZERO
  2788. --*/
  2789. ULONG FASTCALL WK32WOWOutputDebugString(PVDMFRAME pFrame)
  2790. {
  2791. PSZ psz1;
  2792. register PWOWOUTPUTDEBUGSTRING16 parg16;
  2793. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  2794. GETPSZPTRNOLOG(parg16->vpString, psz1);
  2795. #ifdef DEBUG // So we can intermingle LOGGER output & WOW Logging
  2796. if ( !(flOptions & OPT_DEBUG) ) {
  2797. OutputDebugString(psz1);
  2798. } else {
  2799. INT length;
  2800. char text[TMP_LINE_LEN];
  2801. PSZ pszTemp;
  2802. length = strlen(psz1);
  2803. if ( length > TMP_LINE_LEN-1 ) {
  2804. WOW32_strncpy( text, psz1, TMP_LINE_LEN );
  2805. text[TMP_LINE_LEN-2] = '\n';
  2806. text[TMP_LINE_LEN-1] = '\0';
  2807. pszTemp = text;
  2808. } else {
  2809. pszTemp = psz1;
  2810. }
  2811. LOGDEBUG(LOG_ALWAYS, ("%s", pszTemp)); // in debug version
  2812. }
  2813. #else
  2814. OutputDebugString(psz1);
  2815. #endif
  2816. FREEPSZPTR(psz1);
  2817. FREEARGPTR(parg16);
  2818. RETURN(0);
  2819. }
  2820. /* WK32WowFailedExec - WOWExec Failed to Exec Application
  2821. *
  2822. *
  2823. * Entry - Global Variable iW32ExecTaskId
  2824. *
  2825. *
  2826. * Exit
  2827. * SUCCESS TRUE
  2828. *
  2829. */
  2830. ULONG FASTCALL WK32WowFailedExec(PVDMFRAME pFrame)
  2831. {
  2832. UNREFERENCED_PARAMETER(pFrame);
  2833. if(iW32ExecTaskId != -1) {
  2834. ExitVDM(WOWVDM,iW32ExecTaskId);
  2835. iW32ExecTaskId = (UINT)-1;
  2836. ShowStartGlass (0);
  2837. }
  2838. FlushMapFileCaches();
  2839. return TRUE;
  2840. }
  2841. /*++
  2842. Hung App Support
  2843. ================
  2844. There are many levels at which hung app support works. The User will
  2845. bring up the Task List and hit the End Task Button. USER32 will post
  2846. a WM_ENDSESSION message to the app. If the app does not exit after a specified
  2847. timeout them USER will call W32HunAppThread, provided that the task is at the
  2848. client/server boundary. If the app is looping (ie not at the client/server
  2849. boundary) then it will use the HungAppNotifyThread to alter WOW to kill
  2850. the currently running task. For the case of W32EndTask we simply
  2851. return back to the 16 bit kernel and force it to perform and Int 21 4C Exit
  2852. call. For the case of the HungAppNotifyThread we have to somehow grab
  2853. the apps thread - at a point which is "safe". On non x86 platforms this
  2854. means that the emulator must be at a know safe state - ie not actively emulating
  2855. instructions. The worst case is if the app is spinning with interrupts
  2856. disabled.
  2857. Notify Thread will
  2858. Force Interrupts to be Enabled SetMSW()
  2859. Set global flag for heartbeatthread so it knows there is work to do
  2860. wait for the app to exit
  2861. timeout - terminate thread() reduce # of tasks
  2862. Alter Global Flag in 16 bit Kernel, that is checked on TimerTick Routines,
  2863. that routine will:-
  2864. Tidy the stack if on the DOSX stack during h/w interrupt simulation
  2865. Force Int 21 4C exit - might have to patch return address of h/w interrupt
  2866. and then do it at simulated TaskTime.
  2867. Worst Case
  2868. If we don't kill the app in the timeout specified the WOW will put up a dialog
  2869. and then ExitProcess to kill itself.
  2870. Suggestions - if we don't manage to cleanly kill a task we should reduce
  2871. the app count by 2 - (ie the task and WOWExec, so when the last 16 bit app
  2872. goes away we will shutdown WOW). Also in the case put up a dialog box
  2873. stating you should save your work for 16 bit apps too.
  2874. --*/
  2875. /*++
  2876. InitializeHungAppSupport - Setup Necessary Threads and Callbacks
  2877. Routine Description
  2878. Create a HungAppNotification Thread
  2879. Register CallBack Handlers With SoftPC Base which are called when
  2880. interrupt simulation is required.
  2881. Entry
  2882. NONE
  2883. EXIT
  2884. TRUE - Success
  2885. FALSE - Faled
  2886. --*/
  2887. BOOL WK32InitializeHungAppSupport(VOID)
  2888. {
  2889. // Register Interrupt Idle Routine with SoftPC
  2890. ghevWowExecMsgWait = RegisterWOWIdle();
  2891. // Create HungAppNotify Thread
  2892. InitializeCriticalSection(&gcsWOW);
  2893. InitializeCriticalSection(&gcsHungApp); // protects VDM_WOWHUNGAPP bit
  2894. if(!(pfnOut.pfnRegisterUserHungAppHandlers)((PFNW32ET)W32HungAppNotifyThread,
  2895. ghevWowExecMsgWait))
  2896. {
  2897. LOGDEBUG(LOG_ALWAYS,("W32HungAppNotifyThread: Error Failed to RegisterUserHungAppHandlers\n"));
  2898. return FALSE;
  2899. }
  2900. if (!(ghevWaitHungAppNotifyThread = CreateEvent(NULL, TRUE, FALSE, NULL))) {
  2901. LOGDEBUG(LOG_ALWAYS,("WK32InitializeHungAppSupport ERROR: event allocation failure\n"));
  2902. return FALSE;
  2903. }
  2904. return TRUE;
  2905. }
  2906. /*++
  2907. WK32WowWaitForMsgAndEvent
  2908. Routine Description:
  2909. Calls USER32 WowWaitForMsgAndEvent
  2910. Called by WOWEXEC (interrupt dispatch optimization)
  2911. ENTRY
  2912. pFrame->hwnd must be WOWExec's hwnd
  2913. EXIT
  2914. FALSE - A message has arrived, WOWExec must call GetMessage
  2915. TRUE - The interrupt event was toggled, no work for WOWExec
  2916. --*/
  2917. ULONG FASTCALL WK32WowWaitForMsgAndEvent(PVDMFRAME pFrame)
  2918. {
  2919. register PWOWWAITFORMSGANDEVENT16 parg16;
  2920. BOOL RetVal;
  2921. GETARGPTR(pFrame, sizeof(WOWWAITFORMSGANDEVENT16), parg16);
  2922. //
  2923. // This is a private api so lets make sure it is wowexec
  2924. //
  2925. if (ghwndShell != HWND32(parg16->hwnd)) {
  2926. FREEARGPTR(parg16);
  2927. return FALSE;
  2928. }
  2929. //
  2930. // WowExec will set VDM_TIMECHANGE bit in the pntvdmstate
  2931. // when it receives a WM_TIMECHANGE message. It is now safe
  2932. // to Reinit the Virtual Timer Hardware as wowexec is the currently
  2933. // scheduled task, and we expect no one to be polling on
  2934. // timer hardware\Bios tic count.
  2935. //
  2936. if (*pNtVDMState & VDM_TIMECHANGE) {
  2937. SuspendTimerThread();
  2938. ResumeTimerThread();
  2939. }
  2940. BlockWOWIdle(TRUE);
  2941. RetVal = (ULONG) (pfnOut.pfnWowWaitForMsgAndEvent)(ghevWowExecMsgWait);
  2942. BlockWOWIdle(FALSE);
  2943. FREEARGPTR(parg16);
  2944. return RetVal;
  2945. }
  2946. /*++
  2947. WowMsgBoxThread
  2948. Routine Description:
  2949. Worker Thread routine which does all of the msg box work for
  2950. Wk32WowMsgBox (See below)
  2951. ENTRY
  2952. EXIT
  2953. VOID
  2954. --*/
  2955. DWORD WowMsgBoxThread(VOID *pv)
  2956. {
  2957. PWOWMSGBOX16 pWowMsgBox16 = (PWOWMSGBOX16)pv;
  2958. PSZ pszMsg, pszTitle;
  2959. char szMsg[MAX_PATH*2];
  2960. char szTitle[MAX_PATH];
  2961. UINT Style;
  2962. if (pWowMsgBox16->pszMsg) {
  2963. GETPSZPTR(pWowMsgBox16->pszMsg, pszMsg);
  2964. szMsg[MAX_PATH*2 - 1] = '\0';
  2965. WOW32_strncpy(szMsg, pszMsg, MAX_PATH*2 - 1);
  2966. FREEPSZPTR(pszMsg);
  2967. } else {
  2968. szMsg[0] = '\0';
  2969. }
  2970. if (pWowMsgBox16->pszTitle) {
  2971. GETPSZPTR(pWowMsgBox16->pszTitle, pszTitle);
  2972. szTitle[MAX_PATH - 1] = '\0';
  2973. WOW32_strncpy(szTitle, pszTitle, MAX_PATH-1);
  2974. FREEPSZPTR(pszTitle);
  2975. } else {
  2976. szTitle[0] = '\0';
  2977. }
  2978. Style = pWowMsgBox16->dwOptionalStyle | MB_OK | MB_SYSTEMMODAL;
  2979. pWowMsgBox16->dwOptionalStyle = 0xffffffff;
  2980. MessageBox (NULL, szMsg, szTitle, Style);
  2981. return 1;
  2982. }
  2983. /*++
  2984. WK32WowMsgBox
  2985. Routine Description:
  2986. Creates an asynchronous msg box and returns immediately
  2987. without waiting for the msg box to be dismissed. Provided
  2988. for WowExec as WowExec must use its special WowWaitForMsgAndEvent
  2989. api for hardware interrupt dispatching.
  2990. Called by WOWEXEC (interrupt dispatch optimization)
  2991. ENTRY
  2992. pszMsg - Message for MessageBox
  2993. pszTitle - Caption for MessageBox
  2994. dwOptionalStyle - MessageBox style bits additional to
  2995. MB_OK | MB_SYSTEMMODAL
  2996. EXIT
  2997. VOID - nothing is returned as we do not wait for a reply from
  2998. the user.
  2999. --*/
  3000. ULONG FASTCALL WK32WowMsgBox(PVDMFRAME pFrame)
  3001. {
  3002. PWOWMSGBOX16 pWowMsgBox16;
  3003. DWORD Tid;
  3004. HANDLE hThread;
  3005. GETARGPTR(pFrame, sizeof(WOWMSGBOX16), pWowMsgBox16);
  3006. hThread = CreateThread(NULL, 0, WowMsgBoxThread, (PVOID)pWowMsgBox16, 0, &Tid);
  3007. if (hThread) {
  3008. do {
  3009. if (WaitForSingleObject(hThread, 15) != WAIT_TIMEOUT)
  3010. break;
  3011. } while (pWowMsgBox16->dwOptionalStyle != 0xffffffff);
  3012. CloseHandle(hThread);
  3013. }
  3014. else {
  3015. WowMsgBoxThread((PVOID)pWowMsgBox16);
  3016. }
  3017. FREEARGPTR(pWowMsgBox16);
  3018. return 0;
  3019. }
  3020. #ifdef debug
  3021. UINT gLasthtaskKill = 0;
  3022. #endif
  3023. /*++
  3024. W32HungAppNotifyThread
  3025. USER32 Calls this routine:
  3026. 1 - if the App Agreed to the End Task (from Task List)
  3027. 2 - if the app didn't respond to the End Task
  3028. 3 - shutdown
  3029. NTVDM Calls this routine:
  3030. 1 - if an app has touched some h/w that it shouldn't and the user
  3031. requiested to terminate the app (passed NULL for current task)
  3032. WOW32 Calls this routine:
  3033. 1 - when WowExec receives a WM_WOWEXECKILLTASK message.
  3034. ENTRY
  3035. hKillUniqueID - TASK ID of task to kill or NULL for current Task
  3036. EXIT
  3037. NEVER RETURNS - Goes away when WOW is killed
  3038. --*/
  3039. DWORD W32HungAppNotifyThread(UINT htaskKill)
  3040. {
  3041. PTD ptd;
  3042. LPWORD pLockTDB;
  3043. WORD hTask16;
  3044. DWORD dwThreadId;
  3045. int nMsgBoxChoice;
  3046. PTDB pTDB;
  3047. char szModName[9];
  3048. char szErrorMessage[(2 * sizeof(szModName)) + WARNINGMSGLENGTH];
  3049. DWORD dwResult;
  3050. BOOL fSuccess;
  3051. if (!ResetEvent(ghevWaitHungAppNotifyThread)) {
  3052. LOGDEBUG(LOG_ALWAYS,("W32HungAppNotifyThread: ERROR failed to ResetEvent\n"));
  3053. }
  3054. ptd = NULL;
  3055. if (htaskKill) {
  3056. EnterCriticalSection(&gcsWOW);
  3057. ptd = gptdTaskHead;
  3058. /*
  3059. * See if the Task is still alive
  3060. */
  3061. while ((ptd != NULL) && (ptd->htask16 != htaskKill)) {
  3062. ptd = ptd->ptdNext;
  3063. }
  3064. LeaveCriticalSection(&gcsWOW);
  3065. }
  3066. // If we are seeing this notification for a second time, these selectors
  3067. // probably don't match -- which means this 16-bit context is really messed
  3068. // up. We'd better prevent it from doing any 16-bit callbacks at this point
  3069. // or it will result in a crash dlg for the user & will kill the VDM & any
  3070. // other 16-bit apps (tasks) running in this VDM.
  3071. // This situation will occur if the call to WaitForSingleObject() (following
  3072. // the call to SendMessageTimeout() below) actually times-out rather than
  3073. // complete. The thread will actually be dead by the time *this* function
  3074. // gets called again with a now-invalid TDB struct. This situation appears
  3075. // to result from clicking End Task from the task manager or somehow trying
  3076. // to kill a not-hung 16-bit task via external means. Bug #408188
  3077. if((ptd == NULL) || (HIWORD(ptd->vpStack) != HIWORD(ptd->vpCBStack))) {
  3078. #ifdef debug
  3079. // sanity check to make sure this only happens for the same task
  3080. WOW32ASSERTMSG((htaskKill == gLasthtaskKill),
  3081. ("WOW: Unexpected mis-matched selector case\n"));
  3082. gLasthtaskKill = 0;
  3083. #endif
  3084. return 0;
  3085. }
  3086. // point to LockTDB
  3087. GETVDMPTR(vpLockTDB, 2, pLockTDB);
  3088. // If the task is alive then attempt to kill it
  3089. if ( ( ptd != NULL ) || ( htaskKill == 0 ) ) {
  3090. // Set LockTDB == The app we are trying to kill
  3091. // (see \kernel31\TASKING.ASM)
  3092. // and then try to cause a task switch by posting WOWEXEC a message
  3093. // and then posting a message to the app we want to kill
  3094. if ( ptd != NULL) {
  3095. hTask16 = ptd->htask16;
  3096. }
  3097. else {
  3098. // htaskKill == 0
  3099. // Kill the Active Task
  3100. hTask16 = *pCurTDB;
  3101. }
  3102. pTDB = (PTDB)SEGPTR(hTask16, 0);
  3103. WOW32ASSERTMSGF( pTDB && pTDB->TDB_sig == TDB_SIGNATURE,
  3104. ("W32HungAppNotifyThread: TDB sig doesn't match, TDB %x htaskKill %x pTDB %x.\n",
  3105. hTask16, htaskKill, pTDB));
  3106. dwThreadId = pTDB->TDB_ThreadID;
  3107. //
  3108. // if the task to be killed is this task end immediately
  3109. //
  3110. if (dwThreadId == GetCurrentThreadId()) {
  3111. EnterCriticalSection(&gcsHungApp);
  3112. *pNtVDMState |= VDM_WOWHUNGAPP;
  3113. LeaveCriticalSection(&gcsHungApp);
  3114. call_ica_hw_interrupt( KEYBOARD_ICA, KEYBOARD_LINE, 1 );
  3115. //
  3116. // return to 16 bit to process int 9.
  3117. //
  3118. return 0;
  3119. }
  3120. *pLockTDB = hTask16;
  3121. SendMessageTimeout(ghwndShell, WM_WOWEXECHEARTBEAT, 0, 0, SMTO_BLOCK,1*1000,&dwResult);
  3122. //
  3123. // terminate any pending named pipe operations for this thread (ie app)
  3124. //
  3125. VrCancelPipeIo(dwThreadId);
  3126. PostThreadMessage(dwThreadId, WM_KEYDOWN, VK_ESCAPE, 0x1B000A);
  3127. PostThreadMessage(dwThreadId, WM_KEYUP, VK_ESCAPE, 0x1B0001);
  3128. if (WaitForSingleObject(ghevWaitHungAppNotifyThread,
  3129. CMS_WAITTASKEXIT) == 0) {
  3130. LOGDEBUG(2,("W32HungAppNotifyThread: Success with forced task switch\n"));
  3131. ExitThread(EXIT_SUCCESS);
  3132. }
  3133. #ifdef debug
  3134. gLasthtaskKill = htaskKill;
  3135. #endif
  3136. // Failed
  3137. //
  3138. // Probably means the current App is looping in 16 bit land not
  3139. // responding to input.
  3140. // Warn the User if its a different App than the one he wants to kill
  3141. // Don't do this if WOWEXEC is the hung app, since users don't know
  3142. // what that is.
  3143. if (*pLockTDB != *pCurTDB && gptdShell->htask16 != *pCurTDB && *pCurTDB) {
  3144. pTDB = (PTDB)SEGPTR(*pCurTDB, 0);
  3145. WOW32ASSERTMSGF( pTDB && pTDB->TDB_sig == TDB_SIGNATURE,
  3146. ("W32HungAppNotifyThread: Current TDB sig doesn't match, TDB %x htaskKill %x pTDB %x.\n",
  3147. *pCurTDB, htaskKill, pTDB));
  3148. RtlCopyMemory(szModName, pTDB->TDB_ModName, (sizeof szModName)-1);
  3149. szModName[(sizeof szModName) - 1] = 0;
  3150. fSuccess = LoadString(
  3151. hmodWOW32,
  3152. iszCantEndTask,
  3153. szMsgBoxText,
  3154. WARNINGMSGLENGTH
  3155. );
  3156. WOW32ASSERT(fSuccess);
  3157. fSuccess = LoadString(
  3158. hmodWOW32,
  3159. iszApplicationError,
  3160. szCaption,
  3161. WARNINGMSGLENGTH
  3162. );
  3163. WOW32ASSERT(fSuccess);
  3164. _snprintf(
  3165. szErrorMessage,
  3166. sizeof(szErrorMessage)-1,
  3167. szMsgBoxText,
  3168. szModName,
  3169. szModName
  3170. );
  3171. szErrorMessage[sizeof(szErrorMessage)-1] ='\0';
  3172. nMsgBoxChoice =
  3173. MessageBox(
  3174. NULL,
  3175. szErrorMessage,
  3176. szCaption,
  3177. MB_TOPMOST | MB_SETFOREGROUND | MB_TASKMODAL |
  3178. MB_ICONSTOP | MB_OKCANCEL
  3179. );
  3180. if (nMsgBoxChoice == IDCANCEL) {
  3181. ExitThread(0);
  3182. }
  3183. }
  3184. //
  3185. // See code in \mvdm\wow16\drivers\keyboard\keyboard.asm
  3186. // where keyb_int where it handles this interrupt and forces an
  3187. // int 21 function 4c - Exit. It only does this if VDM_WOWHUNGAPP
  3188. // is turned on in NtVDMState, and it clears that bit. We wait for
  3189. // the bit to be clear if it's already set, indicating another instance
  3190. // of this thread has already initiated an INT 9 to kill a task. By
  3191. // waiting we avoid screwing up the count of threads active on the
  3192. // 16-bit side (bThreadsIn16Bit).
  3193. //
  3194. // LATER shouldn't allow user to kill WOWEXEC
  3195. //
  3196. // LATER should enable h/w interrupt before doing this - use 40: area
  3197. // on x86. On MIPS we'd need to call CPU interface.
  3198. //
  3199. EnterCriticalSection(&gcsHungApp);
  3200. while (*pNtVDMState & VDM_WOWHUNGAPP) {
  3201. LeaveCriticalSection(&gcsHungApp);
  3202. LOGDEBUG(LOG_ALWAYS, ("WOW32 W32HungAppNotifyThread waiting for previous INT 9 to clear before dispatching another.\n"));
  3203. Sleep(1 * 1000);
  3204. EnterCriticalSection(&gcsHungApp);
  3205. }
  3206. *pNtVDMState |= VDM_WOWHUNGAPP;
  3207. LeaveCriticalSection(&gcsHungApp);
  3208. call_ica_hw_interrupt( KEYBOARD_ICA, KEYBOARD_LINE, 1 );
  3209. if (WaitForSingleObject(ghevWaitHungAppNotifyThread,
  3210. CMS_WAITTASKEXIT) != 0) {
  3211. LOGDEBUG(LOG_ALWAYS,("W32HungAppNotifyThread: Error, timeout waiting for task to terminate\n"));
  3212. fSuccess = LoadString(
  3213. hmodWOW32,
  3214. iszUnableToEndSelTask,
  3215. szMsgBoxText,
  3216. WARNINGMSGLENGTH);
  3217. WOW32ASSERT(fSuccess);
  3218. fSuccess = LoadString(
  3219. hmodWOW32,
  3220. iszSystemError,
  3221. szCaption,
  3222. WARNINGMSGLENGTH);
  3223. WOW32ASSERT(fSuccess);
  3224. nMsgBoxChoice =
  3225. MessageBox(
  3226. NULL,
  3227. szMsgBoxText,
  3228. szCaption,
  3229. MB_TOPMOST | MB_SETFOREGROUND | MB_TASKMODAL |
  3230. MB_ICONSTOP | MB_OKCANCEL | MB_DEFBUTTON1
  3231. );
  3232. if (nMsgBoxChoice == IDCANCEL) {
  3233. EnterCriticalSection(&gcsHungApp);
  3234. *pNtVDMState &= ~VDM_WOWHUNGAPP;
  3235. LeaveCriticalSection(&gcsHungApp);
  3236. ExitThread(0);
  3237. }
  3238. LOGDEBUG(LOG_ALWAYS, ("W32HungAppNotifyThread: Destroying WOW Process\n"));
  3239. ExitVDM(WOWVDM, ALL_TASKS);
  3240. ExitProcess(0);
  3241. }
  3242. LOGDEBUG(LOG_ALWAYS,("W32HungAppNotifyThread: Success with Keyboard Interrupt\n"));
  3243. } else { // task not found
  3244. LOGDEBUG(LOG_ALWAYS,("W32HungAppNotifyThread: Task already Terminated \n"));
  3245. }
  3246. ExitThread(EXIT_SUCCESS);
  3247. return 0; // remove compiler warning
  3248. }
  3249. /*++
  3250. W32EndTask - Cause Current Task to Exit (HUNG APP SUPPORT)
  3251. Routine Description:
  3252. This routine is called when unthunking WM_ENDSESSION to cause the current
  3253. task to terminate.
  3254. ENTRY
  3255. The apps thread that we want to kill
  3256. EXIT
  3257. DOES NOT RETURN - The task will exit and wind up in WK32WOWKillTask which
  3258. will cause that thread to Exit.
  3259. --*/
  3260. VOID APIENTRY W32EndTask(VOID)
  3261. {
  3262. PARM16 Parm16;
  3263. VPVOID vp = 0;
  3264. LOGDEBUG(LOG_WARNING,("W32EndTask: Forcing Task %04X to Exit\n",CURRENTPTD()->htask16));
  3265. CallBack16(RET_FORCETASKEXIT, &Parm16, 0, &vp);
  3266. //
  3267. // We should Never Come Here, an app should get terminated via calling wk32wowkilltask thunk
  3268. // not by doing an unsimulate call
  3269. //
  3270. WOW32ASSERTMSG(FALSE, "W32EndTask: Error - Returned From ForceTaskExit callback - contact DaveHart");
  3271. }
  3272. ULONG FASTCALL WK32DirectedYield(PVDMFRAME pFrame)
  3273. {
  3274. register PDIRECTEDYIELD16 parg16;
  3275. //
  3276. // This code is duplicated in wkgthunk.c by WOWDirectedYield16.
  3277. // The two must be kept synchronized.
  3278. //
  3279. GETARGPTR(pFrame, sizeof(DIRECTEDYIELD16), parg16);
  3280. BlockWOWIdle(TRUE);
  3281. (pfnOut.pfnDirectedYield)(THREADID32(parg16->hTask16));
  3282. BlockWOWIdle(FALSE);
  3283. FREEARGPTR(parg16);
  3284. RETURN(0);
  3285. }
  3286. /***************************************************************************\
  3287. * EnablePrivilege
  3288. *
  3289. * Enables/disables the specified well-known privilege in the current thread
  3290. * token if there is one, otherwise the current process token.
  3291. *
  3292. * Returns TRUE on success, FALSE on failure
  3293. *
  3294. * History:
  3295. * 12-05-91 Davidc Created
  3296. * 06-15-93 BobDay Stolen from WinLogon
  3297. \***************************************************************************/
  3298. BOOL
  3299. EnablePrivilege(
  3300. ULONG Privilege,
  3301. BOOL Enable
  3302. )
  3303. {
  3304. NTSTATUS Status;
  3305. BOOLEAN WasEnabled;
  3306. //
  3307. // Try the thread token first
  3308. //
  3309. Status = RtlAdjustPrivilege(Privilege,
  3310. (BOOLEAN)Enable,
  3311. TRUE,
  3312. &WasEnabled);
  3313. if (Status == STATUS_NO_TOKEN) {
  3314. //
  3315. // No thread token, use the process token
  3316. //
  3317. Status = RtlAdjustPrivilege(Privilege,
  3318. (BOOLEAN)Enable,
  3319. FALSE,
  3320. &WasEnabled);
  3321. }
  3322. if (!NT_SUCCESS(Status)) {
  3323. LOGDEBUG(LOG_ALWAYS,("WOW32: EnablePrivilege Failed to %s privilege : 0x%lx, status = 0x%lx\n", Enable ? "enable" : "disable", Privilege, Status));
  3324. return(FALSE);
  3325. }
  3326. return(TRUE);
  3327. }
  3328. //*****************************************************************************
  3329. // W32GetAppCompatFlags -
  3330. // Returns the Compatibility flags for the Current Task or of the
  3331. // specified Task.
  3332. // These are the 16-bit kernel's compatibility flags, not to be
  3333. // confused with our separate WOW compatibility flags.
  3334. //
  3335. //*****************************************************************************
  3336. ULONG W32GetAppCompatFlags(HTASK16 hTask16)
  3337. {
  3338. PTDB ptdb;
  3339. if (hTask16 == (HAND16)NULL) {
  3340. hTask16 = CURRENTPTD()->htask16;
  3341. }
  3342. ptdb = (PTDB)SEGPTR((hTask16),0);
  3343. return (ULONG)MAKELONG(ptdb->TDB_CompatFlags, ptdb->TDB_CompatFlags2);
  3344. }
  3345. //*****************************************************************************
  3346. // This is called from COMM.drv via WowCloseComPort in kernel16, whenever
  3347. // a com port needs to be released.
  3348. //
  3349. // PortId 0 is COM1, 1 is COM2 etc.
  3350. // - Nanduri
  3351. //*****************************************************************************
  3352. ULONG FASTCALL WK32WowCloseComPort(PVDMFRAME pFrame)
  3353. {
  3354. register PWOWCLOSECOMPORT16 parg16;
  3355. GETARGPTR(pFrame, sizeof(WOWCLOSECOMPORT16), parg16);
  3356. host_com_close((INT)parg16->wPortId);
  3357. FREEARGPTR(parg16);
  3358. return 0; // quiet compiler, not used.
  3359. }
  3360. //*****************************************************************************
  3361. // WK32WowDelFile
  3362. // The call to demFileDelete will handle the case where there there is an
  3363. // open handle to the file. In case it fails, we try hacking around the case
  3364. // where a font file being held by GDI32.
  3365. //*****************************************************************************
  3366. DWORD FASTCALL WK32WowDelFile(PVDMFRAME pFrame)
  3367. {
  3368. PSZ psz1;
  3369. PWOWDELFILE16 parg16;
  3370. DWORD retval;
  3371. GETARGPTR(pFrame, sizeof(WOWFILEDEL16), parg16);
  3372. GETVDMPTR(parg16->lpFile, 1, psz1);
  3373. LOGDEBUG(fileoclevel,("WK32WOWDelFile: %s \n",psz1));
  3374. retval = demFileDelete(psz1);
  3375. switch(retval) {
  3376. case 0:
  3377. case ERROR_FILE_NOT_FOUND:
  3378. case ERROR_PATH_NOT_FOUND:
  3379. break;
  3380. default:
  3381. // Some Windows Install Programs copy a .FON font file to a temp
  3382. // directory use the font during installation and then try to delete
  3383. // the font - without calling RemoveFontResource(); GDI32 Keeps the
  3384. // Font file open and thus the delete fails.
  3385. // What we attempt here is to assume that the file is a FONT file
  3386. // and try to remove it before deleting it, since the above delete
  3387. // has already failed.
  3388. if ( RemoveFontResourceOem(psz1) ) {
  3389. LOGDEBUG(fileoclevel,("WK32WOWDelFile: RemoveFontResource on %s \n",psz1));
  3390. SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
  3391. }
  3392. if(DeleteFileOem(psz1)) {
  3393. retval = 0;
  3394. }
  3395. }
  3396. if ( retval ) {
  3397. retval |= 0xffff0000;
  3398. }
  3399. FREEVDMPTR(psz1);
  3400. FREEARGPTR(parg16);
  3401. return retval;
  3402. }
  3403. //*****************************************************************************
  3404. // This is called as soon as wow is initialized to notify the 32-bit world
  3405. // what the addresses are of some key kernel variables.
  3406. //
  3407. //*****************************************************************************
  3408. ULONG FASTCALL WK32WOWNotifyWOW32(PVDMFRAME pFrame)
  3409. {
  3410. register PWOWNOTIFYWOW3216 parg16;
  3411. GETARGPTR(pFrame, sizeof(WOWNOTIFYWOW3216), parg16);
  3412. vpDebugWOW = FETCHDWORD(parg16->lpDebugWOW);
  3413. GETVDMPTR(FETCHDWORD(parg16->lpcurTDB), 2, pCurTDB);
  3414. vpnum_tasks = FETCHDWORD(parg16->lpnum_tasks);
  3415. vpLockTDB = FETCHDWORD(parg16->lpLockTDB);
  3416. vptopPDB = FETCHDWORD(parg16->lptopPDB);
  3417. GETVDMPTR(FETCHDWORD(parg16->lpCurDirOwner), 2, pCurDirOwner);
  3418. //
  3419. // IsDebuggerAttached will tell the 16-bit kernel to generate
  3420. // debug events.
  3421. //
  3422. IsDebuggerAttached();
  3423. FREEARGPTR(parg16);
  3424. return 0;
  3425. }
  3426. //*****************************************************************************
  3427. // Currently, this routine is called very very soon after the 16-bit kernel.exe
  3428. // has switched to protected mode. The variables set up here are used in the
  3429. // file i/o routines.
  3430. //*****************************************************************************
  3431. extern VOID demWOWLFNInit(PWOWLFNINIT pLFNInit);
  3432. extern VOID DosWowUpdateTDBDir(UCHAR Drive, LPSTR pszDir);
  3433. extern BOOL DosWowGetTDBDir(UCHAR Drive, LPSTR pCurrentDirectory);
  3434. extern BOOL DosWowDoDirectHDPopup(VOID);
  3435. #if 0
  3436. extern BOOL DosWowGetCompatFlags(LPDWORD, LPDWORD);
  3437. #endif
  3438. //
  3439. // Function returns TRUE if we should do the popup
  3440. // and FALSE if we should not
  3441. //
  3442. ULONG FASTCALL WK32DosWowInit(PVDMFRAME pFrame)
  3443. {
  3444. register PWOWDOSWOWINIT16 parg16;
  3445. PDOSWOWDATA pDosWowData;
  3446. PULONG pTemp;
  3447. WOWLFNINIT LFNInit;
  3448. GETARGPTR(pFrame, sizeof(WOWDOSWOWINIT16), parg16);
  3449. // covert all fixed DOS address to linear addresses for fast WOW thunks.
  3450. pDosWowData = GetRModeVDMPointer(FETCHDWORD(parg16->lpDosWowData));
  3451. DosWowData.lpCDSCount = (DWORD) GetRModeVDMPointer(
  3452. FETCHDWORD(pDosWowData->lpCDSCount));
  3453. pTemp = (PULONG)GetRModeVDMPointer(FETCHDWORD(pDosWowData->lpCDSFixedTable));
  3454. DosWowData.lpCDSFixedTable = (DWORD) GetRModeVDMPointer(FETCHDWORD(*pTemp));
  3455. DosWowData.lpCDSBuffer = (DWORD)GetRModeVDMPointer(
  3456. FETCHDWORD(pDosWowData->lpCDSBuffer));
  3457. DosWowData.lpCurDrv = (DWORD) GetRModeVDMPointer(
  3458. FETCHDWORD(pDosWowData->lpCurDrv));
  3459. DosWowData.lpCurPDB = (DWORD) GetRModeVDMPointer(
  3460. FETCHDWORD(pDosWowData->lpCurPDB));
  3461. DosWowData.lpDrvErr = (DWORD) GetRModeVDMPointer(
  3462. FETCHDWORD(pDosWowData->lpDrvErr));
  3463. DosWowData.lpExterrLocus = (DWORD) GetRModeVDMPointer(
  3464. FETCHDWORD(pDosWowData->lpExterrLocus));
  3465. DosWowData.lpSCS_ToSync = (DWORD) GetRModeVDMPointer(
  3466. FETCHDWORD(pDosWowData->lpSCS_ToSync));
  3467. DosWowData.lpSftAddr = (DWORD) GetRModeVDMPointer(
  3468. FETCHDWORD(pDosWowData->lpSftAddr));
  3469. DosWowData.lpExterr = (DWORD) GetRModeVDMPointer(
  3470. FETCHDWORD(pDosWowData->lpExterr));
  3471. DosWowData.lpExterrActionClass = (DWORD) GetRModeVDMPointer(
  3472. FETCHDWORD(pDosWowData->lpExterrActionClass));
  3473. /* // right here we shall make a dynamic check to see if wow is running on
  3474. // Winterm Server and if so -- whether we need to thunk GetWindowsDirectory
  3475. {
  3476. PDWORD UNALIGNED pdwWinTermFlags;
  3477. GETVDMPTR(FETCHDWORD(parg16->lpdwWinTermFlags), sizeof(DWORD), pdwWinTermFlags);
  3478. if (IsTerminalServer()) {
  3479. *pdwWinTermFlags |= WINTERM_SERVER;
  3480. }
  3481. }
  3482. */
  3483. // excellent chance to have us let ntvdm know we're lfn aware and alive
  3484. LFNInit.pDosWowUpdateTDBDir = DosWowUpdateTDBDir;
  3485. LFNInit.pDosWowGetTDBDir = DosWowGetTDBDir;
  3486. LFNInit.pDosWowDoDirectHDPopup = DosWowDoDirectHDPopup;
  3487. #if 0
  3488. LFNInit.pDosWowGetCompatFlags = DosWowGetCompatFlags;
  3489. #endif
  3490. demWOWLFNInit(&LFNInit);
  3491. FREEARGPTR(parg16);
  3492. return (0);
  3493. }
  3494. //*****************************************************************************
  3495. //
  3496. // WK32InitWowIsKnownDLL(HANDLE hKeyWow)
  3497. //
  3498. // Called by W32Init to read list of known DLLs from the registry.
  3499. //
  3500. // hKeyWow is an open handle to ...\CurrentControlSet\WOW, we use
  3501. // the value REG_SZ value KnownDLLs which looks like "commdlg.dll mmsystem.dll
  3502. // toolhelp.dll olecli.dll olesvr.dll".
  3503. //
  3504. //*****************************************************************************
  3505. VOID WK32InitWowIsKnownDLL(HANDLE hKeyWow)
  3506. {
  3507. int len;
  3508. CHAR sz[2048];
  3509. PSZ pszKnownDLL;
  3510. PCHAR pch;
  3511. ULONG ulSize = sizeof(sz);
  3512. int nCount;
  3513. DWORD dwRegValueType;
  3514. LONG lRegError;
  3515. ULONG ulAttrib;
  3516. //
  3517. // Get the list of known DLLs from the registry.
  3518. //
  3519. lRegError = RegQueryValueEx(
  3520. hKeyWow,
  3521. "KnownDLLs",
  3522. NULL,
  3523. &dwRegValueType,
  3524. sz,
  3525. &ulSize
  3526. );
  3527. if (ERROR_SUCCESS == lRegError && REG_SZ == dwRegValueType) {
  3528. //
  3529. // Allocate memory to hold a copy of this string to be
  3530. // used to hold the strings pointed to by
  3531. // apszKnownDLL[]. This memory won't be freed until
  3532. // WOW goes away.
  3533. //
  3534. pszKnownDLL = malloc_w_or_die(ulSize);
  3535. strncpy(pszKnownDLL, sz, ulSize);
  3536. pszKnownDLL[ulSize-1] = '\0';
  3537. //
  3538. // Lowercase the entire value so that we can search these
  3539. // strings case-sensitive in WK32WowIsKnownDLL.
  3540. //
  3541. WOW32_strlwr(pszKnownDLL);
  3542. //
  3543. // Parse the KnownDLL string into apszKnownDLL array.
  3544. // strtok() does this quite handily.
  3545. //
  3546. nCount = 0;
  3547. pch = apszKnownDLL[0] = pszKnownDLL;
  3548. while (apszKnownDLL[nCount]) {
  3549. nCount++;
  3550. if (nCount >= MAX_KNOWN_DLLS) {
  3551. LOGDEBUG(0,("WOW32 Init: Too many known DLLs, must have %d or fewer.\n", MAX_KNOWN_DLLS-1));
  3552. apszKnownDLL[MAX_KNOWN_DLLS-1] = NULL;
  3553. break;
  3554. }
  3555. pch = WOW32_strchr(pch, ' ');
  3556. if (!pch) {
  3557. break;
  3558. }
  3559. *pch = 0;
  3560. pch++;
  3561. if (0 == *pch) {
  3562. break;
  3563. }
  3564. while (' ' == *pch) {
  3565. pch++;
  3566. }
  3567. apszKnownDLL[nCount] = pch;
  3568. }
  3569. } else {
  3570. LOGDEBUG(0,("InitWowIsKnownDLL: RegQueryValueEx error %ld.\n", lRegError));
  3571. }
  3572. //
  3573. // The Known DLL list is ready, now build up a fully-qualified paths
  3574. // to %windir%\control.exe and %windir%\system32\control.exe
  3575. // for WOWCF_CONTROLEXEHACK below.
  3576. //
  3577. //
  3578. // pszControlExeWinDirPath looks like "c:\winnt\control.exe"
  3579. //
  3580. // strlen("\\control.exe") + NULL
  3581. len = strlen(pszWindowsDirectory) + sizeof(szBackslashControlExe) + 1;
  3582. pszControlExeWinDirPath = malloc_w_or_die(len);
  3583. strncpy(pszControlExeWinDirPath, pszWindowsDirectory, len);
  3584. // dst buffer size verified.
  3585. strcat(pszControlExeWinDirPath, szBackslashControlExe);
  3586. //
  3587. // pszProgmanExeWinDirPath looks like "c:\winnt\progman.exe"
  3588. //
  3589. // strlen("\\progman.exe") + NULL
  3590. len = strlen(pszWindowsDirectory) + sizeof(szBackslashProgmanExe) + 1;
  3591. pszProgmanExeWinDirPath = malloc_w_or_die(len);
  3592. strncpy(pszProgmanExeWinDirPath, pszWindowsDirectory, len);
  3593. // dst buffer size verified.
  3594. strcat(pszProgmanExeWinDirPath, szBackslashProgmanExe);
  3595. //
  3596. // pszControlExeSysDirPath looks like "c:\winnt\system32\control.exe"
  3597. //
  3598. // strlen("\\control.exe") + NULL
  3599. len = cbSystemDirLen + sizeof(szBackslashControlExe) + 1;
  3600. pszControlExeSysDirPath = malloc_w_or_die(len);
  3601. strcpy(pszControlExeSysDirPath, pszSystemDirectory);
  3602. // dst buffer size verified.
  3603. strcat(pszControlExeSysDirPath, szBackslashControlExe);
  3604. //
  3605. // pszProgmanExeSysDirPath looks like "c:\winnt\system32\control.exe"
  3606. //
  3607. // strlen("\\progman.exe") + NULL
  3608. len = cbSystemDirLen + sizeof(szBackslashProgmanExe) + 1;
  3609. pszProgmanExeSysDirPath = malloc_w_or_die(len);
  3610. strcpy(pszProgmanExeSysDirPath, pszSystemDirectory);
  3611. // dst buffer size verified.
  3612. strcat(pszProgmanExeSysDirPath, szBackslashProgmanExe);
  3613. // Make the KnownDLL, CTL3DV2.DLL, file attribute ReadOnly.
  3614. // Later we should do this for all WOW KnownDll's
  3615. len = cbSystemDirLen;
  3616. // 13 == sizeof("\\CTL3DV2.DLL") below
  3617. if(len+13 < sizeof(sz)) {
  3618. strncpy(sz, pszSystemDirectory, len+1); // +1 to get NULL char
  3619. strcat(sz, "\\CTL3DV2.DLL");
  3620. ulAttrib = GetFileAttributesOemSys(sz, TRUE);
  3621. if ((ulAttrib != 0xFFFFFFFF) && !(ulAttrib & FILE_ATTRIBUTE_READONLY)) {
  3622. ulAttrib |= FILE_ATTRIBUTE_READONLY;
  3623. SetFileAttributesOemSys(sz, ulAttrib, TRUE);
  3624. }
  3625. }
  3626. }
  3627. //*****************************************************************************
  3628. //
  3629. // WK32WowIsKnownDLL -
  3630. //
  3631. // This routine is called from within LoadModule (actually MyOpenFile),
  3632. // when kernel31 has determined that the module is not already loaded,
  3633. // and is about to search for the DLL. If the base name of the passed
  3634. // path is a known DLL, we allocate and pass back to the 16-bit side
  3635. // a fully-qualified path to the DLL in the system32 directory.
  3636. //
  3637. //*****************************************************************************
  3638. ULONG FASTCALL WK32WowIsKnownDLL(PVDMFRAME pFrame)
  3639. {
  3640. register WOWISKNOWNDLL16 *parg16;
  3641. PSZ pszPath;
  3642. VPVOID UNALIGNED *pvpszKnownDLLPath;
  3643. PSZ pszKnownDLLPath;
  3644. size_t cbKnownDLLPath;
  3645. char **ppsz;
  3646. char szLowercasePath[13];
  3647. ULONG ul = 0;
  3648. BOOL fProgman = FALSE;
  3649. GETARGPTR(pFrame, sizeof(WOWISKNOWNDLL16), parg16);
  3650. GETPSZPTRNOLOG(parg16->lpszPath, pszPath);
  3651. GETVDMPTR(parg16->lplpszKnownDLLPath, sizeof(*pvpszKnownDLLPath), pvpszKnownDLLPath);
  3652. if (pszPath) {
  3653. //
  3654. // Special hack for apps which WinExec %windir%\control.exe or
  3655. // %windir%\progman.exe. This formerly was only done under a
  3656. // compatibility bit, but now is done for all apps. Both
  3657. // the 3.1[1] control panel and program manager binaries cannot
  3658. // work under WOW because of other shell conflicts, like different
  3659. // .GRP files and conflicting use of the control.ini file for both
  3660. // 16-bit and 32-bit CPLs.
  3661. //
  3662. // Compare the path passed in with the precomputed
  3663. // pszControlExeWinDirPath, which looks like "c:\winnt\control.exe".
  3664. // If it matches, pass back the "Known DLL path" of
  3665. // "c:\winnt\system32\control.exe". Same for progman.exe.
  3666. //
  3667. if (!WOW32_stricmp(pszPath, pszControlExeWinDirPath) ||
  3668. (fProgman = TRUE,
  3669. !WOW32_stricmp(pszPath, pszProgmanExeWinDirPath))) {
  3670. VPVOID vp;
  3671. cbKnownDLLPath = 1 + strlen(fProgman
  3672. ? pszProgmanExeSysDirPath
  3673. : pszControlExeSysDirPath);
  3674. vp = malloc16(cbKnownDLLPath);
  3675. // 16-bit memory may have moved - refresh flat pointers now
  3676. FREEVDMPTR(pvpszKnownDLLPath);
  3677. FREEPSZPTR(pszPath);
  3678. FREEARGPTR(parg16);
  3679. FREEVDMPTR(pFrame);
  3680. GETFRAMEPTR(((PTD)CURRENTPTD())->vpStack, pFrame);
  3681. GETARGPTR(pFrame, sizeof(WOWISKNOWNDLL16), parg16);
  3682. GETPSZPTRNOLOG(parg16->lpszPath, pszPath);
  3683. GETVDMPTR(parg16->lplpszKnownDLLPath, sizeof(*pvpszKnownDLLPath), pvpszKnownDLLPath);
  3684. *pvpszKnownDLLPath = vp;
  3685. if (*pvpszKnownDLLPath) {
  3686. GETPSZPTRNOLOG(*pvpszKnownDLLPath, pszKnownDLLPath);
  3687. RtlCopyMemory(
  3688. pszKnownDLLPath,
  3689. fProgman
  3690. ? pszProgmanExeSysDirPath
  3691. : pszControlExeSysDirPath,
  3692. cbKnownDLLPath);
  3693. // LOGDEBUG(0,("WowIsKnownDLL: %s known(c) -=> %s\n", pszPath, pszKnownDLLPath));
  3694. FLUSHVDMPTR(*pvpszKnownDLLPath, cbKnownDLLPath, pszKnownDLLPath);
  3695. FREEPSZPTR(pszKnownDLLPath);
  3696. ul = 1; // return success, meaning is known dll
  3697. goto Cleanup;
  3698. }
  3699. }
  3700. //
  3701. // We don't mess with attempts to open that include a
  3702. // path.
  3703. //
  3704. if (WOW32_strchr(pszPath, '\\') || WOW32_strchr(pszPath, ':') || strlen(pszPath) > 12) {
  3705. // LOGDEBUG(0,("WowIsKnownDLL: %s has a path, not checking.\n", pszPath));
  3706. goto Cleanup;
  3707. }
  3708. //
  3709. // Make a lowercase copy of the path.
  3710. //
  3711. WOW32_strncpy(szLowercasePath, pszPath, sizeof(szLowercasePath));
  3712. szLowercasePath[sizeof(szLowercasePath)-1] = 0;
  3713. WOW32_strlwr(szLowercasePath);
  3714. //
  3715. // Step through apszKnownDLL trying to find this DLL
  3716. // in the list.
  3717. //
  3718. for (ppsz = &apszKnownDLL[0]; *ppsz; ppsz++) {
  3719. //
  3720. // We compare case-sensitive for speed, since we're
  3721. // careful to lowercase the strings in apszKnownDLL
  3722. // and szLowercasePath.
  3723. //
  3724. if (!WOW32_strcmp(szLowercasePath, *ppsz)) {
  3725. //
  3726. // We found the DLL in the list, now build up
  3727. // a buffer for the 16-bit side containing
  3728. // the full path to that DLL in the system32
  3729. // directory.
  3730. //
  3731. cbKnownDLLPath = cbSystemDirLen +
  3732. 1 + // "\"
  3733. strlen(szLowercasePath) +
  3734. 1; // null
  3735. *pvpszKnownDLLPath = malloc16(cbKnownDLLPath);
  3736. if (*pvpszKnownDLLPath) {
  3737. #ifndef _X86_
  3738. HANDLE hFile;
  3739. #endif
  3740. GETPSZPTRNOLOG(*pvpszKnownDLLPath, pszKnownDLLPath);
  3741. #ifndef _X86_
  3742. // On RISC platforms, wx86 support tells 32-bit apps that
  3743. // the system dir is SYS32X86 instead of SYSTEM32. This
  3744. // allows us to keep the x86 binaries separate from the
  3745. // native RISC binaries in the SYSTEM32 dir. It also
  3746. // prevents x86 setup programs from clobbering the native
  3747. // RISC binaries & replacing them with an x86 version in the
  3748. // SYSTEM32 dir. Unfortunately several "32-bit" programs
  3749. // have 16-bit components (Most notably Outlook forms
  3750. // support). These 16-bit components will also be copied to
  3751. // the SYS32X86 dir. This is not a problem unless the
  3752. // binary shows up in our KnownDLLs list. This code attempts
  3753. // to locate KnownDLLs in the SYS32X86 dir on RISC machines
  3754. // before looking in the SYSTEM32 dir. See bug #321335.
  3755. strcpy(pszKnownDLLPath, pszWindowsDirectory);
  3756. // Fortunately this is the same len as "\\SYSTEM32\\" which
  3757. // means we don't need to adjust cbKnownDLLPath above.
  3758. strcat(pszKnownDLLPath, "\\SYS32X86\\");
  3759. strcat(pszKnownDLLPath, szLowercasePath);
  3760. // see if this knowndll exists in the sys32x86 dir
  3761. hFile = CreateFile(pszKnownDLLPath,
  3762. GENERIC_READ,
  3763. FILE_SHARE_READ,
  3764. NULL,
  3765. OPEN_EXISTING,
  3766. FILE_ATTRIBUTE_NORMAL,
  3767. NULL);
  3768. if(hFile != INVALID_HANDLE_VALUE) {
  3769. CloseHandle(hFile);
  3770. //Yep, that's what we'll go with
  3771. LOGDEBUG(0,("WowIsKnownDLL: %s known -=> %s\n",
  3772. pszPath,
  3773. pszKnownDLLPath));
  3774. FLUSHVDMPTR(*pvpszKnownDLLPath,
  3775. cbKnownDLLPath,
  3776. pszKnownDLLPath);
  3777. FREEPSZPTR(pszKnownDLLPath);
  3778. ul = 1; // return success, meaning is known dll
  3779. goto Cleanup;
  3780. }
  3781. // otherwise we just fall through & use system32 dir
  3782. #endif // ifndef _X86_
  3783. strcpy(pszKnownDLLPath, pszSystemDirectory);
  3784. strcat(pszKnownDLLPath, "\\");
  3785. strcat(pszKnownDLLPath, szLowercasePath);
  3786. // LOGDEBUG(0,("WowIsKnownDLL: %s known -=> %s\n", pszPath, pszKnownDLLPath));
  3787. FLUSHVDMPTR(*pvpszKnownDLLPath, cbKnownDLLPath, pszKnownDLLPath);
  3788. FREEPSZPTR(pszKnownDLLPath);
  3789. ul = 1; // return success, meaning is known dll
  3790. goto Cleanup;
  3791. }
  3792. }
  3793. }
  3794. //
  3795. // We've checked the Known DLL list and come up empty, or
  3796. // malloc16 failed.
  3797. //
  3798. // LOGDEBUG(0,("WowIsKnownDLL: %s is not a known DLL.\n", szLowercasePath));
  3799. } else {
  3800. //
  3801. // pszPath is NULL, so free the 16-bit buffer pointed
  3802. // to by *pvpszKnownDLLPath.
  3803. //
  3804. if (*pvpszKnownDLLPath) {
  3805. free16(*pvpszKnownDLLPath);
  3806. ul = 1;
  3807. }
  3808. }
  3809. Cleanup:
  3810. FLUSHVDMPTR(parg16->lplpszKnownDLLPath, sizeof(*pvpszKnownDLLPath), pvpszKnownDLLPath);
  3811. FREEVDMPTR(pvpszKnownDLLPath);
  3812. FREEPSZPTR(pszPath);
  3813. FREEARGPTR(parg16);
  3814. return ul;
  3815. }
  3816. VOID RemoveHmodFromCache(HAND16 hmod16)
  3817. {
  3818. INT i;
  3819. //
  3820. // blow this guy out of the hinst/hmod cache
  3821. // if we find it, slide the other entries up to overwrite it
  3822. // and then zero out the last entry
  3823. //
  3824. for (i = 0; i < CHMODCACHE; i++) {
  3825. if (ghModCache[i].hMod16 == hmod16) {
  3826. // if we're not at the last entry, slide the rest up 1
  3827. if (i != CHMODCACHE-1) {
  3828. RtlMoveMemory((PVOID)(ghModCache+i),
  3829. (CONST VOID *)(ghModCache+i+1),
  3830. sizeof(HMODCACHE)*(CHMODCACHE-i-1) );
  3831. }
  3832. i--;
  3833. // the last entry is now either a dup or the one going away
  3834. ghModCache[CHMODCACHE-1].hMod16 =
  3835. ghModCache[CHMODCACHE-1].hInst16 = 0;
  3836. }
  3837. }
  3838. }
  3839. //
  3840. // AddTaskSharedList
  3841. //
  3842. WORD
  3843. AddTaskSharedList(
  3844. PTD pTD,
  3845. PSZ pszModName,
  3846. PSZ pszFilePath
  3847. ) {
  3848. SHAREDTASK SharedTask;
  3849. VDMINFO VdmInfo;
  3850. RtlZeroMemory(&VdmInfo, sizeof(VDMINFO));
  3851. SharedTask.dwThreadId = pTD->dwThreadID;
  3852. SharedTask.hTask16 = pTD->htask16;
  3853. SharedTask.hMod16 = pTD->hMod16;
  3854. strncpy(SharedTask.szModName, pszModName,8);
  3855. SharedTask.szModName[8] = 0;
  3856. strncpy(SharedTask.szFilePath, pszFilePath, 128);
  3857. SharedTask.szFilePath[127] = 0;
  3858. VdmInfo.iTask = pTD->VDMInfoiTaskID;
  3859. VdmInfo.VDMState = ASKING_TO_ADD_WOWTASK;
  3860. VdmInfo.Enviornment = &SharedTask;
  3861. VdmInfo.EnviornmentSize = sizeof(SHAREDTASK);
  3862. VdmInfo.Reserved = W32HungAppNotifyThread;
  3863. if(GetNextVDMCommand(&VdmInfo)) {
  3864. pTD->VDMInfoiTaskID = VdmInfo.iTask;
  3865. }
  3866. return pTD->htask16;
  3867. }
  3868. VOID W32RefreshCurrentDirectories (PCHAR lpszzEnv)
  3869. {
  3870. LPSTR lpszVal;
  3871. CHAR chDrive, achEnvDrive[] = "=?:";
  3872. if (lpszzEnv) {
  3873. while(*lpszzEnv) {
  3874. if(*lpszzEnv == '=' &&
  3875. (chDrive = (CHAR)toupper(*(lpszzEnv+1))) >= 'A' &&
  3876. chDrive <= 'Z' &&
  3877. (*(PCHAR)((ULONG)lpszzEnv+2) == ':')) {
  3878. lpszVal = (PCHAR)((ULONG)lpszzEnv + 4);
  3879. achEnvDrive[1] = chDrive;
  3880. SetEnvironmentVariable (achEnvDrive,lpszVal);
  3881. }
  3882. lpszzEnv = WOW32_strchr(lpszzEnv,'\0');
  3883. lpszzEnv++;
  3884. }
  3885. *(PUCHAR)DosWowData.lpSCS_ToSync = (UCHAR)0xff;
  3886. }
  3887. }
  3888. /* WK32CheckUserGdi - hack routine to support Simcity. See the explanation
  3889. * in kernel31\3ginterf.asm routine HackCheck.
  3890. *
  3891. *
  3892. * Entry - pszPath Full Path of the file in the module table
  3893. *
  3894. * Exit
  3895. * SUCCESS
  3896. * 1
  3897. *
  3898. * FAILURE
  3899. * 0
  3900. *
  3901. */
  3902. ULONG FASTCALL WK32CheckUserGdi(PVDMFRAME pFrame)
  3903. {
  3904. PWOWCHECKUSERGDI16 parg16;
  3905. PSTR psz;
  3906. CHAR szPath[MAX_PATH+10];
  3907. UINT cb;
  3908. ULONG ul;
  3909. //
  3910. // Get arguments.
  3911. //
  3912. GETARGPTR(pFrame, sizeof(WOWCHECKUSERGDI16), parg16);
  3913. psz = SEGPTR(FETCHWORD(parg16->pszPathSegment),
  3914. FETCHWORD(parg16->pszPathOffset));
  3915. FREEARGPTR(parg16);
  3916. // limit at MAX_PATH assures the subsequent strcpy's won't overflow
  3917. strncpy(szPath, pszSystemDirectory, MAX_PATH);
  3918. szPath[MAX_PATH-1] = '\0';
  3919. cb = strlen(szPath);
  3920. strcpy(szPath + cb, "\\GDI.EXE");
  3921. if (WOW32_stricmp(szPath, psz) == 0)
  3922. goto Success;
  3923. strcpy(szPath + cb, "\\USER.EXE");
  3924. if (WOW32_stricmp(szPath, psz) == 0)
  3925. goto Success;
  3926. ul = 0;
  3927. goto Done;
  3928. Success:
  3929. ul = 1;
  3930. Done:
  3931. return ul;
  3932. }
  3933. /* WK32ExitKernel - Force the Distruction of the WOW Process
  3934. * Formerly known as WK32KillProcess.
  3935. *
  3936. * Called when the 16 bit kernel exits and by KillWOW and
  3937. * checked WOWExec when the user wants to nuke the shared WOW.
  3938. *
  3939. * ENTRY
  3940. *
  3941. *
  3942. * EXIT
  3943. * Never Returns - The Process Goes Away
  3944. *
  3945. */
  3946. ULONG FASTCALL WK32ExitKernel(PVDMFRAME pFrame)
  3947. {
  3948. PEXITKERNEL16 parg16;
  3949. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  3950. WOW32ASSERTMSGF(
  3951. ! parg16->wExitCode,
  3952. ("\n"
  3953. "WOW ERROR: ExitKernel(0x%x) called on 16-bit side.\n"
  3954. "========== Please contact DOSWOW alias.\n"
  3955. "\n\n",
  3956. parg16->wExitCode
  3957. ));
  3958. ExitVDM(WOWVDM, ALL_TASKS);
  3959. ExitProcess(parg16->wExitCode);
  3960. return 0; // Never executed, here to avoid compiler warning.
  3961. }
  3962. /* WK32FatalExit - Called as FatalExitThunk by kernel16 FatalExit
  3963. *
  3964. *
  3965. * parg16->f1 is FatalExit code
  3966. *
  3967. */
  3968. ULONG FASTCALL WK32FatalExit(PVDMFRAME pFrame)
  3969. {
  3970. PFATALEXIT16 parg16;
  3971. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  3972. WOW32ASSERTMSGF(
  3973. FALSE,
  3974. ("\n"
  3975. "WOW ERROR: FatalExit(0x%x) called by 16-bit WOW kernel.\n"
  3976. "========== Contact the DOSWOW alias.\n"
  3977. "\n\n",
  3978. FETCHWORD(parg16->f1)
  3979. ));
  3980. // Sometimes we get this with no harm done (app bug)
  3981. ExitVDM(WOWVDM, ALL_TASKS);
  3982. ExitProcess(parg16->f1);
  3983. return 0; // Never executed, here to avoid compiler warning.
  3984. }
  3985. //
  3986. // WowPartyByNumber is present on checked builds only as a convenience
  3987. // to WOW developers who need a quick, temporary thunk for debugging.
  3988. // The checked wowexec.exe has a menu item, Party By Number, which
  3989. // collects a number and string parameter and calls this thunk.
  3990. //
  3991. #ifdef DEBUG
  3992. #pragma warning (4:4723) // lower to -W4
  3993. ULONG FASTCALL WK32WowPartyByNumber(PVDMFRAME pFrame)
  3994. {
  3995. PWOWPARTYBYNUMBER16 parg16;
  3996. PSZ psz;
  3997. ULONG ulRet = 0;
  3998. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  3999. GETPSZPTR(parg16->psz, psz);
  4000. switch (parg16->dw) {
  4001. case 0: // Access violation
  4002. *(char *)0xa0000000 = 0;
  4003. break;
  4004. case 1: // Stack overflow
  4005. {
  4006. char EatStack[2048];
  4007. strcpy(EatStack, psz);
  4008. WK32WowPartyByNumber(pFrame);
  4009. strcpy(EatStack, psz);
  4010. }
  4011. break;
  4012. case 2: // Datatype misalignment
  4013. {
  4014. DWORD adw[2];
  4015. PDWORD pdw = (void *)((char *)adw + 2);
  4016. *pdw = (DWORD)-1;
  4017. //
  4018. // On some platforms the above will just work (hardware or
  4019. // emulation), so we force it with RaiseException.
  4020. //
  4021. RaiseException((DWORD)EXCEPTION_DATATYPE_MISALIGNMENT,
  4022. 0, 0, NULL);
  4023. }
  4024. break;
  4025. case 3: // Integer divide by zero
  4026. ulRet = 1 / (parg16->dw - 3);
  4027. break;
  4028. case 4: // Other exception
  4029. RaiseException((DWORD)EXCEPTION_ARRAY_BOUNDS_EXCEEDED,
  4030. EXCEPTION_NONCONTINUABLE, 0, NULL);
  4031. break;
  4032. case 5: // gpm16
  4033. //
  4034. // Quick test that WOWGetProcModule16 is working
  4035. //
  4036. {
  4037. char sz[256];
  4038. _snprintf(sz, sizeof(sz)-1, "GetProcModule16(%lx) == %x\n", gpfn16GetProcModule, WOWGetProcModule16(gpfn16GetProcModule));
  4039. sz[sizeof(sz)-1] = '\0';
  4040. OutputDebugString(sz);
  4041. }
  4042. break;
  4043. default:
  4044. {
  4045. char szMsg[2*255];
  4046. _snprintf(szMsg, sizeof(szMsg)-1, "WOW Unhandled Party By Number (%d, '%s')", parg16->dw, psz);
  4047. szMsg[sizeof(szMsg)-1] ='\0';
  4048. MessageBeep(0);
  4049. MessageBox(NULL, szMsg, "WK32WowPartyByNumber", MB_OK | MB_ICONEXCLAMATION);
  4050. }
  4051. }
  4052. FREEPSZPTR(psz);
  4053. FREEARGPTR(parg16);
  4054. return ulRet;
  4055. }
  4056. #endif
  4057. //
  4058. // MyVerQueryValue checks several popular code page values for the given
  4059. // string. This may need to be extended ala WinFile's wfdlgs2.c to search
  4060. // the translation table. For now we only need a few.
  4061. // Note: *puLen returns # chars copied into *lplpBuffer including NULL
  4062. //
  4063. BOOL
  4064. FASTCALL
  4065. MyVerQueryValue(
  4066. const LPVOID pBlock,
  4067. LPSTR lpName,
  4068. LPVOID * lplpBuffer,
  4069. PUINT puLen
  4070. )
  4071. {
  4072. #define SFILEN 25 // Length of apszSFI strings without null
  4073. static PSZ apszSFI[] = {
  4074. "\\StringFileInfo\\040904E4\\",
  4075. "\\StringFileInfo\\04090000\\"
  4076. };
  4077. char szSubBlock[128];
  4078. BOOL fRet;
  4079. int i;
  4080. strcpy(szSubBlock+SFILEN, lpName);
  4081. for (fRet = FALSE, i = 0;
  4082. i < (sizeof apszSFI / sizeof apszSFI[0]) && !fRet;
  4083. i++) {
  4084. RtlCopyMemory(szSubBlock, apszSFI[i], SFILEN);
  4085. fRet = VerQueryValue(pBlock, szSubBlock, lplpBuffer, puLen);
  4086. }
  4087. return fRet;
  4088. }
  4089. //
  4090. // Utility routine to fetch the Product Name and Product Version strings
  4091. // from a given EXE.
  4092. //
  4093. BOOL
  4094. FASTCALL
  4095. WowGetProductNameVersion(
  4096. PSZ pszExePath,
  4097. PSZ pszProductName,
  4098. DWORD cbProductName,
  4099. PSZ pszProductVersion,
  4100. DWORD cbProductVersion,
  4101. PSZ pszParamName,
  4102. PSZ pszParam,
  4103. DWORD cbParam
  4104. )
  4105. {
  4106. DWORD len;
  4107. DWORD dwZeroMePlease;
  4108. DWORD cbVerInfo;
  4109. LPVOID lpVerInfo = NULL;
  4110. LPSTR pName;
  4111. DWORD cbName;
  4112. LPSTR pVersion;
  4113. DWORD cbVersion;
  4114. BOOL fRet;
  4115. DWORD cbParamValue;
  4116. LPSTR pParamValue;
  4117. fRet = (
  4118. (cbVerInfo = GetFileVersionInfoSize(pszExePath, &dwZeroMePlease)) &&
  4119. (lpVerInfo = malloc_w(cbVerInfo)) &&
  4120. GetFileVersionInfo(pszExePath, 0, cbVerInfo, lpVerInfo) &&
  4121. MyVerQueryValue(lpVerInfo, "ProductName", &pName, &cbName) &&
  4122. cbName <= cbProductName &&
  4123. MyVerQueryValue(lpVerInfo, "ProductVersion", &pVersion, &cbVersion) &&
  4124. cbVersion <= cbProductVersion
  4125. );
  4126. if (fRet && NULL != pszParamName && NULL != pszParam) {
  4127. fRet = MyVerQueryValue(lpVerInfo, pszParamName, &pParamValue, &cbParamValue) &&
  4128. cbParamValue <= cbParam;
  4129. }
  4130. if (fRet) {
  4131. len = min(cbName, cbProductName) - 1;
  4132. strncpy(pszProductName, pName, len);
  4133. pszProductName[len] = '\0';
  4134. len = min(cbVersion, cbProductVersion) - 1;
  4135. strncpy(pszProductVersion, pVersion, len);
  4136. pszProductVersion[len] = '\0';
  4137. if (NULL != pszParamName && NULL != pszParam) {
  4138. len = min(cbParamValue, cbParam) - 1;
  4139. strncpy(pszParam, pParamValue, len);
  4140. pszParam[len] = '\0';
  4141. }
  4142. }
  4143. if (lpVerInfo) {
  4144. free_w(lpVerInfo);
  4145. }
  4146. return fRet;
  4147. }
  4148. #if 0 // currently unused
  4149. //
  4150. // This routine is simpler to use if you are doing an exact match
  4151. // against a particular name/version pair.
  4152. //
  4153. BOOL
  4154. FASTCALL
  4155. WowDoNameVersionMatch(
  4156. PSZ pszExePath,
  4157. PSZ pszProductName,
  4158. PSZ pszProductVersion
  4159. )
  4160. {
  4161. DWORD dwJunk;
  4162. DWORD cbVerInfo;
  4163. LPVOID lpVerInfo = NULL;
  4164. LPSTR pName;
  4165. LPSTR pVersion;
  4166. BOOL fRet;
  4167. fRet = (
  4168. (cbVerInfo = GetFileVersionInfoSize(pszExePath, &dwJunk)) &&
  4169. (lpVerInfo = malloc_w(cbVerInfo)) &&
  4170. GetFileVersionInfo(pszExePath, 0, cbVerInfo, lpVerInfo) &&
  4171. MyVerQueryValue(lpVerInfo, "ProductName", &pName, &dwJunk) &&
  4172. ! WOW32_stricmp(pszProductName, pName) &&
  4173. MyVerQueryValue(lpVerInfo, "ProductVersion", &pVersion, &dwJunk) &&
  4174. ! WOW32_stricmp(pszProductVersion, pVersion)
  4175. );
  4176. if (lpVerInfo) {
  4177. free_w(lpVerInfo);
  4178. }
  4179. return fRet;
  4180. }
  4181. #endif
  4182. //
  4183. // This thunk is called by kernel31's GetModuleHandle
  4184. // when it cannot find a handle for given filename.
  4185. //
  4186. // We look to see if this task has any child apps
  4187. // spawned via WinOldAp, and if so we look to see
  4188. // if the module name matches for any of them.
  4189. // If it does, we return the hmodule of the
  4190. // associated WinOldAp. Otherwise we return 0
  4191. //
  4192. ULONG FASTCALL WK32WowGetModuleHandle(PVDMFRAME pFrame)
  4193. {
  4194. PWOWGETMODULEHANDLE16 parg16;
  4195. ULONG ul;
  4196. PSZ pszModuleName;
  4197. PTD ptd;
  4198. PWOAINST pWOA;
  4199. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  4200. GETPSZPTR(parg16->lpszModuleName, pszModuleName);
  4201. ptd = CURRENTPTD();
  4202. EnterCriticalSection(&ptd->csTD);
  4203. pWOA = ptd->pWOAList;
  4204. while (pWOA && WOW32_strcmp(pszModuleName, pWOA->szModuleName)) {
  4205. pWOA = pWOA->pNext;
  4206. }
  4207. if (pWOA && pWOA->ptdWOA) {
  4208. ul = pWOA->ptdWOA->hMod16;
  4209. LOGDEBUG(LOG_ALWAYS, ("WK32WowGetModuleHandle(%s) returning %04x.\n",
  4210. pszModuleName, ul));
  4211. } else {
  4212. ul = 0;
  4213. }
  4214. LeaveCriticalSection(&ptd->csTD);
  4215. return ul;
  4216. }
  4217. //
  4218. // This function is called by kernel31's CreateTask after it's
  4219. // allocated memory for the TDB, the selector of which serves
  4220. // as the htask. We want to enforce uniqueness of these htasks
  4221. // across all WOW VDMs in the system, so this function attempts
  4222. // to reserve the given htask in the shared memory structure.
  4223. // If successful the htask is returned, if it's already in use
  4224. // 0 is returned and CreateTask will allocate another selector
  4225. // and try again.
  4226. //
  4227. // -- DaveHart 24-Apr-96
  4228. //
  4229. ULONG FASTCALL WK32WowReserveHtask(PVDMFRAME pFrame)
  4230. {
  4231. PWOWRESERVEHTASK16 parg16;
  4232. ULONG ul;
  4233. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  4234. ul = parg16->htask;
  4235. FREEARGPTR(parg16);
  4236. return ul;
  4237. }
  4238. /*
  4239. * This function is called by kernel31 to dispatch a wow lfn api call
  4240. * the responsible party here is in dem code and all we have to do is to
  4241. * - retrieve it's frame pointer
  4242. *
  4243. *
  4244. */
  4245. ULONG FASTCALL WK32WOWLFNEntry(PVDMFRAME pFrame)
  4246. {
  4247. PWOWLFNFRAMEPTR16 parg16;
  4248. LPVOID lpUserFrame;
  4249. ULONG ul;
  4250. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  4251. // now retrieve a flat pointer
  4252. GETMISCPTR(parg16->lpUserFrame, lpUserFrame);
  4253. ul = demWOWLFNEntry(lpUserFrame);
  4254. FREEMISCPTR(lpUserFrame);
  4255. FREEARGPTR(parg16);
  4256. return(ul);
  4257. }
  4258. //
  4259. // This function is called by kernel31 to start or stop the
  4260. // shared WOW shutdown timer.
  4261. //
  4262. ULONG FASTCALL WK32WowShutdownTimer(PVDMFRAME pFrame)
  4263. {
  4264. PWOWSHUTDOWNTIMER16 parg16;
  4265. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  4266. if (parg16->fEnable) {
  4267. //
  4268. // When this thunk is called with fEnable == 1, to turn on the shutdown
  4269. // timer, it is initially called on the task that is shutting down. Since
  4270. // we want to be on WowExec's thread so SetTimer will work right, in this
  4271. // case we post a message to WowExec asking it to call this API again, but
  4272. // on the right thread.
  4273. //
  4274. if (ghShellTDB != pFrame->wTDB) {
  4275. PostMessage(ghwndShell, WM_WOWEXECSTARTTIMER, 0, 0);
  4276. } else {
  4277. #ifdef WX86
  4278. TermWx86System();
  4279. #endif
  4280. SetTimer(ghwndShell, 1, dwSharedWowTimeout, NULL);
  4281. }
  4282. } else {
  4283. //
  4284. // A task was started before the timer expired, kill it.
  4285. //
  4286. WOW32ASSERTMSG(ghShellTDB == pFrame->wTDB, "WowShutdownTimer(0) called on non-WowExec thread\n");
  4287. KillTimer(ghwndShell, 1);
  4288. }
  4289. FREEARGPTR(parg16);
  4290. return 0;
  4291. }
  4292. //
  4293. // This function is called by kernel31 to shrink the process's
  4294. // working set to a minimum.
  4295. //
  4296. ULONG FASTCALL WK32WowTrimWorkingSet(PVDMFRAME pFrame)
  4297. {
  4298. SetProcessWorkingSetSize(ghProcess, 0xffffffff, 0xffffffff);
  4299. return 0;
  4300. }
  4301. //
  4302. // IsQuickBooksVersion2 used by WK32SetAppCompatFlags below.
  4303. //
  4304. BOOL FASTCALL IsQuickBooksVersion2(WORD pModule)
  4305. {
  4306. BOOL fRet;
  4307. PSZ pszModuleFileName;
  4308. HANDLE hEXE;
  4309. HANDLE hSec = 0;
  4310. PVOID pEXE = NULL;
  4311. PIMAGE_DOS_HEADER pMZ;
  4312. PIMAGE_OS2_HEADER pNE;
  4313. PBYTE pNResTab;
  4314. DWORD cbVerInfo;
  4315. DWORD dwJunk;
  4316. fRet = FALSE;
  4317. //
  4318. // see wow16\inc\newexe.inc, NEW_EXE1 struct, ne_pfileinfo
  4319. // is at offset 10, a near pointer within the segment referenced
  4320. // by hmod. This points to kernel.inc's OPENSTRUC which has
  4321. // the filename buffer at offset 8.
  4322. //
  4323. pszModuleFileName = SEGPTR(pModule, (*(WORD *)SEGPTR(pModule, 10)) + 8);
  4324. hEXE = CreateFile(
  4325. pszModuleFileName,
  4326. GENERIC_READ,
  4327. FILE_SHARE_READ | FILE_SHARE_WRITE,
  4328. NULL, // security
  4329. OPEN_EXISTING,
  4330. 0, // flags & attributes
  4331. NULL
  4332. );
  4333. if (INVALID_HANDLE_VALUE == hEXE) {
  4334. goto Cleanup;
  4335. }
  4336. hSec = CreateFileMapping(
  4337. hEXE,
  4338. NULL, // security
  4339. PAGE_READONLY,
  4340. 0, // max size hi
  4341. 0, // max size lo both zero == file size
  4342. NULL // name
  4343. );
  4344. if ( ! hSec) {
  4345. goto Cleanup;
  4346. }
  4347. pEXE = MapViewOfFile(
  4348. hSec,
  4349. FILE_MAP_READ,
  4350. 0, // offset hi
  4351. 0, // offset lo
  4352. 0 // size to map zero == entire file
  4353. );
  4354. // if MapViewOfFile failed assume it is not QuickBooks 2.0
  4355. if (!pEXE ) {
  4356. goto Cleanup;
  4357. }
  4358. pMZ = pEXE;
  4359. if (IMAGE_DOS_SIGNATURE != pMZ->e_magic) {
  4360. WOW32ASSERTMSG(IMAGE_DOS_SIGNATURE == pMZ->e_magic, "WOW IsQuickBooks MZ sig.\n");
  4361. goto Cleanup;
  4362. }
  4363. pNE = (PVOID) ((PBYTE)pEXE + pMZ->e_lfanew);
  4364. if (IMAGE_OS2_SIGNATURE != pNE->ne_magic) {
  4365. WOW32ASSERTMSG(IMAGE_OS2_SIGNATURE == pNE->ne_magic, "WOW IsQuickBooks NE sig.\n");
  4366. goto Cleanup;
  4367. }
  4368. pNResTab = (PBYTE)pEXE + pNE->ne_nrestab;
  4369. //
  4370. // The first entry in the non-resident names table is
  4371. // the NE description specified in the .DEF file.
  4372. // We have the culprit if it matches the string below,
  4373. // note the initial 'R' is a length byte, 0x52 bytes follow,
  4374. // so we compare 0x53.
  4375. //
  4376. // Of course Intuit is full of clever programmers, so this
  4377. // description string still appears in QBW.EXE v3.1 and probably
  4378. // later. Thankfully someone there thought to add version
  4379. // resources between v2 and v3, so if there are version
  4380. // resources we'll say it's not v2.
  4381. //
  4382. fRet = RtlEqualMemory(
  4383. pNResTab,
  4384. "RQuickBooks for Windows Version 2. Copyright 1993 Intuit Inc. All rights reserved.",
  4385. 0x53
  4386. );
  4387. if (fRet) {
  4388. cbVerInfo = GetFileVersionInfoSize(pszModuleFileName, &dwJunk);
  4389. fRet = !cbVerInfo;
  4390. }
  4391. Cleanup:
  4392. if (pEXE) {
  4393. UnmapViewOfFile(pEXE);
  4394. }
  4395. if (hSec) {
  4396. CloseHandle(hSec);
  4397. }
  4398. if (INVALID_HANDLE_VALUE != hEXE) {
  4399. CloseHandle(hEXE);
  4400. }
  4401. return fRet;
  4402. }
  4403. // the code below is stolen (with some enhancements) from
  4404. // then original WOWShouldWeSayWin95
  4405. //
  4406. BOOL FASTCALL fnInstallShieldOverrideVersionFlag(PTDB pTDB)
  4407. {
  4408. CHAR szModName[9];
  4409. PCHAR pch;
  4410. CHAR szName[16];
  4411. CHAR szVersion[16];
  4412. CHAR szVerSubstring[4];
  4413. DWORD dwSubVer;
  4414. PSTR pszFileName;
  4415. RtlCopyMemory(szModName, pTDB->TDB_ModName, 8);
  4416. for (pch = &szModName[7]; ' ' == *pch && pch >= szModName; --pch);
  4417. *++pch = '\0';
  4418. if (WOW32_stricmp(szModName, "ISSET_SE")) {
  4419. return(FALSE);
  4420. }
  4421. // now having the pTDB retrieve module file name from pExe
  4422. // this guy's sitting in TDB_pModule -- and we know it's a real thing
  4423. // not an alias
  4424. //
  4425. // see wow16\inc\newexe.inc, NEW_EXE1 struct, ne_pfileinfo
  4426. // is at offset 10, a near pointer within the segment referenced
  4427. // by hmod. This points to kernel.inc's OPENSTRUC which has
  4428. // the filename buffer at offset 8.
  4429. //
  4430. pszFileName = SEGPTR(pTDB->TDB_pModule, (*(WORD *)SEGPTR(pTDB->TDB_pModule, 10)) + 8);
  4431. if (!WowGetProductNameVersion(pszFileName,
  4432. szName,
  4433. sizeof(szName),
  4434. szVersion,
  4435. sizeof(szVersion),
  4436. NULL, NULL, 0) ||
  4437. WOW32_stricmp(szName, "InstallSHIELD")) {
  4438. return(FALSE);
  4439. }
  4440. //
  4441. // now we definitely know it's installshield and it's version is in szVersion
  4442. //
  4443. //
  4444. // InstallShield _Setup SDK_ setup.exe shipped
  4445. // with VC++ 4.0 is stamped 2.20.903.0 but also
  4446. // needs to be lied to about it being Win95.
  4447. // According to [email protected] versions
  4448. // 2.20.903.0 through 2.20.905.0 need this.
  4449. // We'll settle for 2.20.903* - 2.20.905*
  4450. // These are based on the 3.0 codebase but
  4451. // bear the 2.20.x version stamps.
  4452. //
  4453. if (RtlEqualMemory(szVersion, "2.20.90", 7) &&
  4454. ('3' == szVersion[7] ||
  4455. '4' == szVersion[7] ||
  4456. '5' == szVersion[7]) ) {
  4457. return(TRUE);
  4458. }
  4459. //
  4460. // We want to lie in GetVersion if the version stamp on
  4461. // the InstallShield setup.exe is 3.00.xxx.0, where
  4462. // xxx is 000 through 087. Later versions know how
  4463. // to detect NT.
  4464. //
  4465. if (!RtlEqualMemory(szVersion, "3.00.", 5)) {
  4466. return(FALSE);
  4467. }
  4468. RtlCopyMemory(szVerSubstring, &szVersion[5], 3);
  4469. szVerSubstring[3] = 0;
  4470. RtlCharToInteger(szVerSubstring, 10, &dwSubVer);
  4471. if (dwSubVer >= 88 && dwSubVer != 101) {
  4472. return(FALSE);
  4473. }
  4474. return(TRUE); // version 3.00.000 - 3.00.087
  4475. }
  4476. BOOL FASTCALL fnInstallTimelineOverrideVersionFlag(PTDB pTDB)
  4477. {
  4478. CHAR szModName[9];
  4479. PCHAR pch;
  4480. CHAR szName[64];
  4481. CHAR szVersion[16];
  4482. CHAR szFileVersion[16];
  4483. PSTR pszFileName;
  4484. RtlCopyMemory(szModName, pTDB->TDB_ModName, 8);
  4485. for (pch = &szModName[7]; ' ' == *pch && pch >= szModName; --pch);
  4486. *++pch = '\0';
  4487. if (WOW32_stricmp(szModName, "INSTBIN")) { // instbin is an installer for
  4488. return(FALSE);
  4489. }
  4490. // now having the pTDB retrieve module file name from pExe
  4491. // this guy's sitting in TDB_pModule -- and we know it's a real thing
  4492. // not an alias
  4493. //
  4494. // see wow16\inc\newexe.inc, NEW_EXE1 struct, ne_pfileinfo
  4495. // is at offset 10, a near pointer within the segment referenced
  4496. // by hmod. This points to kernel.inc's OPENSTRUC which has
  4497. // the filename buffer at offset 8.
  4498. //
  4499. pszFileName = SEGPTR(pTDB->TDB_pModule, (*(WORD *)SEGPTR(pTDB->TDB_pModule, 10)) + 8);
  4500. // now retrieve version resources
  4501. if (!WowGetProductNameVersion(pszFileName,
  4502. szName,
  4503. sizeof(szName),
  4504. szVersion,
  4505. sizeof(szVersion),
  4506. "FileVersion",
  4507. szFileVersion,
  4508. sizeof(szFileVersion)) ||
  4509. WOW32_stricmp(szName, "Symantec Install for Windows Applications")) {
  4510. return(FALSE);
  4511. }
  4512. // so it is Symantec install -- check versions
  4513. if (!WOW32_stricmp(szVersion, "3.4") && !WOW32_stricmp(szFileVersion, "3.4.1.1")) {
  4514. return(FALSE);
  4515. }
  4516. return(TRUE); // we can munch on Win95 -- this is not the same install as
  4517. // used in timeline application
  4518. }
  4519. typedef BOOL (FASTCALL *PFNOVERRIDEVERSIONFLAG)(PTDB);
  4520. PFNOVERRIDEVERSIONFLAG rgOverrideFns[] = {
  4521. fnInstallShieldOverrideVersionFlag,
  4522. fnInstallTimelineOverrideVersionFlag
  4523. };
  4524. // this function is to be used when we set "3.1" compat flag in the registry
  4525. // then we call these functions to override the flag if function returns true
  4526. // if returns TRUE then the version flag is set to 95
  4527. // if returns FALSE then the version flag is left to what it was in the registry
  4528. BOOL IsOverrideVersionFlag(PTDB pTDB)
  4529. {
  4530. int i;
  4531. BOOL fOverride = FALSE;
  4532. for (i = 0; i < sizeof(rgOverrideFns)/sizeof(rgOverrideFns[0]) && !fOverride; ++i) {
  4533. fOverride = (*rgOverrideFns[i])(pTDB);
  4534. }
  4535. return(fOverride);
  4536. }
  4537. //
  4538. // This function replaces the original assembler in
  4539. // kernel31\miscapi.asm. It's the same, except it special-cases
  4540. // some flags based on more than just the module name (for
  4541. // example version stamps).
  4542. //
  4543. // Note that we're still running on the creator thread,
  4544. // so CURRENTPTD() refers to the parent of the app we're
  4545. // looking up flags for.
  4546. //
  4547. ULONG FASTCALL WK32SetAppCompatFlags(PVDMFRAME pFrame)
  4548. {
  4549. PSETAPPCOMPATFLAGS16 parg16;
  4550. DWORD dwAppCompatFlags = 0;
  4551. PTDB pTDB;
  4552. char szModName[9];
  4553. char szAppCompatFlags[12]; // 0x00000000
  4554. GETARGPTR(pFrame, sizeof(*parg16), parg16);
  4555. pTDB = (PVOID)SEGPTR(parg16->TDB,0);
  4556. //
  4557. // Hacks don't apply to 4.0 or above
  4558. //
  4559. if (pTDB->TDB_ExpWinVer < 0x400) {
  4560. RtlCopyMemory(szModName, pTDB->TDB_ModName, sizeof(szModName)-1);
  4561. szModName[sizeof(szModName)-1] = 0;
  4562. szAppCompatFlags[0] = 0;
  4563. if (GetProfileString(
  4564. "Compatibility",
  4565. szModName,
  4566. "",
  4567. szAppCompatFlags,
  4568. sizeof(szAppCompatFlags))) {
  4569. dwAppCompatFlags = strtoul(szAppCompatFlags, NULL, 0);
  4570. }
  4571. //
  4572. // SOME hacks don't apply to 3.1 or above
  4573. //
  4574. // one hack (enumeration of helv ) is valid for 30a as well
  4575. // see bug 41092
  4576. if (pTDB->TDB_ExpWinVer == 0x30a) {
  4577. dwAppCompatFlags &= GACF_31VALIDMASK | GACF_ENUMHELVNTMSRMN | GACF_HACKWINFLAGS;
  4578. }
  4579. else if (pTDB->TDB_ExpWinVer > 0x30a) {
  4580. dwAppCompatFlags &= GACF_31VALIDMASK | GACF_HACKWINFLAGS;
  4581. }
  4582. //
  4583. // Intuit QuickBooks 2.0 needs to have GACF_RANDOM3XUI turned on,
  4584. // but later versions don't want it on. Win9x prompts the user with
  4585. // a warning that leads to a help file that tells the user to turn
  4586. // on this bit using a little tool if they're using QBW v2. We are
  4587. // going to just do the right thing by looking at the Description
  4588. // field of the EXE header for a string we expect only to find in
  4589. // v2, and if it's there turn on GACF_RANDOM3XUI.
  4590. //
  4591. if (pTDB->TDB_ExpWinVer == 0x30a &&
  4592. RtlEqualMemory(szModName, "QBW", 4)) {
  4593. if (IsQuickBooksVersion2(pTDB->TDB_pModule)) {
  4594. dwAppCompatFlags |= GACF_RANDOM3XUI;
  4595. }
  4596. }
  4597. // this code checks to see that ISSET_SE in adobe premier 4.2
  4598. // is told that it's running on Win95
  4599. if (IsOverrideVersionFlag(pTDB)) {
  4600. dwAppCompatFlags &= ~GACF_WINVER31;
  4601. }
  4602. LOGDEBUG(LOG_ALWAYS, ("WK32SetAppCompatFlags '%s' got %x (%s).\n",
  4603. szModName, dwAppCompatFlags, szAppCompatFlags));
  4604. }
  4605. FREEARGPTR(parg16);
  4606. return dwAppCompatFlags;
  4607. }
  4608. //
  4609. // This function is called by mciavi32 to facilitate usage of a 16-bit mciavi
  4610. // instead
  4611. //
  4612. //
  4613. BOOL WOWUseMciavi16(VOID)
  4614. {
  4615. return((BOOL)(CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_USEMCIAVI16));
  4616. }
  4617. VOID WOWExitVdm(ULONG iWowTask)
  4618. {
  4619. ExitVDM(WOWVDM, iWowTask);
  4620. }
  4621. #if 0
  4622. BOOL DosWowGetCompatFlags(LPDWORD lpdwCF, LPDWORD lpdwCFEx)
  4623. {
  4624. if (NULL != lpdwCF) {
  4625. *lpdwCF = CURRENTPTD()->dwWOWCompatFlags;
  4626. }
  4627. if (NULL != lpdwCFEx) {
  4628. *lpdwCFEx = CURRENTPTD()->dwWOWCompatFlagsEx;
  4629. }
  4630. return(TRUE);
  4631. }
  4632. #endif
  4633. typedef struct {
  4634. LPCSTR pszMatchPath;
  4635. int cbMatchPathLen;
  4636. PSZ pszMapPath;
  4637. int cbMapPathLen;
  4638. int dwCLSID;
  4639. BOOL fIsShortPath;
  4640. }
  4641. MATCHMAPPATH,*PMATCHMAPPATH;
  4642. #define WOWCSIDL_AllUsers -1
  4643. const CHAR szStartMenu[] = "\\startm~1";
  4644. const CHAR szAllUsers[] = "\\alluse~1";
  4645. const CHAR szDesktop[] = "\\desktop";
  4646. const CHAR szAllUsersStartMenu[] = "\\Profiles\\All Users\\Start Menu\\Programs";
  4647. const CHAR szSystem[] = "\\System";
  4648. const CHAR szStartMenuPrograms[] = "\\Start Menu";
  4649. #define CBSZSYSTEM (sizeof(szSystem)/sizeof(CHAR)-1)
  4650. MATCHMAPPATH MatchMapPath[ ]=
  4651. {
  4652. {szStartMenu,
  4653. sizeof(szStartMenu)/sizeof(CHAR)-1, //strlen(szStartMenu) == sizeof(szStartMenu)-1
  4654. NULL,
  4655. 0,
  4656. CSIDL_COMMON_STARTMENU,
  4657. TRUE
  4658. },
  4659. {szStartMenuPrograms,
  4660. sizeof(szStartMenuPrograms)/sizeof(CHAR)-1,
  4661. NULL,
  4662. 0,
  4663. CSIDL_COMMON_STARTMENU,
  4664. FALSE
  4665. },
  4666. {szAllUsers,
  4667. sizeof(szAllUsers)/sizeof(CHAR)-1, //strlen(szAllUsers) == sizeof(szAllUsers)-1
  4668. NULL,
  4669. 0,
  4670. WOWCSIDL_AllUsers,
  4671. TRUE
  4672. },
  4673. {szDesktop,
  4674. sizeof(szDesktop)/sizeof(CHAR)-1,
  4675. NULL,
  4676. 0,
  4677. CSIDL_COMMON_DESKTOPDIRECTORY,
  4678. TRUE
  4679. },
  4680. {szAllUsersStartMenu,
  4681. sizeof(szAllUsersStartMenu)/sizeof(CHAR)-1,
  4682. NULL,
  4683. 0,
  4684. CSIDL_COMMON_PROGRAMS,
  4685. FALSE
  4686. }
  4687. };
  4688. PSZ SyncSysFile[] ={
  4689. "\\user.exe",
  4690. "\\ole2.dll",
  4691. "\\olesvr.dll",
  4692. "\\compobj.dll",
  4693. "\\storage.dll",
  4694. "\\commdlg.dll",
  4695. "\\mmsystem.dll",
  4696. "\\gdi.exe"
  4697. // add the rest of the 16-bit system binaries
  4698. };
  4699. DWORD cbSystemDirLen;
  4700. DWORD cbWinDirLen; // Len doesn't include NULL char
  4701. VOID W32Init9xSpecialPath(
  4702. )
  4703. {
  4704. char szBuf[ MAX_PATH ];
  4705. int cb;
  4706. PMATCHMAPPATH pMatchMapPath;
  4707. pMatchMapPath = MatchMapPath + sizeof(MatchMapPath)/sizeof(MATCHMAPPATH);
  4708. while(pMatchMapPath-- != MatchMapPath) {
  4709. szBuf[0]='\0';
  4710. if (pMatchMapPath->dwCLSID > 0) {
  4711. SHGetSpecialFolderPath(NULL,
  4712. szBuf,
  4713. pMatchMapPath->dwCLSID,
  4714. FALSE
  4715. );
  4716. }
  4717. else
  4718. if (WOWCSIDL_AllUsers == pMatchMapPath->dwCLSID) {
  4719. cb = sizeof(szBuf);
  4720. GetAllUsersProfileDirectory(szBuf, &cb);
  4721. }
  4722. if(pMatchMapPath->fIsShortPath) {
  4723. DPM_GetShortPathName(szBuf,szBuf,sizeof(szBuf));
  4724. }
  4725. cb=strlen(szBuf)+1;
  4726. if (1 < cb){
  4727. LPSTR lpStr=NULL;
  4728. lpStr=malloc_w_or_die(cb);
  4729. strncpy(lpStr,szBuf,cb);
  4730. lpStr[cb-1] = '\0';
  4731. pMatchMapPath->pszMapPath=lpStr;
  4732. pMatchMapPath->cbMapPathLen=cb;
  4733. }
  4734. else {
  4735. pMatchMapPath->pszMapPath=NULL;
  4736. pMatchMapPath->cbMapPathLen=0;
  4737. }
  4738. }
  4739. //
  4740. // Lower case windows directory and get its length
  4741. //
  4742. _strlwr(pszWindowsDirectory);
  4743. cbWinDirLen=strlen(pszWindowsDirectory);
  4744. cbSystemDirLen=strlen(pszSystemDirectory);
  4745. }
  4746. // See if a 9x special path. If so, try mapping it to NT special path
  4747. // i.e. c:\winnt\startm~1 becomes c:\docume~1\alluse~1\startm~1
  4748. BOOL W32Map9xSpecialPath(PSZ sz9xPath,
  4749. PSZ szNewPath,
  4750. DWORD dwNewSize
  4751. )
  4752. {
  4753. PSZ pszTemp=sz9xPath;
  4754. PMATCHMAPPATH pMatchMap;
  4755. if( !_strnicmp( pszTemp,pszWindowsDirectory,cbWinDirLen) && pszTemp[cbWinDirLen] == '\\') {
  4756. pMatchMap = MatchMapPath + sizeof(MatchMapPath)/sizeof(MATCHMAPPATH);
  4757. while(pMatchMap-- != MatchMapPath) {
  4758. // move lpPathName past windowsdirectory
  4759. pszTemp = sz9xPath + cbWinDirLen;
  4760. if (!WOW32_strnicmp( pszTemp,pMatchMap->pszMatchPath, pMatchMap->cbMatchPathLen) &&
  4761. (!pszTemp[pMatchMap->cbMatchPathLen] || pszTemp[pMatchMap->cbMatchPathLen]=='\\'))
  4762. {
  4763. // move lpPathName past MatchPath
  4764. pszTemp += pMatchMap->cbMatchPathLen;
  4765. if(pMatchMap->cbMapPathLen + strlen(pszTemp) >= dwNewSize) {
  4766. LOGDEBUG(LOG_WARNING, ("Not enough space to map 9x<%s> to NT\n",sz9xPath));
  4767. return FALSE;
  4768. }
  4769. memcpy( szNewPath,
  4770. pMatchMap->pszMapPath,
  4771. pMatchMap->cbMapPathLen
  4772. );
  4773. // copy rest of lpPathName after cbMapPathLen
  4774. strcpy(szNewPath + pMatchMap->cbMapPathLen-1,
  4775. pszTemp
  4776. );
  4777. LOGDEBUG(LOG_WARNING, ("Mapping 9x<%s> to NT<%s>\n", sz9xPath, szNewPath));
  4778. return TRUE;
  4779. }
  4780. }
  4781. if (CURRENTPTD()->dwWOWCompatFlags2 & WOWCF2_SYNCSYSFILE) {
  4782. PSZ *ppszSyncSysFile;
  4783. pszTemp = sz9xPath + cbWinDirLen;
  4784. if (!WOW32_strnicmp(pszTemp,szSystem,CBSZSYSTEM) && pszTemp[CBSZSYSTEM]=='\\') {
  4785. pszTemp += CBSZSYSTEM; // mv past "%windir%\system"
  4786. ppszSyncSysFile = SyncSysFile + sizeof(SyncSysFile)/sizeof(PSZ);
  4787. while (ppszSyncSysFile-- != SyncSysFile) {
  4788. if (!WOW32_stricmp(pszTemp,*ppszSyncSysFile)){
  4789. if (strlen(pszTemp) + cbSystemDirLen >= dwNewSize) {
  4790. LOGDEBUG(LOG_WARNING, ("Not enough space to sync 9x<%s> to NT\n",sz9xPath));
  4791. return FALSE;
  4792. }
  4793. memcpy(szNewPath,pszSystemDirectory,cbSystemDirLen);
  4794. strcpy(szNewPath+cbSystemDirLen,pszTemp);
  4795. LOGDEBUG(LOG_WARNING, ("Mapping System<%s> to System32<%s>\n",sz9xPath,szNewPath));
  4796. return TRUE;
  4797. }
  4798. }
  4799. }
  4800. }
  4801. }
  4802. return FALSE;
  4803. }
  4804. DWORD dmOldBitsPerPel=0;
  4805. DWORD dmChangeCount=0;
  4806. /*
  4807. * WK32ChangeDisplayMode
  4808. * WK32RevertDisplayMode
  4809. * - changes display settings for apps automatically
  4810. * both assume that they get called only for apps with
  4811. * wow compat flag WOWCFEX_256DISPMODE.
  4812. * - global variables dmOldBitsPerPel and dwChangeCount
  4813. * are protected by critical sections in functions that
  4814. * call WK32ChangeDisplayMode and WK32RevertDisplayMode
  4815. *
  4816. */
  4817. void WK32ChangeDisplayMode(DWORD dmBitsPerPel) {
  4818. DEVMODEA dm;
  4819. if (EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &dm)) {
  4820. if (!dmChangeCount++) {
  4821. dmOldBitsPerPel = dm.dmBitsPerPel;
  4822. }
  4823. if (dmBitsPerPel != dm.dmBitsPerPel) {
  4824. dm.dmBitsPerPel = dmBitsPerPel;
  4825. ChangeDisplaySettingsA(&dm, CDS_FULLSCREEN);
  4826. }
  4827. }
  4828. }
  4829. void WK32RevertDisplayMode(void) {
  4830. DEVMODEA dm;
  4831. if (dmChangeCount &&
  4832. !--dmChangeCount &&
  4833. EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &dm) &&
  4834. dm.dmBitsPerPel <= 8 &&
  4835. dmOldBitsPerPel > dm.dmBitsPerPel)
  4836. {
  4837. dm.dmBitsPerPel = dmOldBitsPerPel;
  4838. ChangeDisplaySettingsA(&dm, CDS_FULLSCREEN);
  4839. }
  4840. }
  4841. PSZ szKeepVars[] = {
  4842. "ComSpec",
  4843. "Prompt",
  4844. "Path",
  4845. "TMP",
  4846. "TEMP",
  4847. "windir"
  4848. };
  4849. #define NUM_ENV_VARS (sizeof szKeepVars / sizeof szKeepVars[0])
  4850. // This strips down the environment variables to essentially this:
  4851. // COMSPEC, PATH, PROMPT, TMP, TEMP, windir
  4852. // There are some lame apps that seem to think that environments can't get any
  4853. // bigger than 512 bytes!!! Here we do our best to accomodate them.
  4854. //
  4855. // We also allow the expansion of the list of vars we keep from the cmdline
  4856. // parameter strings associated with the USEMINIMALENVIRONMENT app compatibility
  4857. // flag that got us here.
  4858. //
  4859. // The environment is laid out as follows:
  4860. // var1 = yada_yada_yada/NULL
  4861. // var2 = yada_yada_yada/NULL
  4862. // : :
  4863. // varN = yada_yada_yada/NULL/NULL
  4864. // goo
  4865. // Sig
  4866. // \NULL\NULL\NULL\NULL
  4867. //
  4868. // where:
  4869. // goo = magic number "0x01 0x00" followed by variable stuff depending
  4870. // on mode and other factors
  4871. // Sig = WOW_ENV_SIG - our signature DWORD
  4872. //
  4873. // Our signature DWORD allows us to scan past all the goo without having to
  4874. // re-figure out what the goo format is (calculated in WK32WowPassEnvironment)
  4875. // -- giving us the length of the environment + the goo.
  4876. //
  4877. // We copy the truncated environment into the original environment segment.
  4878. // This shouldn;t be a problem since we are shrinking it.
  4879. //
  4880. void WOWStripDownTheEnvironment(WORD segPSP)
  4881. {
  4882. PSZ pLoc;
  4883. PSZ pGoo, pSig;
  4884. PSZ pNewEnv, pTempEnv, pEnv;
  4885. DWORD i, j, len, loc, dwVars;
  4886. PWORD p;
  4887. LPSTR *pFlagArgv = NULL;
  4888. LPSTR *pArgv;
  4889. PFLAGINFOBITS pFlagInfoBits;
  4890. pLoc = (PSZ)SEGPTR(segPSP,0x2c); // 0x2c = offset of env seg in the PSP
  4891. p = (PWORD)pLoc;
  4892. pEnv = (PSZ)SEGPTR(*p,0); // get flat ptr to env seg
  4893. len = WOW32GetEnvironmentPtrs(pEnv, &pGoo, &pSig, &dwVars);
  4894. if(!pGoo || !pSig)
  4895. return;
  4896. // allocate a temporary environment
  4897. pTempEnv = (PSZ)malloc_w(len);
  4898. if(!pTempEnv)
  4899. return;
  4900. // get the list of additional environment vars we want to keep
  4901. pFlagInfoBits = CheckFlagInfo(WOWCOMPATFLAGS2,WOWCF2_USEMINIMALENVIRONMENT);
  4902. if(pFlagInfoBits) {
  4903. pFlagArgv = pFlagInfoBits->pFlagArgv;
  4904. }
  4905. // copy the original environment to the temp buffer
  4906. RtlCopyMemory(pTempEnv, pEnv, len);
  4907. pNewEnv = pEnv; // new environment will be copied into the original segment
  4908. pEnv = pTempEnv;
  4909. // go through each environment var in the original environment list
  4910. for(i = 0; i < dwVars; i++) {
  4911. len = strlen(pEnv) + 1; // add NULL to len
  4912. // get strlen up to "=" char in the var string
  4913. pLoc = WOW32_strchr(pEnv, '=');
  4914. loc = (int)(pLoc - pEnv);
  4915. // only compare strings with an "=" in them
  4916. if(loc) {
  4917. // compare this string with all strings in our "keep" list
  4918. for(j = 0; j < NUM_ENV_VARS; j++) {
  4919. // only compare up to the "=" char
  4920. if(!WOW32_strnicmp(szKeepVars[j], pEnv, loc)) {
  4921. // copy "keeper" into the new environment
  4922. strcpy(pNewEnv, pEnv);
  4923. // advance to 1st char past the NULL
  4924. pNewEnv += len;
  4925. // move on to next string in the original environment
  4926. break;
  4927. }
  4928. }
  4929. // now check the list of exceptions to save
  4930. if(pFlagArgv && pFlagInfoBits->dwFlagArgc > 0) {
  4931. pArgv = pFlagArgv;
  4932. for(j = 0; j < pFlagInfoBits->dwFlagArgc; j++) {
  4933. if(!WOW32_strnicmp(*pArgv, pEnv, loc)) {
  4934. // copy "keeper" into the new environment
  4935. strcpy(pNewEnv, pEnv);
  4936. // advance to 1st char past the NULL
  4937. pNewEnv += len;
  4938. // move on to next string in the original environment
  4939. break;
  4940. }
  4941. pArgv++;
  4942. }
  4943. }
  4944. }
  4945. // advance past the NULL (or to 2nd NULL when at end of list)
  4946. pEnv += len;
  4947. }
  4948. *pNewEnv++ = '\0'; // add 2nd NULL at end of new environment vars section
  4949. pEnv++;
  4950. // copy the goo after the environment vars section
  4951. len = pSig - pGoo;
  4952. RtlCopyMemory(pNewEnv, pEnv, len);
  4953. free_w(pTempEnv);
  4954. }
  4955. // Gets ptrs to the various sections of the environment segment.
  4956. // Returns: total length of all environment info (including the goo & signature)
  4957. DWORD WOW32GetEnvironmentPtrs(IN PSZ pEnv,
  4958. OUT PSZ *pGoo,
  4959. OUT PSZ *pSig,
  4960. OUT PDWORD pdw)
  4961. {
  4962. int len;
  4963. DWORD dwSIG = WOW_ENV_SIG;
  4964. PSZ p;
  4965. p = pEnv;
  4966. // get the length of the vars= section (including the double NULL at end)
  4967. len = WOWGetEnvironmentSize(p, pdw);
  4968. p += len; // point to the start of the goo (pointing at magic number)
  4969. *pGoo = p;
  4970. // locate the start of our signature
  4971. p += sizeof(WORD); // skip past magic number WORD
  4972. *pSig = NULL;
  4973. while(*p) {
  4974. if(*(DWORD *)p == dwSIG) {
  4975. *pSig = p;
  4976. p += sizeof(DWORD);
  4977. break;
  4978. }
  4979. p += strlen(p) + 1;
  4980. }
  4981. return(p - pEnv);
  4982. }
  4983. #define BYTE_FORM 0x00000001
  4984. #define WORD_FORM 0x00000002
  4985. #define DWORD_FORM 0x00000004
  4986. /*++
  4987. WK32WowDivideOverflowEx -
  4988. Code to handle the WOWCFEX_DIVIDEOVERFLOWPATCH compatibility flag. The flag
  4989. is detected in krnl386 while handling the divide_overflow() exception and
  4990. this function is called.
  4991. Unfortunately there are so many forms of this instruction making it very
  4992. difficult to determine where the divisor came (memory, register, etc) from.
  4993. So instead of trying to compute a resonable value based on the divisor, we
  4994. we just divide the dividend by 2 & return to the faulting (I)DIV instruction
  4995. and let them try again. We could very well end up back here again several
  4996. times for the same instruction until the divide gets out of the overflow
  4997. range. We don't change the divisor in memory since the app may be depending
  4998. on that value for something else. By changing the AX & possibly DX registers
  4999. we are only changing the result of the DIV instruction.
  5000. Return values: Depend on the form of the instruction.
  5001. dividend in AX - adjusted dividend in AX, DX unchanged
  5002. dividend in DX:AX - adjusted dividend in DX:AX
  5003. dividend in EDX:EAX - adjusted dividend in memory pointed to by local[0]
  5004. and local[1]. The divide_overflow() code needs to
  5005. fetch and load the new adjusted dividend values into
  5006. EDX and EAX. We return 0 in both AX and DX to signal
  5007. divide_overflow() that it has to do this. We have to
  5008. do it this way since we can only return a DWORD from
  5009. our thunk functions.
  5010. --*/
  5011. ULONG FASTCALL WK32WowDivideOverflowEx(PVDMFRAME pFrame)
  5012. {
  5013. WORD ax, dx;
  5014. DWORD eax, edx;
  5015. DWORD dwForm = WORD_FORM;
  5016. BOOL bSignedIDiv = FALSE;
  5017. BOOL bNegativeDividend = FALSE;
  5018. PBYTE pDivInst, pDiv;
  5019. PDWORD pStackLocal;
  5020. register PWOWDIVIDEOVERFLOW parg16;
  5021. GETARGPTR(pFrame, sizeof(WOWDIVIDEOVERFLOW), parg16);
  5022. // get flat ptr to the DIV (or IDIV) instruction
  5023. GETMISCPTR(parg16->csip, pDivInst);
  5024. pDiv = pDivInst;
  5025. // get flat ptr to local memory on the 16-bit stack
  5026. GETMISCPTR(parg16->local, (PBYTE)pStackLocal);
  5027. pStackLocal[0] = 0;
  5028. pStackLocal[1] = 0;
  5029. // if 32-bit div instruction (this can preceed or follow segment override)
  5030. if(*pDivInst == 0x66) {
  5031. dwForm = DWORD_FORM;
  5032. pDivInst++;
  5033. }
  5034. // check for segment override (store specified segment in ss)
  5035. switch(*pDivInst) {
  5036. case 0x26: // ES
  5037. // fall through
  5038. case 0x2e: // CS
  5039. // fall through
  5040. case 0x36: // SS
  5041. // fall through
  5042. case 0x3e: // DS
  5043. // fall through
  5044. case 0x67: // Address size override
  5045. // fall through
  5046. case 0x64: // FS
  5047. // fall through
  5048. case 0x65: // GS
  5049. pDivInst++;
  5050. break;
  5051. }
  5052. // if 32-bit div instruction (we have to check again)
  5053. if(*pDivInst == 0x66) {
  5054. dwForm = DWORD_FORM;
  5055. pDivInst++;
  5056. }
  5057. // see if byte divide (WORD & DWORD are 0xf7)
  5058. if(*pDivInst == 0xf6) {
  5059. dwForm = BYTE_FORM;
  5060. }
  5061. pDivInst++;
  5062. // see if unsigned DIV (0xn0-0xn7) or signed IDIV(0xn8-0xnF) instruction
  5063. // where n = [3, 7, B, F] (for ModR/M forms only)
  5064. if(*pDivInst & 0x08) {
  5065. bSignedIDiv = TRUE;
  5066. }
  5067. // BYTE Form: AX is being divided. Result: AL = Quotient, AH = Remainder
  5068. if(dwForm == BYTE_FORM) {
  5069. ax = LOWORD(parg16->eax);
  5070. // IDIV: Overflow exception occurs if you overflow the sign bit
  5071. // if IDIV instruction and dividend is negative...
  5072. if(bSignedIDiv && (parg16->eax & 0x00008000)) {
  5073. ax = ax ^ 0xFFFF; // do a signed divide by 2
  5074. ax = ax >> 1;
  5075. ax = ax ^ 0xFFFF;
  5076. }
  5077. else {
  5078. ax = ax >> 1;
  5079. }
  5080. dx = LOWORD(parg16->edx); // DX needs to be unaltered
  5081. }
  5082. // WORD Form: DX:AX is being divided. Result: AX = Quotient, DX = Remainder
  5083. else if(dwForm == WORD_FORM) {
  5084. eax = MAKELONG(LOWORD(parg16->eax), LOWORD(parg16->edx));
  5085. // IDIV: Overflow exception occurs if you overflow the sign bit
  5086. // if IDIV instruction and dividend is negative...
  5087. if(bSignedIDiv && (eax & 0x80000000)) {
  5088. eax = eax ^ 0xFFFFFFFF; // do a signed divide by 2
  5089. eax = eax >> 1;
  5090. eax = eax ^ 0xFFFFFFFF;
  5091. }
  5092. else {
  5093. eax = eax >> 1;
  5094. }
  5095. ax = LOWORD(eax);
  5096. dx = HIWORD(eax);
  5097. }
  5098. // DWORD form: EDX:EAX is being divided. Result: EAX = Quotient, EDX = rem.
  5099. else {
  5100. eax = parg16->eax;
  5101. edx = parg16->edx;
  5102. // IDIV: Overflow exception occurs if you overflow the sign bit
  5103. // if IDIV instruction and dividend is negative...
  5104. if(bSignedIDiv && (parg16->edx & 0x80000000)) {
  5105. eax = eax ^ 0xFFFFFFFF; // do a signed divide by 2
  5106. eax = eax >> 1;
  5107. edx = edx ^ 0xFFFFFFFF;
  5108. // if low bit is set in edx, "shift" it into eax
  5109. if(edx & 0x1) {
  5110. eax |= 0x80000000;
  5111. }
  5112. eax = eax ^ 0xFFFFFFFF;
  5113. edx = edx >> 1;
  5114. edx = edx ^ 0xFFFFFFFF;
  5115. }
  5116. else {
  5117. eax = eax >> 1;
  5118. // if low bit is set in edx, "shift" it into eax
  5119. if(edx & 0x1) {
  5120. eax |= 0x80000000;
  5121. }
  5122. edx = edx >> 1;
  5123. }
  5124. pStackLocal[0] = eax;
  5125. pStackLocal[1] = edx;
  5126. ax = 0; // inform divide_overflow() handler that the two dwords are
  5127. dx = 0; // in local[0] and local[1]
  5128. }
  5129. FREEPSZPTR(pDiv);
  5130. FREEPSZPTR(pStackLocal);
  5131. return(MAKELONG(ax, dx));
  5132. }