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.

2143 lines
61 KiB

  1. //
  2. // Debug squirty functions
  3. //
  4. #include "stock.h"
  5. #pragma hdrstop
  6. #include "shellp.h"
  7. #include <platform.h> // LINE_SEPARATOR_STR and friends
  8. #include <winbase.h> // for GetModuleFileNameA
  9. #include <strsafe.h>
  10. #define DM_DEBUG 0
  11. #ifdef DEBUG
  12. // --------------------------------------------------------------------------
  13. // AttachUserModeDebugger
  14. //
  15. // Arguments: <none>
  16. //
  17. // Returns: <none>
  18. //
  19. // Purpose: Attaches a user-mode debugger to the current process if one
  20. // is not already attached. This allows the ASSERT/RIP/TRACE to
  21. // be debugged in a user-mode debugger rather than ending up in
  22. // the kernel debugger which is sometimes limiting.
  23. //
  24. // History: 2000-08-21 vtan created
  25. // --------------------------------------------------------------------------
  26. void AttachUserModeDebugger (void)
  27. {
  28. // Win95 does not support IsDebuggerPresent so we must
  29. // GetProcAddress for it below or we would fail to load.
  30. // In fact, we punt completely on Win9x
  31. if (GetVersion() & 0x80000000) return;
  32. __try
  33. {
  34. typedef BOOL (WINAPI *ISDEBUGGERPRESENT)();
  35. ISDEBUGGERPRESENT _IsDebuggerPresent = (ISDEBUGGERPRESENT)GetProcAddress(GetModuleHandleA("KERNEL32"), "IsDebuggerPresent");
  36. if (_IsDebuggerPresent && !_IsDebuggerPresent())
  37. {
  38. HKEY hKeyAEDebug;
  39. TCHAR szDebugger[MAX_PATH];
  40. szDebugger[0] = TEXT('\0');
  41. // Read HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AEDebug\Debugger
  42. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  43. TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AEDebug"),
  44. 0,
  45. KEY_QUERY_VALUE,
  46. &hKeyAEDebug))
  47. {
  48. DWORD dwDebuggerSize;
  49. dwDebuggerSize = sizeof(szDebugger);
  50. (LONG)RegQueryValueEx(hKeyAEDebug,
  51. TEXT("Debugger"),
  52. NULL,
  53. NULL,
  54. (LPBYTE)&szDebugger,
  55. &dwDebuggerSize);
  56. (LONG)RegCloseKey(hKeyAEDebug);
  57. }
  58. if (szDebugger[0] != TEXT('\0'))
  59. {
  60. static const TCHAR s_szDrWatsonImageName[] = TEXT("drwtsn32");
  61. HRESULT hr;
  62. BOOL fWatson = FALSE;
  63. TCHAR szCommandLine[MAX_PATH + 64];
  64. // Duplicate the string to szCommandLine and NULL terminate
  65. // to compare directly for "drwtsn32" which we do NOT want
  66. // attached to the process.
  67. hr = StringCchCopy(szCommandLine, ARRAYSIZE(szCommandLine), szDebugger);
  68. if (SUCCEEDED(hr))
  69. {
  70. szCommandLine[ARRAYSIZE(s_szDrWatsonImageName)-1] = TEXT('\0');
  71. if (lstrcmpi(szCommandLine, s_szDrWatsonImageName) == 0)
  72. {
  73. fWatson = TRUE;
  74. }
  75. }
  76. if (!fWatson)
  77. {
  78. HANDLE hEvent;
  79. SECURITY_ATTRIBUTES securityAttributes;
  80. // Create an unnamed event which is passed to the debugger as an
  81. // inherited handle. It will signal this handle to release this
  82. // thread when the debugger is completely attached to the process.
  83. securityAttributes.nLength = sizeof(securityAttributes);
  84. securityAttributes.lpSecurityDescriptor = NULL;
  85. securityAttributes.bInheritHandle = TRUE;
  86. hEvent = CreateEvent(&securityAttributes, TRUE, FALSE, NULL);
  87. if (hEvent != NULL)
  88. {
  89. STARTUPINFO startupInfo;
  90. PROCESS_INFORMATION processInformation;
  91. ZeroMemory(&startupInfo, sizeof(startupInfo));
  92. ZeroMemory(&processInformation, sizeof(processInformation));
  93. startupInfo.cb = sizeof(startupInfo);
  94. // Now formulate the command line to pass to the debugger.
  95. // It's in the form "cdb -p %ld -e %ld -gGx".
  96. hr = StringCchPrintf(szCommandLine, ARRAYSIZE(szCommandLine), szDebugger, GetCurrentProcessId(), hEvent); // ok to truncate - devs can figure it out
  97. if (SUCCEEDED(hr))
  98. {
  99. if (CreateProcess(NULL,
  100. szCommandLine,
  101. NULL,
  102. NULL,
  103. TRUE,
  104. 0,
  105. NULL,
  106. NULL,
  107. &startupInfo,
  108. &processInformation) != FALSE)
  109. {
  110. // Now wait for the event. Give a generous 10 seconds
  111. // for the debugger to signal this event. If the debugger
  112. // doesn't then continue execution. Close all handles.
  113. (DWORD)WaitForSingleObject(hEvent, INFINITE);
  114. (BOOL)CloseHandle(processInformation.hProcess);
  115. (BOOL)CloseHandle(processInformation.hThread);
  116. }
  117. }
  118. (BOOL)CloseHandle(hEvent);
  119. }
  120. }
  121. else
  122. {
  123. OutputDebugStringA("drwtsn32 detected in AEDebug. Dropping to KD\r\n");
  124. }
  125. }
  126. }
  127. }
  128. __except (EXCEPTION_CONTINUE_EXECUTION)
  129. {
  130. }
  131. }
  132. #endif /* DEBUG */
  133. // UnicodeFromAnsi is used by shlwapi so it should not be inside the ifdef debug
  134. //
  135. /*----------------------------------------------------------
  136. Purpose: This function converts a multi-byte string to a
  137. wide-char string.
  138. If pszBuf is non-NULL and the converted string can fit in
  139. pszBuf, then *ppszWide will point to the given buffer.
  140. Otherwise, this function will allocate a buffer that can
  141. hold the converted string.
  142. If pszAnsi is NULL, then *ppszWide will be freed. Note
  143. that pszBuf must be the same pointer between the call
  144. that converted the string and the call that frees the
  145. string.
  146. Returns: TRUE
  147. FALSE (if out of memory)
  148. */
  149. BOOL
  150. UnicodeFromAnsi(
  151. LPWSTR * ppwszWide,
  152. LPCSTR pszAnsi, // NULL to clean up
  153. LPWSTR pwszBuf,
  154. int cchBuf)
  155. {
  156. BOOL bRet;
  157. // Convert the string?
  158. if (pszAnsi)
  159. {
  160. // Yes; determine the converted string length
  161. int cch;
  162. LPWSTR pwsz;
  163. int cchAnsi = lstrlenA(pszAnsi)+1;
  164. cch = MultiByteToWideChar(CP_ACP, 0, pszAnsi, cchAnsi, NULL, 0);
  165. // String too big, or is there no buffer?
  166. if (cch > cchBuf || NULL == pwszBuf)
  167. {
  168. // Yes; allocate space
  169. cchBuf = cch + 1;
  170. pwsz = (LPWSTR)LocalAlloc(LPTR, CbFromCchW(cchBuf));
  171. }
  172. else
  173. {
  174. // No; use the provided buffer
  175. pwsz = pwszBuf;
  176. }
  177. if (pwsz)
  178. {
  179. // Convert the string
  180. cch = MultiByteToWideChar(CP_ACP, 0, pszAnsi, cchAnsi, pwsz, cchBuf);
  181. bRet = (0 < cch);
  182. }
  183. else
  184. {
  185. bRet = FALSE;
  186. }
  187. *ppwszWide = pwsz;
  188. }
  189. else
  190. {
  191. // No; was this buffer allocated?
  192. if (*ppwszWide && pwszBuf != *ppwszWide)
  193. {
  194. // Yes; clean up
  195. LocalFree((HLOCAL)*ppwszWide);
  196. *ppwszWide = NULL;
  197. }
  198. bRet = TRUE;
  199. }
  200. return bRet;
  201. }
  202. #if 0 // nobody seems to use this one any more
  203. /*----------------------------------------------------------
  204. Purpose: This function converts a wide-char string to a multi-byte
  205. string.
  206. If pszBuf is non-NULL and the converted string can fit in
  207. pszBuf, then *ppszAnsi will point to the given buffer.
  208. Otherwise, this function will allocate a buffer that can
  209. hold the converted string.
  210. If pszWide is NULL, then *ppszAnsi will be freed. Note
  211. that pszBuf must be the same pointer between the call
  212. that converted the string and the call that frees the
  213. string.
  214. Returns: TRUE
  215. FALSE (if out of memory)
  216. Cond: --
  217. */
  218. BOOL
  219. AnsiFromUnicode(
  220. LPSTR * ppszAnsi,
  221. LPCWSTR pwszWide, // NULL to clean up
  222. LPSTR pszBuf,
  223. int cchBuf)
  224. {
  225. BOOL bRet;
  226. // Convert the string?
  227. if (pwszWide)
  228. {
  229. // Yes; determine the converted string length
  230. int cch;
  231. LPSTR psz;
  232. cch = WideCharToMultiByte(CP_ACP, 0, pwszWide, -1, NULL, 0, NULL, NULL);
  233. // String too big, or is there no buffer?
  234. if (cch > cchBuf || NULL == pszBuf)
  235. {
  236. // Yes; allocate space
  237. cchBuf = cch + 1;
  238. psz = (LPSTR)LocalAlloc(LPTR, CbFromCchA(cchBuf));
  239. }
  240. else
  241. {
  242. // No; use the provided buffer
  243. ASSERT(pszBuf);
  244. psz = pszBuf;
  245. }
  246. if (psz)
  247. {
  248. // Convert the string
  249. cch = WideCharToMultiByte(CP_ACP, 0, pwszWide, -1, psz, cchBuf, NULL, NULL);
  250. bRet = (0 < cch);
  251. }
  252. else
  253. {
  254. bRet = FALSE;
  255. }
  256. *ppszAnsi = psz;
  257. }
  258. else
  259. {
  260. // No; was this buffer allocated?
  261. if (*ppszAnsi && pszBuf != *ppszAnsi)
  262. {
  263. // Yes; clean up
  264. LocalFree((HLOCAL)*ppszAnsi);
  265. *ppszAnsi = NULL;
  266. }
  267. bRet = TRUE;
  268. }
  269. return bRet;
  270. }
  271. #endif // 0
  272. #if defined(DEBUG) || defined(PRODUCT_PROF)
  273. // (c_szCcshellIniFile and c_szCcshellIniSecDebug are declared in debug.h)
  274. extern CHAR const FAR c_szCcshellIniFile[];
  275. extern CHAR const FAR c_szCcshellIniSecDebug[];
  276. HANDLE g_hDebugOutputFile = INVALID_HANDLE_VALUE;
  277. void ShellDebugAppendToDebugFileA(LPCSTR pszOutputString)
  278. {
  279. if (g_hDebugOutputFile != INVALID_HANDLE_VALUE)
  280. {
  281. DWORD cbWrite = lstrlenA(pszOutputString);
  282. WriteFile(g_hDebugOutputFile, pszOutputString, cbWrite, &cbWrite, NULL);
  283. }
  284. }
  285. void ShellDebugAppendToDebugFileW(LPCWSTR pszOutputString)
  286. {
  287. if (g_hDebugOutputFile != INVALID_HANDLE_VALUE)
  288. {
  289. char szBuf[500];
  290. DWORD cbWrite = WideCharToMultiByte(CP_ACP, 0, pszOutputString, -1, szBuf, ARRAYSIZE(szBuf), NULL, NULL);
  291. WriteFile(g_hDebugOutputFile, szBuf, cbWrite, &cbWrite, NULL);
  292. }
  293. }
  294. //
  295. // We cannot link to shlwapi, because comctl32 cannot link to shlwapi.
  296. // Duplicate some functions here so unicode stuff can run on Win95 platforms.
  297. //
  298. VOID MyOutputDebugStringWrapW(LPCWSTR lpOutputString)
  299. {
  300. if (staticIsOS(OS_NT))
  301. {
  302. OutputDebugStringW(lpOutputString);
  303. ShellDebugAppendToDebugFileW(lpOutputString);
  304. }
  305. else
  306. {
  307. char szBuf[1024+40];
  308. WideCharToMultiByte(CP_ACP, 0, lpOutputString, -1, szBuf, ARRAYSIZE(szBuf), NULL, NULL);
  309. OutputDebugStringA(szBuf);
  310. ShellDebugAppendToDebugFileA(szBuf);
  311. }
  312. }
  313. #define OutputDebugStringW MyOutputDebugStringWrapW
  314. VOID MyOutputDebugStringWrapA(LPCSTR lpOutputString)
  315. {
  316. OutputDebugStringA(lpOutputString);
  317. ShellDebugAppendToDebugFileA(lpOutputString);
  318. }
  319. #define OutputDebugStringA MyOutputDebugStringWrapA
  320. /*----------------------------------------------------------
  321. Purpose: Special verion of atoi. Supports hexadecimal too.
  322. If this function returns FALSE, *piRet is set to 0.
  323. Returns: TRUE if the string is a number, or contains a partial number
  324. FALSE if the string is not a number
  325. Cond: --
  326. */
  327. static
  328. BOOL
  329. MyStrToIntExA(
  330. LPCSTR pszString,
  331. DWORD dwFlags, // STIF_ bitfield
  332. LONGLONG FAR * piRet)
  333. {
  334. #define IS_DIGIT(ch) InRange(ch, '0', '9')
  335. BOOL bRet;
  336. LONGLONG n;
  337. BOOL bNeg = FALSE;
  338. LPCSTR psz;
  339. LPCSTR pszAdj;
  340. // Skip leading whitespace
  341. //
  342. for (psz = pszString; *psz == ' ' || *psz == '\n' || *psz == '\t'; psz = CharNextA(psz))
  343. ;
  344. // Determine possible explicit signage
  345. //
  346. if (*psz == '+' || *psz == '-')
  347. {
  348. bNeg = (*psz == '+') ? FALSE : TRUE;
  349. psz++;
  350. }
  351. // Or is this hexadecimal?
  352. //
  353. pszAdj = CharNextA(psz);
  354. if ((STIF_SUPPORT_HEX & dwFlags) &&
  355. *psz == '0' && (*pszAdj == 'x' || *pszAdj == 'X'))
  356. {
  357. // Yes
  358. // (Never allow negative sign with hexadecimal numbers)
  359. bNeg = FALSE;
  360. psz = CharNextA(pszAdj);
  361. pszAdj = psz;
  362. // Do the conversion
  363. //
  364. for (n = 0; ; psz = CharNextA(psz))
  365. {
  366. if (IS_DIGIT(*psz))
  367. n = 0x10 * n + *psz - '0';
  368. else
  369. {
  370. CHAR ch = *psz;
  371. int n2;
  372. if (ch >= 'a')
  373. ch -= 'a' - 'A';
  374. n2 = ch - 'A' + 0xA;
  375. if (n2 >= 0xA && n2 <= 0xF)
  376. n = 0x10 * n + n2;
  377. else
  378. break;
  379. }
  380. }
  381. // Return TRUE if there was at least one digit
  382. bRet = (psz != pszAdj);
  383. }
  384. else
  385. {
  386. // No
  387. pszAdj = psz;
  388. // Do the conversion
  389. for (n = 0; IS_DIGIT(*psz); psz = CharNextA(psz))
  390. n = 10 * n + *psz - '0';
  391. // Return TRUE if there was at least one digit
  392. bRet = (psz != pszAdj);
  393. }
  394. *piRet = bNeg ? -n : n;
  395. return bRet;
  396. }
  397. #endif
  398. #ifdef DEBUG
  399. EXTERN_C g_bUseNewLeakDetection = FALSE;
  400. DWORD g_dwDumpFlags = 0; // DF_*
  401. #ifdef FULL_DEBUG
  402. ULONGLONG g_qwTraceFlags = TF_ERROR | TF_WARNING; // TF_*
  403. DWORD g_dwBreakFlags = BF_ASSERT | BF_ONERRORMSG; // BF_*
  404. #else
  405. ULONGLONG g_qwTraceFlags = TF_ERROR; // TF_*
  406. DWORD g_dwBreakFlags = BF_ASSERT; // BF_*
  407. #endif
  408. DWORD g_dwPrototype = 0;
  409. DWORD g_dwFuncTraceFlags = 0; // FTF_*
  410. // TLS slot used to store depth for CcshellFuncMsg indentation
  411. static DWORD g_tlsStackDepth = TLS_OUT_OF_INDEXES;
  412. // Hack stack depth counter used when g_tlsStackDepth is not available
  413. static DWORD g_dwHackStackDepth = 0;
  414. static char g_szIndentLeader[] = " ";
  415. static WCHAR g_wszIndentLeader[] = L" ";
  416. static CHAR const FAR c_szNewline[] = LINE_SEPARATOR_STR; // (Deliberately CHAR)
  417. static WCHAR const FAR c_wszNewline[] = TEXTW(LINE_SEPARATOR_STR);
  418. extern CHAR const FAR c_szTrace[]; // (Deliberately CHAR)
  419. extern CHAR const FAR c_szErrorDbg[]; // (Deliberately CHAR)
  420. extern CHAR const FAR c_szWarningDbg[]; // (Deliberately CHAR)
  421. extern WCHAR const FAR c_wszTrace[];
  422. extern WCHAR const FAR c_wszErrorDbg[];
  423. extern WCHAR const FAR c_wszWarningDbg[];
  424. extern const CHAR FAR c_szAssertMsg[];
  425. extern CHAR const FAR c_szAssertFailed[];
  426. extern const WCHAR FAR c_wszAssertMsg[];
  427. extern WCHAR const FAR c_wszAssertFailed[];
  428. extern CHAR const FAR c_szRip[];
  429. extern CHAR const FAR c_szRipNoFn[];
  430. extern CHAR const FAR c_szRipMsg[];
  431. extern WCHAR const FAR c_wszRip[];
  432. extern WCHAR const FAR c_wszRipNoFn[];
  433. /*-------------------------------------------------------------------------
  434. Purpose: Adds one of the following prefix strings to pszBuf:
  435. "t MODULE "
  436. "err MODULE "
  437. "wrn MODULE "
  438. Returns the count of characters written.
  439. */
  440. int
  441. SetPrefixStringA(
  442. OUT LPSTR pszBuf,
  443. IN UINT cchBuf,
  444. IN ULONGLONG qwFlags)
  445. {
  446. if (TF_ALWAYS == qwFlags)
  447. StringCchCopyA(pszBuf, cchBuf, c_szTrace); // ok to truncate - debug message
  448. else if (IsFlagSet(qwFlags, TF_WARNING))
  449. StringCchCopyA(pszBuf, cchBuf, c_szWarningDbg); // ok to truncate - debug message
  450. else if (IsFlagSet(qwFlags, TF_ERROR))
  451. StringCchCopyA(pszBuf, cchBuf, c_szErrorDbg); // ok to truncate - debug message
  452. else
  453. StringCchCopyA(pszBuf, cchBuf, c_szTrace); // ok to truncate - debug message
  454. return lstrlenA(pszBuf);
  455. }
  456. int
  457. SetPrefixStringW(
  458. OUT LPWSTR pszBuf,
  459. IN UINT cchBuf,
  460. IN ULONGLONG qwFlags)
  461. {
  462. if (TF_ALWAYS == qwFlags)
  463. StringCchCopyW(pszBuf, cchBuf, c_wszTrace); // ok to truncate - debug message
  464. else if (IsFlagSet(qwFlags, TF_WARNING))
  465. StringCchCopyW(pszBuf, cchBuf, c_wszWarningDbg);// ok to truncate - debug message
  466. else if (IsFlagSet(qwFlags, TF_ERROR))
  467. StringCchCopyW(pszBuf, cchBuf, c_wszErrorDbg); // ok to truncate - debug message
  468. else
  469. StringCchCopyW(pszBuf, cchBuf, c_wszTrace); // ok to truncate - debug message
  470. return lstrlenW(pszBuf);
  471. }
  472. static
  473. LPCSTR
  474. _PathFindFileNameA(
  475. LPCSTR pPath)
  476. {
  477. LPCSTR pT;
  478. for (pT = pPath; *pPath; pPath = CharNextA(pPath)) {
  479. if ((pPath[0] == '\\' || pPath[0] == ':' || pPath[0] == '/')
  480. && pPath[1] && pPath[1] != '\\' && pPath[1] != '/')
  481. pT = pPath + 1;
  482. }
  483. return pT;
  484. }
  485. static
  486. LPCWSTR
  487. _PathFindFileNameW(
  488. LPCWSTR pPath)
  489. {
  490. LPCWSTR pT;
  491. for (pT = pPath; *pPath; pPath++) {
  492. if ((pPath[0] == TEXTW('\\') || pPath[0] == TEXTW(':') || pPath[0] == TEXTW('/'))
  493. && pPath[1] && pPath[1] != TEXTW('\\') && pPath[1] != TEXTW('/'))
  494. pT = pPath + 1;
  495. }
  496. return pT;
  497. }
  498. /*-------------------------------------------------------------------------
  499. Purpose: Returns TRUE if this process is a shell-related process.
  500. */
  501. BOOL _IsShellProcess()
  502. {
  503. CHAR szModuleName[MAX_PATH];
  504. if (GetModuleFileNameA(NULL, szModuleName, sizeof(CHAR) * MAX_PATH) > 0 )
  505. {
  506. if (StrStrIA(szModuleName, "explorer.exe") ||
  507. StrStrIA(szModuleName, "iexplore.exe") ||
  508. StrStrIA(szModuleName, "rundll32.exe") ||
  509. StrStrIA(szModuleName, "mshtmpad.exe"))
  510. {
  511. // yes, the exe is a shell one
  512. return TRUE;
  513. }
  514. }
  515. // not a normal shell executable
  516. return FALSE;
  517. }
  518. // FEATURE (scotth): Use the Ccshell functions. _AssertMsg and
  519. // _DebugMsg are obsolete. They will be removed once all the
  520. // components don't have TEXT() wrapping their debug strings anymore.
  521. void
  522. WINCAPI
  523. _AssertMsgA(
  524. BOOL f,
  525. LPCSTR pszMsg, ...)
  526. {
  527. CHAR ach[1024+40];
  528. va_list vArgs;
  529. if (!f)
  530. {
  531. int cch;
  532. StringCchCopyA(ach, ARRAYSIZE(ach), c_szAssertMsg); // ok to truncate - debug message
  533. cch = lstrlenA(ach);
  534. va_start(vArgs, pszMsg);
  535. StringCchVPrintfA(&ach[cch], ARRAYSIZE(ach) - cch, pszMsg, vArgs); // ok to truncate - debug message
  536. va_end(vArgs);
  537. OutputDebugStringA(ach);
  538. OutputDebugStringA(c_szNewline);
  539. if (IsFlagSet(g_dwBreakFlags, BF_ASSERT))
  540. {
  541. // MSDEV USERS: This is not the real assert. Hit
  542. // Shift-F11 to jump back to the caller.
  543. DEBUG_BREAK; // ASSERT
  544. }
  545. }
  546. }
  547. void
  548. WINCAPI
  549. _AssertMsgW(
  550. BOOL f,
  551. LPCWSTR pszMsg, ...)
  552. {
  553. WCHAR ach[1024+40];
  554. va_list vArgs;
  555. if (!f)
  556. {
  557. int cch;
  558. StringCchCopyW(ach, ARRAYSIZE(ach), c_wszAssertMsg); // ok to truncate - debug message
  559. cch = lstrlenW(ach);
  560. va_start(vArgs, pszMsg);
  561. StringCchVPrintfW(&ach[cch], ARRAYSIZE(ach) - cch, pszMsg, vArgs); // ok to truncate - debug message
  562. va_end(vArgs);
  563. OutputDebugStringW(ach);
  564. OutputDebugStringW(c_wszNewline);
  565. if (IsFlagSet(g_dwBreakFlags, BF_ASSERT))
  566. {
  567. // MSDEV USERS: This is not the real assert. Hit
  568. // Shift-F11 to jump back to the caller.
  569. DEBUG_BREAK; // ASSERT
  570. }
  571. }
  572. }
  573. void
  574. _AssertStrLenW(
  575. LPCWSTR pszStr,
  576. int iLen)
  577. {
  578. if (pszStr && iLen < lstrlenW(pszStr))
  579. {
  580. // MSDEV USERS: This is not the real assert. Hit
  581. // Shift-F11 to jump back to the caller.
  582. DEBUG_BREAK; // ASSERT
  583. }
  584. }
  585. void
  586. _AssertStrLenA(
  587. LPCSTR pszStr,
  588. int iLen)
  589. {
  590. if (pszStr && iLen < lstrlenA(pszStr))
  591. {
  592. // MSDEV USERS: This is not the real assert. Hit
  593. // Shift-F11 to jump back to the caller.
  594. DEBUG_BREAK; // ASSERT
  595. }
  596. }
  597. void
  598. WINCAPI
  599. _DebugMsgA(
  600. ULONGLONG flag,
  601. LPCSTR pszMsg, ...)
  602. {
  603. CHAR ach[5*MAX_PATH+40]; // Handles 5*largest path + slop for message
  604. va_list vArgs;
  605. if (TF_ALWAYS == flag || (IsFlagSet(g_qwTraceFlags, flag) && flag))
  606. {
  607. int cch;
  608. cch = SetPrefixStringA(ach, ARRAYSIZE(ach), flag);
  609. va_start(vArgs, pszMsg);
  610. try
  611. {
  612. StringCchVPrintfA(&ach[cch], ARRAYSIZE(ach) - cch, pszMsg, vArgs); // ok to truncate - debug message
  613. }
  614. except(EXCEPTION_EXECUTE_HANDLER)
  615. {
  616. OutputDebugString(TEXT("CCSHELL: DebugMsg exception: "));
  617. OutputDebugStringA(pszMsg);
  618. }
  619. __endexcept
  620. va_end(vArgs);
  621. OutputDebugStringA(ach);
  622. OutputDebugStringA(c_szNewline);
  623. if (TF_ALWAYS != flag &&
  624. ((flag & TF_ERROR) && IsFlagSet(g_dwBreakFlags, BF_ONERRORMSG) ||
  625. (flag & TF_WARNING) && IsFlagSet(g_dwBreakFlags, BF_ONWARNMSG)))
  626. {
  627. // MSDEV USERS: This is not the real assert. Hit
  628. // Shift-F11 to jump back to the caller.
  629. DEBUG_BREAK; // ASSERT
  630. }
  631. }
  632. }
  633. void
  634. WINCAPI
  635. _DebugMsgW(
  636. ULONGLONG flag,
  637. LPCWSTR pszMsg, ...)
  638. {
  639. WCHAR ach[5*MAX_PATH+40]; // Handles 5*largest path + slop for message
  640. va_list vArgs;
  641. if (TF_ALWAYS == flag || (IsFlagSet(g_qwTraceFlags, flag) && flag))
  642. {
  643. int cch;
  644. SetPrefixStringW(ach, ARRAYSIZE(ach), flag);
  645. cch = lstrlenW(ach);
  646. va_start(vArgs, pszMsg);
  647. try
  648. {
  649. StringCchVPrintfW(&ach[cch], ARRAYSIZE(ach) - cch, pszMsg, vArgs); // ok to truncate - debug message
  650. }
  651. except(EXCEPTION_EXECUTE_HANDLER)
  652. {
  653. OutputDebugString(TEXT("CCSHELL: DebugMsg exception: "));
  654. OutputDebugStringW(pszMsg);
  655. }
  656. __endexcept
  657. va_end(vArgs);
  658. OutputDebugStringW(ach);
  659. OutputDebugStringW(c_wszNewline);
  660. if (TF_ALWAYS != flag &&
  661. ((flag & TF_ERROR) && IsFlagSet(g_dwBreakFlags, BF_ONERRORMSG) ||
  662. (flag & TF_WARNING) && IsFlagSet(g_dwBreakFlags, BF_ONWARNMSG)))
  663. {
  664. // MSDEV USERS: This is not the real assert. Hit
  665. // Shift-F11 to jump back to the caller.
  666. DEBUG_BREAK; // ASSERT
  667. }
  668. }
  669. }
  670. //
  671. // Smart debug functions
  672. //
  673. /*----------------------------------------------------------
  674. Purpose: Displays assertion string.
  675. Returns: TRUE to debugbreak
  676. */
  677. BOOL
  678. CcshellAssertFailedA(
  679. LPCSTR pszFile,
  680. int line,
  681. LPCSTR pszEval,
  682. BOOL bBreakInside)
  683. {
  684. BOOL bRet = FALSE;
  685. LPCSTR psz;
  686. CHAR ach[256];
  687. psz = _PathFindFileNameA(pszFile);
  688. StringCchPrintfA(ach, ARRAYSIZE(ach), c_szAssertFailed, psz, line, pszEval); // ok to truncate - debug message
  689. OutputDebugStringA(ach);
  690. if (IsFlagSet(g_dwBreakFlags, BF_ASSERT))
  691. {
  692. if (bBreakInside)
  693. {
  694. // !!! ASSERT !!!! ASSERT !!!! ASSERT !!!
  695. // MSDEV USERS: This is not the real assert. Hit
  696. // Shift-F11 to jump back to the caller.
  697. DEBUG_BREAK; // ASSERT
  698. // !!! ASSERT !!!! ASSERT !!!! ASSERT !!!
  699. }
  700. else
  701. bRet = TRUE;
  702. }
  703. return bRet;
  704. }
  705. /*----------------------------------------------------------
  706. Purpose: Displays assertion string.
  707. */
  708. BOOL
  709. CcshellAssertFailedW(
  710. LPCWSTR pszFile,
  711. int line,
  712. LPCWSTR pszEval,
  713. BOOL bBreakInside)
  714. {
  715. BOOL bRet = FALSE;
  716. LPCWSTR psz;
  717. WCHAR ach[1024]; // Some callers use more than 256
  718. psz = _PathFindFileNameW(pszFile);
  719. // If psz == NULL, CharPrevW failed which implies we are running on Win95. We can get this
  720. // if we get an assert in some of the W functions in shlwapi... Call the A version of assert...
  721. if (!psz)
  722. {
  723. char szFile[MAX_PATH];
  724. char szEval[256]; // since the total output is thhis size should be enough...
  725. WideCharToMultiByte(CP_ACP, 0, pszFile, -1, szFile, ARRAYSIZE(szFile), NULL, NULL);
  726. WideCharToMultiByte(CP_ACP, 0, pszEval, -1, szEval, ARRAYSIZE(szEval), NULL, NULL);
  727. return CcshellAssertFailedA(szFile, line, szEval, bBreakInside);
  728. }
  729. StringCchPrintfW(ach, ARRAYSIZE(ach), c_wszAssertFailed, psz, line, pszEval); // ok to truncate - debug message
  730. OutputDebugStringW(ach);
  731. if (IsFlagSet(g_dwBreakFlags, BF_ASSERT))
  732. {
  733. if (bBreakInside)
  734. {
  735. // !!! ASSERT !!!! ASSERT !!!! ASSERT !!!
  736. // MSDEV USERS: This is not the real assert. Hit
  737. // Shift-F11 to jump back to the caller.
  738. DEBUG_BREAK; // ASSERT
  739. // !!! ASSERT !!!! ASSERT !!!! ASSERT !!!
  740. }
  741. else
  742. bRet = TRUE;
  743. }
  744. return bRet;
  745. }
  746. /*----------------------------------------------------------
  747. Purpose: Displays a RIP string.
  748. Returns: TRUE to debugbreak
  749. */
  750. BOOL
  751. CcshellRipA(
  752. LPCSTR pszFile,
  753. int line,
  754. LPCSTR pszEval,
  755. BOOL bBreakInside)
  756. {
  757. BOOL bRet = FALSE;
  758. LPCSTR psz;
  759. CHAR ach[256];
  760. psz = _PathFindFileNameA(pszFile);
  761. StringCchPrintfA(ach, ARRAYSIZE(ach), c_szRipNoFn, psz, line, pszEval); // ok to truncate - debug message
  762. OutputDebugStringA(ach);
  763. if (_IsShellProcess() || IsFlagSet(g_dwBreakFlags, BF_RIP))
  764. {
  765. if (bBreakInside)
  766. {
  767. // !!! RIP !!!! RIP !!!! RIP !!!
  768. // MSDEV USERS: This is not the real RIP. Hit
  769. // Shift-F11 to jump back to the caller.
  770. DEBUG_BREAK; // ASSERT
  771. // !!! RIP !!!! RIP !!!! RIP !!!
  772. }
  773. else
  774. bRet = TRUE;
  775. }
  776. return bRet;
  777. }
  778. /*----------------------------------------------------------
  779. Purpose: Displays a RIP string.
  780. */
  781. BOOL
  782. CcshellRipW(
  783. LPCWSTR pszFile,
  784. int line,
  785. LPCWSTR pszEval,
  786. BOOL bBreakInside)
  787. {
  788. BOOL bRet = FALSE;
  789. LPCWSTR psz;
  790. WCHAR ach[256];
  791. psz = _PathFindFileNameW(pszFile);
  792. // If psz == NULL, CharPrevW failed which implies we are running on Win95.
  793. // We can get this if we get an assert in some of the W functions in
  794. // shlwapi... Call the A version of assert...
  795. if (!psz)
  796. {
  797. char szFile[MAX_PATH];
  798. char szEval[256]; // since the total output is thhis size should be enough...
  799. WideCharToMultiByte(CP_ACP, 0, pszFile, -1, szFile, ARRAYSIZE(szFile), NULL, NULL);
  800. WideCharToMultiByte(CP_ACP, 0, pszEval, -1, szEval, ARRAYSIZE(szEval), NULL, NULL);
  801. return CcshellRipA(szFile, line, szEval, bBreakInside);
  802. }
  803. StringCchPrintfW(ach, ARRAYSIZE(ach), c_wszRipNoFn, psz, line, pszEval); // ok to truncate - debug message
  804. OutputDebugStringW(ach);
  805. if (_IsShellProcess() || IsFlagSet(g_dwBreakFlags, BF_RIP))
  806. {
  807. if (bBreakInside)
  808. {
  809. // !!! RIP !!!! RIP !!!! RIP !!!
  810. // MSDEV USERS: This is not the real assert. Hit
  811. // Shift-F11 to jump back to the caller.
  812. DEBUG_BREAK; // ASSERT
  813. // !!! RIP !!!! RIP !!!! RIP !!!
  814. }
  815. else
  816. bRet = TRUE;
  817. }
  818. return bRet;
  819. }
  820. BOOL
  821. WINCAPI
  822. CcshellRipMsgA(
  823. BOOL f,
  824. LPCSTR pszMsg, ...)
  825. {
  826. CHAR ach[1024+40];
  827. va_list vArgs;
  828. if (!f)
  829. {
  830. OutputDebugStringA(c_szRipMsg);
  831. va_start(vArgs, pszMsg);
  832. StringCchVPrintfA(ach, ARRAYSIZE(ach), pszMsg, vArgs); // ok to truncate - debug message
  833. va_end(vArgs);
  834. OutputDebugStringA(ach);
  835. OutputDebugStringA(c_szNewline);
  836. if (_IsShellProcess() || IsFlagSet(g_dwBreakFlags, BF_RIP))
  837. {
  838. // MSDEV USERS: This is not the real assert. Hit
  839. // Shift-F11 to jump back to the caller.
  840. DEBUG_BREAK; // ASSERT
  841. }
  842. }
  843. return FALSE;
  844. }
  845. BOOL
  846. WINCAPI
  847. CcshellRipMsgW(
  848. BOOL f,
  849. LPCSTR pszMsg, ...) // (this is deliberately CHAR)
  850. {
  851. WCHAR ach[1024+40];
  852. va_list vArgs;
  853. if (!f)
  854. {
  855. LPWSTR pwsz;
  856. WCHAR wszBuf[128];
  857. OutputDebugStringA(c_szRipMsg);
  858. // (We convert the string, rather than simply input an
  859. // LPCWSTR parameter, so the caller doesn't have to wrap
  860. // all the string constants with the TEXT() macro.)
  861. ach[0] = L'\0'; // In case this fails
  862. if (UnicodeFromAnsi(&pwsz, pszMsg, wszBuf, SIZECHARS(wszBuf)))
  863. {
  864. va_start(vArgs, pszMsg);
  865. StringCchVPrintfW(ach, ARRAYSIZE(ach), pwsz, vArgs); // ok to truncate - debug message
  866. va_end(vArgs);
  867. UnicodeFromAnsi(&pwsz, NULL, wszBuf, 0);
  868. }
  869. OutputDebugStringW(ach);
  870. OutputDebugStringA(c_szNewline);
  871. if (_IsShellProcess() || IsFlagSet(g_dwBreakFlags, BF_RIP))
  872. {
  873. // MSDEV USERS: This is not the real assert. Hit
  874. // Shift-F11 to jump back to the caller.
  875. DEBUG_BREAK; // ASSERT
  876. }
  877. }
  878. return FALSE;
  879. }
  880. /*----------------------------------------------------------
  881. Purpose: Keep track of the stack depth for function call trace
  882. messages.
  883. */
  884. void
  885. CcshellStackEnter(void)
  886. {
  887. if (TLS_OUT_OF_INDEXES != g_tlsStackDepth)
  888. {
  889. DWORD dwDepth;
  890. dwDepth = PtrToUlong(TlsGetValue(g_tlsStackDepth));
  891. TlsSetValue(g_tlsStackDepth, (LPVOID)(ULONG_PTR)(dwDepth + 1));
  892. }
  893. else
  894. {
  895. g_dwHackStackDepth++;
  896. }
  897. }
  898. /*----------------------------------------------------------
  899. Purpose: Keep track of the stack depth for functionc all trace
  900. messages.
  901. */
  902. void
  903. CcshellStackLeave(void)
  904. {
  905. if (TLS_OUT_OF_INDEXES != g_tlsStackDepth)
  906. {
  907. DWORD dwDepth;
  908. dwDepth = PtrToUlong(TlsGetValue(g_tlsStackDepth));
  909. if (EVAL(0 < dwDepth))
  910. {
  911. EVAL(TlsSetValue(g_tlsStackDepth, (LPVOID)(ULONG_PTR)(dwDepth - 1)));
  912. }
  913. }
  914. else
  915. {
  916. if (EVAL(0 < g_dwHackStackDepth))
  917. {
  918. g_dwHackStackDepth--;
  919. }
  920. }
  921. }
  922. /*----------------------------------------------------------
  923. Purpose: Return the stack depth.
  924. */
  925. static
  926. DWORD
  927. CcshellGetStackDepth(void)
  928. {
  929. DWORD dwDepth;
  930. if (TLS_OUT_OF_INDEXES != g_tlsStackDepth)
  931. {
  932. dwDepth = PtrToUlong(TlsGetValue(g_tlsStackDepth));
  933. }
  934. else
  935. {
  936. dwDepth = g_dwHackStackDepth;
  937. }
  938. return dwDepth;
  939. }
  940. /*----------------------------------------------------------
  941. Purpose: Wide-char version of CcshellAssertMsgA
  942. */
  943. void
  944. CDECL
  945. CcshellAssertMsgW(
  946. BOOL f,
  947. LPCSTR pszMsg, ...)
  948. {
  949. WCHAR ach[1024+40]; // Largest path plus extra
  950. va_list vArgs;
  951. if (!f)
  952. {
  953. WCHAR wszBuf[1024];
  954. LPWSTR pszEnd;
  955. LPWSTR pwsz;
  956. HRESULT hr = StringCchCopyExW(ach, ARRAYSIZE(ach), c_wszAssertMsg, &pszEnd, NULL, 0);
  957. if (SUCCEEDED(hr))
  958. {
  959. va_start(vArgs, pszMsg);
  960. // (We convert the string, rather than simply input an
  961. // LPCWSTR parameter, so the caller doesn't have to wrap
  962. // all the string constants with the TEXT() macro.)
  963. if (UnicodeFromAnsi(&pwsz, pszMsg, wszBuf, SIZECHARS(wszBuf)))
  964. {
  965. StringCchVPrintfW(pszEnd, ach + ARRAYSIZE(ach) - pszEnd, pwsz, vArgs); // ok to truncate - debug message
  966. UnicodeFromAnsi(&pwsz, NULL, wszBuf, 0);
  967. }
  968. va_end(vArgs);
  969. OutputDebugStringW(ach);
  970. OutputDebugStringW(c_wszNewline);
  971. }
  972. if (IsFlagSet(g_dwBreakFlags, BF_ASSERT))
  973. {
  974. // !!! ASSERT !!!! ASSERT !!!! ASSERT !!!
  975. // MSDEV USERS: This is not the real assert. Hit
  976. // Shift-F11 to jump back to the caller.
  977. DEBUG_BREAK; // ASSERT
  978. // !!! ASSERT !!!! ASSERT !!!! ASSERT !!!
  979. }
  980. }
  981. }
  982. /*----------------------------------------------------------
  983. Purpose: Wide-char version of CcshellDebugMsgA. Note this
  984. function deliberately takes an ANSI format string
  985. so our trace messages don't all need to be wrapped
  986. in TEXT().
  987. */
  988. void
  989. CDECL
  990. CcshellDebugMsgW(
  991. ULONGLONG flag,
  992. LPCSTR pszMsg, ...) // (this is deliberately CHAR)
  993. {
  994. WCHAR ach[1024+40]; // Largest path plus extra
  995. va_list vArgs;
  996. if (TF_ALWAYS == flag || (IsFlagSet(g_qwTraceFlags, flag) && flag))
  997. {
  998. int cch;
  999. WCHAR wszBuf[1024];
  1000. LPWSTR pwsz;
  1001. SetPrefixStringW(ach, ARRAYSIZE(ach), flag);
  1002. cch = lstrlenW(ach);
  1003. va_start(vArgs, pszMsg);
  1004. // (We convert the string, rather than simply input an
  1005. // LPCWSTR parameter, so the caller doesn't have to wrap
  1006. // all the string constants with the TEXT() macro.)
  1007. if (UnicodeFromAnsi(&pwsz, pszMsg, wszBuf, SIZECHARS(wszBuf)))
  1008. {
  1009. StringCchVPrintfW(&ach[cch], ARRAYSIZE(ach) - cch, pwsz, vArgs); // ok to truncate - debug message
  1010. UnicodeFromAnsi(&pwsz, NULL, wszBuf, 0);
  1011. }
  1012. va_end(vArgs);
  1013. OutputDebugStringW(ach);
  1014. OutputDebugStringW(c_wszNewline);
  1015. if (TF_ALWAYS != flag &&
  1016. ((flag & TF_ERROR) && IsFlagSet(g_dwBreakFlags, BF_ONERRORMSG) ||
  1017. (flag & TF_WARNING) && IsFlagSet(g_dwBreakFlags, BF_ONWARNMSG)))
  1018. {
  1019. // MSDEV USERS: This is not the real assert. Hit
  1020. // Shift-F11 to jump back to the caller.
  1021. DEBUG_BREAK; // ASSERT
  1022. }
  1023. }
  1024. }
  1025. /*-------------------------------------------------------------------------
  1026. Purpose: Since the ATL code does not pass in a flag parameter,
  1027. we'll hardcode and check for TF_ATL.
  1028. */
  1029. void CDECL ShellAtlTraceW(LPCWSTR pszMsg, ...)
  1030. {
  1031. WCHAR ach[1024+40]; // Largest path plus extra
  1032. va_list vArgs;
  1033. if (g_qwTraceFlags & TF_ATL)
  1034. {
  1035. LPWSTR pszEnd;
  1036. HRESULT hr;
  1037. SetPrefixStringW(ach, ARRAYSIZE(ach), TF_ATL);
  1038. hr = StringCchCatExW(ach, ARRAYSIZE(ach), L"(ATL) ", &pszEnd, NULL, 0);
  1039. if (SUCCEEDED(hr))
  1040. {
  1041. va_start(vArgs, pszMsg);
  1042. StringCchVPrintfW(pszEnd, ach + ARRAYSIZE(ach) - pszEnd, pszMsg, vArgs); // ok to truncate - debug message
  1043. va_end(vArgs);
  1044. OutputDebugStringW(ach);
  1045. }
  1046. }
  1047. }
  1048. /*----------------------------------------------------------
  1049. Purpose: Wide-char version of CcshellFuncMsgA. Note this
  1050. function deliberately takes an ANSI format string
  1051. so our trace messages don't all need to be wrapped
  1052. in TEXT().
  1053. */
  1054. void
  1055. CDECL
  1056. CcshellFuncMsgW(
  1057. ULONGLONG flag,
  1058. LPCSTR pszMsg, ...) // (this is deliberately CHAR)
  1059. {
  1060. WCHAR ach[1024+40]; // Largest path plus extra
  1061. va_list vArgs;
  1062. if (IsFlagSet(g_qwTraceFlags, TF_FUNC) &&
  1063. IsFlagSet(g_dwFuncTraceFlags, flag))
  1064. {
  1065. int cch;
  1066. WCHAR wszBuf[1024];
  1067. LPWSTR pwsz;
  1068. DWORD dwStackDepth;
  1069. LPWSTR pszLeaderEnd;
  1070. WCHAR chSave;
  1071. // Determine the indentation for trace message based on
  1072. // stack depth.
  1073. dwStackDepth = CcshellGetStackDepth();
  1074. if (dwStackDepth < SIZECHARS(g_szIndentLeader))
  1075. {
  1076. pszLeaderEnd = &g_wszIndentLeader[dwStackDepth];
  1077. }
  1078. else
  1079. {
  1080. pszLeaderEnd = &g_wszIndentLeader[SIZECHARS(g_wszIndentLeader)-1];
  1081. }
  1082. chSave = *pszLeaderEnd;
  1083. *pszLeaderEnd = '\0';
  1084. StringCchPrintfW(ach, ARRAYSIZE(ach), L"%s %s", c_wszTrace, g_wszIndentLeader); // ok to truncate - debug message
  1085. *pszLeaderEnd = chSave;
  1086. // Compose remaining string
  1087. cch = lstrlenW(ach);
  1088. va_start(vArgs, pszMsg);
  1089. // (We convert the string, rather than simply input an
  1090. // LPCWSTR parameter, so the caller doesn't have to wrap
  1091. // all the string constants with the TEXT() macro.)
  1092. if (UnicodeFromAnsi(&pwsz, pszMsg, wszBuf, SIZECHARS(wszBuf)))
  1093. {
  1094. StringCchVPrintfW(&ach[cch], ARRAYSIZE(ach) - cch, pwsz, vArgs); // ok to truncate - debug message
  1095. UnicodeFromAnsi(&pwsz, NULL, wszBuf, 0);
  1096. }
  1097. va_end(vArgs);
  1098. OutputDebugStringW(ach);
  1099. OutputDebugStringW(c_wszNewline);
  1100. }
  1101. }
  1102. /*----------------------------------------------------------
  1103. Purpose: Assert failed message only
  1104. */
  1105. void
  1106. CDECL
  1107. CcshellAssertMsgA(
  1108. BOOL f,
  1109. LPCSTR pszMsg, ...)
  1110. {
  1111. CHAR ach[1024+40]; // Largest path plus extra
  1112. va_list vArgs;
  1113. if (!f)
  1114. {
  1115. LPSTR pszEnd;
  1116. HRESULT hr = StringCchCopyExA(ach, ARRAYSIZE(ach), c_szAssertMsg, &pszEnd, NULL, 0);
  1117. if (SUCCEEDED(hr))
  1118. {
  1119. va_start(vArgs, pszMsg);
  1120. StringCchVPrintfA(pszEnd, ach + ARRAYSIZE(ach) - pszEnd, pszMsg, vArgs); // ok to truncate - debug message
  1121. va_end(vArgs);
  1122. OutputDebugStringA(ach);
  1123. OutputDebugStringA(c_szNewline);
  1124. }
  1125. if (IsFlagSet(g_dwBreakFlags, BF_ASSERT))
  1126. {
  1127. // !!! ASSERT !!!! ASSERT !!!! ASSERT !!!
  1128. // MSDEV USERS: This is not the real assert. Hit
  1129. // Shift-F11 to jump back to the caller.
  1130. DEBUG_BREAK; // ASSERT
  1131. // !!! ASSERT !!!! ASSERT !!!! ASSERT !!!
  1132. }
  1133. }
  1134. }
  1135. /*----------------------------------------------------------
  1136. Purpose: Debug spew
  1137. */
  1138. void
  1139. CDECL
  1140. CcshellDebugMsgA(
  1141. ULONGLONG flag,
  1142. LPCSTR pszMsg, ...)
  1143. {
  1144. CHAR ach[1024+40]; // Largest path plus extra
  1145. va_list vArgs;
  1146. if (TF_ALWAYS == flag || (IsFlagSet(g_qwTraceFlags, flag) && flag))
  1147. {
  1148. int cch;
  1149. cch = SetPrefixStringA(ach, ARRAYSIZE(ach), flag);
  1150. va_start(vArgs, pszMsg);
  1151. StringCchVPrintfA(&ach[cch], ARRAYSIZE(ach) - cch, pszMsg, vArgs); // ok to truncate - debug message
  1152. va_end(vArgs);
  1153. OutputDebugStringA(ach);
  1154. OutputDebugStringA(c_szNewline);
  1155. if (TF_ALWAYS != flag &&
  1156. ((flag & TF_ERROR) && IsFlagSet(g_dwBreakFlags, BF_ONERRORMSG) ||
  1157. (flag & TF_WARNING) && IsFlagSet(g_dwBreakFlags, BF_ONWARNMSG)))
  1158. {
  1159. // MSDEV USERS: This is not the real assert. Hit
  1160. // Shift-F11 to jump back to the caller.
  1161. DEBUG_BREAK; // ASSERT
  1162. }
  1163. }
  1164. }
  1165. /*-------------------------------------------------------------------------
  1166. Purpose: Since the ATL code does not pass in a flag parameter,
  1167. we'll hardcode and check for TF_ATL.
  1168. */
  1169. void CDECL ShellAtlTraceA(LPCSTR pszMsg, ...)
  1170. {
  1171. CHAR ach[1024+40]; // Largest path plus extra
  1172. va_list vArgs;
  1173. if (g_qwTraceFlags & TF_ATL)
  1174. {
  1175. LPSTR pszEnd;
  1176. HRESULT hr;
  1177. SetPrefixStringA(ach, ARRAYSIZE(ach), TF_ATL);
  1178. hr = StringCchCatExA(ach, ARRAYSIZE(ach), "(ATL) ", &pszEnd, NULL, 0);
  1179. if (SUCCEEDED(hr))
  1180. {
  1181. va_start(vArgs, pszMsg);
  1182. StringCchVPrintfA(pszEnd, ach + ARRAYSIZE(ach) - pszEnd, pszMsg, vArgs); // ok to truncate - debug message
  1183. va_end(vArgs);
  1184. OutputDebugStringA(ach);
  1185. }
  1186. }
  1187. }
  1188. /*----------------------------------------------------------
  1189. Purpose: Debug spew for function trace calls
  1190. */
  1191. void
  1192. CDECL
  1193. CcshellFuncMsgA(
  1194. ULONGLONG flag,
  1195. LPCSTR pszMsg, ...)
  1196. {
  1197. CHAR ach[1024+40]; // Largest path plus extra
  1198. va_list vArgs;
  1199. if (IsFlagSet(g_qwTraceFlags, TF_FUNC) &&
  1200. IsFlagSet(g_dwFuncTraceFlags, flag))
  1201. {
  1202. int cch;
  1203. DWORD dwStackDepth;
  1204. LPSTR pszLeaderEnd;
  1205. CHAR chSave;
  1206. // Determine the indentation for trace message based on
  1207. // stack depth.
  1208. dwStackDepth = CcshellGetStackDepth();
  1209. if (dwStackDepth < sizeof(g_szIndentLeader))
  1210. {
  1211. pszLeaderEnd = &g_szIndentLeader[dwStackDepth];
  1212. }
  1213. else
  1214. {
  1215. pszLeaderEnd = &g_szIndentLeader[sizeof(g_szIndentLeader)-1];
  1216. }
  1217. chSave = *pszLeaderEnd;
  1218. *pszLeaderEnd = '\0';
  1219. StringCchPrintfA(ach, ARRAYSIZE(ach), "%s %s", c_szTrace, g_szIndentLeader); // ok to truncate - debug message
  1220. *pszLeaderEnd = chSave;
  1221. // Compose remaining string
  1222. cch = lstrlenA(ach);
  1223. va_start(vArgs, pszMsg);
  1224. StringCchVPrintfA(&ach[cch], ARRAYSIZE(ach) - cch, pszMsg, vArgs); // ok to truncate - debug message
  1225. va_end(vArgs);
  1226. OutputDebugStringA(ach);
  1227. OutputDebugStringA(c_szNewline);
  1228. }
  1229. }
  1230. /*-------------------------------------------------------------------------
  1231. Purpose: Spews a trace message if hrTest is a failure code.
  1232. */
  1233. HRESULT
  1234. TraceHR(
  1235. HRESULT hrTest,
  1236. LPCSTR pszExpr,
  1237. LPCSTR pszFile,
  1238. int iLine)
  1239. {
  1240. CHAR ach[1024+40]; // Largest path plus extra
  1241. if (g_qwTraceFlags & TF_WARNING &&
  1242. FAILED(hrTest))
  1243. {
  1244. int cch;
  1245. cch = SetPrefixStringA(ach, ARRAYSIZE(ach), TF_WARNING);
  1246. StringCchPrintfA(&ach[cch], ARRAYSIZE(ach) - cch,
  1247. "THR: Failure of \"%s\" at %s, line %d (%#08lx)",
  1248. pszExpr, _PathFindFileNameA(pszFile), iLine, hrTest); // ok to truncate - debug message
  1249. OutputDebugStringA(ach);
  1250. OutputDebugStringA(c_szNewline);
  1251. if (IsFlagSet(g_dwBreakFlags, BF_THR))
  1252. {
  1253. // !!! THR !!!! THR !!!! THR !!!
  1254. // MSDEV USERS: This is not the real assert. Hit
  1255. // Shift-F11 to jump back to the caller.
  1256. DEBUG_BREAK; // ASSERT
  1257. // !!! THR !!!! THR !!!! THR !!!
  1258. }
  1259. }
  1260. return hrTest;
  1261. }
  1262. /*-------------------------------------------------------------------------
  1263. Purpose: Spews a trace message if bTest is false.
  1264. */
  1265. BOOL
  1266. TraceBool(
  1267. BOOL bTest,
  1268. LPCSTR pszExpr,
  1269. LPCSTR pszFile,
  1270. int iLine)
  1271. {
  1272. CHAR ach[1024+40]; // Largest path plus extra
  1273. if (g_qwTraceFlags & TF_WARNING && !bTest)
  1274. {
  1275. int cch;
  1276. cch = SetPrefixStringA(ach, ARRAYSIZE(ach), TF_WARNING);
  1277. StringCchPrintfA(&ach[cch], ARRAYSIZE(ach) - cch,
  1278. "TBOOL: Failure of \"%s\" at %s, line %d",
  1279. pszExpr, _PathFindFileNameA(pszFile), iLine); // ok to truncate - debug message
  1280. OutputDebugStringA(ach);
  1281. OutputDebugStringA(c_szNewline);
  1282. if (IsFlagSet(g_dwBreakFlags, BF_THR))
  1283. {
  1284. // !!! TBOOL !!!! TBOOL !!!! TBOOL !!!
  1285. // MSDEV USERS: This is not the real assert. Hit
  1286. // Shift-F11 to jump back to the caller.
  1287. DEBUG_BREAK; // ASSERT
  1288. // !!! TBOOL !!!! TBOOL !!!! TBOOL !!!
  1289. }
  1290. }
  1291. return bTest;
  1292. }
  1293. /*-------------------------------------------------------------------------
  1294. Purpose: Spews a trace message if iTest is -1.
  1295. */
  1296. int
  1297. TraceInt(
  1298. int iTest,
  1299. LPCSTR pszExpr,
  1300. LPCSTR pszFile,
  1301. int iLine)
  1302. {
  1303. CHAR ach[1024+40]; // Largest path plus extra
  1304. if (g_qwTraceFlags & TF_WARNING && -1 == iTest)
  1305. {
  1306. int cch;
  1307. cch = SetPrefixStringA(ach, ARRAYSIZE(ach), TF_WARNING);
  1308. StringCchPrintfA(&ach[cch], ARRAYSIZE(ach) - cch,
  1309. "TINT: Failure of \"%s\" at %s, line %d",
  1310. pszExpr, _PathFindFileNameA(pszFile), iLine); // ok to truncate - debug message
  1311. OutputDebugStringA(ach);
  1312. OutputDebugStringA(c_szNewline);
  1313. if (IsFlagSet(g_dwBreakFlags, BF_THR))
  1314. {
  1315. // !!! TINT !!!! TINT !!!! TINT !!!
  1316. // MSDEV USERS: This is not the real assert. Hit
  1317. // Shift-F11 to jump back to the caller.
  1318. DEBUG_BREAK; // ASSERT
  1319. // !!! TINT !!!! TINT !!!! TINT !!!
  1320. }
  1321. }
  1322. return iTest;
  1323. }
  1324. /*-------------------------------------------------------------------------
  1325. Purpose: Spews a trace message if pvTest is NULL.
  1326. */
  1327. LPVOID
  1328. TracePtr(
  1329. LPVOID pvTest,
  1330. LPCSTR pszExpr,
  1331. LPCSTR pszFile,
  1332. int iLine)
  1333. {
  1334. CHAR ach[1024+40]; // Largest path plus extra
  1335. if (g_qwTraceFlags & TF_WARNING && NULL == pvTest)
  1336. {
  1337. int cch;
  1338. cch = SetPrefixStringA(ach, ARRAYSIZE(ach), TF_WARNING);
  1339. StringCchPrintfA(&ach[cch], ARRAYSIZE(ach) - cch,
  1340. "TPTR: Failure of \"%s\" at %s, line %d",
  1341. pszExpr, _PathFindFileNameA(pszFile), iLine); // ok to truncate - debug message
  1342. OutputDebugStringA(ach);
  1343. OutputDebugStringA(c_szNewline);
  1344. if (IsFlagSet(g_dwBreakFlags, BF_THR))
  1345. {
  1346. // !!! TPTR !!!! TPTR !!!! TPTR !!!
  1347. // MSDEV USERS: This is not the real assert. Hit
  1348. // Shift-F11 to jump back to the caller.
  1349. DEBUG_BREAK; // ASSERT
  1350. // !!! TPTR !!!! TPTR !!!! TPTR !!!
  1351. }
  1352. }
  1353. return pvTest;
  1354. }
  1355. /*-------------------------------------------------------------------------
  1356. Purpose: Spews a trace message if dwTest is a Win32 failure code.
  1357. */
  1358. DWORD
  1359. TraceWin32(
  1360. DWORD dwTest,
  1361. LPCSTR pszExpr,
  1362. LPCSTR pszFile,
  1363. int iLine)
  1364. {
  1365. CHAR ach[1024+40]; // Largest path plus extra
  1366. if (g_qwTraceFlags & TF_WARNING &&
  1367. ERROR_SUCCESS != dwTest)
  1368. {
  1369. int cch;
  1370. cch = SetPrefixStringA(ach, ARRAYSIZE(ach), TF_WARNING);
  1371. StringCchPrintfA(&ach[cch], ARRAYSIZE(ach) - cch,
  1372. "TW32: Failure of \"%s\" at %s, line %d (%#08lx)",
  1373. pszExpr, _PathFindFileNameA(pszFile), iLine, dwTest); // ok to truncate - debug message
  1374. OutputDebugStringA(ach);
  1375. OutputDebugStringA(c_szNewline);
  1376. if (IsFlagSet(g_dwBreakFlags, BF_THR))
  1377. {
  1378. // !!! THR !!!! THR !!!! THR !!!
  1379. // MSDEV USERS: This is not the real assert. Hit
  1380. // Shift-F11 to jump back to the caller.
  1381. DEBUG_BREAK; // ASSERT
  1382. // !!! THR !!!! THR !!!! THR !!!
  1383. }
  1384. }
  1385. return dwTest;
  1386. }
  1387. //
  1388. // Debug .ini functions
  1389. //
  1390. #pragma data_seg(DATASEG_READONLY)
  1391. // (These are deliberately CHAR)
  1392. CHAR const FAR c_szNull[] = "";
  1393. CHAR const FAR c_szZero[] = "0";
  1394. CHAR const FAR c_szIniKeyBreakFlags[] = "BreakFlags";
  1395. CHAR const FAR c_szIniKeyTraceFlags[] = "TraceFlags";
  1396. CHAR const FAR c_szIniKeyFuncTraceFlags[] = "FuncTraceFlags";
  1397. CHAR const FAR c_szIniKeyDumpFlags[] = "DumpFlags";
  1398. CHAR const FAR c_szIniKeyProtoFlags[] = "Prototype";
  1399. #pragma data_seg()
  1400. // Some of the .ini processing code was pimped from the sync engine.
  1401. //
  1402. typedef struct _INIKEYHEADER
  1403. {
  1404. LPCTSTR pszSectionName;
  1405. LPCTSTR pszKeyName;
  1406. LPCTSTR pszDefaultRHS;
  1407. } INIKEYHEADER;
  1408. typedef struct _BOOLINIKEY
  1409. {
  1410. INIKEYHEADER ikh;
  1411. LPDWORD puStorage;
  1412. DWORD dwFlag;
  1413. } BOOLINIKEY;
  1414. typedef struct _INTINIKEY
  1415. {
  1416. INIKEYHEADER ikh;
  1417. LPDWORD puStorage;
  1418. } INTINIKEY;
  1419. #define PutIniIntCmp(idsSection, idsKey, nNewValue, nSave) \
  1420. if ((nNewValue) != (nSave)) PutIniInt(idsSection, idsKey, nNewValue)
  1421. #define WritePrivateProfileInt(szApp, szKey, i, lpFileName) \
  1422. {CHAR sz[7]; \
  1423. WritePrivateProfileString(szApp, szKey, SzFromInt(sz, i), lpFileName);}
  1424. #ifdef BOOL_INI_VALUES
  1425. /* Boolean TRUE strings used by IsIniYes() (comparison is case-insensitive) */
  1426. static LPCTSTR s_rgpszTrue[] =
  1427. {
  1428. TEXT("1"),
  1429. TEXT("On"),
  1430. TEXT("True"),
  1431. TEXT("Y"),
  1432. TEXT("Yes")
  1433. };
  1434. /* Boolean FALSE strings used by IsIniYes() (comparison is case-insensitive) */
  1435. static LPCTSTR s_rgpszFalse[] =
  1436. {
  1437. TEXT("0"),
  1438. TEXT("Off"),
  1439. TEXT("False"),
  1440. TEXT("N"),
  1441. TEXT("No")
  1442. };
  1443. #endif
  1444. #ifdef BOOL_INI_VALUES
  1445. /*----------------------------------------------------------
  1446. Purpose: Determines whether a string corresponds to a boolean
  1447. TRUE value.
  1448. Returns: The boolean value (TRUE or FALSE)
  1449. */
  1450. BOOL
  1451. PRIVATE
  1452. IsIniYes(
  1453. LPCTSTR psz)
  1454. {
  1455. int i;
  1456. BOOL bNotFound = TRUE;
  1457. BOOL bResult;
  1458. ASSERT(psz);
  1459. /* Is the value TRUE? */
  1460. for (i = 0; i < ARRAYSIZE(s_rgpszTrue); i++)
  1461. {
  1462. if (IsSzEqual(psz, s_rgpszTrue[i]))
  1463. {
  1464. bResult = TRUE;
  1465. bNotFound = FALSE;
  1466. break;
  1467. }
  1468. }
  1469. /* Is the value FALSE? */
  1470. if (bNotFound)
  1471. {
  1472. for (i = 0; i < ARRAYSIZE(s_rgpszFalse); i++)
  1473. {
  1474. if (IsSzEqual(psz, s_rgpszFalse[i]))
  1475. {
  1476. bResult = FALSE;
  1477. bNotFound = FALSE;
  1478. break;
  1479. }
  1480. }
  1481. /* Is the value a known string? */
  1482. if (bNotFound)
  1483. {
  1484. /* No. Whine about it. */
  1485. TraceMsg(TF_WARNING, "IsIniYes() called on unknown Boolean RHS '%s'.", psz);
  1486. bResult = FALSE;
  1487. }
  1488. }
  1489. return bResult;
  1490. }
  1491. /*----------------------------------------------------------
  1492. Purpose: Process keys with boolean RHSs.
  1493. */
  1494. void
  1495. PRIVATE
  1496. ProcessBooleans(void)
  1497. {
  1498. int i;
  1499. for (i = 0; i < ARRAYSIZE(s_rgbik); i++)
  1500. {
  1501. DWORD dwcbKeyLen;
  1502. TCHAR szRHS[MAX_BUF];
  1503. BOOLINIKEY * pbik = &(s_rgbik[i]);
  1504. LPCTSTR lpcszRHS;
  1505. /* Look for key. */
  1506. dwcbKeyLen = GetPrivateProfileString(pbik->ikh.pszSectionName,
  1507. pbik->ikh.pszKeyName, TEXT(""), szRHS,
  1508. SIZECHARS(szRHS), c_szCcshellIniFile);
  1509. if (dwcbKeyLen)
  1510. lpcszRHS = szRHS;
  1511. else
  1512. lpcszRHS = pbik->ikh.pszDefaultRHS;
  1513. if (IsIniYes(lpcszRHS))
  1514. {
  1515. if (IsFlagClear(*(pbik->puStorage), pbik->dwFlag))
  1516. TraceMsg(TF_GENERAL, "ProcessIniFile(): %s set in %s![%s].",
  1517. pbik->ikh.pszKeyName,
  1518. c_szCcshellIniFile,
  1519. pbik->ikh.pszSectionName);
  1520. SetFlag(*(pbik->puStorage), pbik->dwFlag);
  1521. }
  1522. else
  1523. {
  1524. if (IsFlagSet(*(pbik->puStorage), pbik->dwFlag))
  1525. TraceMsg(TF_GENERAL, "ProcessIniFile(): %s cleared in %s![%s].",
  1526. pbik->ikh.pszKeyName,
  1527. c_szCcshellIniFile,
  1528. pbik->ikh.pszSectionName);
  1529. ClearFlag(*(pbik->puStorage), pbik->dwFlag);
  1530. }
  1531. }
  1532. }
  1533. #endif
  1534. /*----------------------------------------------------------
  1535. Purpose: This function reads a .ini file to determine the debug
  1536. flags to set. The .ini file and section are specified
  1537. by the following manifest constants:
  1538. SZ_DEBUGINI
  1539. SZ_DEBUGSECTION
  1540. The debug variables that are set by this function are
  1541. g_dwDumpFlags, g_qwTraceFlags, g_dwBreakFlags, and
  1542. g_dwFuncTraceFlags, g_dwPrototype.
  1543. Returns: TRUE if initialization is successful
  1544. */
  1545. BOOL
  1546. PUBLIC
  1547. CcshellGetDebugFlags(void)
  1548. {
  1549. CHAR szRHS[MAX_PATH];
  1550. ULONGLONG val;
  1551. // (scotth): Yes, COMCTL32 exports StrToIntEx, but I
  1552. // don't want to cause a dependency delta and force everyone
  1553. // to get a new comctl32 just because they built debug.
  1554. // So use a local version of StrToIntEx.
  1555. // Trace Flags
  1556. GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1557. c_szIniKeyTraceFlags,
  1558. c_szNull,
  1559. szRHS,
  1560. SIZECHARS(szRHS),
  1561. c_szCcshellIniFile);
  1562. if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1563. g_qwTraceFlags = val;
  1564. #ifdef FULL_DEBUG
  1565. else
  1566. g_qwTraceFlags = 3; // default to TF_ERROR and TF_WARNING trace messages
  1567. #endif
  1568. TraceMsgA(DM_DEBUG, "CcshellGetDebugFlags(): %s set to %#16I64x.",
  1569. c_szIniKeyTraceFlags, g_qwTraceFlags);
  1570. // Function trace Flags
  1571. GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1572. c_szIniKeyFuncTraceFlags,
  1573. c_szNull,
  1574. szRHS,
  1575. SIZECHARS(szRHS),
  1576. c_szCcshellIniFile);
  1577. if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1578. g_dwFuncTraceFlags = (DWORD)val;
  1579. TraceMsgA(DM_DEBUG, "CcshellGetDebugFlags(): %s set to %#08x.",
  1580. c_szIniKeyFuncTraceFlags, g_dwFuncTraceFlags);
  1581. // Dump Flags
  1582. GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1583. c_szIniKeyDumpFlags,
  1584. c_szNull,
  1585. szRHS,
  1586. SIZECHARS(szRHS),
  1587. c_szCcshellIniFile);
  1588. if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1589. g_dwDumpFlags = (DWORD)val;
  1590. TraceMsgA(DM_DEBUG, "CcshellGetDebugFlags(): %s set to %#08x.",
  1591. c_szIniKeyDumpFlags, g_dwDumpFlags);
  1592. // Break Flags
  1593. GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1594. c_szIniKeyBreakFlags,
  1595. c_szNull,
  1596. szRHS,
  1597. SIZECHARS(szRHS),
  1598. c_szCcshellIniFile);
  1599. if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1600. g_dwBreakFlags = (DWORD)val;
  1601. #ifdef FULL_DEBUG
  1602. else
  1603. g_dwBreakFlags = 5; // default to break on ASSERT and TF_ERROR
  1604. #endif
  1605. TraceMsgA(DM_DEBUG, "CcshellGetDebugFlags(): %s set to %#08x.",
  1606. c_szIniKeyBreakFlags, g_dwBreakFlags);
  1607. // Prototype Flags
  1608. GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1609. c_szIniKeyProtoFlags,
  1610. c_szNull,
  1611. szRHS,
  1612. SIZECHARS(szRHS),
  1613. c_szCcshellIniFile);
  1614. if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1615. g_dwPrototype = (DWORD)val;
  1616. // Are we using the new leak detection from shelldbg.dll?
  1617. GetPrivateProfileStringA("ShellDbg",
  1618. "NewLeakDetection",
  1619. c_szNull,
  1620. szRHS,
  1621. SIZECHARS(szRHS),
  1622. c_szCcshellIniFile);
  1623. if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1624. g_bUseNewLeakDetection = BOOLIFY(val);
  1625. TraceMsgA(DM_DEBUG, "CcshellGetDebugFlags(): %s set to %#08x.",
  1626. c_szIniKeyProtoFlags, g_dwPrototype);
  1627. GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1628. "DebugOutputFile",
  1629. c_szNull,
  1630. szRHS,
  1631. SIZECHARS(szRHS),
  1632. c_szCcshellIniFile);
  1633. if (szRHS[0] != TEXT('\0'))
  1634. {
  1635. g_hDebugOutputFile = CreateFileA(szRHS, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  1636. }
  1637. return TRUE;
  1638. }
  1639. // Function to call in allocspy.dll (GetShellMallocSpy)
  1640. typedef BOOL (__stdcall *pfnGSMS) (IShellMallocSpy **ppout);
  1641. STDAPI_(void) IMSAddToList(BOOL bAdd, void*pv, SIZE_T cb)
  1642. {
  1643. static BOOL bDontTry=FALSE;
  1644. static IShellMallocSpy *pms=NULL;
  1645. if (!bDontTry && pms == NULL)
  1646. {
  1647. pfnGSMS pfnGetShellMallocSpy;
  1648. HMODULE hmod;
  1649. bDontTry = TRUE; // assume failure
  1650. if (hmod = LoadLibraryA("ALLOCSPY.DLL"))
  1651. {
  1652. pfnGetShellMallocSpy = (pfnGSMS) GetProcAddress(hmod, "GetShellMallocSpy");
  1653. pfnGetShellMallocSpy(&pms);
  1654. }
  1655. }
  1656. if (bDontTry)
  1657. return;
  1658. if (bAdd)
  1659. pms->lpVtbl->AddToList(pms, pv, cb);
  1660. else
  1661. pms->lpVtbl->RemoveFromList(pms, pv);
  1662. }
  1663. #endif // DEBUG
  1664. #ifdef PRODUCT_PROF
  1665. DWORD g_dwProfileCAP = 0;
  1666. BOOL PUBLIC CcshellGetDebugFlags(void)
  1667. {
  1668. CHAR szRHS[MAX_PATH];
  1669. LONGLONG val;
  1670. GetPrivateProfileStringA(c_szCcshellIniSecDebug,
  1671. "Profile",
  1672. "",
  1673. szRHS,
  1674. SIZECHARS(szRHS),
  1675. c_szCcshellIniFile);
  1676. if (MyStrToIntExA(szRHS, STIF_SUPPORT_HEX, &val))
  1677. g_dwProfileCAP = (DWORD)val;
  1678. return TRUE;
  1679. }
  1680. #endif // PRODUCT_PROF
  1681. #ifdef DEBUG
  1682. // turn on path whacking for full-debug builds
  1683. #ifdef FULL_DEBUG
  1684. static BOOL g_fWhackPathBuffers = TRUE;
  1685. #else
  1686. static BOOL g_fWhackPathBuffers = FALSE;
  1687. #endif
  1688. void DEBUGWhackPathBufferA(LPSTR psz, UINT cch)
  1689. {
  1690. if (g_fWhackPathBuffers)
  1691. {
  1692. if (psz && IS_VALID_WRITE_BUFFER(psz, char, cch))
  1693. {
  1694. FillMemory(psz, cch * sizeof(char), 0xFE);
  1695. }
  1696. }
  1697. }
  1698. void DEBUGWhackPathBufferW(LPWSTR psz, UINT cch)
  1699. {
  1700. if (g_fWhackPathBuffers)
  1701. {
  1702. if (psz && IS_VALID_WRITE_BUFFER(psz, WCHAR, cch))
  1703. {
  1704. FillMemory(psz, cch * sizeof(WCHAR), 0xFE);
  1705. }
  1706. }
  1707. }
  1708. void DEBUGWhackPathStringA(LPSTR psz, UINT cch)
  1709. {
  1710. if (g_fWhackPathBuffers)
  1711. {
  1712. if (psz && IS_VALID_WRITE_BUFFER(psz, char, cch) && IS_VALID_STRING_PTRA(psz, -1))
  1713. {
  1714. UINT len = lstrlenA(psz);
  1715. if (len >= cch)
  1716. {
  1717. TraceMsg(TF_WARNING, "DEBUGWhackPathStringA: caller of caller passed strange Path string (strlen > buffer size)");
  1718. }
  1719. else
  1720. {
  1721. FillMemory(psz+len+1, (cch-len-1) * sizeof(char), 0xFE);
  1722. }
  1723. }
  1724. }
  1725. }
  1726. void DEBUGWhackPathStringW(LPWSTR psz, UINT cch)
  1727. {
  1728. if (g_fWhackPathBuffers)
  1729. {
  1730. if (psz && IS_VALID_WRITE_BUFFER(psz, WCHAR, cch) && IS_VALID_STRING_PTRW(psz, -1))
  1731. {
  1732. UINT len = lstrlenW(psz);
  1733. if (len >= cch)
  1734. {
  1735. TraceMsg(TF_WARNING, "DEBUGWhackPathStringW: caller of caller passed strange Path string (strlen > buffer size)");
  1736. }
  1737. else
  1738. {
  1739. FillMemory(psz+len+1, (cch-len-1) * sizeof(WCHAR), 0xFE);
  1740. }
  1741. }
  1742. }
  1743. }
  1744. #endif // DEBUG