Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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