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

3080 lines
83 KiB

  1. /*++
  2. *
  3. * WOW v1.0
  4. *
  5. * Copyright (c) 1991, Microsoft Corporation
  6. *
  7. * WOW32.C
  8. * WOW32 16-bit API support
  9. *
  10. * History:
  11. * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
  12. * Multi-Tasking 23-May-1991 Matt Felton [mattfe]
  13. * WOW as DLL 06-Dec-1991 Sudeep Bharati (sudeepb)
  14. * Cleanup and rework multi tasking feb 6 (mattfe)
  15. * added notification thread for task creation mar-11 (mattfe)
  16. * added basic exception handling for retail build apr-3 92 mattfe
  17. * use host_ExitThread apr-17 92 daveh
  18. * Hung App Support june-22 82 mattfe
  19. --*/
  20. #include "precomp.h"
  21. #pragma hdrstop
  22. #include "wktbl.h"
  23. #include "wutbl.h"
  24. #include "wgtbl.h"
  25. #include "wstbl.h"
  26. #include "wkbtbl.h"
  27. #include "wshltbl.h"
  28. #include "wmmtbl.h"
  29. #include "wsocktbl.h"
  30. #include "wthtbl.h"
  31. #include "wowit.h"
  32. #include <stdarg.h>
  33. #include <ntcsrdll.h>
  34. #include <tsappcmp.h>
  35. /* Function Prototypes */
  36. DWORD W32SysErrorBoxThread2(PTDB pTDB);
  37. VOID StartDebuggerForWow(VOID);
  38. BOOLEAN LoadCriticalStringResources(void);
  39. // For Dynamic Patch Module support
  40. extern PFAMILY_TABLE *pgDpmWowFamTbls;
  41. extern PDPMMODULESETS *pgDpmWowModuleSets;
  42. extern DECLSPEC_IMPORT ULONG *ExpLdt;
  43. #define LDT_DESC_PRESENT 0x8000
  44. #define STD_SELECTOR_BITS 0x7
  45. MODNAME(wow32.c);
  46. // for logging iloglevel to a file
  47. #ifdef DEBUG
  48. CHAR szLogFile[128];
  49. int fLog;
  50. HANDLE hfLog;
  51. UCHAR gszAssert[256];
  52. #endif
  53. /* iloglevel = 16 MAX the world (all 16 bit kernel internal calls
  54. * iloglevel = 14 All internal WOW kernel Calls
  55. * ilogeveel = 12 All USER GDI call + return Codes
  56. * iloglevel = 5 Returns From Calls
  57. * iloglevel = 3 Calling Parameters
  58. */
  59. INT flOptions; // command line optin
  60. #ifdef DEBUG
  61. INT iLogLevel; // logging level; 0 implies none
  62. INT fDebugWait=0; // Single Step, 0 = No single step
  63. #endif
  64. HANDLE hmodWOW32;
  65. HANDLE hHostInstance;
  66. #ifdef DEBUG
  67. INT fLogFilter = -1; // Logging Code Fiters
  68. WORD fLogTaskFilter = (WORD)-1; // Filter Logging for Specific TaskID
  69. #endif
  70. #ifdef DEBUG
  71. BOOL fSkipLog; // TRUE to temporarily skip certain logging
  72. INT iReqLogLevel; // Current Output LogLevel
  73. INT iCircBuffer = CIRC_BUFFERS-1; // Current Buffer
  74. CHAR achTmp[CIRC_BUFFERS][TMP_LINE_LEN] = {" "}; // Circular Buffer
  75. CHAR *pachTmp = &achTmp[0][0];
  76. WORD awfLogFunctionFilter[FILTER_FUNCTION_MAX] = {0xffff,0,0,0,0,0,0,0,0,0}; // Specific Filter API Array
  77. PWORD pawfLogFunctionFilter = awfLogFunctionFilter;
  78. INT iLogFuncFiltIndex; // Index Into Specific Array for Debugger Extensions
  79. #endif
  80. #ifdef DEBUG_MEMLEAK
  81. CRITICAL_SECTION csMemLeak;
  82. #endif
  83. UINT iW32ExecTaskId = (UINT)-1; // Base Task ID of Task Being Exec'd
  84. UINT nWOWTasks = 0; // # of WOW tasks running
  85. BOOL fBoot = TRUE; // TRUE During the Boot Process
  86. HANDLE ghevWaitCreatorThread = (HANDLE)-1; // Used to Syncronize creation of a new thread
  87. BOOL fWowMode; // Flag used to determine wow mode.
  88. // currently defaults to FALSE (real mode wow)
  89. // This is used by the memory access macros
  90. // to properly form linear addresses.
  91. // When running on an x86 box, it will be
  92. // initialized to the mode the first wow
  93. // bop call is made in. This flag can go
  94. // away when we no longer want to run real
  95. // mode wow. (Daveh 7/25/91)
  96. HANDLE hWOWHeap;
  97. HANDLE ghProcess; // WOW Process Handle
  98. PFNWOWHANDLERSOUT pfnOut;
  99. PTD * pptdWOA;
  100. PTD gptdShell;
  101. DWORD fThunkStrRtns; // used as a BOOL
  102. BOOL gfDebugExceptions; // set to 1 in debugger to
  103. // enable debugging of W32Exception
  104. BOOL gfIgnoreInputAssertGiven;
  105. DWORD dwSharedWowTimeout;
  106. WORD gwKrnl386CodeSeg1; // code segs of krnl386.exe
  107. WORD gwKrnl386CodeSeg2;
  108. WORD gwKrnl386CodeSeg3;
  109. WORD gwKrnl386DataSeg1;
  110. extern PFAMILY_TABLE *pgDpmWowFamTbls;
  111. extern PDPMMODULESETS *pgDpmWowModuleNames;
  112. #ifndef _X86_
  113. PUCHAR IntelMemoryBase; // Start of emulated CPU's memory
  114. #endif
  115. DWORD gpsi = 0;
  116. DWORD gpfn16GetProcModule;
  117. /* for WinFax Lite install hack -- see wow32fax.c */
  118. char szWINFAX[] = "WINFAX";
  119. char szModem[] = "modem";
  120. char szINSTALL[] = "INSTALL";
  121. char szWINFAXCOMx[80];
  122. BOOL gbWinFaxHack = FALSE;
  123. #define TOOLONGLIMIT _MAX_PATH
  124. #define WARNINGMSGLENGTH 255
  125. PSZ aszCriticalStrings[CRITICAL_STRING_COUNT];
  126. char szEmbedding[] = "embedding";
  127. char szDevices[] = "devices";
  128. char szBoot[] = "boot";
  129. char szShell[] = "shell";
  130. char szServerKey[] = "protocol\\StdFileEditing\\server";
  131. char szPicture[] = "picture";
  132. char szPostscript[] = "postscript";
  133. char szZapfDingbats[] = "ZAPFDINGBATS";
  134. char szZapf_Dingbats[] = "ZAPF DINGBATS";
  135. char szSymbol[] = "SYMBOL";
  136. char szTmsRmn[] = "TMS RMN";
  137. char szHelv[] = "HELV";
  138. char szMavisCourier[]= "MAVIS BEACON COURIER FP";
  139. char szWinDotIni[] = "win.ini";
  140. char szSystemDotIni[] = "system.ini";
  141. char szExplorerDotExe[] = "Explorer.exe";
  142. char szDrWtsn32[] = "drwtsn32";
  143. PSTR pszWinIniFullPath = NULL;
  144. PSTR pszWindowsDirectory = NULL;
  145. PSTR pszSystemDirectory = NULL;
  146. PWSTR pszSystemDirectoryW = NULL;
  147. BOOL gbDBCSEnable = FALSE;
  148. DWORD cbSystemDirLen = 0; // Len of *SHORT* path to system32 dir not incl NULL
  149. DWORD cbSystemDirLenW = 0;// # WCHARS in *LONG* Wpath to sys32 dir not incl NULL
  150. DWORD cbWindowsDirLen = 0; // Len of short path to c:\windows dir not incl NULL
  151. DWORD cbWinIniFullPathLen = 0; // Len of short path to win.ini not incl NULL
  152. #ifdef FE_SB
  153. char szSystemMincho[] = {(char) 0xbc, (char) 0xbd, (char) 0xc3, (char) 0xd1,
  154. (char) 0x96, (char) 0xbe, (char) 0x92, (char) 0xa9,
  155. (char) 0 };
  156. char szMsMincho[] = { (char) 0x82, (char) 0x6c, (char) 0x82, (char) 0x72,
  157. (char) 0x20, (char) 0x96, (char) 0xbe, (char) 0x92,
  158. (char) 0xa9, (char) 0};
  159. #endif
  160. extern CRITICAL_SECTION VdmLoadCritSec;
  161. extern LIST_ENTRY TimerList;
  162. extern BOOL InitializeGdiHandleMappingTable(void);
  163. extern void DeleteGdiHandleMappingTables(void);
  164. PVOID pfnGetVersionExA; // Used with Version Lie hack. Function pointer to GetVersionExA
  165. // See WK32GetProcAddress32W in wkgthunk.c
  166. PVOID pfnCreateDirectoryA; // Used with GtCompCreateDirectoryA in wkgthunk.c
  167. PVOID pfnLoadLibraryA; // Used with GtCompLoadLibraryA in wkgthunk.c
  168. PVOID pfnCreateFileA; // Used with GtCompCreateFileA in wkgthunk.c
  169. PVOID pfnMoveFileA; // Used with GtCompMoveFileA in wkgthunk.c
  170. // Given to us by the terminal server folks to detect if we are in TS.
  171. BOOL IsTerminalAppServer(void)
  172. {
  173. OSVERSIONINFOEX osVersionInfo;
  174. DWORDLONG dwlConditionMask = 0;
  175. BOOL fIsWTS;
  176. osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  177. fIsWTS = GetVersionEx((OSVERSIONINFO *)&osVersionInfo) &&
  178. (osVersionInfo.wSuiteMask & VER_SUITE_TERMINAL) &&
  179. !(osVersionInfo.wSuiteMask & VER_SUITE_SINGLEUSERTS);
  180. return fIsWTS;
  181. }
  182. BOOLEAN
  183. W32DllInitialize(
  184. IN PVOID DllHandle,
  185. IN ULONG Reason,
  186. IN PCONTEXT Context OPTIONAL
  187. )
  188. /*++
  189. Routine Description: DllMain function called during ntvdm's
  190. LoadLibrary("wow32")
  191. Arguments:
  192. DllHandle - set global hmodWOW32
  193. Reason - Attach or Detach
  194. Context - Not Used
  195. Return Value:
  196. STATUS_SUCCESS
  197. --*/
  198. {
  199. HMODULE hKrnl32dll;
  200. UNREFERENCED_PARAMETER(Context);
  201. hmodWOW32 = DllHandle;
  202. switch ( Reason ) {
  203. case DLL_PROCESS_ATTACH:
  204. if (!CreateSmallHeap()) {
  205. return FALSE;
  206. }
  207. if ((hWOWHeap = HeapCreate (0,
  208. INITIAL_WOW_HEAP_SIZE,
  209. GROW_HEAP_AS_NEEDED)) == NULL)
  210. return FALSE;
  211. //
  212. // Set up a global WindowsDirectory to be used by other WOW functions.
  213. //
  214. {
  215. char szBuf[MAX_PATH];
  216. int ccb;
  217. ccb = GetSystemDirectory(szBuf, sizeof szBuf);
  218. if (ccb == 0 || ccb >= MAX_PATH)
  219. {
  220. LOGDEBUG(0,("W32INIT ERROR: system path failed\n"));
  221. return(FALSE);
  222. }
  223. ccb++;
  224. pszSystemDirectoryW = malloc_w_or_die(ccb * sizeof(WCHAR));
  225. // Returns length in WCHARS
  226. cbSystemDirLenW = GetSystemDirectoryW(pszSystemDirectoryW, ccb);
  227. WOW32ASSERTMSG((ccb > (INT)cbSystemDirLenW),
  228. ("WOW::DLL_PROCESS_ATTACH:System dir mis-match\n"));
  229. cbSystemDirLen = GetShortPathName(szBuf, szBuf, sizeof szBuf);
  230. if (cbSystemDirLen == 0 || cbSystemDirLen >= MAX_PATH)
  231. {
  232. LOGDEBUG(0,("W32INIT ERROR: system path failed 2\n"));
  233. return(FALSE);
  234. }
  235. ccb = cbSystemDirLen + 1;
  236. pszSystemDirectory = malloc_w_or_die(ccb);
  237. RtlCopyMemory(pszSystemDirectory, szBuf, ccb);
  238. if(!GetSystemWindowsDirectory(szBuf, sizeof szBuf) ) {
  239. WOW32ASSERTMSG(FALSE, "WOW32: couldnt get windows directory, terminating.\n");
  240. WOWStartupFailed(); // never returns.
  241. }
  242. GetShortPathName(szBuf, szBuf, sizeof szBuf);
  243. cbWindowsDirLen = strlen(szBuf);
  244. ccb = cbWindowsDirLen + 1;
  245. pszWindowsDirectory = malloc_w_or_die(ccb);
  246. RtlCopyMemory(pszWindowsDirectory, szBuf, ccb);
  247. pszWinIniFullPath = malloc_w_or_die(ccb + 8); // "\win.ini"
  248. cbWinIniFullPathLen = cbWindowsDirLen + 8;
  249. RtlCopyMemory(pszWinIniFullPath, szBuf, ccb);
  250. pszWinIniFullPath[ ccb - 1 ] = '\\';
  251. RtlCopyMemory(pszWinIniFullPath + ccb, szWinDotIni, 8);
  252. }
  253. // initialize hook stubs data.
  254. W32InitHookState(hmodWOW32);
  255. // initialize the thunk table offsets. do it here so the debug process
  256. // gets them.
  257. InitThunkTableOffsets();
  258. //
  259. // initialization for named pipe handling in file thunks
  260. //
  261. InitializeCriticalSection(&VdmLoadCritSec);
  262. //
  263. // Load Critical Error Strings
  264. //
  265. if (!LoadCriticalStringResources()) {
  266. MessageBox(NULL, "The Win16 subsystem could not load critical string resources from wow32.dll, terminating.",
  267. "Win16 subsystem load failure", MB_ICONEXCLAMATION | MB_OK);
  268. return FALSE;
  269. }
  270. W32EWExecer();
  271. InitializeListHead(&TimerList);
  272. if (IsTerminalAppServer()) {
  273. //
  274. // Load tsappcmp.dll
  275. //
  276. HANDLE dllHandle = SafeLoadLibrary (L"tsappcmp.dll");
  277. if (dllHandle) {
  278. gpfnTermsrvCORIniFile = (PTERMSRVCORINIFILE) GetProcAddress(
  279. dllHandle,
  280. "TermsrvCORIniFile"
  281. );
  282. ASSERT(gpfnTermsrvCORIniFile != NULL);
  283. }
  284. }
  285. //
  286. // WHISTLER RAID BUG 366613
  287. // Used for redirecting WK32GetProcAddress32W call on GetVersionExA
  288. //
  289. hKrnl32dll = GetModuleHandle("Kernel32.dll");
  290. if(hKrnl32dll)
  291. {
  292. pfnGetVersionExA = GetProcAddress(hKrnl32dll, "GetVersionExA");
  293. pfnCreateDirectoryA = GetProcAddress(hKrnl32dll, "CreateDirectoryA");
  294. pfnLoadLibraryA = GetProcAddress(hKrnl32dll, "LoadLibraryA");
  295. pfnCreateFileA = GetProcAddress(hKrnl32dll, "CreateFileA");
  296. pfnMoveFileA = GetProcAddress(hKrnl32dll, "MoveFileA");
  297. }
  298. break;
  299. case DLL_THREAD_ATTACH:
  300. IsDebuggerAttached(); // Yes, this routine has side-effects.
  301. break;
  302. case DLL_THREAD_DETACH:
  303. break;
  304. case DLL_PROCESS_DETACH:
  305. /*
  306. * Tell base he can nolonger callback to us.
  307. */
  308. RegisterWowBaseHandlers(NULL);
  309. DeleteCriticalSection(&VdmLoadCritSec);
  310. DeleteGdiHandleMappingTables();
  311. HeapDestroy (hWOWHeap);
  312. break;
  313. default:
  314. break;
  315. }
  316. return TRUE;
  317. }
  318. BOOLEAN
  319. LoadCriticalStringResources(
  320. void
  321. )
  322. /*++
  323. Routine Description: Loads strings we want around even if we can't allocate
  324. memory. Called during wow32 DLL load.
  325. Arguments:
  326. none
  327. Return Value:
  328. TRUE if all strings loaded and aszCriticalStrings initialized.
  329. --*/
  330. {
  331. int i, n;
  332. PSZ psz, pszStringBuffer;
  333. DWORD cbTotal;
  334. DWORD cbUsed;
  335. DWORD cbStrLen;
  336. DWORD rgdwStringOffset[CRITICAL_STRING_COUNT];
  337. //
  338. // Allocate too much memory for strings (maximum possible) at first,
  339. // reallocate to the real size when we're done loading strings.
  340. //
  341. cbTotal = CRITICAL_STRING_COUNT * CCH_MAX_STRING_RESOURCE;
  342. psz = pszStringBuffer = malloc_w(cbTotal);
  343. if ( ! psz ) {
  344. return FALSE;
  345. }
  346. cbUsed = 0;
  347. for ( n = 0; n < CRITICAL_STRING_COUNT; n++ ) {
  348. //
  349. // LoadString return value doesn't count null terminator.
  350. //
  351. cbStrLen = LoadString(hmodWOW32, n, psz, CCH_MAX_STRING_RESOURCE);
  352. if ( ! cbStrLen ) {
  353. return FALSE;
  354. }
  355. rgdwStringOffset[n] = cbUsed;
  356. psz += cbStrLen + 1;
  357. cbUsed += cbStrLen + 1;
  358. }
  359. // Now, alloc a smaller buffer of the correct size
  360. // Note: HeapRealloc(IN_PLACE) won't work because allocations are
  361. // page-sorted by size -- meaning that changing the size will cause
  362. // the memory to move to a new page.
  363. psz = malloc_w(cbUsed);
  364. // copy the strings into the smaller buffer
  365. // if we can't alloc the smaller buffer, just go with the big one
  366. if (psz) {
  367. RtlCopyMemory(psz, pszStringBuffer, cbUsed);
  368. free_w(pszStringBuffer);
  369. pszStringBuffer = psz;
  370. }
  371. // save the offsets in the critical string array
  372. for (i = 0; i < n; i++) {
  373. aszCriticalStrings[i] = pszStringBuffer + rgdwStringOffset[i];
  374. }
  375. return TRUE;
  376. }
  377. //***************************************************************************
  378. // Continues ExitWindowsExec api call after logoff and subsequent logon
  379. // Uses Events to synchronize across all wow vdms
  380. //
  381. //***************************************************************************
  382. BOOL W32EWExecer(VOID)
  383. {
  384. STARTUPINFO StartupInfo;
  385. PROCESS_INFORMATION ProcessInformation;
  386. BOOL CreateProcessStatus;
  387. BYTE abT[REGISTRY_BUFFER_SIZE];
  388. if (W32EWExecData(EWEXEC_QUERY, (LPSTR)abT, sizeof(abT))) {
  389. HANDLE hevT;
  390. if (hevT = CreateEvent(NULL, TRUE, FALSE, WOWSZ_EWEXECEVENT)) {
  391. if (GetLastError() == 0) {
  392. W32EWExecData(EWEXEC_DEL, (LPSTR)NULL, 0);
  393. LOGDEBUG(0, ("WOW:Execing dos app - %s\r\n", abT));
  394. RtlZeroMemory((PVOID)&StartupInfo, (DWORD)sizeof(StartupInfo));
  395. StartupInfo.cb = sizeof(StartupInfo);
  396. StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
  397. StartupInfo.wShowWindow = SW_NORMAL;
  398. CreateProcessStatus = CreateProcess(
  399. NULL,
  400. abT,
  401. NULL, // security
  402. NULL, // security
  403. FALSE, // inherit handles
  404. CREATE_NEW_CONSOLE | CREATE_DEFAULT_ERROR_MODE,
  405. NULL, // environment strings
  406. NULL, // current directory
  407. &StartupInfo,
  408. &ProcessInformation
  409. );
  410. if (CreateProcessStatus) {
  411. WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
  412. CloseHandle( ProcessInformation.hProcess );
  413. CloseHandle( ProcessInformation.hThread );
  414. }
  415. SetEvent(hevT);
  416. }
  417. else {
  418. WaitForSingleObject(hevT, INFINITE);
  419. }
  420. CloseHandle(hevT);
  421. }
  422. }
  423. return 0;
  424. }
  425. //***************************************************************************
  426. // W32EWExecData -
  427. // sets/resets the 'commandline', ie input to ExitWindowssExec api in the
  428. // registry - 'WOW' key 'EWExec' value
  429. //
  430. //***************************************************************************
  431. BOOL W32EWExecData(DWORD fnid, LPSTR lpData, DWORD cb)
  432. {
  433. BOOL bRet = FALSE;
  434. BYTE abT[REGISTRY_BUFFER_SIZE];
  435. switch (fnid) {
  436. case EWEXEC_SET:
  437. bRet = WriteProfileString(WOWSZ_EWEXECVALUE,
  438. WOWSZ_EWEXECVALUE,
  439. lpData);
  440. break;
  441. case EWEXEC_DEL:
  442. bRet = WriteProfileString(WOWSZ_EWEXECVALUE,
  443. NULL, NULL);
  444. break;
  445. case EWEXEC_QUERY:
  446. if (bRet = GetProfileString(WOWSZ_EWEXECVALUE,
  447. WOWSZ_EWEXECVALUE,
  448. "", abT, sizeof(abT))) {
  449. cb = min(cb, sizeof(abT));
  450. cb = min(cb, strlen(abT)+1);
  451. strncpy(lpData, abT, cb);
  452. lpData[cb-1] = '\0';
  453. }
  454. break;
  455. default:
  456. WOW32ASSERT(FALSE);
  457. break;
  458. }
  459. return !!bRet;
  460. }
  461. /* W32Init - Initialize WOW support
  462. *
  463. * ENTRY
  464. *
  465. * EXIT
  466. * TRUE if successful, FALSE if not
  467. */
  468. BOOL W32Init(VOID)
  469. {
  470. HKEY WowKey;
  471. DWORD cb;
  472. DWORD dwType;
  473. PTD ptd;
  474. PFNWOWHANDLERSIN pfnIn;
  475. LANGID LangID;
  476. #ifndef _X86_
  477. //
  478. // This is the one and only call to Sim32GetVDMPointer in WOW32.
  479. // All other cases should use WOWGetVDMPointer. This one is necessary
  480. // to set up the base memory address used by GetRModeVDMPointerMacro.
  481. // (There's also a call in GetPModeVDMPointerAssert, but that's in
  482. // the checked build only and only as a fallback mechanism.)
  483. //
  484. IntelMemoryBase = Sim32GetVDMPointer(0,0,0);
  485. #endif
  486. // Set the global DPM tables.
  487. BuildGlobalDpmStuffForWow(pgDpmWowFamTbls, pgDpmWowModuleSets);
  488. InitGlobalDpmTables(pgDpmWowFamTbls, NUM_WOW_FAMILIES_HOOKED);
  489. fWowMode = ((getMSW() & MSW_PE) ? TRUE : FALSE);
  490. // Boost the HourGlass
  491. ShowStartGlass(10000);
  492. LangID = GetSystemDefaultLangID();
  493. if (PRIMARYLANGID(LangID) == LANG_JAPANESE ||
  494. PRIMARYLANGID(LangID) == LANG_KOREAN ||
  495. PRIMARYLANGID(LangID) == LANG_CHINESE ) {
  496. gbDBCSEnable = TRUE;
  497. }
  498. // Give USER32 our entry points
  499. RtlZeroMemory(&pfnIn, sizeof(pfnIn));
  500. pfnIn.pfnLocalAlloc = W32LocalAlloc;
  501. pfnIn.pfnLocalReAlloc = W32LocalReAlloc;
  502. pfnIn.pfnLocalLock = W32LocalLock;
  503. pfnIn.pfnLocalUnlock = W32LocalUnlock;
  504. pfnIn.pfnLocalSize = W32LocalSize;
  505. pfnIn.pfnLocalFree = W32LocalFree;
  506. pfnIn.pfnGetExpWinVer = W32GetExpWinVer;
  507. pfnIn.pfn16GlobalAlloc = W32GlobalAlloc16;
  508. pfnIn.pfn16GlobalFree = W32GlobalFree16;
  509. pfnIn.pfnEmptyCB = W32EmptyClipboard;
  510. pfnIn.pfnFindResourceEx = W32FindResource;
  511. pfnIn.pfnLoadResource = W32LoadResource;
  512. pfnIn.pfnFreeResource = W32FreeResource;
  513. pfnIn.pfnLockResource = W32LockResource;
  514. pfnIn.pfnUnlockResource = W32UnlockResource;
  515. pfnIn.pfnSizeofResource = W32SizeofResource;
  516. pfnIn.pfnWowWndProcEx = (PFNWOWWNDPROCEX)W32Win16WndProcEx;
  517. pfnIn.pfnWowDlgProcEx = (PFNWOWDLGPROCEX)W32Win16DlgProcEx;
  518. pfnIn.pfnWowEditNextWord = W32EditNextWord;
  519. pfnIn.pfnWowCBStoreHandle = WU32ICBStoreHandle;
  520. pfnIn.pfnGetProcModule16 = WOWGetProcModule16;
  521. pfnIn.pfnWowMsgBoxIndirectCallback = WowMsgBoxIndirectCallback;
  522. pfnIn.pfnWowIlstrsmp = WOWlstrcmp16;
  523. pfnIn.pfnWOWTellWOWThehDlg = WOWTellWOWThehDlg;
  524. pfnIn.pfnWowTask16SchedNotify = NULL;
  525. gpsi = UserRegisterWowHandlers(&pfnIn, &pfnOut);
  526. RegisterWowBaseHandlers(W32DDEFreeGlobalMem32);
  527. // Allocate a Temporary TD for the first thread
  528. ptd = CURRENTPTD() = malloc_w_or_die(sizeof(TD));
  529. RtlZeroMemory(ptd, sizeof(*ptd));
  530. InitializeCriticalSection(&ptd->csTD);
  531. // Create Global Wait Event - Used During Task Creation To Syncronize with New Thread
  532. if (!(ghevWaitCreatorThread = CreateEvent(NULL, FALSE, FALSE, NULL))) {
  533. LOGDEBUG(0,(" W32INIT ERROR: event creation failure\n"));
  534. return FALSE;
  535. }
  536. if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE,
  537. "SYSTEM\\CurrentControlSet\\Control\\WOW",
  538. 0,
  539. KEY_QUERY_VALUE,
  540. &WowKey
  541. ) != 0){
  542. LOGDEBUG(0,(" W32INIT ERROR: Registry Opening failed\n"));
  543. return FALSE;
  544. }
  545. //
  546. // If present, read the SharedWowTimeout value and convert
  547. // from seconds to milliseconds, which is what SetTimer
  548. // uses. Maximum interval for SetTimer is 0x7fffffff.
  549. // No need to enforce a minimum, as SetTimer treats a
  550. // zero timeout as a one millsecond timeout.
  551. //
  552. cb = sizeof(dwSharedWowTimeout);
  553. if ( ! RegQueryValueEx(WowKey,
  554. "SharedWowTimeout",
  555. NULL,
  556. &dwType,
  557. (LPBYTE) &dwSharedWowTimeout,
  558. &cb) && REG_DWORD == dwType) {
  559. //
  560. // Prevent overflow in the conversion to millseconds below.
  561. // This caps the timeout to 2,147,483 seconds, or 24.8 days.
  562. //
  563. dwSharedWowTimeout = min( dwSharedWowTimeout,
  564. (0x7fffffff / 1000) );
  565. } else {
  566. //
  567. // Didn't find SharedWowTimeout value or it's the wrong type.
  568. //
  569. dwSharedWowTimeout = 1 * 60 * 60; // 1 hour in seconds
  570. }
  571. dwSharedWowTimeout *= 1000;
  572. //
  573. // If present (it usually isn't) read ThunkNLS value entry.
  574. //
  575. cb = sizeof(fThunkStrRtns);
  576. if (RegQueryValueEx(WowKey,
  577. "ThunkNLS",
  578. NULL,
  579. &dwType,
  580. (LPBYTE) &fThunkStrRtns,
  581. &cb) || dwType != REG_DWORD) {
  582. //
  583. // Didn't find the registry value or it's the wrong type,
  584. // so we use the default behavior which is to thunk outside the
  585. // US.
  586. //
  587. fThunkStrRtns = GetSystemDefaultLCID() !=
  588. MAKELCID(
  589. MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
  590. SORT_DEFAULT
  591. );
  592. } else {
  593. //
  594. // We did find a ThunkNLS value in the registry, warn on debug builds
  595. // to save testers and developers who turn it on for one bug but forget
  596. // to turn it back off.
  597. //
  598. #ifdef DEBUG
  599. OutputDebugString("WOW Warning: ThunkNLS registry value overriding default NLS tranlation.\n");
  600. #endif
  601. }
  602. //
  603. // Initialize list of known DLLs used by WK32WowIsKnownDLL
  604. // from the registry.
  605. //
  606. WK32InitWowIsKnownDLL(WowKey);
  607. RegCloseKey (WowKey);
  608. //
  609. // Initialize param mapping cache
  610. //
  611. //
  612. InitParamMap();
  613. //
  614. // Set our GDI batching limit from win.ini. This is useful for SGA and
  615. // other performance measurements which require each API to do its own
  616. // work. To set the batching size to 1, which is most common, put the
  617. // following in win.ini:
  618. //
  619. // [WOW]
  620. // BatchLimit=1
  621. //
  622. // or using ini:
  623. //
  624. // ini WOW.BatchLimit = 1
  625. //
  626. // Note that this code only changes the batch limit if the above
  627. // line is in win.ini, otherwise we use default batching. It's
  628. // important that this code be in the free build to be useful.
  629. //
  630. {
  631. extern DWORD dwWOWBatchLimit; // declared in wkman.c
  632. dwWOWBatchLimit = GetProfileInt("WOW", // section
  633. "BatchLimit", // key
  634. 0 // default if not found
  635. );
  636. }
  637. ghProcess = NtCurrentProcess();
  638. // setup the GDI table for handle conversion
  639. if(InitializeGdiHandleMappingTable() == FALSE)
  640. return(FALSE);
  641. #ifdef DEBUG
  642. #ifdef i386
  643. if (IsDebuggerAttached()) {
  644. if (GetProfileInt("WOWDebug", "debugbreaks", 0))
  645. *pNtVDMState |= VDM_BREAK_DEBUGGER;
  646. if (GetProfileInt("WOWDebug", "exceptions", 0))
  647. *pNtVDMState |= VDM_BREAK_EXCEPTIONS;
  648. }
  649. #endif
  650. if (IsDebuggerAttached() && (flOptions & OPT_BREAKONNEWTASK)) {
  651. OutputDebugString("\nW32Init - Initialization Complete, Set any Breakpoints Now, type g to continue\n\n");
  652. DbgBreakPoint();
  653. }
  654. #endif
  655. // Initialize ClipBoard formats structure.
  656. InitCBFormats ();
  657. // This is to initialize the InquireVisRgn for FileMaker Pro 2.0
  658. // InquireVisRgn is an undocumented API Win 3.1 API.
  659. InitVisRgn();
  660. // HUNG APP SUPPORT
  661. if (!WK32InitializeHungAppSupport()) {
  662. LOGDEBUG(LOG_ALWAYS, ("W32INIT Error: InitializeHungAppSupport Failed"));
  663. return FALSE;
  664. }
  665. SetPriorityClass(ghProcess, NORMAL_PRIORITY_CLASS);
  666. #ifdef DEBUG_MEMLEAK
  667. // for memory leak support
  668. InitializeCriticalSection(&csMemLeak);
  669. #endif
  670. // 9x Special Path Map Initialization
  671. // i.e. c:\winnt\startm~1 will be c:\documents and settings\all users\start menu
  672. W32Init9xSpecialPath();
  673. return TRUE;
  674. }
  675. /* Thunk Dispatch Table
  676. *
  677. *
  678. */
  679. #ifdef DEBUG_OR_WOWPROFILE
  680. PA32 awThunkTables[] = {
  681. {W32TAB(aw32WOW, "All ", cAPIThunks)}
  682. };
  683. #endif
  684. #ifdef DEBUG_OR_WOWPROFILE // define symbols for API profiling only (debugger extension)
  685. INT iThunkTableMax = NUMEL(awThunkTables);
  686. PPA32 pawThunkTables = awThunkTables;
  687. #endif // WOWPROFILE
  688. /* WOW32UnimplementedAPI - Error Thunk is Not Implemented
  689. *
  690. * Stub thunk table entry for all unimplemented APIs on
  691. * the checked build, and on the free build NOPAPI and
  692. * LOCALAPI entries point here as well.
  693. *
  694. * ENTRY
  695. *
  696. * EXIT
  697. *
  698. */
  699. ULONG FASTCALL WOW32UnimplementedAPI(PVDMFRAME pFrame)
  700. {
  701. #ifdef DEBUG
  702. INT iFun;
  703. iFun = pFrame->wCallID;
  704. LOGDEBUG(2,("WOW32: Warning! %s: Function %i %s is not implemented.\n",
  705. GetModName(iFun),
  706. GetOrdinal(iFun),
  707. aw32WOW[iFun].lpszW32
  708. ));
  709. //
  710. // After complaining once about each API, patch the thunk table so
  711. // future calls to the API will (mostly) silently slip by in WOW32NopAPI.
  712. //
  713. aw32WOW[iFun].lpfnW32 = WOW32NopAPI;
  714. #else
  715. UNREFERENCED_PARAMETER(pFrame);
  716. #endif
  717. return FALSE;
  718. }
  719. #ifdef DEBUG
  720. /* WOW32Unimplemented95API - Error Thunk is Not Implemented
  721. *
  722. * Stub thunk table entry for Win95 unimplemented APIs on
  723. * the checked build, and for now on the free build as well.
  724. *
  725. * ENTRY
  726. *
  727. * EXIT
  728. *
  729. */
  730. ULONG FASTCALL WOW32Unimplemented95API(PVDMFRAME pFrame)
  731. {
  732. INT iFun;
  733. iFun = pFrame->wCallID;
  734. WOW32ASSERTMSGF (FALSE, ("New-for-Win95/NT5 %s API %s #%i not implemented, contact DaveHart.\n",
  735. GetModName(iFun),
  736. aw32WOW[iFun].lpszW32,
  737. GetOrdinal(iFun)
  738. ));
  739. //
  740. // After complaining once about each API, patch the thunk table so
  741. // future calls to the API will silently slip by.
  742. //
  743. aw32WOW[iFun].lpfnW32 = NOPAPI;
  744. return FALSE;
  745. }
  746. /* WOW32NopAPI - Thunk to do nothing - checked build only.
  747. *
  748. * All Function tables point here for APIs which should do nothing.
  749. *
  750. * ENTRY
  751. *
  752. * EXIT
  753. *
  754. */
  755. ULONG FASTCALL WOW32NopAPI(PVDMFRAME pFrame)
  756. {
  757. INT iFun;
  758. iFun = pFrame->wCallID;
  759. LOGDEBUG(4,("%s: Function %i %s is NOP'd\n", GetModName(iFun), GetOrdinal(iFun), aw32WOW[iFun].lpszW32));
  760. return FALSE;
  761. }
  762. /* WOW32LocalAPI - ERROR Should Have Been Handled in 16 BIT
  763. * Checked build only
  764. *
  765. * All Function tables point here for Local API Error Messages
  766. *
  767. * ENTRY
  768. * Module startup registers:
  769. *
  770. * EXIT
  771. *
  772. *
  773. */
  774. ULONG FASTCALL WOW32LocalAPI(PVDMFRAME pFrame)
  775. {
  776. INT iFun;
  777. iFun = pFrame->wCallID;
  778. WOW32ASSERTMSGF (FALSE, ("Error - %s: Function %i %s should be handled by 16-bit code\n",
  779. GetModName(iFun),
  780. GetOrdinal(iFun),
  781. aw32WOW[iFun].lpszW32
  782. ));
  783. return FALSE;
  784. }
  785. #endif // DEBUG
  786. LPFNW32 FASTCALL W32PatchCodeWithLpfnw32(PVDMFRAME pFrame , LPFNW32 lpfnW32 )
  787. {
  788. VPVOID vpCode;
  789. LPBYTE lpCode;
  790. #ifdef DEBUG
  791. INT iFun = pFrame->wCallID;
  792. #endif
  793. #ifdef DEBUG_OR_WOWPROFILE
  794. //
  795. // On checked builds do not patch calls to the 4 special
  796. // thunks above, since many entries will point to each one,
  797. // the routines could not easily distinguish which 16-bit
  798. // entrypoint was called.
  799. //
  800. if (flOptions & OPT_DONTPATCHCODE ||
  801. lpfnW32 == UNIMPLEMENTEDAPI ||
  802. lpfnW32 == UNIMPLEMENTED95API ||
  803. lpfnW32 == NOPAPI ||
  804. lpfnW32 == LOCALAPI ) {
  805. goto Done;
  806. }
  807. #endif
  808. //
  809. // just return the thunk function if called in real mode
  810. //
  811. if (!fWowMode) {
  812. goto Done;
  813. }
  814. // the thunk looks like so.
  815. //
  816. // push HI_WCALLID (3bytes) - 0th byte is opcode.
  817. // push 0xfnid (3bytes)
  818. // call wow16call (5bytes)
  819. // ThunksCSIP:
  820. //
  821. // point to the 1st word (the hiword)
  822. vpCode = (DWORD)pFrame->wThunkCSIP - (0x5 + 0x3 + 0x2);
  823. WOW32ASSERT(HI_WCALLID == 0); // we need to revisit wow32.c if this
  824. // value is changed to a non-zero value
  825. WOW32ASSERT(HIWORD(iFun) == HI_WCALLID);
  826. GETVDMPTR(vpCode, 0x2 + 0x3, lpCode);
  827. WOW32ASSERT(lpCode != NULL);
  828. WOW32ASSERT(*(PWORD16)(lpCode) == HIWORD(iFun));
  829. WOW32ASSERT(*(PWORD16)(lpCode+0x3) == LOWORD(iFun));
  830. *((PWORD16)lpCode) = HIWORD((DWORD)lpfnW32);
  831. lpCode += 0x3; // seek to the 2nd word (the loword)
  832. *((PWORD16)lpCode) = LOWORD((DWORD)lpfnW32);
  833. FLUSHVDMCODEPTR(vpCode, 0x2 + 0x3, lpCode);
  834. FREEVDMPTR(lpCode);
  835. Done:
  836. return lpfnW32;
  837. }
  838. /* W32Dispatch - Recipient of all WOW16 API calls (sort of)
  839. *
  840. * "sort of" means that the word "all" above hasn't been true since 8/93:
  841. * 1. Most calls to the 16-bit kernel are handled by krnl386.exe on the
  842. * 16-bit side (this has always been true).
  843. * 2. A FEW (MulDiv, GetMetaFileBits, SetMetaFileBits) GDI API's are thunked
  844. * by GDI.exe in 16-bit land.
  845. * 3. There is an "Interpreted Thunk" mechanism which thunks API's that have
  846. * relatively simple parameter thunks (ie. int16 -> int32, str16->str32,
  847. * and no structs) and require no special hacks. The code for these thunks
  848. * is generated at compile time. See mvdm\wow32\genwowit.txt for a brief
  849. * description of how this works. See wow.it for the list of API's that are
  850. * currently handled by this mechanism. If an API does require a special
  851. * hack, it will need to be yanked from the list in wow.it and the dispatch
  852. * table macro, IT() (currently only used in: wgtbl2.h, wkbdtbl2.h,
  853. * wktbl2.h, and wutbl2.h), must be updated as appropriate. The new thunk
  854. * will have to be hand coded as the rest of our thunks are.
  855. * 4. On CHECKED x86 builds & ALL RISC builds, all API's not subject to the
  856. * above exceptions are dispatched through this function.
  857. * - That's about it -- until we change it again, in which case this note
  858. * could be terribly misleading. cmjones 10/08/97
  859. *
  860. * Having said that:
  861. * This routine dispatches to the relavant WOW thunk routine via
  862. * jump tables wktbl.c wutbl.c wgtbl.c based on a function id on the 16 bit
  863. * stack.
  864. *
  865. * In debug versions it also calls routines to log parameters.
  866. *
  867. * ENTRY
  868. * None (x86 registers contain parameters)
  869. *
  870. * EXIT
  871. * None (x86 registers/memory updated appropriately)
  872. */
  873. VOID W32Dispatch()
  874. {
  875. INT iFun;
  876. ULONG ulReturn;
  877. DWORD dwThunkCSIP;
  878. VPVOID vpCurrentStack;
  879. register PTD ptd;
  880. register PVDMFRAME pFrame;
  881. #ifdef DEBUG_OR_WOWPROFILE
  882. INT iFunT;
  883. #endif
  884. #ifdef WOWPROFILE
  885. LONGLONG dwTics;
  886. #endif
  887. try {
  888. vpCurrentStack = VDMSTACK(); // Get 16 bit ss:sp
  889. // Use WOWGetVDMPointer here since we can get called in RealMode on
  890. // Errors
  891. pFrame = WOWGetVDMPointer(vpCurrentStack, sizeof(VDMFRAME), fWowMode);
  892. ptd = CURRENTPTD(); // Setup Task Pointer
  893. ptd->vpStack = vpCurrentStack; // Save 16 bit ss:sp
  894. // ssync 16-bit & 32-bit common dialog structs (see wcommdlg.c)
  895. if(ptd->CommDlgTd) {
  896. dwThunkCSIP = (DWORD)(pFrame->wThunkCSIP);
  897. Ssync_WOW_CommDlg_Structs(ptd->CommDlgTd, w16to32, dwThunkCSIP);
  898. }
  899. WOW32ASSERT( FIELD_OFFSET(TD,vpStack) == 0 );
  900. LOGARGS(3,pFrame); // Perform Function Logging
  901. iFun = pFrame->wCallID;
  902. #ifdef DEBUG_OR_WOWPROFILE
  903. iFunT = ISFUNCID(iFun) ? iFun : GetFuncId(iFun) ;
  904. #endif
  905. if (ISFUNCID(iFun)) {
  906. #ifdef DEBUG
  907. if (cAPIThunks && iFunT >= cAPIThunks) {
  908. LOGDEBUG(LOG_ALWAYS,("W32Dispatch: Task %04x thunked to function %d, cAPIThunks = %d.\n",
  909. pFrame->wTDB, iFunT, cAPIThunks));
  910. WOW32ASSERT(FALSE);
  911. }
  912. #endif
  913. iFun = (INT)aw32WOW[iFun].lpfnW32;
  914. if ( ! HIWORD(iFun)) {
  915. #ifdef WOWPROFILE // For API profiling only (debugger extension)
  916. dwTics = GetWOWTicDiff(0I64);
  917. #endif // WOWPROFILE
  918. ulReturn = InterpretThunk(pFrame, iFun);
  919. goto AfterApiCall;
  920. } else {
  921. W32PatchCodeWithLpfnw32(pFrame, (LPFNW32)iFun);
  922. }
  923. }
  924. #ifdef WOWPROFILE // For API profiling only (debugger extension)
  925. dwTics = GetWOWTicDiff(0I64);
  926. #endif // WOWPROFILE
  927. ulReturn = (*((LPFNW32)iFun))(pFrame); // Dispatch to Thunk
  928. AfterApiCall:
  929. // ssync 16-bit & 32-bit common dialog structs (see wcommdlg.c)
  930. if(ptd->CommDlgTd) {
  931. Ssync_WOW_CommDlg_Structs(ptd->CommDlgTd, w32to16, dwThunkCSIP);
  932. }
  933. #ifdef WOWPROFILE // For API profiling only (debugger extension)
  934. dwTics = GetWOWTicDiff(dwTics);
  935. iFun = iFunT;
  936. // add time ellapsed for call to total
  937. aw32WOW[iFun].cTics += dwTics;
  938. aw32WOW[iFun].cCalls++; // inc # times this API called
  939. #endif // WOWPROFILE
  940. FREEVDMPTR(pFrame); // Set the 16-bit return code
  941. GETFRAMEPTR(ptd->vpStack, pFrame);
  942. LOGRETURN(5,pFrame,ulReturn); // Log return Values
  943. pFrame->wAX = LOW(ulReturn); // Pass Back Return Value form thunk
  944. pFrame->wDX = HIW(ulReturn);
  945. #ifdef DEBUG
  946. // If OPT_DEBUGRETURN is set, diddle the RetID as approp.
  947. if (flOptions & OPT_DEBUGRETURN) {
  948. if (pFrame->wRetID == RET_RETURN) {
  949. pFrame->wRetID = RET_DEBUGRETURN;
  950. flOptions &= ~OPT_DEBUGRETURN;
  951. }
  952. }
  953. // Put the current logging level where 16-bit code can get it
  954. // Use ROMBIOS Hard DISK information as a safe address
  955. *(PBYTE)GetVDMAddr(0x0040,0x0042) = (BYTE)(iLogLevel/10+'0');
  956. *(PBYTE)GetVDMAddr(0x0040,0x0043) = (BYTE)(iLogLevel%10+'0');
  957. #endif // DEBUG
  958. FREEVDMPTR(pFrame);
  959. SETVDMSTACK(ptd->vpStack);
  960. } except (W32Exception(GetExceptionCode(), GetExceptionInformation())) {
  961. }
  962. }
  963. /* W32Exception - Handle WOW32 thread exceptions
  964. *
  965. * ENTRY
  966. * None (x86 registers contain parameters)
  967. *
  968. * EXIT
  969. * None (x86 registers/memory updated appropriately)
  970. *
  971. */
  972. INT W32Exception(DWORD dwException, PEXCEPTION_POINTERS pexi)
  973. {
  974. PTD ptd;
  975. PVDMFRAME pFrame;
  976. int len;
  977. DWORD dwButtonPushed;
  978. char szTask[9];
  979. HMODULE hModule;
  980. char szModule[_MAX_PATH + 1];
  981. PSZ pszModuleFilePart;
  982. PSZ pszErrorFormatString;
  983. char szErrorMessage[TOOLONGLIMIT + 4*WARNINGMSGLENGTH];
  984. char szDialogText[TOOLONGLIMIT + 4*WARNINGMSGLENGTH];
  985. PTDB pTDB;
  986. NTSTATUS Status;
  987. HANDLE DebugPort;
  988. PRTL_CRITICAL_SECTION PebLockPointer;
  989. CHAR AeDebuggerCmdLine[256];
  990. CHAR AeAutoDebugString[8];
  991. BOOL AeAutoDebug;
  992. WORD wDebugButton;
  993. if (!gfDebugExceptions) {
  994. //
  995. // If the process is being debugged, just let the exception happen
  996. // so that the debugger can see it. This way the debugger can ignore
  997. // all first chance exceptions.
  998. //
  999. DebugPort = (HANDLE)NULL;
  1000. Status = NtQueryInformationProcess(
  1001. GetCurrentProcess(),
  1002. ProcessDebugPort,
  1003. (PVOID)&DebugPort,
  1004. sizeof(DebugPort),
  1005. NULL
  1006. );
  1007. if ( NT_SUCCESS(Status) && DebugPort) {
  1008. //
  1009. // Process is being debugged.
  1010. // Return a code that specifies that the exception
  1011. // processing is to continue
  1012. //
  1013. return EXCEPTION_CONTINUE_SEARCH;
  1014. }
  1015. }
  1016. //
  1017. // NtClose can raise exceptions if NtGlobalFlag is set for it.
  1018. // We want to ignore these exceptions if we're not being debugged,
  1019. // since the errors will be returned from the APIs and we generally
  1020. // don't have control over what handles the app closes. (Well, that's
  1021. // not true for file I/O, but it is true for RegCloseKey.)
  1022. //
  1023. if (STATUS_INVALID_HANDLE == dwException ||
  1024. STATUS_HANDLE_NOT_CLOSABLE == dwException) {
  1025. return EXCEPTION_CONTINUE_EXECUTION;
  1026. }
  1027. //
  1028. // See if a debugger has been programmed in. If so, use the
  1029. // debugger specified. If not then there is no AE Cancel support
  1030. // DEVL systems will default the debugger command line. Retail
  1031. // systems will not.
  1032. //
  1033. // The above paragraph was copied from the system exception
  1034. // popup in base. It is no longer true. On retail systems,
  1035. // AeDebug.Auto is set to 1 and AeDebug.Debugger is
  1036. // "drwtsn32 -p %ld -e %ld -g".
  1037. //
  1038. // This means if we support AeDebug for stress, customers don't see
  1039. // our exception popup and misalignment handling -- instead they get
  1040. // a nearly-useless drwtsn32.log and popup.
  1041. //
  1042. // SO, we check for this situation and act as if no debugger was
  1043. // enabled.
  1044. //
  1045. wDebugButton = 0;
  1046. AeAutoDebug = FALSE;
  1047. //
  1048. // If we are holding the PebLock, then the createprocess will fail
  1049. // because a new thread will also need this lock. Avoid this by peeking
  1050. // inside the PebLock and looking to see if we own it. If we do, then just allow
  1051. // a regular popup.
  1052. //
  1053. PebLockPointer = NtCurrentPeb()->FastPebLock;
  1054. if ( PebLockPointer->OwningThread != NtCurrentTeb()->ClientId.UniqueThread ) {
  1055. try {
  1056. if ( GetProfileString(
  1057. "AeDebug",
  1058. "Debugger",
  1059. NULL,
  1060. AeDebuggerCmdLine,
  1061. sizeof(AeDebuggerCmdLine)-1
  1062. ) ) {
  1063. wDebugButton = SEB_CANCEL;
  1064. if ( GetProfileString(
  1065. "AeDebug",
  1066. "Auto",
  1067. "0",
  1068. AeAutoDebugString,
  1069. sizeof(AeAutoDebugString)-1
  1070. ) ) {
  1071. if ( !WOW32_strcmp(AeAutoDebugString,"1") ) {
  1072. AeAutoDebug = TRUE;
  1073. }
  1074. }
  1075. }
  1076. } except (EXCEPTION_EXECUTE_HANDLER) {
  1077. wDebugButton = 0;
  1078. AeAutoDebug = FALSE;
  1079. }
  1080. }
  1081. //
  1082. // See comment above about drwtsn32
  1083. //
  1084. if (AeAutoDebug &&
  1085. !WOW32_strnicmp(AeDebuggerCmdLine, szDrWtsn32, (sizeof szDrWtsn32) - 1)) {
  1086. wDebugButton = 0;
  1087. AeAutoDebug = FALSE;
  1088. }
  1089. ptd = CURRENTPTD();
  1090. GETFRAMEPTR(ptd->vpStack, pFrame);
  1091. pTDB = (PVOID)SEGPTR(ptd->htask16,0);
  1092. //
  1093. // Get a zero-terminated copy of the Win16 task name.
  1094. //
  1095. RtlZeroMemory(szTask, sizeof(szTask));
  1096. RtlCopyMemory(szTask, pTDB->TDB_ModName, sizeof(szTask)-1);
  1097. //
  1098. // Translate exception address to module name in szModule.
  1099. //
  1100. len = strlen(CRITSTR(TheWin16Subsystem)) + 1;
  1101. len = min(len, sizeof(szModule));
  1102. strncpy(szModule, CRITSTR(TheWin16Subsystem), len);
  1103. szModule[len-1] = '\0';
  1104. RtlPcToFileHeader(pexi->ExceptionRecord->ExceptionAddress, (PVOID *)&hModule);
  1105. GetModuleFileName(hModule, szModule, sizeof(szModule));
  1106. pszModuleFilePart = WOW32_strrchr(szModule, '\\');
  1107. if (pszModuleFilePart) {
  1108. pszModuleFilePart++;
  1109. } else {
  1110. pszModuleFilePart = szModule;
  1111. }
  1112. //
  1113. // Format error message into szErrorMessage
  1114. //
  1115. switch (dwException) {
  1116. case EXCEPTION_ACCESS_VIOLATION:
  1117. pszErrorFormatString = CRITSTR(CausedAV);
  1118. break;
  1119. case EXCEPTION_STACK_OVERFLOW:
  1120. pszErrorFormatString = CRITSTR(CausedStackOverflow);
  1121. break;
  1122. case EXCEPTION_DATATYPE_MISALIGNMENT:
  1123. pszErrorFormatString = CRITSTR(CausedAlignmentFault);
  1124. break;
  1125. case EXCEPTION_ILLEGAL_INSTRUCTION:
  1126. case EXCEPTION_PRIV_INSTRUCTION:
  1127. pszErrorFormatString = CRITSTR(CausedIllegalInstr);
  1128. break;
  1129. case EXCEPTION_IN_PAGE_ERROR:
  1130. pszErrorFormatString = CRITSTR(CausedInPageError);
  1131. break;
  1132. case EXCEPTION_INT_DIVIDE_BY_ZERO:
  1133. pszErrorFormatString = CRITSTR(CausedIntDivideZero);
  1134. break;
  1135. case EXCEPTION_FLT_DENORMAL_OPERAND:
  1136. case EXCEPTION_FLT_DIVIDE_BY_ZERO:
  1137. case EXCEPTION_FLT_INEXACT_RESULT:
  1138. case EXCEPTION_FLT_INVALID_OPERATION:
  1139. case EXCEPTION_FLT_OVERFLOW:
  1140. case EXCEPTION_FLT_STACK_CHECK:
  1141. case EXCEPTION_FLT_UNDERFLOW:
  1142. pszErrorFormatString = CRITSTR(CausedFloatException);
  1143. break;
  1144. default:
  1145. pszErrorFormatString = CRITSTR(CausedException);
  1146. }
  1147. _snprintf(szErrorMessage,
  1148. sizeof(szErrorMessage)-1,
  1149. pszErrorFormatString,
  1150. szTask,
  1151. pszModuleFilePart,
  1152. pexi->ExceptionRecord->ExceptionAddress,
  1153. dwException
  1154. );
  1155. szErrorMessage[sizeof(szErrorMessage)-1] = '\0';
  1156. LOGDEBUG(LOG_ALWAYS, ("W32Exception:\n%s\n",szErrorMessage));
  1157. //
  1158. // Format dialog text into szDialogText and display.
  1159. //
  1160. if (AeAutoDebug) {
  1161. dwButtonPushed = 2;
  1162. } else {
  1163. if (wDebugButton == SEB_CANCEL) {
  1164. _snprintf(szDialogText,
  1165. sizeof(szDialogText)-1,
  1166. "%s\n%s\n%s\n%s\n",
  1167. szErrorMessage,
  1168. CRITSTR(ChooseClose),
  1169. CRITSTR(ChooseCancel),
  1170. (dwException == EXCEPTION_DATATYPE_MISALIGNMENT)
  1171. ? CRITSTR(ChooseIgnoreAlignment)
  1172. : CRITSTR(ChooseIgnore)
  1173. );
  1174. szDialogText[sizeof(szDialogText)-1] = '\0';
  1175. } else {
  1176. _snprintf(szDialogText,
  1177. sizeof(szDialogText)-1,
  1178. "%s\n%s\n%s\n",
  1179. szErrorMessage,
  1180. CRITSTR(ChooseClose),
  1181. (dwException == EXCEPTION_DATATYPE_MISALIGNMENT)
  1182. ? CRITSTR(ChooseIgnoreAlignment)
  1183. : CRITSTR(ChooseIgnore)
  1184. );
  1185. szDialogText[sizeof(szDialogText)-1] = '\0';
  1186. }
  1187. dwButtonPushed = WOWSysErrorBox(
  1188. CRITSTR(ApplicationError),
  1189. szDialogText,
  1190. SEB_CLOSE,
  1191. wDebugButton,
  1192. SEB_IGNORE | SEB_DEFBUTTON
  1193. );
  1194. }
  1195. //
  1196. // If CANCEL is chosen Launch Debugger.
  1197. //
  1198. if (dwButtonPushed == 2) {
  1199. BOOL b;
  1200. STARTUPINFO StartupInfo;
  1201. PROCESS_INFORMATION ProcessInformation;
  1202. CHAR CmdLine[256];
  1203. NTSTATUS ntStatus;
  1204. HANDLE EventHandle;
  1205. SECURITY_ATTRIBUTES sa;
  1206. sa.nLength = sizeof(sa);
  1207. sa.lpSecurityDescriptor = NULL;
  1208. sa.bInheritHandle = TRUE;
  1209. EventHandle = CreateEvent(&sa,TRUE,FALSE,NULL);
  1210. RtlZeroMemory(&StartupInfo,sizeof(StartupInfo));
  1211. sprintf(CmdLine,AeDebuggerCmdLine,GetCurrentProcessId(),EventHandle);
  1212. StartupInfo.cb = sizeof(StartupInfo);
  1213. StartupInfo.lpDesktop = "Winsta0\\Default";
  1214. CsrIdentifyAlertableThread();
  1215. b = CreateProcess(
  1216. NULL,
  1217. CmdLine,
  1218. NULL,
  1219. NULL,
  1220. TRUE,
  1221. 0,
  1222. NULL,
  1223. NULL,
  1224. &StartupInfo,
  1225. &ProcessInformation
  1226. );
  1227. if ( b && EventHandle) {
  1228. //
  1229. // Do an alertable wait on the event
  1230. //
  1231. ntStatus = NtWaitForSingleObject(
  1232. EventHandle,
  1233. TRUE,
  1234. NULL
  1235. );
  1236. return EXCEPTION_CONTINUE_SEARCH;
  1237. } else {
  1238. LOGDEBUG(0, ("W32Exception unable to start debugger.\n"));
  1239. goto KillTask;
  1240. }
  1241. }
  1242. //
  1243. // If IGNORE is chosen and it's an EXCEPTION_DATATYPE_MISALIGNMENT,
  1244. // turn on software emulation of misaligned access and restart the
  1245. // faulting instruction. Otherwise, just fail the API and continue.
  1246. //
  1247. if (dwButtonPushed == 3) {
  1248. if (dwException == EXCEPTION_DATATYPE_MISALIGNMENT) {
  1249. SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT);
  1250. LOGDEBUG(0, ("W32Exception disabling alignment fault exceptions at user's request.\n"));
  1251. return EXCEPTION_CONTINUE_EXECUTION;
  1252. }
  1253. LOGDEBUG(0, ("W32Exception ignoring at user's request via EXCEPTION_EXECUTE_HANDLER\n"));
  1254. return EXCEPTION_EXECUTE_HANDLER;
  1255. }
  1256. //
  1257. // If user typed CLOSE or Any of the above fail,
  1258. // force just the task to die.
  1259. //
  1260. KillTask:
  1261. LOGDEBUG(0, ("W32Exception killing task via RET_FORCETASKEXIT\n"));
  1262. GETFRAMEPTR(ptd->vpStack, pFrame);
  1263. pFrame->wRetID = RET_FORCETASKEXIT;
  1264. return EXCEPTION_EXECUTE_HANDLER;
  1265. }
  1266. #ifdef DEBUG
  1267. VOID StartDebuggerForWow(VOID)
  1268. /*++
  1269. Routine Description:
  1270. This routine checks to see if there's a debugger attached to WOW. If not,
  1271. it attempts to spawn one with a command to attach to WOW. If the system
  1272. was booted with /DEBUG in boot.ini (kernel debugger enabled), we'll run
  1273. "ntsd -d" otherwise we'll run "ntsd".
  1274. Arguments:
  1275. None.
  1276. Return Value:
  1277. None.
  1278. --*/
  1279. {
  1280. BOOL fKernelDebuggerEnabled, b;
  1281. NTSTATUS Status;
  1282. SYSTEM_KERNEL_DEBUGGER_INFORMATION KernelDebuggerInformation;
  1283. ULONG ulReturnLength;
  1284. SECURITY_ATTRIBUTES sa;
  1285. STARTUPINFO StartupInfo;
  1286. PROCESS_INFORMATION ProcessInformation;
  1287. CHAR szCmdLine[256];
  1288. HANDLE hEvent;
  1289. //
  1290. // Are we being run under a debugger ?
  1291. //
  1292. if (IsDebuggerAttached()) {
  1293. //
  1294. // No need to start one.
  1295. //
  1296. return;
  1297. }
  1298. //
  1299. // Is the kernel debugger enabled?
  1300. //
  1301. Status = NtQuerySystemInformation(
  1302. SystemKernelDebuggerInformation,
  1303. &KernelDebuggerInformation,
  1304. sizeof(KernelDebuggerInformation),
  1305. &ulReturnLength
  1306. );
  1307. if (NT_SUCCESS(Status) &&
  1308. (ulReturnLength >= sizeof(KernelDebuggerInformation))) {
  1309. fKernelDebuggerEnabled = KernelDebuggerInformation.KernelDebuggerEnabled;
  1310. } else {
  1311. fKernelDebuggerEnabled = FALSE;
  1312. LOGDEBUG(0,("StartDebuggerForWow: NtQuerySystemInformation(kdinfo) returns 0x%8.8x, return length 0x%08x.\n",
  1313. Status, ulReturnLength));
  1314. }
  1315. //
  1316. // Create an event for NTSD to signal once it has fully connected
  1317. // and is ready for the exception. We force the handle to be inherited.
  1318. //
  1319. sa.nLength = sizeof(sa);
  1320. sa.lpSecurityDescriptor = NULL;
  1321. sa.bInheritHandle = TRUE;
  1322. hEvent = CreateEvent(&sa, TRUE, FALSE, NULL);
  1323. //
  1324. // Build debugger command line.
  1325. //
  1326. _snprintf(szCmdLine,
  1327. sizeof(szCmdLine)-1,
  1328. "ntsd %s -p %lu -e %lu -x -g -G",
  1329. fKernelDebuggerEnabled ? "-d" : "",
  1330. GetCurrentProcessId(),
  1331. hEvent
  1332. );
  1333. szCmdLine[sizeof(szCmdLine)-1] = '\0';
  1334. RtlZeroMemory(&StartupInfo,sizeof(StartupInfo));
  1335. StartupInfo.cb = sizeof(StartupInfo);
  1336. b = CreateProcess(
  1337. NULL,
  1338. szCmdLine,
  1339. NULL,
  1340. NULL,
  1341. TRUE, // fInheritHandles
  1342. CREATE_DEFAULT_ERROR_MODE,
  1343. NULL,
  1344. NULL,
  1345. &StartupInfo,
  1346. &ProcessInformation
  1347. );
  1348. if (b) {
  1349. CloseHandle(ProcessInformation.hProcess);
  1350. CloseHandle(ProcessInformation.hThread);
  1351. if (hEvent) {
  1352. //
  1353. // Wait for debugger to initialize.
  1354. //
  1355. WaitForSingleObject(hEvent, INFINITE);
  1356. }
  1357. }
  1358. CloseHandle(hEvent);
  1359. return;
  1360. }
  1361. #endif // DEBUG
  1362. BOOL IsDebuggerAttached(VOID)
  1363. /*++
  1364. Routine Description:
  1365. Checks to see if there's a debugger attached to WOW. If there is,
  1366. this routine also turns on a bit in the 16-bit kernel's DS so it
  1367. can do its part to report debug events.
  1368. Arguments:
  1369. None.
  1370. Return Value:
  1371. FALSE - no debugger attached or NtQueryInformationProcess fails.
  1372. TRUE - debugger is definitely attached.
  1373. --*/
  1374. {
  1375. NTSTATUS Status;
  1376. HANDLE MyDebugPort;
  1377. LPBYTE lpDebugWOW;
  1378. static BOOL fDebuggerAttached = FALSE;
  1379. static BOOL fKernel16Notified = FALSE;
  1380. //
  1381. // Don't bother checking if we already have been told that
  1382. // there is a debugger attached, since debuggers cannot detach.
  1383. //
  1384. if (!fDebuggerAttached) {
  1385. //
  1386. // Query our ProcessDebugPort, if it is nonzero we have
  1387. // a debugger attached.
  1388. //
  1389. Status = NtQueryInformationProcess(
  1390. NtCurrentProcess(),
  1391. ProcessDebugPort,
  1392. (PVOID)&MyDebugPort,
  1393. sizeof(MyDebugPort),
  1394. NULL
  1395. );
  1396. fDebuggerAttached = NT_SUCCESS(Status) && (MyDebugPort != NULL);
  1397. }
  1398. //
  1399. // If we have a debugger attached share that information
  1400. // with the 16-bit kernel.
  1401. //
  1402. if (!fKernel16Notified && fDebuggerAttached && vpDebugWOW != 0) {
  1403. GETVDMPTR(vpDebugWOW, 1, lpDebugWOW);
  1404. *lpDebugWOW |= 1;
  1405. FREEVDMPTR(lpDebugWOW);
  1406. DBGNotifyDebugged( TRUE );
  1407. fKernel16Notified = TRUE;
  1408. }
  1409. return fDebuggerAttached;
  1410. }
  1411. void *
  1412. WOWGetVDMPointer(
  1413. VPVOID Address,
  1414. DWORD Count,
  1415. BOOL ProtectedMode
  1416. )
  1417. /*++
  1418. Routine Description:
  1419. This routine converts a 16/16 address to a linear address.
  1420. WARNING NOTE - This routine has been optimized so protect mode LDT lookup
  1421. falls stright through.
  1422. Arguments:
  1423. Address -- specifies the address in seg:offset format
  1424. Size -- specifies the size of the region to be accessed.
  1425. ProtectedMode -- true if the address is a protected mode address
  1426. Return Value:
  1427. The pointer.
  1428. --*/
  1429. {
  1430. if (ProtectedMode) {
  1431. return GetPModeVDMPointer(Address, Count);
  1432. } else {
  1433. return GetRModeVDMPointer(Address);
  1434. }
  1435. }
  1436. PVOID FASTCALL
  1437. GetPModeVDMPointerAssert(
  1438. DWORD Address
  1439. #ifdef DEBUG
  1440. , DWORD Count
  1441. #endif
  1442. )
  1443. /*++
  1444. Routine Description:
  1445. Convert a 16:16 protected mode address to the equivalent flat pointer.
  1446. Arguments:
  1447. Address -- specifies the address in selector:offset format
  1448. Return Value:
  1449. The pointer.
  1450. --*/
  1451. {
  1452. #ifdef DEBUG
  1453. void *vp;
  1454. #endif
  1455. // what to do if this assert fires?? Currently "nothing" seems to work OK.
  1456. WOW32WARNMSG((ExpLdt),("WOW::GetPModeVDMPointerAssert: ExpLdt == NULL\n"));
  1457. //
  1458. // Check to see if the descriptor is marked present
  1459. // We assume here that ExpLdt is DWORD ALIGNED to avoid a slower
  1460. // unaligned access on risc.
  1461. //
  1462. if (!((ExpLdt)[(Address >> 18) | 1] & LDT_DESC_PRESENT)) {
  1463. PARM16 Parm16;
  1464. ULONG ul;
  1465. if ((HIWORD(Address) & STD_SELECTOR_BITS) == STD_SELECTOR_BITS) {
  1466. // We've determined that the selector is valid and not
  1467. // present. So we call over to kernel16 to have it load
  1468. // the selector into a segment register. This forces a
  1469. // segment fault, and the segment should be brought in.
  1470. // Note that CallBack16 also calls this routine, so we could
  1471. // theoretically get into an infinite recursion loop here.
  1472. // This could only happen if selectors like the 16-bit stack
  1473. // were not present, which would mean we are hosed anyway.
  1474. // Such a loop should terminate with a stack fault eventually.
  1475. Parm16.WndProc.lParam = (LONG) Address;
  1476. CallBack16(RET_FORCESEGMENTFAULT, &Parm16, 0, &ul);
  1477. } else {
  1478. // We come here if the address can't be resolved. A null
  1479. // selector is special-cased to allow for a null 16:16
  1480. // pointer to be passed.
  1481. if (HIWORD(Address)) {
  1482. LOGDEBUG(LOG_ALWAYS,("WOW::GetVDMPointer: *** Invalid 16:16 address %04x:%04x\n",
  1483. HIWORD(Address), LOWORD(Address)));
  1484. // If we get here, then we are about to return a bogus
  1485. // flat pointer.
  1486. // I would prefer to eventually assert this, but it
  1487. // appears to be overactive for winfax lite.
  1488. //WOW32ASSERT(FALSE);
  1489. }
  1490. }
  1491. }
  1492. #ifdef DEBUG
  1493. if (vp = GetPModeVDMPointerMacro(Address, Count)) {
  1494. #ifdef _X86_
  1495. //
  1496. // Check the selector limit on x86 only and return NULL if
  1497. // the limit is too small.
  1498. //
  1499. if (SelectorLimit &&
  1500. (Address & 0xFFFF) + Count > SelectorLimit[Address >> 19] + 1)
  1501. {
  1502. WOW32ASSERTMSGF (FALSE, ("WOW32 limit check assertion: %04x:%04x size %x is beyond limit %x.\n",
  1503. Address >> 16,
  1504. Address & 0xFFFF,
  1505. Count,
  1506. SelectorLimit[Address >> 19]
  1507. ));
  1508. return vp;
  1509. }
  1510. #endif
  1511. #if 0 // this code is a paranoid check, only useful when debugging GetPModeVDMPointer.
  1512. if (vp != Sim32GetVDMPointer(Address, Count, TRUE)) {
  1513. LOGDEBUG(LOG_ALWAYS,
  1514. ("GetPModeVDMPointer: GetPModeVDMPointerMacro(%x) returns %x, Sim32 returns %x!\n",
  1515. Address, vp, Sim32GetVDMPointer(Address, Count, TRUE)));
  1516. vp = Sim32GetVDMPointer(Address, Count, TRUE);
  1517. }
  1518. #endif
  1519. return vp;
  1520. } else {
  1521. return NULL;
  1522. }
  1523. #else
  1524. return GetPModeVDMPointerMacro(Address, 0); // No limit check on free build.
  1525. #endif // DEBUG
  1526. }
  1527. ULONG FASTCALL WK32WOWGetFastAddress( PVDMFRAME pFrame )
  1528. {
  1529. return 0;
  1530. }
  1531. ULONG FASTCALL WK32WOWGetFastCbRetAddress( PVDMFRAME pFrame )
  1532. {
  1533. return( 0L );
  1534. }
  1535. ULONG FASTCALL WK32WOWGetTableOffsets( PVDMFRAME pFrame )
  1536. {
  1537. PWOWGETTABLEOFFSETS16 parg16;
  1538. PTABLEOFFSETS pto16;
  1539. GETARGPTR(pFrame, sizeof(PDWORD16), parg16);
  1540. GETVDMPTR(parg16->vpThunkTableOffsets, sizeof(TABLEOFFSETS), pto16);
  1541. RtlCopyMemory(pto16, &tableoffsets, sizeof(TABLEOFFSETS));
  1542. FLUSHVDMPTR(parg16->vpThunkTableOffsets, sizeof(TABLEOFFSETS), pto16);
  1543. FREEVDMPTR(pto16);
  1544. FREEARGPTR(parg16);
  1545. return 1;
  1546. }
  1547. ULONG FASTCALL WK32WOWGetFlatAddressArray( PVDMFRAME pFrame )
  1548. {
  1549. return (ULONG)FlatAddress;
  1550. }
  1551. #ifdef DEBUG
  1552. /*
  1553. * DoAssert - do an assertion. called after the expression has been evaluted
  1554. *
  1555. * Input:
  1556. *
  1557. *
  1558. * Note if the requested log level is not what we want we don't output
  1559. * but we always output to the circular buffer - just in case.
  1560. *
  1561. *
  1562. */
  1563. int DoAssert(PSZ szAssert, PSZ szModule, UINT line, UINT loglevel)
  1564. {
  1565. INT savefloptions;
  1566. //
  1567. // Start a debugger for WOW if there isn't already one.
  1568. //
  1569. // Until now StartDebuggerForWow was started by
  1570. // the exception filter, which meant asserts on a
  1571. // checked build got the debugger but the user didn't see
  1572. // the assertion text on the debugger screen because
  1573. // logprintf was called before the debugger attached.
  1574. // -- DaveHart 31-Jan-95
  1575. //
  1576. StartDebuggerForWow();
  1577. savefloptions = flOptions;
  1578. flOptions |= OPT_DEBUG; // *always* print the message
  1579. //
  1580. // szAssert is NULL for bare-bones WOW32ASSERT()
  1581. //
  1582. if (szAssert == NULL) {
  1583. LOGDEBUG(loglevel, ("WOW32 assertion failure: %s line %d\n", szModule, line));
  1584. } else {
  1585. LOGDEBUG(loglevel, ("%s", szAssert));
  1586. }
  1587. flOptions = savefloptions;
  1588. if (IsDebuggerAttached()) {
  1589. DbgBreakPoint();
  1590. } else {
  1591. DWORD dw = SetErrorMode(0);
  1592. RaiseException(EXCEPTION_WOW32_ASSERTION, 0, 0, NULL);
  1593. SetErrorMode(dw);
  1594. }
  1595. return 0;
  1596. }
  1597. /*
  1598. * sprintf_gszAssert
  1599. *
  1600. * Used by WOW32ASSERTMSGF to format the assertion text into
  1601. * a global buffer, gszAssert. There is probably a better way.
  1602. *
  1603. * DaveHart 15-Jun-95.
  1604. *
  1605. */
  1606. int _cdecl sprintf_gszAssert(PSZ pszFmt, ...)
  1607. {
  1608. va_list VarArgs;
  1609. va_start(VarArgs, pszFmt);
  1610. return vsprintf(gszAssert, pszFmt, VarArgs);
  1611. }
  1612. /*
  1613. * logprintf - format log print routine
  1614. *
  1615. * Input:
  1616. * iReqLogLevel - Requested Logging Level
  1617. *
  1618. * Note if the requested log level is not what we want we don't output
  1619. * but we always output to the circular buffer - just in case.
  1620. *
  1621. *
  1622. */
  1623. VOID logprintf(PSZ pszFmt, ...)
  1624. {
  1625. DWORD lpBytesWritten;
  1626. int len;
  1627. char text[1024];
  1628. va_list arglist;
  1629. va_start(arglist, pszFmt);
  1630. len = vsprintf(text, pszFmt, arglist);
  1631. // fLog states (set by !wow32.logfile debugger extension):
  1632. // 0 -> no logging;
  1633. // 1 -> log to file
  1634. // 2 -> create log file
  1635. // 3 -> close log file
  1636. if(fLog > 1) {
  1637. if(fLog == 2) {
  1638. if((hfLog = CreateFile(szLogFile,
  1639. GENERIC_WRITE,
  1640. FILE_SHARE_WRITE,
  1641. NULL,
  1642. CREATE_ALWAYS,
  1643. FILE_ATTRIBUTE_NORMAL,
  1644. NULL)) != INVALID_HANDLE_VALUE) {
  1645. fLog = 1;
  1646. }
  1647. else {
  1648. hfLog = NULL;
  1649. fLog = 0;
  1650. OutputDebugString("Couldn't open log file!\n");
  1651. }
  1652. }
  1653. else {
  1654. FlushFileBuffers(hfLog);
  1655. CloseHandle(hfLog);
  1656. hfLog = NULL;
  1657. fLog = 0;
  1658. }
  1659. }
  1660. if ( len > TMP_LINE_LEN-1 ) {
  1661. text[TMP_LINE_LEN-2] = '\n';
  1662. text[TMP_LINE_LEN-1] = '\0'; /* Truncate to 128 */
  1663. }
  1664. IFLOG(iReqLogLevel) {
  1665. // write to file?
  1666. if (fLog) {
  1667. WriteFile(hfLog, text, len, &lpBytesWritten, NULL);
  1668. }
  1669. // write to terminal?
  1670. else if (flOptions & OPT_DEBUG) {
  1671. OutputDebugString(text);
  1672. }
  1673. }
  1674. // This strcpy is overflow safe because of the explicit NULL placed in the
  1675. // src string: text[TMP_LINE_LEN-1] = '\0'; above.
  1676. strcpy(&achTmp[iCircBuffer][0], text);
  1677. if (--iCircBuffer < 0 ) {
  1678. iCircBuffer = CIRC_BUFFERS-1;
  1679. }
  1680. }
  1681. /*
  1682. * checkloging - Some Functions we don't want to log
  1683. *
  1684. * Entry
  1685. * fLogFilter = Filter for Specific Modules - Kernel, User, GDI etc.
  1686. * fLogTaskFilter = Filter for specific TaskID
  1687. *
  1688. * Exit: TRUE - OK to LOG Event
  1689. * FALSE - Don't Log Event
  1690. *
  1691. */
  1692. BOOL checkloging(register PVDMFRAME pFrame)
  1693. {
  1694. INT i;
  1695. BOOL bReturn;
  1696. INT iFun = GetFuncId(pFrame->wCallID);
  1697. PTABLEOFFSETS pto = &tableoffsets;
  1698. // Filter on Specific Call IDs
  1699. if (awfLogFunctionFilter[0] != 0xffff) {
  1700. INT nOrdinal;
  1701. nOrdinal = GetOrdinal(iFun);
  1702. bReturn = FALSE;
  1703. for (i=0; i < FILTER_FUNCTION_MAX ; i++) {
  1704. if (awfLogFunctionFilter[i] == nOrdinal) {
  1705. bReturn = TRUE;
  1706. break;
  1707. }
  1708. }
  1709. } else {
  1710. bReturn = TRUE;
  1711. }
  1712. // Do not LOG Internal Kernel Calls below level 20
  1713. if (iLogLevel < 20 ) {
  1714. if((iFun == FUN_WOWOUTPUTDEBUGSTRING) ||
  1715. ((iFun < pto->user) && (iFun >= FUN_WOWINITTASK)))
  1716. bReturn = FALSE;
  1717. }
  1718. // LOG Only Specific TaskID
  1719. if (fLogTaskFilter != 0xffff) {
  1720. if (fLogTaskFilter != pFrame->wTDB) {
  1721. bReturn = FALSE;
  1722. }
  1723. }
  1724. // LOG Filter On Modules USER/GDI/Kernel etc.
  1725. switch (ModFromCallID(iFun)) {
  1726. case MOD_KERNEL:
  1727. if ((fLogFilter & FILTER_KERNEL) == 0 )
  1728. bReturn = FALSE;
  1729. break;
  1730. case MOD_USER:
  1731. if ((fLogFilter & FILTER_USER) == 0 )
  1732. bReturn = FALSE;
  1733. break;
  1734. case MOD_GDI:
  1735. if ((fLogFilter & FILTER_GDI) == 0 )
  1736. bReturn = FALSE;
  1737. break;
  1738. case MOD_KEYBOARD:
  1739. if ((fLogFilter & FILTER_KEYBOARD) == 0 )
  1740. bReturn = FALSE;
  1741. break;
  1742. case MOD_SOUND:
  1743. if ((fLogFilter & FILTER_SOUND) == 0 )
  1744. bReturn = FALSE;
  1745. break;
  1746. case MOD_MMEDIA:
  1747. if ((fLogFilter & FILTER_MMEDIA) == 0 )
  1748. bReturn = FALSE;
  1749. break;
  1750. case MOD_WINSOCK:
  1751. if ((fLogFilter & FILTER_WINSOCK) == 0 )
  1752. bReturn = FALSE;
  1753. break;
  1754. case MOD_COMMDLG:
  1755. if ((fLogFilter & FILTER_COMMDLG) == 0 ) {
  1756. bReturn = FALSE;
  1757. }
  1758. break;
  1759. #ifdef FE_IME
  1760. case MOD_WINNLS:
  1761. if ((fLogFilter & FILTER_WINNLS) == 0 )
  1762. bReturn = FALSE;
  1763. break;
  1764. #endif // FE_IME
  1765. #ifdef FE_SB
  1766. case MOD_WIFEMAN:
  1767. if ((fLogFilter & FILTER_WIFEMAN) == 0 )
  1768. bReturn = FALSE;
  1769. break;
  1770. #endif
  1771. default:
  1772. break;
  1773. }
  1774. return (bReturn);
  1775. }
  1776. /*
  1777. * Argument Logging For Tracing API Calls
  1778. *
  1779. *
  1780. */
  1781. VOID logargs(INT iLog, register PVDMFRAME pFrame)
  1782. {
  1783. register PBYTE pbArgs;
  1784. INT iFun;
  1785. INT cbArgs;
  1786. if (checkloging(pFrame)) {
  1787. iFun = GetFuncId(pFrame->wCallID);
  1788. cbArgs = aw32WOW[iFun].cbArgs; // Get Number of Parameters
  1789. if ((fLogFilter & FILTER_VERBOSE) == 0 ) {
  1790. LOGDEBUG(iLog,("%s(", aw32WOW[iFun].lpszW32));
  1791. } else {
  1792. LOGDEBUG(iLog,("%04X %08X %04X %s:%s(",pFrame->wTDB, pFrame->vpCSIP,pFrame->wAppDS, GetModName(iFun), aw32WOW[iFun].lpszW32));
  1793. }
  1794. GETARGPTR(pFrame, cbArgs, pbArgs);
  1795. pbArgs += cbArgs;
  1796. //
  1797. // Log the function arguments a word at a time.
  1798. // The first iteration of the while loop is unrolled so
  1799. // that the main loop doesn't have to figure out whether
  1800. // or not to print a comma.
  1801. //
  1802. if (cbArgs > 0) {
  1803. pbArgs -= sizeof(WORD);
  1804. cbArgs -= sizeof(WORD);
  1805. LOGDEBUG(iLog,("%04x", *(PWORD16)pbArgs));
  1806. while (cbArgs > 0) {
  1807. pbArgs -= sizeof(WORD);
  1808. cbArgs -= sizeof(WORD);
  1809. LOGDEBUG(iLog,(",%04x", *(PWORD16)pbArgs));
  1810. }
  1811. }
  1812. FREEARGPTR(pbArgs);
  1813. LOGDEBUG(iLog,(")\n"));
  1814. if (fDebugWait != 0) {
  1815. DbgPrint("WOWSingle Step\n");
  1816. DbgBreakPoint();
  1817. }
  1818. }
  1819. }
  1820. /*
  1821. * logreturn - Log Return Values From Call
  1822. *
  1823. * Entry
  1824. *
  1825. * Exit - None
  1826. */
  1827. VOID logreturn(INT iLog, register PVDMFRAME pFrame, ULONG ulReturn)
  1828. {
  1829. INT iFun;
  1830. if (checkloging(pFrame)) {
  1831. iFun = GetFuncId(pFrame->wCallID);
  1832. if ((fLogFilter & FILTER_VERBOSE) == 0 ) {
  1833. LOGDEBUG(iLog,("%s: %lx\n", aw32WOW[iFun].lpszW32, ulReturn));
  1834. } else {
  1835. LOGDEBUG(iLog,("%04X %08X %04X %s:%s: %lx\n", pFrame->wTDB, pFrame->vpCSIP, pFrame->wAppDS, GetModName(iFun), aw32WOW[iFun].lpszW32, ulReturn));
  1836. }
  1837. }
  1838. }
  1839. #endif // DEBUG
  1840. PVOID FASTCALL malloc_w (ULONG size)
  1841. {
  1842. PVOID pv;
  1843. pv = HeapAlloc(hWOWHeap, 0, size + TAILCHECK);
  1844. WOW32ASSERTMSG(pv, "WOW32: malloc_w failing, returning NULL\n");
  1845. #ifdef DEBUG_MEMLEAK
  1846. WOW32DebugMemLeak(pv, size, ML_MALLOC_W);
  1847. #endif
  1848. return pv;
  1849. }
  1850. DWORD FASTCALL size_w (PVOID pv)
  1851. {
  1852. DWORD dwSize;
  1853. dwSize = HeapSize(hWOWHeap, 0, pv) - TAILCHECK;
  1854. return(dwSize);
  1855. }
  1856. PVOID FASTCALL malloc_w_zero (ULONG size)
  1857. {
  1858. PVOID pv;
  1859. pv = HeapAlloc(hWOWHeap, HEAP_ZERO_MEMORY, size + TAILCHECK);
  1860. WOW32ASSERTMSG(pv, "WOW32: malloc_w_zero failing, returning NULL\n");
  1861. #ifdef DEBUG_MEMLEAK
  1862. WOW32DebugMemLeak(pv, size, ML_MALLOC_W_ZERO);
  1863. #endif
  1864. return pv;
  1865. }
  1866. VOID FASTCALL free_w (PVOID p)
  1867. {
  1868. #ifdef DEBUG_MEMLEAK
  1869. WOW32DebugFreeMem(p);
  1870. #endif
  1871. if(p) {
  1872. HeapFree(hWOWHeap, 0, (LPSTR)(p));
  1873. }
  1874. }
  1875. //
  1876. // malloc_w_or_die is for use by *initialization* code only, when we
  1877. // can't get WOW going because, for example, we can't allocate a buffer
  1878. // to hold the known DLL list.
  1879. //
  1880. // malloc_w_or_die should not be used by API or message thunks or worker
  1881. // routines called by API or message thunks.
  1882. //
  1883. PVOID FASTCALL malloc_w_or_die(ULONG size)
  1884. {
  1885. PVOID pv;
  1886. if (!(pv = malloc_w(size))) {
  1887. WOW32ASSERTMSG(pv, "WOW32: malloc_w_or_die failing, terminating.\n");
  1888. WOWStartupFailed(); // never returns.
  1889. }
  1890. return pv;
  1891. }
  1892. LPSTR malloc_w_strcpy_vp16to32(VPVOID vpstr16, BOOL bMulti, INT cMax)
  1893. {
  1894. return(ThunkStr16toStr32(NULL, vpstr16, cMax, bMulti));
  1895. }
  1896. LPSTR ThunkStr16toStr32(LPSTR pdst32, VPVOID vpsrc16, INT cChars, BOOL bMulti)
  1897. /*++
  1898. Thunks a 16-bit string to a 32-bit ANSI string.
  1899. bMulti == TRUE means we are thunking a multi-string which is a list of NULL
  1900. *separated* strings that *terminate* with a double NULL.
  1901. Notes: If the original 32-bit buffer is too small to contain the new string,
  1902. it will be free'd and a new 32-bit buffer will be allocated. If a new
  1903. 32-bit buffer can't be allocated, the ptr to the original 32-bit
  1904. buffer is returned with no changes to the contents.
  1905. Returns: ptr to the original 32-bit buffer
  1906. OR ptr to a new 32-bit buffer if the original buffer was too small
  1907. OR NULL if psrc is NULL.
  1908. --*/
  1909. {
  1910. PBYTE pbuf32;
  1911. LPSTR psrc16;
  1912. INT buf16size, iLen;
  1913. INT buf32size = 0;
  1914. GETPSZPTR(vpsrc16, psrc16);
  1915. if(!psrc16) {
  1916. // the app doesn't want a buffer for this anymore
  1917. // (this is primarily for comdlg support)
  1918. if(pdst32) {
  1919. free_w(pdst32);
  1920. }
  1921. return(NULL);
  1922. }
  1923. if(bMulti) {
  1924. iLen = Multi_strlen(psrc16) + 1;
  1925. } else {
  1926. iLen = (INT)(strlen(psrc16) + 1);
  1927. }
  1928. buf16size = max(cChars, iLen);
  1929. if(pdst32) {
  1930. buf32size = (INT)size_w(pdst32);
  1931. }
  1932. // if 32-bit buffer is too small, NULL, or invalid -- alloc a bigger buffer
  1933. if((buf32size < buf16size) || (!pdst32) || (buf32size == 0xFFFFFFFF)) {
  1934. if(pbuf32 = (PBYTE)malloc_w(buf16size)) {
  1935. // now copy to the new 32-bit buffer
  1936. if(bMulti) {
  1937. Multi_strcpy(pbuf32, psrc16);
  1938. } else {
  1939. strncpy((PBYTE)pbuf32, psrc16, buf16size);
  1940. pbuf32[buf16size-1] = '\0';
  1941. }
  1942. // get rid of the old buffer
  1943. if(pdst32) {
  1944. free_w(pdst32);
  1945. }
  1946. pdst32 = pbuf32;
  1947. }
  1948. else {
  1949. WOW32ASSERTMSG(0, "WOW32: ThunkStr16toStr32: malloc_w failed!\n");
  1950. }
  1951. }
  1952. // else just use the original 32-bit buffer (99% of the time)
  1953. else if(pdst32) {
  1954. if(bMulti) {
  1955. Multi_strcpy(pdst32, psrc16);
  1956. } else {
  1957. strncpy(pdst32, psrc16, buf32size);
  1958. pdst32[buf32size-1] = '\0';
  1959. }
  1960. }
  1961. FREEPSZPTR(psrc16);
  1962. return(pdst32);
  1963. }
  1964. //
  1965. // WOWStartupFailed puts up a fatal error box and terminates WOW.
  1966. //
  1967. PVOID WOWStartupFailed(VOID)
  1968. {
  1969. char szCaption[256];
  1970. char szMsgBoxText[1024];
  1971. LoadString(hmodWOW32, iszStartupFailed, szMsgBoxText, sizeof szMsgBoxText);
  1972. LoadString(hmodWOW32, iszSystemError, szCaption, sizeof szCaption);
  1973. MessageBox(GetDesktopWindow(),
  1974. szMsgBoxText,
  1975. szCaption,
  1976. MB_SETFOREGROUND | MB_TASKMODAL | MB_ICONSTOP | MB_OK | MB_DEFBUTTON1);
  1977. ExitVDM(WOWVDM, ALL_TASKS); // Tell Win32 All Tasks are gone.
  1978. ExitProcess(EXIT_FAILURE);
  1979. return (PVOID)NULL;
  1980. }
  1981. #ifdef FIX_318197_NOW
  1982. char*
  1983. WOW32_strchr(
  1984. const char* psz,
  1985. int c
  1986. )
  1987. {
  1988. if (gbDBCSEnable) {
  1989. unsigned int cc;
  1990. for (; (cc = *psz); psz++) {
  1991. if (IsDBCSLeadByte((BYTE)cc)) {
  1992. if (*++psz == '\0') {
  1993. return NULL;
  1994. }
  1995. if ((unsigned int)c == ((cc << 8) | *psz) ) { // DBCS match
  1996. return (char*)(psz - 1);
  1997. }
  1998. }
  1999. else if ((unsigned int)c == cc) {
  2000. return (char*)psz; // SBCS match
  2001. }
  2002. }
  2003. if ((unsigned int)c == cc) { // NULL match
  2004. return (char*)psz;
  2005. }
  2006. return NULL;
  2007. }
  2008. else {
  2009. return strchr(psz, c);
  2010. }
  2011. }
  2012. char*
  2013. WOW32_strrchr(
  2014. const char* psz,
  2015. int c
  2016. )
  2017. {
  2018. if (gbDBCSEnable) {
  2019. char* r = NULL;
  2020. unsigned int cc;
  2021. do {
  2022. cc = *psz;
  2023. if (IsDBCSLeadByte((BYTE)cc)) {
  2024. if (*++psz) {
  2025. if ((unsigned int)c == ((cc << 8) | *psz) ) { // DBCS match
  2026. r = (char*)(psz - 1);
  2027. }
  2028. }
  2029. else if (!r) {
  2030. // return pointer to '\0'
  2031. r = (char*)psz;
  2032. }
  2033. }
  2034. else if ((unsigned int)c == cc) {
  2035. r = (char*)psz; // SBCS match
  2036. }
  2037. } while (*psz++);
  2038. return r;
  2039. }
  2040. else {
  2041. return strrchr(psz, c);
  2042. }
  2043. }
  2044. char*
  2045. WOW32_strstr(
  2046. const char* str1,
  2047. const char* str2
  2048. )
  2049. {
  2050. if (gbDBCSEnable) {
  2051. char *cp, *endp;
  2052. char *s1, *s2;
  2053. cp = (char*)str1;
  2054. endp = (char*)str1 + strlen(str1) - strlen(str2);
  2055. while (*cp && (cp <= endp)) {
  2056. s1 = cp;
  2057. s2 = (char*)str2;
  2058. while ( *s1 && *s2 && (*s1 == *s2) ) {
  2059. s1++;
  2060. s2++;
  2061. }
  2062. if (!(*s2)) {
  2063. return cp; // success!
  2064. }
  2065. cp = CharNext(cp);
  2066. }
  2067. return NULL;
  2068. }
  2069. else {
  2070. return strstr(str1, str2);
  2071. }
  2072. }
  2073. int
  2074. WOW32_strncmp(
  2075. const char* str1,
  2076. const char* str2,
  2077. size_t n
  2078. )
  2079. {
  2080. if (gbDBCSEnable) {
  2081. int retval;
  2082. if (n == 0) {
  2083. return 0;
  2084. }
  2085. retval = CompareStringA( GetThreadLocale(),
  2086. LOCALE_USE_CP_ACP,
  2087. str1,
  2088. n,
  2089. str2,
  2090. n );
  2091. if (retval == 0) {
  2092. //
  2093. // The caller is not expecting failure. Try the system
  2094. // default locale id.
  2095. //
  2096. retval = CompareStringA( GetSystemDefaultLCID(),
  2097. LOCALE_USE_CP_ACP,
  2098. str1,
  2099. n,
  2100. str2,
  2101. n );
  2102. }
  2103. if (retval == 0) {
  2104. if (str1 && str2) {
  2105. //
  2106. // The caller is not expecting failure. We've never had a
  2107. // failure indicator before. We'll do a best guess by calling
  2108. // the C runtimes to do a non-locale sensitive compare.
  2109. //
  2110. return strncmp(str1, str2, n);
  2111. }
  2112. else if (str1) {
  2113. return 1;
  2114. }
  2115. else if (str2) {
  2116. return -1;
  2117. }
  2118. else {
  2119. return 0;
  2120. }
  2121. }
  2122. return retval - 2;
  2123. }
  2124. else {
  2125. return strncmp(str1, str2, n);
  2126. }
  2127. }
  2128. int
  2129. WOW32_strnicmp(
  2130. const char* str1,
  2131. const char* str2,
  2132. size_t n
  2133. )
  2134. {
  2135. if (gbDBCSEnable) {
  2136. int retval;
  2137. if (n == 0) {
  2138. return 0;
  2139. }
  2140. retval = CompareStringA( GetThreadLocale(),
  2141. LOCALE_USE_CP_ACP | NORM_IGNORECASE,
  2142. str1,
  2143. n,
  2144. str2,
  2145. n );
  2146. if (retval == 0) {
  2147. //
  2148. // The caller is not expecting failure. Try the system
  2149. // default locale id.
  2150. //
  2151. retval = CompareStringA( GetSystemDefaultLCID(),
  2152. LOCALE_USE_CP_ACP | NORM_IGNORECASE,
  2153. str1,
  2154. n,
  2155. str2,
  2156. n );
  2157. }
  2158. if (retval == 0) {
  2159. if (str1 && str2) {
  2160. //
  2161. // The caller is not expecting failure. We've never had a
  2162. // failure indicator before. We'll do a best guess by calling
  2163. // the C runtimes to do a non-locale sensitive compare.
  2164. //
  2165. return _strnicmp(str1, str2, n);
  2166. }
  2167. else if (str1) {
  2168. return 1;
  2169. }
  2170. else if (str2) {
  2171. return -1;
  2172. }
  2173. else {
  2174. return 0;
  2175. }
  2176. }
  2177. return retval - 2;
  2178. }
  2179. else {
  2180. return _strnicmp(str1, str2, n);
  2181. }
  2182. }
  2183. #endif
  2184. //****************************************************************************
  2185. #ifdef DEBUG_OR_WOWPROFILE
  2186. LONGLONG GetWOWTicDiff(LONGLONG dwPrevCount) {
  2187. /*
  2188. * Returns difference between a previous Tick count & the current tick count
  2189. *
  2190. * NOTE: Tick counts are in unspecified units (PerfFreq is in Hz)
  2191. */
  2192. LONGLONG dwDiff;
  2193. LARGE_INTEGER PerfCount, PerfFreq;
  2194. NtQueryPerformanceCounter(&PerfCount, &PerfFreq);
  2195. dwDiff = PerfCount.QuadPart - dwPrevCount;
  2196. return(dwDiff);
  2197. }
  2198. INT GetFuncId(DWORD iFun)
  2199. {
  2200. INT i;
  2201. static DWORD dwLastInput = -1;
  2202. static DWORD dwLastOutput = -1;
  2203. if (iFun == dwLastInput) {
  2204. iFun = dwLastOutput;
  2205. } else {
  2206. dwLastInput = iFun;
  2207. if (!ISFUNCID(iFun)) {
  2208. for (i = 0; i < cAPIThunks; i++) {
  2209. if (aw32WOW[i].lpfnW32 == (LPFNW32)iFun) {
  2210. iFun = i;
  2211. break;
  2212. }
  2213. }
  2214. }
  2215. dwLastOutput = iFun;
  2216. }
  2217. return iFun;
  2218. }
  2219. #endif // DEBUG_OR_WOWPROFILE
  2220. // for debugging memory leaks
  2221. #ifdef DEBUG_MEMLEAK
  2222. LPMEMLEAK lpMemLeakStart = NULL;
  2223. ULONG ulalloc_Count = 1L;
  2224. DWORD dwAllocFlags = 0;
  2225. VOID WOW32DebugMemLeak(PVOID lp, ULONG size, DWORD fHow)
  2226. {
  2227. PVOID pvCallersAddress, pvCallersCaller;
  2228. LPMEMLEAK lpml;
  2229. HGLOBAL h32 = NULL; // lp from ML_GLOBALTYPE's are really HGLOBAL's
  2230. if(lp) {
  2231. // if we are tracking this type
  2232. if(dwAllocFlags & fHow) {
  2233. // allocate a tracking node
  2234. if(lpml = GlobalAlloc(GPTR, sizeof(MEMLEAK))) {
  2235. lpml->lp = lp;
  2236. lpml->size = size;
  2237. lpml->fHow = fHow;
  2238. lpml->Count = ulalloc_Count++; // save when originally alloc'd
  2239. RtlGetCallersAddress(&pvCallersAddress, &pvCallersCaller);
  2240. lpml->CallersAddress = pvCallersCaller;
  2241. EnterCriticalSection(&csMemLeak);
  2242. lpml->lpmlNext = lpMemLeakStart;
  2243. lpMemLeakStart = lpml;
  2244. LeaveCriticalSection(&csMemLeak);
  2245. }
  2246. WOW32WARNMSG(lpml,"WOW32DebugMemLeak: can't alloc node\n");
  2247. }
  2248. // add "EnD" signature for heap tail corruption checking
  2249. if(fHow & ML_GLOBALTYPE) {
  2250. h32 = (HGLOBAL)lp;
  2251. lp = GlobalLock(h32);
  2252. }
  2253. if(lp) {
  2254. ((CHAR *)(lp))[size++] = 'E';
  2255. ((CHAR *)(lp))[size++] = 'n';
  2256. ((CHAR *)(lp))[size++] = 'D';
  2257. ((CHAR *)(lp))[size++] = '\0';
  2258. if(h32) {
  2259. GlobalUnlock(h32);
  2260. }
  2261. }
  2262. }
  2263. }
  2264. VOID WOW32DebugReMemLeak(PVOID lpNew, PVOID lpOrig, ULONG size, DWORD fHow)
  2265. {
  2266. PVOID pvCallersAddress, pvCallersCaller;
  2267. HGLOBAL h32 = NULL; // lp from ML_GLOBALTYPE's are really HGLOBAL's
  2268. LPMEMLEAK lpml = lpMemLeakStart;
  2269. if(lpNew) {
  2270. if(dwAllocFlags & fHow) {
  2271. // look for original ptr in the list
  2272. while(lpml) {
  2273. if(lpml->lp == lpOrig) {
  2274. break;
  2275. }
  2276. lpml = lpml->lpmlNext;
  2277. }
  2278. WOW32WARNMSG(lpml,
  2279. "WOW32DebugReMemLeak: can't find original node\n");
  2280. // if we found the original ptr
  2281. if(lpml) {
  2282. // update our struct with new ptr if necessary
  2283. if(lpNew != lpOrig) {
  2284. lpml->lp = lpNew;
  2285. }
  2286. lpml->size = size;
  2287. lpml->fHow |= fHow;
  2288. RtlGetCallersAddress(&pvCallersAddress, &pvCallersCaller);
  2289. lpml->CallersAddress = pvCallersCaller;
  2290. ulalloc_Count++;
  2291. }
  2292. }
  2293. // for heap tail corruption checking
  2294. if(fHow & ML_GLOBALTYPE) {
  2295. h32 = (HGLOBAL)lpNew;
  2296. lpNew = GlobalLock(h32);
  2297. }
  2298. if(lpNew) {
  2299. ((CHAR *)(lpNew))[size++] = 'E';
  2300. ((CHAR *)(lpNew))[size++] = 'n';
  2301. ((CHAR *)(lpNew))[size++] = 'D';
  2302. ((CHAR *)(lpNew))[size++] = '\0';
  2303. if(h32) {
  2304. GlobalUnlock(h32);
  2305. }
  2306. }
  2307. }
  2308. }
  2309. VOID WOW32DebugFreeMem(PVOID lp)
  2310. {
  2311. LPMEMLEAK lpmlPrev;
  2312. LPMEMLEAK lpml = lpMemLeakStart;
  2313. if(lp && dwAllocFlags) {
  2314. while(lpml) {
  2315. lpmlPrev = lpml;
  2316. if(lpml->lp == lp) {
  2317. WOW32DebugCorruptionCheck(lp, lpml->size);
  2318. EnterCriticalSection(&csMemLeak);
  2319. if(lpml == lpMemLeakStart) {
  2320. lpMemLeakStart = lpml->lpmlNext;
  2321. }
  2322. else {
  2323. lpmlPrev->lpmlNext = lpml->lpmlNext;
  2324. }
  2325. GlobalFree(lpml); // free the LPMEMLEAK node
  2326. LeaveCriticalSection(&csMemLeak);
  2327. break;
  2328. }
  2329. else {
  2330. lpml = lpml->lpmlNext;
  2331. }
  2332. }
  2333. WOW32WARNMSG((lpml), "WOW32DebugFreeMem: can't find node\n");
  2334. }
  2335. }
  2336. VOID WOW32DebugCorruptionCheck(PVOID lp, DWORD size)
  2337. {
  2338. if(lp && size) {
  2339. if(!((((CHAR *)(lp))[size++] == 'E') &&
  2340. (((CHAR *)(lp))[size++] == 'n') &&
  2341. (((CHAR *)(lp))[size++] == 'D') &&
  2342. (((CHAR *)(lp))[size++] == '\0')) ) {
  2343. WOW32ASSERTMSG(FALSE,"WOW32DebugCorruptionCheck: Corrupt tail!!\n");
  2344. }
  2345. }
  2346. }
  2347. DWORD WOW32DebugGetMemSize(PVOID lp)
  2348. {
  2349. LPMEMLEAK lpml = lpMemLeakStart;
  2350. while(lpml) {
  2351. if(lpml->lp == lp) {
  2352. return(lpml->size);
  2353. }
  2354. lpml = lpml->lpmlNext;
  2355. }
  2356. return(0);
  2357. }
  2358. // NOTE: this is called ONLY IF built with DEBUG_MEMLEAK
  2359. HGLOBAL WOW32DebugGlobalAlloc(UINT flags, DWORD dwSize)
  2360. {
  2361. HGLOBAL h32;
  2362. h32 = GlobalAlloc(flags, dwSize + TAILCHECK);
  2363. WOW32DebugMemLeak((PVOID)h32, dwSize, ML_GLOBALALLOC);
  2364. return(h32);
  2365. }
  2366. // NOTE: this is called ONLY IF built with DEBUG_MEMLEAK
  2367. HGLOBAL WOW32DebugGlobalReAlloc(HGLOBAL h32, DWORD dwSize, UINT flags)
  2368. {
  2369. HGLOBAL h32New;
  2370. PVOID lp32Orig;
  2371. // get the original pointer & check the memory for tail corruption
  2372. lp32Orig = (PVOID)GlobalLock(h32);
  2373. WOW32DebugCorruptionCheck(lp32Orig, WOW32DebugGetMemSize((PVOID)h32));
  2374. GlobalUnlock(h32);
  2375. h32New = GlobalReAlloc(h32, dwSize + TAILCHECK, flags);
  2376. // fix our memory list to account for the realloc
  2377. WOW32DebugReMemLeak((PVOID)h32New,
  2378. (PVOID)h32,
  2379. dwSize + TAILCHECK,
  2380. ML_GLOBALREALLOC);
  2381. return(h32New);
  2382. }
  2383. // NOTE: this is called ONLY IF built with DEBUG_MEMLEAK
  2384. HGLOBAL WOW32DebugGlobalFree(HGLOBAL h32)
  2385. {
  2386. WOW32DebugFreeMem((PVOID)h32);
  2387. h32 = GlobalFree(h32);
  2388. if(h32) {
  2389. LOGDEBUG(0, ("WOW32DebugFreeMem: Lock count not 0!\n"));
  2390. }
  2391. else {
  2392. if(GetLastError() != NO_ERROR) {
  2393. LOGDEBUG(0, ("WOW32DebugFreeMem: GlobalFree failed!\n"));
  2394. }
  2395. }
  2396. return(h32);
  2397. }
  2398. #endif // DEBUG_MEMLEAK