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.

2206 lines
58 KiB

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