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

1536 lines
39 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1993 - 1993.
  5. //
  6. // File: debug.cxx
  7. //
  8. // Contents: Shell debugging functionality
  9. //
  10. //----------------------------------------------------------------------------
  11. /*
  12. * DEBUG.CXX
  13. *
  14. * Developer's API to the Debug Module
  15. */
  16. #include <headers.h>
  17. #include "debug.h"
  18. #include "dalibc.h"
  19. #ifdef _DEBUG
  20. // Globals
  21. HINSTANCE g_hinstMain = NULL;
  22. HWND g_hwndMain = NULL;
  23. ULONG g_cInitCount = 0;
  24. BOOL g_fInit = FALSE;
  25. BOOL g_fOutputToConsole = FALSE;
  26. CRITICAL_SECTION g_csTrace;
  27. CRITICAL_SECTION g_csResDlg;
  28. // TAGS and stuff
  29. /*
  30. * Number of TAG's registered so far.
  31. *
  32. */
  33. TAG tagMac;
  34. /*
  35. * Mapping from TAG's to information about them. Entries
  36. * 0...tagMac-1 are valid.
  37. */
  38. TGRC mptagtgrc[tagMax];
  39. TAG tagCom1 = tagNull;
  40. TAG tagError = tagNull;
  41. TAG tagWarn = tagNull;
  42. TAG tagAssertPop = tagNull;
  43. TAG tagTestFailures = tagNull;
  44. TAG tagRRETURN = tagNull;
  45. TAG tagLeaks = tagNull;
  46. TAG tagMagic = tagNull;
  47. TAG tagIWatch = tagNull;
  48. TAG tagIWatch2 = tagNull;
  49. TAG tagReadMapFile = tagNull;
  50. TAG tagLeakFilter = tagNull;
  51. TAG tagHookMemory = tagNull;
  52. TAG tagHookBreak = tagNull;
  53. TAG tagCheckAlways = tagNull;
  54. TAG tagCheckCRT = tagNull;
  55. TAG tagDelayFree = tagNull;
  56. /*
  57. * Handle for debug output file. This file is opened during init,
  58. * and output is sent to it when enabled.
  59. */
  60. HANDLE hfileDebugOutput = NULL;
  61. /*
  62. * static variables to prevent infinite recursion when calling
  63. * SpitPchToDisk
  64. */
  65. static BOOL fInSpitPchToDisk = FALSE;
  66. static CHAR szNewline[] = "\r\n";
  67. static CHAR szBackslash[] = "\\";
  68. static CHAR szStateFileExt[] = ".tag";
  69. static CHAR szDbgOutFileExt[] = ".log";
  70. static CHAR szStateFileName[] = "capone.dbg";
  71. static CHAR szDbgOutFileName[] = "capone.log";
  72. /*
  73. * Global temporary buffer for handling TraceTag output. Since
  74. * this code is non-reentrant and not recursive, a single buffer
  75. * for all Demilayr callers will work ok.
  76. */
  77. CHAR rgchTraceTagBuffer[1024] = { 0 };
  78. void DeinitDebug(void);
  79. const LPTSTR GetHResultName(HRESULT r);
  80. void DebugOutput( CHAR * sz );
  81. VOID SpitPchToDisk(CHAR * pch, UINT cch, HANDLE hfile);
  82. VOID SpitSzToDisk( CHAR * sz, HANDLE hfile);
  83. TAG TagRegisterSomething(
  84. TGTY tgty, CHAR * szOwner, CHAR * szDescrip, BOOL fEnabled = FALSE);
  85. BOOL EnableTag(TAG tag, BOOL fEnable);
  86. // F u n c t i o n s
  87. // for some reason GetModuleFileNameA(NULL, rgch, sizeof(rgch));
  88. // seems to return a different length (one including the terminating null?)
  89. // when run under NT and Purify. So I made the dot detector non-fixed!
  90. int findDot(char *string)
  91. {
  92. int value = -1; // default to return err
  93. int index = 0; // start at the beggining
  94. while(string[++index])
  95. if(string[index]=='.') {
  96. value = index;
  97. break;
  98. }
  99. return(value);
  100. }
  101. /*
  102. * InitDebug
  103. *
  104. * Purpose:
  105. * Called to initialize the Debug Module. Sets up any debug
  106. * structures. This routine DOES NOT restore the state of the
  107. * Debug Module, since TAGs can't be registered until after
  108. * this routine exit. The routine RestoreDefaultDebugState()
  109. * should be called to restore the state of all TAGs after
  110. * all TAGs have been registered.
  111. *
  112. * Parameters:
  113. * hinstance Pointer to application instance
  114. * phwnd Pointer to main application window
  115. *
  116. * Returns:
  117. * error code
  118. */
  119. void
  120. InitDebug(HINSTANCE hinst, HWND hwnd)
  121. {
  122. static struct
  123. {
  124. TAG * ptag;
  125. TGTY tgty;
  126. LPSTR pszClass;
  127. LPSTR pszDescr;
  128. BOOL fEnabled;
  129. }
  130. g_ataginfo[] =
  131. {
  132. &tagCom1, tgtyOther, "!Debug", "Enable Disk for debug output", TRUE,
  133. &tagAssertPop, tgtyOther, "!Debug", "Popups on asserts", TRUE,
  134. &tagReadMapFile, tgtyOther, "!Debug", "Read MAP file for stack traces", TRUE,
  135. &tagLeaks, tgtyOther, "!Memory", "Memory Leaks", FALSE,
  136. &tagMagic, tgtyOther, "!Memory", "Module/MAP file parsing", FALSE,
  137. &tagError, tgtyTrace, "!Trace", "Errors", TRUE,
  138. &tagWarn, tgtyTrace, "!Trace", "Warnings", FALSE,
  139. &tagTestFailures, tgtyTrace, "!Trace", "THR, IGNORE_HR", TRUE,
  140. &tagRRETURN, tgtyTrace, "!Trace", "RRETURN", FALSE,
  141. &tagIWatch, tgtyTrace, "!Watch", "Interface watch", FALSE,
  142. &tagIWatch2, tgtyOther, "!Watch", "Interface watch (create wrap, no trace)", FALSE,
  143. &tagLeakFilter, tgtyOther, "!Memory", "Filter out known leaks", FALSE,
  144. &tagHookMemory, tgtyOther, "!Memory", "Watch unexp sysmem allocs", FALSE,
  145. &tagHookBreak, tgtyOther, "!Memory", "Break on simulated failure", FALSE,
  146. &tagCheckAlways, tgtyOther, "!Memory", "Check Mem on every alloc/free", FALSE,
  147. &tagCheckCRT, tgtyOther, "!Memory", "Include CRT types in leak detection", FALSE,
  148. &tagDelayFree, tgtyOther, "!Memory", "Keep freed blocks in heap list", FALSE,
  149. };
  150. TGRC * ptgrc;
  151. CHAR rgch[MAX_PATH];
  152. int i;
  153. g_cInitCount++;
  154. if (g_fInit)
  155. return;
  156. g_fInit = TRUE;
  157. g_hinstMain = hinst;
  158. g_hwndMain = hwnd;
  159. // don't want windows to put up message box on INT 24H errors.
  160. SetErrorMode(0x0001);
  161. InitializeCriticalSection(&g_csTrace);
  162. InitializeCriticalSection(&g_csResDlg);
  163. // Initialize simulated failures
  164. SetSimFailCounts(0, 1);
  165. // Initialize TAG array
  166. tagMac = tagMin;
  167. // enable tagNull at end of RestoreDefaultDebugState
  168. ptgrc = mptagtgrc + tagNull;
  169. ptgrc->tgty = tgtyNull;
  170. ptgrc->fEnabled = FALSE;
  171. ptgrc->ulBitFlags = TGRC_DEFAULT_FLAGS;
  172. ptgrc->szOwner = "dgreene";
  173. ptgrc->szDescrip = "NULL";
  174. // Open debug output file
  175. if (g_hinstMain)
  176. {
  177. #ifndef _MAC
  178. UINT cch = (UINT) GetModuleFileNameA(g_hinstMain, rgch, sizeof(rgch));
  179. int dotLoc = findDot(rgch);
  180. Assert(dotLoc!=-1);
  181. strcpy(&rgch[dotLoc], szDbgOutFileExt);
  182. #else
  183. TCHAR achAppLoc[MAX_PATH];
  184. DWORD dwRet;
  185. short iRet;
  186. dwRet = GetModuleFileName(g_hinstMain, achAppLoc, ARRAY_SIZE(achAppLoc));
  187. Assert (dwRet != 0);
  188. iRet = GetFileTitle(achAppLoc,rgch,sizeof(rgch));
  189. Assert(iRet == 0);
  190. strcat (rgch, szDbgOutFileExt);
  191. #endif
  192. }
  193. else
  194. strcpy(rgch, szDbgOutFileName);
  195. hfileDebugOutput = CreateFileA(rgch,
  196. GENERIC_WRITE,
  197. FILE_SHARE_WRITE,
  198. NULL,
  199. CREATE_ALWAYS,
  200. FILE_ATTRIBUTE_NORMAL,
  201. (HANDLE) NULL);
  202. if (hfileDebugOutput != INVALID_HANDLE_VALUE)
  203. {
  204. char rgch2[100];
  205. rgch2[(sizeof(rgch2)/sizeof(rgch2[0])) - 1] = 0;
  206. _snprintf(rgch2, (sizeof(rgch2)/sizeof(rgch2[0])) - 1, "logging hinst %p to %s\r\n", g_hinstMain, rgch);
  207. SpitSzToDisk(rgch2, hfileDebugOutput);
  208. Assert(hfileDebugOutput);
  209. }
  210. for (i = 0; i < ARRAY_SIZE(g_ataginfo); i++)
  211. {
  212. *g_ataginfo[i].ptag = TagRegisterSomething(
  213. g_ataginfo[i].tgty,
  214. g_ataginfo[i].pszClass,
  215. g_ataginfo[i].pszDescr,
  216. g_ataginfo[i].fEnabled);
  217. }
  218. fInSpitPchToDisk = FALSE;
  219. }
  220. /*
  221. * DeinitDebug
  222. *
  223. * Undoes InitDebug().
  224. */
  225. void
  226. DeinitDebug(void)
  227. {
  228. TAG tag;
  229. TGRC * ptgrc;
  230. g_cInitCount--;
  231. if (g_cInitCount)
  232. return;
  233. // Close the debug output file
  234. if (hfileDebugOutput)
  235. {
  236. CHAR rgch[100];
  237. rgch[(sizeof(rgch)/sizeof(rgch[0])) - 1] = 0;
  238. _snprintf(rgch, (sizeof(rgch)/sizeof(rgch[0])) - 1, "Done logging for hinst %d\r\n", (ULONG_PTR)g_hinstMain);
  239. SpitSzToDisk(rgch, hfileDebugOutput);
  240. CloseHandle(hfileDebugOutput);
  241. hfileDebugOutput = NULL;
  242. }
  243. // Free the tag strings if not already done
  244. for (tag = tagMin, ptgrc = mptagtgrc + tag;
  245. tag < tagMac; tag++, ptgrc++)
  246. {
  247. if (ptgrc->TestFlag(TGRC_FLAG_VALID))
  248. {
  249. LocalFree(ptgrc->szOwner);
  250. ptgrc->szOwner = NULL;
  251. LocalFree(ptgrc->szDescrip);
  252. ptgrc->szDescrip = NULL;
  253. }
  254. }
  255. // Set flags to FALSE. Need to separate from loop above so that
  256. // final memory leak trace tag can work.
  257. for (tag=tagMin, ptgrc = mptagtgrc + tag;
  258. tag < tagMac; tag++, ptgrc++)
  259. {
  260. if (ptgrc->TestFlag(TGRC_FLAG_VALID))
  261. {
  262. ptgrc->fEnabled = FALSE;
  263. ptgrc->ClearFlag(TGRC_FLAG_VALID);
  264. }
  265. }
  266. DeleteCriticalSection(&g_csTrace);
  267. DeleteCriticalSection(&g_csResDlg);
  268. }
  269. //+---------------------------------------------------------------------------
  270. //
  271. // Function: SendDebugOutputToConsole
  272. //
  273. // Synopsis: If called, causes all debug output to go the the console as
  274. // well as the debugger.
  275. //
  276. //----------------------------------------------------------------------------
  277. void
  278. SendDebugOutputToConsole(void)
  279. {
  280. g_fOutputToConsole = TRUE;
  281. }
  282. /*
  283. * FReadDebugState
  284. *
  285. * Purpose:
  286. * Read the debug state information file whose name is given by the
  287. * string szDebugFile. Set up the tag records accordingly.
  288. *
  289. * Parameters:
  290. * szDebugFile Name of debug file to read
  291. *
  292. * Returns:
  293. * TRUE if file was successfully read; FALSE otherwise.
  294. *
  295. */
  296. BOOL
  297. FReadDebugState( CHAR * szDebugFile )
  298. {
  299. HANDLE hfile = NULL;
  300. TGRC tgrc;
  301. TGRC * ptgrc;
  302. TAG tag;
  303. INT cchOwner;
  304. CHAR rgchOwner[MAX_PATH];
  305. INT cchDescrip;
  306. CHAR rgchDescrip[MAX_PATH];
  307. BOOL fReturn = FALSE;
  308. DWORD cRead;
  309. hfile = CreateFileA(szDebugFile,
  310. GENERIC_READ,
  311. FILE_SHARE_READ,
  312. NULL,
  313. OPEN_EXISTING,
  314. FILE_ATTRIBUTE_NORMAL,
  315. (HANDLE) NULL);
  316. if (hfile != INVALID_HANDLE_VALUE)
  317. {
  318. for (;;)
  319. {
  320. if (!ReadFile(hfile, &tgrc, sizeof(TGRC), &cRead, NULL))
  321. break;
  322. if (cRead == 0)
  323. break;
  324. if (!ReadFile(hfile, &cchOwner, sizeof(UINT), &cRead, NULL))
  325. goto ErrorReturn;
  326. Assert(cchOwner <= sizeof(rgchOwner));
  327. if (!ReadFile(hfile, rgchOwner, cchOwner, &cRead, NULL))
  328. goto ErrorReturn;
  329. if (!ReadFile(hfile, &cchDescrip, sizeof(UINT), &cRead, NULL))
  330. goto ErrorReturn;
  331. Assert(cchDescrip <= sizeof(rgchDescrip));
  332. if (!ReadFile(hfile, rgchDescrip, cchDescrip, &cRead, NULL))
  333. goto ErrorReturn;
  334. ptgrc = mptagtgrc + tagMin;
  335. for (tag = tagMin; tag < tagMac; tag++)
  336. {
  337. if (ptgrc->TestFlag(TGRC_FLAG_VALID) &&
  338. !strcmp(rgchOwner, ptgrc->szOwner) &&
  339. !strcmp(rgchDescrip, ptgrc->szDescrip))
  340. {
  341. ptgrc->fEnabled = tgrc.fEnabled;
  342. Assert(tgrc.TestFlag(TGRC_FLAG_VALID));
  343. ptgrc->ulBitFlags = tgrc.ulBitFlags;
  344. break;
  345. }
  346. ptgrc++;
  347. }
  348. }
  349. CloseHandle(hfile);
  350. fReturn = TRUE;
  351. }
  352. goto Exit;
  353. ErrorReturn:
  354. if (hfile)
  355. CloseHandle(hfile);
  356. Exit:
  357. return fReturn;
  358. }
  359. /*
  360. * FWriteDebugState
  361. *
  362. * Purpose:
  363. * Writes the current state of the Debug Module to the file
  364. * name given. The saved state can be restored later by calling
  365. * FReadDebugState.
  366. *
  367. * Parameters:
  368. * szDebugFile Name of the file to create and write the debug
  369. * state to.
  370. *
  371. * Returns:
  372. * TRUE if file was successfully written; FALSE otherwise.
  373. */
  374. BOOL
  375. FWriteDebugState( CHAR * szDebugFile )
  376. {
  377. HANDLE hfile = NULL;
  378. TAG tag;
  379. UINT cch;
  380. TGRC * ptgrc;
  381. BOOL fReturn = FALSE;
  382. DWORD cWrite;
  383. hfile = CreateFileA(szDebugFile,
  384. GENERIC_WRITE,
  385. FILE_SHARE_WRITE,
  386. NULL,
  387. CREATE_ALWAYS,
  388. FILE_ATTRIBUTE_NORMAL,
  389. (HANDLE) NULL);
  390. if (hfile != INVALID_HANDLE_VALUE)
  391. {
  392. for (tag = tagMin; tag < tagMac; tag++)
  393. {
  394. ptgrc = mptagtgrc + tag;
  395. if (!ptgrc->TestFlag(TGRC_FLAG_VALID))
  396. continue;
  397. Assert(ptgrc->szOwner);
  398. Assert(ptgrc->szDescrip);
  399. if (!WriteFile(hfile, ptgrc, sizeof(TGRC), &cWrite, NULL))
  400. goto ErrorReturn;
  401. // SZ fields will be overwritten when read back
  402. cch = strlen(ptgrc->szOwner) + 1;
  403. if (!WriteFile(hfile, &cch, sizeof(UINT), &cWrite, NULL))
  404. goto ErrorReturn;
  405. if (!WriteFile(hfile, ptgrc->szOwner, cch, &cWrite, NULL))
  406. goto ErrorReturn;
  407. cch = strlen(ptgrc->szDescrip) + 1;
  408. if (!WriteFile(hfile, &cch, sizeof(UINT), &cWrite, NULL))
  409. goto ErrorReturn;
  410. if (!WriteFile(hfile, ptgrc->szDescrip, cch, &cWrite, NULL))
  411. goto ErrorReturn;
  412. }
  413. CloseHandle(hfile);
  414. fReturn = TRUE;
  415. }
  416. goto Exit;
  417. ErrorReturn:
  418. if (hfile)
  419. CloseHandle(hfile);
  420. DeleteFileA(szDebugFile);
  421. Exit:
  422. return fReturn;
  423. }
  424. //+------------------------------------------------------------------------
  425. //
  426. // Function: SaveDefaultDebugState
  427. //
  428. // Synopsis: Saves the debug state of the executing program to a file
  429. // of the same name, substituting the ".tag" suffix.
  430. //
  431. // Arguments: [void]
  432. //
  433. //-------------------------------------------------------------------------
  434. void
  435. SaveDefaultDebugState( void )
  436. {
  437. CHAR rgch[MAX_PATH] = "";
  438. if (g_hinstMain)
  439. {
  440. #ifndef _MAC
  441. UINT cch = (UINT) GetModuleFileNameA(g_hinstMain, rgch, sizeof(rgch));
  442. int dotLoc = findDot(rgch);
  443. Assert(dotLoc!=-1);
  444. strcpy(&rgch[dotLoc], szStateFileExt);
  445. #else
  446. TCHAR achAppLoc[MAX_PATH];
  447. DWORD dwRet;
  448. short iRet;
  449. dwRet = GetModuleFileNameA(g_hinstMain, achAppLoc, ARRAY_SIZE(achAppLoc));
  450. Assert (dwRet != 0);
  451. iRet = GetFileTitle(achAppLoc,rgch,sizeof(rgch));
  452. Assert(iRet == 0);
  453. strcat (rgch, szStateFileExt);
  454. #endif
  455. }
  456. else
  457. {
  458. strcat(rgch, szStateFileName);
  459. }
  460. FWriteDebugState(rgch);
  461. }
  462. //+------------------------------------------------------------------------
  463. //
  464. // Function: RestoreDefaultDebugState
  465. //
  466. // Synopsis: Restores the debug state for the executing program from
  467. // the state file of the same name, substituting the ".tag"
  468. // suffix.
  469. //
  470. // Arguments: [void]
  471. //
  472. //-------------------------------------------------------------------------
  473. void
  474. RestoreDefaultDebugState( void )
  475. {
  476. CHAR rgch[MAX_PATH] = "";
  477. if (!g_fInit)
  478. {
  479. DebugOutput("RestoreDefaultDebugState: Debug library not initialized\n");
  480. return;
  481. }
  482. if (g_hinstMain)
  483. {
  484. #ifndef _MAC
  485. UINT cch = (UINT) GetModuleFileNameA(g_hinstMain, rgch, sizeof(rgch));
  486. int dotLoc = findDot(rgch);
  487. Assert(dotLoc!=-1);
  488. strcpy(&rgch[dotLoc], szStateFileExt);
  489. #else
  490. TCHAR achAppLoc[MAX_PATH];
  491. DWORD dwRet;
  492. short iRet;
  493. dwRet = GetModuleFileName(g_hinstMain, achAppLoc, ARRAY_SIZE(achAppLoc));
  494. Assert (dwRet != 0);
  495. iRet = GetFileTitle(achAppLoc,rgch,sizeof(rgch));
  496. Assert(iRet == 0);
  497. strcat (rgch, szStateFileExt);
  498. #endif
  499. }
  500. else
  501. {
  502. strcat(rgch, szStateFileName);
  503. }
  504. FReadDebugState(rgch);
  505. mptagtgrc[tagNull].fEnabled = TRUE;
  506. }
  507. /*
  508. * IsTagEnabled
  509. *
  510. * Purpose:
  511. * Returns a boolean value indicating whether the given TAG
  512. * has been enabled or disabled by the user.
  513. *
  514. * Parameters:
  515. * tag The TAG to check
  516. *
  517. * Returns:
  518. * TRUE if the TAG has been enabled.
  519. * FALSE if the TAG has been disabled.
  520. */
  521. BOOL
  522. IsTagEnabled(TAG tag)
  523. {
  524. return mptagtgrc[tag].TestFlag(TGRC_FLAG_VALID) &&
  525. mptagtgrc[tag].fEnabled;
  526. }
  527. /*
  528. * EnableTag
  529. *
  530. * Purpose:
  531. * Sets or resets the TAG value given. Allows code to enable or
  532. * disable TAG'd assertions and trace switches.
  533. *
  534. * Parameters:
  535. * tag The TAG to enable or disable
  536. * fEnable TRUE if TAG should be enabled, FALSE if it should
  537. * be disabled.
  538. * Returns:
  539. * old state of tag (TRUE if tag was enabled, otherwise FALSE)
  540. *
  541. */
  542. BOOL EnableTag( TAG tag, BOOL fEnable )
  543. {
  544. BOOL fOld;
  545. Assert(mptagtgrc[tag].TestFlag(TGRC_FLAG_VALID));
  546. fOld = mptagtgrc[tag].fEnabled;
  547. mptagtgrc[tag].fEnabled = fEnable;
  548. return fOld;
  549. }
  550. /*
  551. * SpitPchToDisk
  552. *
  553. * Purpose:
  554. * Writes the given string to the (previously opened) debug module
  555. * disk file. Does NOT write newline-return; caller should embed it
  556. * in string.
  557. *
  558. * Parameters:
  559. * pch Pointer to an array of characters.
  560. * cch Number of characters to spit.
  561. * pfile file to which to write, or NULL to use
  562. * debug output file.
  563. */
  564. void
  565. SpitPchToDisk( CHAR * pch, UINT cch, HANDLE hfile )
  566. {
  567. DWORD cWrite;
  568. if (fInSpitPchToDisk) // already inside this function
  569. return; // aVOID recursion
  570. if (hfile && pch && cch)
  571. {
  572. fInSpitPchToDisk = TRUE;
  573. WriteFile(hfile, pch, cch, &cWrite, NULL);
  574. fInSpitPchToDisk = FALSE;
  575. }
  576. }
  577. /*
  578. * SpitSzToDisk
  579. *
  580. * Purpose:
  581. * Writes the given string to the (previously opened) debug module
  582. * disk file. Does NOT write newline-return; caller should embed it
  583. * in string.
  584. *
  585. * Parameters:
  586. * sz String to spit.
  587. * pfile file to which to write, or NULL to use
  588. * debug output file.
  589. *
  590. * Because this function calls fflush(), we're assuming for the
  591. * sake of reasonable performance that only debug functions making
  592. * output to disk are calling this function. We can't put this in
  593. * SpitPchToDisk because calls that function, and any
  594. * enabled trace tag would degrade performance.
  595. */
  596. VOID
  597. SpitSzToDisk( CHAR * sz, HANDLE hfile )
  598. {
  599. if (hfile && sz)
  600. {
  601. SpitPchToDisk(sz, strlen(sz), hfile);
  602. }
  603. }
  604. /*
  605. * TagRegisterSomething
  606. *
  607. * Purpose:
  608. * Does actual work of allocating TAG, and initializing TGRC.
  609. * The owner and description strings are duplicated from the
  610. * arguments passed in.
  611. *
  612. * Parameters:
  613. * tgty Tag type to register.
  614. * szOwner Owner.
  615. * szDescrip Description.
  616. *
  617. * Returns:
  618. * New TAG, or tagNull if none is available.
  619. */
  620. TAG
  621. TagRegisterSomething(
  622. TGTY tgty,
  623. CHAR * szOwner,
  624. CHAR * szDescrip,
  625. BOOL fEnabled)
  626. {
  627. TAG tag;
  628. TAG tagNew = tagNull;
  629. TGRC * ptgrc;
  630. CHAR * szOwnerDup = NULL;
  631. CHAR * szDescripDup = NULL;
  632. UINT cb;
  633. for (tag = tagMin, ptgrc = mptagtgrc + tag; tag < tagMac;
  634. tag++, ptgrc++)
  635. {
  636. if (ptgrc->TestFlag(TGRC_FLAG_VALID))
  637. {
  638. if(!(strcmp(szOwner, ptgrc->szOwner) ||
  639. strcmp(szDescrip, ptgrc->szDescrip)))
  640. {
  641. return tag;
  642. }
  643. }
  644. else if (tagNew == tagNull)
  645. tagNew= tag;
  646. }
  647. // Make duplicate copies.
  648. Assert(szOwner);
  649. Assert(szDescrip);
  650. cb = strlen(szOwner) + 1;
  651. // we use LocalAlloc here instead of new so
  652. // we don't interfere with leak reporting because of the
  653. // dependency between the debug library and the
  654. // leak reporting code (i.e., don't touch this --Erik)
  655. szOwnerDup = (LPSTR) LocalAlloc(LMEM_FIXED, cb);
  656. if (szOwnerDup == NULL)
  657. {
  658. goto Error;
  659. }
  660. strcpy(szOwnerDup, szOwner);
  661. cb = strlen(szDescrip) + 1;
  662. szDescripDup = (LPSTR) LocalAlloc(LMEM_FIXED, cb);
  663. if (szDescripDup == NULL)
  664. {
  665. goto Error;
  666. }
  667. strcpy(szDescripDup, szDescrip);
  668. if (tagNew == tagNull)
  669. {
  670. if (tagMac >= tagMax)
  671. {
  672. #ifdef NEVER
  673. AssertSz(FALSE, "Too many tags registered already!");
  674. #endif
  675. Assert(FALSE);
  676. return tagNull;
  677. }
  678. tag = tagMac++;
  679. }
  680. else
  681. tag = tagNew;
  682. ptgrc = mptagtgrc + tag;
  683. ptgrc->fEnabled = fEnabled;
  684. ptgrc->ulBitFlags = TGRC_DEFAULT_FLAGS;
  685. ptgrc->tgty = tgty;
  686. ptgrc->szOwner = szOwnerDup;
  687. ptgrc->szDescrip = szDescripDup;
  688. return tag;
  689. Error:
  690. LocalFree(szOwnerDup);
  691. LocalFree(szDescripDup);
  692. return tagNull;
  693. }
  694. /*
  695. * DeregisterTag
  696. *
  697. * Purpose:
  698. * Deregisters tag, removing it from tag table.
  699. *
  700. * Parameters:
  701. * tag Tag to deregister.
  702. */
  703. void
  704. DeregisterTag(TAG tag)
  705. {
  706. // don't allow deregistering the tagNull entry
  707. // but exit gracefully
  708. if (!tag)
  709. return;
  710. Assert(tag < tagMac);
  711. Assert(mptagtgrc[tag].TestFlag(TGRC_FLAG_VALID));
  712. mptagtgrc[tag].fEnabled = FALSE;
  713. mptagtgrc[tag].ClearFlag(TGRC_FLAG_VALID);
  714. LocalFree(mptagtgrc[tag].szOwner);
  715. mptagtgrc[tag].szOwner = NULL;
  716. LocalFree(mptagtgrc[tag].szDescrip);
  717. mptagtgrc[tag].szDescrip = NULL;
  718. }
  719. /*
  720. * TagRegisterTrace
  721. *
  722. * Purpose:
  723. * Registers a class of trace points, and returns an identifying
  724. * TAG for that class.
  725. *
  726. * Parameters:
  727. * szOwner The email name of the developer writing the code
  728. * that registers the class.
  729. * szDescrip A short description of the class of trace points.
  730. * For instance: "All calls to PvAlloc() and HvFree()"
  731. *
  732. * Returns:
  733. * TAG identifying class of trace points, to be used in calls to
  734. * the trace routines.
  735. */
  736. TAG
  737. TagRegisterTrace( CHAR * szOwner, CHAR * szDescrip, BOOL fEnabled )
  738. {
  739. if (!g_fInit)
  740. {
  741. DebugOutput("TagRegisterTrace: Debug library not initialized\n");
  742. return tagNull;
  743. }
  744. return TagRegisterSomething(tgtyTrace, szOwner, szDescrip, fEnabled);
  745. }
  746. TAG
  747. TagRegisterOther( CHAR * szOwner, CHAR * szDescrip, BOOL fEnabled )
  748. {
  749. if (!g_fInit)
  750. {
  751. OutputDebugStringA("TagRegisterOther: Debug library not initialized");
  752. return tagNull;
  753. }
  754. return TagRegisterSomething(tgtyOther, szOwner, szDescrip, fEnabled);
  755. }
  756. TAG
  757. TagError( void )
  758. {
  759. return tagError;
  760. }
  761. TAG
  762. TagWarning( void )
  763. {
  764. return tagWarn;
  765. }
  766. TAG
  767. TagLeakFilter( void )
  768. {
  769. return tagLeakFilter;
  770. }
  771. TAG
  772. TagHookMemory(void)
  773. {
  774. return tagHookMemory;
  775. }
  776. TAG
  777. TagHookBreak(void)
  778. {
  779. return tagHookBreak;
  780. }
  781. TAG
  782. TagLeaks(void)
  783. {
  784. return tagLeaks;
  785. }
  786. TAG
  787. TagCheckAlways(void)
  788. {
  789. return tagCheckAlways;
  790. }
  791. TAG
  792. TagCheckCRT(void)
  793. {
  794. return tagCheckCRT;
  795. }
  796. TAG
  797. TagDelayFree(void)
  798. {
  799. return tagDelayFree;
  800. }
  801. /*
  802. * Purpose:
  803. * Clears the debug screen
  804. */
  805. void
  806. ClearDebugScreen( void )
  807. {
  808. #ifndef _MAC
  809. TraceTag((tagNull, "\x1B[2J"));
  810. #endif
  811. }
  812. /*
  813. * DebugOutput
  814. *
  815. * Purpose:
  816. * Writes the given string out the debug port.
  817. * Does NOT write newline-return; caller should embed it in string.
  818. *
  819. * Parameters:
  820. * sz String to spit.
  821. */
  822. void DebugOutput( CHAR * sz )
  823. {
  824. #ifdef NEVER
  825. HANDLE hfile;
  826. hfile = CreateFileA("COM1", GENERIC_READ | GENERIC_WRITE,
  827. 0, NULL, OPEN_EXISTING,
  828. FILE_ATTRIBUTE_NORMAL, NULL);
  829. if (hfile != INVALID_HANDLE_VALUE)
  830. {
  831. DWORD lcbWritten;
  832. WriteFile(hfile, sz, (DWORD) strlen(sz), &lcbWritten, NULL);
  833. CloseHandle(hfile);
  834. }
  835. #endif // NEVER
  836. OutputDebugStringA(sz);
  837. }
  838. /*
  839. * TaggedTrace
  840. *
  841. * Purpose:
  842. * Uses the given format string and parameters to render a
  843. * string into a buffer. The rendered string is sent to the
  844. * destination indicated by the given tag, or sent to the bit
  845. * bucket if the tag is disabled.
  846. *
  847. * Arguments:
  848. * tag Identifies the tag group
  849. * szFmt Format string for _snprintf (qqv)
  850. */
  851. BOOL __cdecl
  852. TaggedTrace(TAG tag, CHAR * szFmt, ...)
  853. {
  854. BOOL f;
  855. va_list valMarker;
  856. va_start(valMarker, szFmt);
  857. f = TaggedTraceListEx(tag, 0, szFmt, valMarker);
  858. va_end(valMarker);
  859. return f;
  860. }
  861. BOOL __cdecl
  862. TaggedTraceEx(TAG tag, USHORT usFlags, CHAR * szFmt, ...)
  863. {
  864. BOOL f;
  865. va_list valMarker;
  866. va_start(valMarker, szFmt);
  867. f = TaggedTraceListEx(tag, usFlags, szFmt, valMarker);
  868. va_end(valMarker);
  869. return f;
  870. }
  871. BOOL __cdecl
  872. TaggedTraceListEx(TAG tag, USHORT usFlags, CHAR * szFmt, va_list valMarker)
  873. {
  874. static CHAR szFmtOwner[] = "DA %s (%lx): ";
  875. static CHAR szFmtHR[] = "<%ls (0x%lx)>";
  876. static CHAR szHRID[] = "%hr";
  877. TGRC * ptgrc;
  878. int cch;
  879. if (!g_fInit)
  880. {
  881. DebugOutput("TaggedTrace: Debug library not initialized\n");
  882. return FALSE;
  883. }
  884. if (tag == tagNull)
  885. ptgrc = mptagtgrc + tagCom1;
  886. else
  887. ptgrc = mptagtgrc + tag;
  888. if (!ptgrc->fEnabled)
  889. return FALSE;
  890. EnterCriticalSection(&g_csTrace);
  891. Assert(ptgrc->TestFlag(TGRC_FLAG_VALID));
  892. if (!(usFlags & TAG_NONAME))
  893. {
  894. cch = _snprintf(
  895. rgchTraceTagBuffer,
  896. ARRAY_SIZE(rgchTraceTagBuffer),
  897. szFmtOwner,
  898. ptgrc->szOwner,
  899. GetCurrentThreadId());
  900. }
  901. else
  902. {
  903. cch = 0;
  904. }
  905. hrvsnprintf(
  906. rgchTraceTagBuffer + cch,
  907. ARRAY_SIZE(rgchTraceTagBuffer) - cch,
  908. szFmt,
  909. valMarker);
  910. if (ptgrc->TestFlag(TGRC_FLAG_DISK))
  911. {
  912. SpitSzToDisk(rgchTraceTagBuffer, hfileDebugOutput);
  913. SpitSzToDisk(szNewline, hfileDebugOutput);
  914. }
  915. if ((usFlags & TAG_USECONSOLE) || g_fOutputToConsole)
  916. printf(rgchTraceTagBuffer);
  917. if (!(usFlags & TAG_USECONSOLE))
  918. DebugOutput(rgchTraceTagBuffer);
  919. if (!(usFlags & TAG_NONEWLINE))
  920. {
  921. if ((usFlags & TAG_USECONSOLE) || g_fOutputToConsole)
  922. printf(szNewline);
  923. if (!(usFlags & TAG_USECONSOLE))
  924. DebugOutput(szNewline);
  925. }
  926. LeaveCriticalSection(&g_csTrace);
  927. if (ptgrc->TestFlag(TGRC_FLAG_BREAK))
  928. {
  929. return MessageBoxA(
  930. NULL,
  931. ptgrc->szDescrip,
  932. "Trace Tag Break, OK=Ignore, Cancel=Int3",
  933. MB_SETFOREGROUND | MB_TASKMODAL
  934. | MB_ICONEXCLAMATION | MB_OKCANCEL) == IDCANCEL;
  935. }
  936. return FALSE;
  937. }
  938. #ifdef NEVER
  939. void TaggedTraceCallers(TAG tag, int iStart, int cTotal)
  940. {
  941. DWORD adwEip[32];
  942. int i;
  943. int c;
  944. int ib;
  945. LPSTR pstr;
  946. if (!IsTagEnabled(tag))
  947. return;
  948. if (cTotal > ARRAY_SIZE(adwEip))
  949. cTotal = ARRAY_SIZE(adwEip);
  950. c = GetStackBacktrace(iStart + 1, cTotal, adwEip);
  951. for (i = 0; i < c; i++)
  952. {
  953. MapAddressToFunctionOffset((LPBYTE) adwEip[i], &pstr, &ib);
  954. TaggedTraceEx(tag, TAG_NONAME, " %08x %s + 0x%x",
  955. adwEip[i], pstr, ib);
  956. }
  957. }
  958. #endif // NEVER
  959. //+---------------------------------------------------------------
  960. //
  961. // Function: GetHResultName
  962. //
  963. // Synopsis: Returns a printable string for the given hresult
  964. //
  965. // Arguments: [scode] -- The status code to report.
  966. //
  967. // Notes: This function disappears in retail builds.
  968. //
  969. //----------------------------------------------------------------
  970. const LPTSTR
  971. GetHResultName(HRESULT r)
  972. {
  973. LPTSTR lpstr;
  974. #define CASE_SCODE(sc) \
  975. case sc: lpstr = _T(#sc); break;
  976. switch (r) {
  977. /* SCODE's defined in SCODE.H */
  978. CASE_SCODE(S_OK)
  979. CASE_SCODE(S_FALSE)
  980. CASE_SCODE(OLE_S_USEREG)
  981. CASE_SCODE(OLE_S_STATIC)
  982. CASE_SCODE(OLE_S_MAC_CLIPFORMAT)
  983. CASE_SCODE(DRAGDROP_S_DROP)
  984. CASE_SCODE(DRAGDROP_S_USEDEFAULTCURSORS)
  985. CASE_SCODE(DRAGDROP_S_CANCEL)
  986. CASE_SCODE(DATA_S_SAMEFORMATETC)
  987. CASE_SCODE(VIEW_S_ALREADY_FROZEN)
  988. CASE_SCODE(CACHE_S_FORMATETC_NOTSUPPORTED)
  989. CASE_SCODE(CACHE_S_SAMECACHE)
  990. CASE_SCODE(CACHE_S_SOMECACHES_NOTUPDATED)
  991. CASE_SCODE(OLEOBJ_S_INVALIDVERB)
  992. CASE_SCODE(OLEOBJ_S_CANNOT_DOVERB_NOW)
  993. CASE_SCODE(OLEOBJ_S_INVALIDHWND)
  994. CASE_SCODE(INPLACE_S_TRUNCATED)
  995. CASE_SCODE(CONVERT10_S_NO_PRESENTATION)
  996. CASE_SCODE(MK_S_REDUCED_TO_SELF)
  997. CASE_SCODE(MK_S_ME)
  998. CASE_SCODE(MK_S_HIM)
  999. CASE_SCODE(MK_S_US)
  1000. CASE_SCODE(MK_S_MONIKERALREADYREGISTERED)
  1001. CASE_SCODE(STG_S_CONVERTED)
  1002. CASE_SCODE(E_UNEXPECTED)
  1003. CASE_SCODE(E_NOTIMPL)
  1004. CASE_SCODE(E_OUTOFMEMORY)
  1005. CASE_SCODE(E_INVALIDARG)
  1006. CASE_SCODE(E_NOINTERFACE)
  1007. CASE_SCODE(E_POINTER)
  1008. CASE_SCODE(E_HANDLE)
  1009. CASE_SCODE(E_ABORT)
  1010. CASE_SCODE(E_FAIL)
  1011. CASE_SCODE(E_ACCESSDENIED)
  1012. /* SCODE's defined in DVOBJ.H */
  1013. CASE_SCODE(DATA_E_FORMATETC)
  1014. // same as DATA_E_FORMATETC CASE_SCODE(DV_E_FORMATETC)
  1015. CASE_SCODE(VIEW_E_DRAW)
  1016. // same as VIEW_E_DRAW CASE_SCODE(E_DRAW)
  1017. CASE_SCODE(CACHE_E_NOCACHE_UPDATED)
  1018. /* SCODE's defined in OLE2.H */
  1019. CASE_SCODE(OLE_E_OLEVERB)
  1020. CASE_SCODE(OLE_E_ADVF)
  1021. CASE_SCODE(OLE_E_ENUM_NOMORE)
  1022. CASE_SCODE(OLE_E_ADVISENOTSUPPORTED)
  1023. CASE_SCODE(OLE_E_NOCONNECTION)
  1024. CASE_SCODE(OLE_E_NOTRUNNING)
  1025. CASE_SCODE(OLE_E_NOCACHE)
  1026. CASE_SCODE(OLE_E_BLANK)
  1027. CASE_SCODE(OLE_E_CLASSDIFF)
  1028. CASE_SCODE(OLE_E_CANT_GETMONIKER)
  1029. CASE_SCODE(OLE_E_CANT_BINDTOSOURCE)
  1030. CASE_SCODE(OLE_E_STATIC)
  1031. CASE_SCODE(OLE_E_PROMPTSAVECANCELLED)
  1032. CASE_SCODE(OLE_E_INVALIDRECT)
  1033. CASE_SCODE(OLE_E_WRONGCOMPOBJ)
  1034. CASE_SCODE(OLE_E_INVALIDHWND)
  1035. CASE_SCODE(DV_E_DVTARGETDEVICE)
  1036. CASE_SCODE(DV_E_STGMEDIUM)
  1037. CASE_SCODE(DV_E_STATDATA)
  1038. CASE_SCODE(DV_E_LINDEX)
  1039. CASE_SCODE(DV_E_TYMED)
  1040. CASE_SCODE(DV_E_CLIPFORMAT)
  1041. CASE_SCODE(DV_E_DVASPECT)
  1042. CASE_SCODE(DV_E_DVTARGETDEVICE_SIZE)
  1043. CASE_SCODE(DV_E_NOIVIEWOBJECT)
  1044. CASE_SCODE(CONVERT10_E_OLESTREAM_GET)
  1045. CASE_SCODE(CONVERT10_E_OLESTREAM_PUT)
  1046. CASE_SCODE(CONVERT10_E_OLESTREAM_FMT)
  1047. CASE_SCODE(CONVERT10_E_OLESTREAM_BITMAP_TO_DIB)
  1048. CASE_SCODE(CONVERT10_E_STG_FMT)
  1049. CASE_SCODE(CONVERT10_E_STG_NO_STD_STREAM)
  1050. CASE_SCODE(CONVERT10_E_STG_DIB_TO_BITMAP)
  1051. CASE_SCODE(CLIPBRD_E_CANT_OPEN)
  1052. CASE_SCODE(CLIPBRD_E_CANT_EMPTY)
  1053. CASE_SCODE(CLIPBRD_E_CANT_SET)
  1054. CASE_SCODE(CLIPBRD_E_BAD_DATA)
  1055. CASE_SCODE(CLIPBRD_E_CANT_CLOSE)
  1056. CASE_SCODE(DRAGDROP_E_NOTREGISTERED)
  1057. CASE_SCODE(DRAGDROP_E_ALREADYREGISTERED)
  1058. CASE_SCODE(DRAGDROP_E_INVALIDHWND)
  1059. CASE_SCODE(OLEOBJ_E_NOVERBS)
  1060. CASE_SCODE(INPLACE_E_NOTUNDOABLE)
  1061. CASE_SCODE(INPLACE_E_NOTOOLSPACE)
  1062. /* SCODE's defined in STORAGE.H */
  1063. CASE_SCODE(STG_E_INVALIDFUNCTION)
  1064. CASE_SCODE(STG_E_FILENOTFOUND)
  1065. CASE_SCODE(STG_E_PATHNOTFOUND)
  1066. CASE_SCODE(STG_E_TOOMANYOPENFILES)
  1067. CASE_SCODE(STG_E_ACCESSDENIED)
  1068. CASE_SCODE(STG_E_INVALIDHANDLE)
  1069. CASE_SCODE(STG_E_INSUFFICIENTMEMORY)
  1070. CASE_SCODE(STG_E_INVALIDPOINTER)
  1071. CASE_SCODE(STG_E_NOMOREFILES)
  1072. CASE_SCODE(STG_E_DISKISWRITEPROTECTED)
  1073. CASE_SCODE(STG_E_SEEKERROR)
  1074. CASE_SCODE(STG_E_WRITEFAULT)
  1075. CASE_SCODE(STG_E_READFAULT)
  1076. CASE_SCODE(STG_E_LOCKVIOLATION)
  1077. CASE_SCODE(STG_E_FILEALREADYEXISTS)
  1078. CASE_SCODE(STG_E_INVALIDPARAMETER)
  1079. CASE_SCODE(STG_E_MEDIUMFULL)
  1080. CASE_SCODE(STG_E_ABNORMALAPIEXIT)
  1081. CASE_SCODE(STG_E_INVALIDHEADER)
  1082. CASE_SCODE(STG_E_INVALIDNAME)
  1083. CASE_SCODE(STG_E_UNKNOWN)
  1084. CASE_SCODE(STG_E_UNIMPLEMENTEDFUNCTION)
  1085. CASE_SCODE(STG_E_INVALIDFLAG)
  1086. CASE_SCODE(STG_E_INUSE)
  1087. CASE_SCODE(STG_E_NOTCURRENT)
  1088. CASE_SCODE(STG_E_REVERTED)
  1089. CASE_SCODE(STG_E_CANTSAVE)
  1090. CASE_SCODE(STG_E_OLDFORMAT)
  1091. CASE_SCODE(STG_E_OLDDLL)
  1092. CASE_SCODE(STG_E_SHAREREQUIRED)
  1093. /* SCODE's defined in COMPOBJ.H */
  1094. CASE_SCODE(CO_E_NOTINITIALIZED)
  1095. CASE_SCODE(CO_E_ALREADYINITIALIZED)
  1096. CASE_SCODE(CO_E_CANTDETERMINECLASS)
  1097. CASE_SCODE(CO_E_CLASSSTRING)
  1098. CASE_SCODE(CO_E_IIDSTRING)
  1099. CASE_SCODE(CO_E_APPNOTFOUND)
  1100. CASE_SCODE(CO_E_APPSINGLEUSE)
  1101. CASE_SCODE(CO_E_ERRORINAPP)
  1102. CASE_SCODE(CO_E_DLLNOTFOUND)
  1103. CASE_SCODE(CO_E_ERRORINDLL)
  1104. CASE_SCODE(CO_E_WRONGOSFORAPP)
  1105. CASE_SCODE(CO_E_OBJNOTREG)
  1106. CASE_SCODE(CO_E_OBJISREG)
  1107. CASE_SCODE(CO_E_OBJNOTCONNECTED)
  1108. CASE_SCODE(CO_E_APPDIDNTREG)
  1109. CASE_SCODE(CLASS_E_NOAGGREGATION)
  1110. CASE_SCODE(CLASS_E_CLASSNOTAVAILABLE)
  1111. CASE_SCODE(REGDB_E_READREGDB)
  1112. CASE_SCODE(REGDB_E_WRITEREGDB)
  1113. CASE_SCODE(REGDB_E_KEYMISSING)
  1114. CASE_SCODE(REGDB_E_INVALIDVALUE)
  1115. CASE_SCODE(REGDB_E_CLASSNOTREG)
  1116. CASE_SCODE(REGDB_E_IIDNOTREG)
  1117. CASE_SCODE(RPC_E_CALL_REJECTED)
  1118. CASE_SCODE(RPC_E_CALL_CANCELED)
  1119. CASE_SCODE(RPC_E_CANTPOST_INSENDCALL)
  1120. CASE_SCODE(RPC_E_CANTCALLOUT_INASYNCCALL)
  1121. CASE_SCODE(RPC_E_CANTCALLOUT_INEXTERNALCALL)
  1122. CASE_SCODE(RPC_E_CONNECTION_TERMINATED)
  1123. #if defined(NO_NTOLEBUGS)
  1124. CASE_SCODE(RPC_E_SERVER_DIED)
  1125. #endif // NO_NTOLEBUGS
  1126. CASE_SCODE(RPC_E_CLIENT_DIED)
  1127. CASE_SCODE(RPC_E_INVALID_DATAPACKET)
  1128. CASE_SCODE(RPC_E_CANTTRANSMIT_CALL)
  1129. CASE_SCODE(RPC_E_CLIENT_CANTMARSHAL_DATA)
  1130. CASE_SCODE(RPC_E_CLIENT_CANTUNMARSHAL_DATA)
  1131. CASE_SCODE(RPC_E_SERVER_CANTMARSHAL_DATA)
  1132. CASE_SCODE(RPC_E_SERVER_CANTUNMARSHAL_DATA)
  1133. CASE_SCODE(RPC_E_INVALID_DATA)
  1134. CASE_SCODE(RPC_E_INVALID_PARAMETER)
  1135. CASE_SCODE(RPC_E_UNEXPECTED)
  1136. /* SCODE's defined in MONIKER.H */
  1137. CASE_SCODE(MK_E_CONNECTMANUALLY)
  1138. CASE_SCODE(MK_E_EXCEEDEDDEADLINE)
  1139. CASE_SCODE(MK_E_NEEDGENERIC)
  1140. CASE_SCODE(MK_E_UNAVAILABLE)
  1141. CASE_SCODE(MK_E_SYNTAX)
  1142. CASE_SCODE(MK_E_NOOBJECT)
  1143. CASE_SCODE(MK_E_INVALIDEXTENSION)
  1144. CASE_SCODE(MK_E_INTERMEDIATEINTERFACENOTSUPPORTED)
  1145. CASE_SCODE(MK_E_NOTBINDABLE)
  1146. CASE_SCODE(MK_E_NOTBOUND)
  1147. CASE_SCODE(MK_E_CANTOPENFILE)
  1148. CASE_SCODE(MK_E_MUSTBOTHERUSER)
  1149. CASE_SCODE(MK_E_NOINVERSE)
  1150. CASE_SCODE(MK_E_NOSTORAGE)
  1151. #if defined(NO_NTOLEBUGS)
  1152. CASE_SCODE(MK_S_MONIKERALREADYREGISTERED)
  1153. #endif //NO_NTOLEBUGS
  1154. // Forms error codes
  1155. // CASE_SCODE(FORMS_E_NOPAGESSPECIFIED)
  1156. // CASE_SCODE(FORMS_E_NOPAGESINTERSECT)
  1157. // Dispatch error codes
  1158. CASE_SCODE(DISP_E_MEMBERNOTFOUND)
  1159. CASE_SCODE(DISP_E_PARAMNOTFOUND)
  1160. CASE_SCODE(DISP_E_BADPARAMCOUNT)
  1161. CASE_SCODE(DISP_E_BADINDEX)
  1162. CASE_SCODE(DISP_E_UNKNOWNINTERFACE)
  1163. CASE_SCODE(DISP_E_NONAMEDARGS)
  1164. CASE_SCODE(DISP_E_EXCEPTION)
  1165. CASE_SCODE(DISP_E_TYPEMISMATCH)
  1166. CASE_SCODE(DISP_E_UNKNOWNNAME)
  1167. // Typinfo error codes
  1168. CASE_SCODE(TYPE_E_REGISTRYACCESS)
  1169. CASE_SCODE(TYPE_E_LIBNOTREGISTERED)
  1170. CASE_SCODE(TYPE_E_UNDEFINEDTYPE)
  1171. CASE_SCODE(TYPE_E_WRONGTYPEKIND)
  1172. CASE_SCODE(TYPE_E_ELEMENTNOTFOUND)
  1173. CASE_SCODE(TYPE_E_INVALIDID)
  1174. CASE_SCODE(TYPE_E_CANTLOADLIBRARY)
  1175. default:
  1176. lpstr = _T("UNKNOWN SCODE");
  1177. }
  1178. #undef CASE_SCODE
  1179. return lpstr;
  1180. }
  1181. //+---------------------------------------------------------------------------
  1182. //
  1183. // Function: hrvsnprintf
  1184. //
  1185. // Synopsis: Prints a string to a buffer, interpreting %hr as a
  1186. // format string for an HRESULT.
  1187. //
  1188. // Arguments: [achBuf] -- The buffer to print into.
  1189. // [cchBuf] -- The size of the buffer.
  1190. // [pstrFmt] -- The format string.
  1191. // [valMarker] -- List of arguments to format string.
  1192. //
  1193. // Returns: Number of characters printed to the buffer not including
  1194. // the terminating NULL. In case of buffer overflow, returns
  1195. // -1.
  1196. //
  1197. // Modifies: [achBuf]
  1198. //
  1199. //----------------------------------------------------------------------------
  1200. int
  1201. hrvsnprintf(char * achBuf, int cchBuf, const char * pstrFmt, va_list valMarker)
  1202. {
  1203. static char achFmtHR[] = "<%ls (0x%lx)>";
  1204. static char achHRID[] = "%hr";
  1205. char * buf = NULL;
  1206. int cch;
  1207. int cchTotal;
  1208. const char * lpstr;
  1209. const char * lpstrLast;
  1210. int cFormat;
  1211. HRESULT hrVA;
  1212. //
  1213. // Scan for %hr tokens. If found, print the corresponding
  1214. // hresult into the buffer.
  1215. //
  1216. // Need to copy a const string since we plan to modify it below
  1217. buf = (char *) malloc ((lstrlen(pstrFmt) + 1) * sizeof(char));
  1218. lstrcpy(buf,pstrFmt);
  1219. cch = 0;
  1220. cchTotal = 0;
  1221. cFormat = 0;
  1222. lpstrLast = buf;
  1223. lpstr = buf;
  1224. while (*lpstr)
  1225. {
  1226. if (*lpstr != '%')
  1227. {
  1228. lpstr++;
  1229. }
  1230. else if (lpstr[1] == '%')
  1231. {
  1232. lpstr += 2;
  1233. }
  1234. else if (StrCmpNA(lpstr, achHRID, ARRAY_SIZE(achHRID) - 1))
  1235. {
  1236. cFormat++;
  1237. lpstr++;
  1238. }
  1239. else
  1240. {
  1241. //
  1242. // Print format string up to the hresult.
  1243. //
  1244. * (char *) lpstr = 0;
  1245. cch = _vsnprintf(
  1246. achBuf + cchTotal,
  1247. cchBuf - cchTotal,
  1248. lpstrLast,
  1249. valMarker);
  1250. * (char *) lpstr = '%';
  1251. if (cch == -1)
  1252. break;
  1253. cchTotal += cch;
  1254. //
  1255. // Advance valMarker for each printed format.
  1256. //
  1257. while (cFormat-- > 0)
  1258. {
  1259. //
  1260. // BUGBUG (adams): Won't work for floats, as their stack size
  1261. // is not four bytes.
  1262. //
  1263. va_arg(valMarker, void *);
  1264. }
  1265. //
  1266. // Print hresult into buffer.
  1267. //
  1268. hrVA = va_arg(valMarker, HRESULT);
  1269. cch = _snprintf(
  1270. achBuf + cchTotal,
  1271. cchBuf - cchTotal,
  1272. achFmtHR,
  1273. GetHResultName(hrVA),
  1274. hrVA);
  1275. if (cch == -1)
  1276. break;
  1277. cchTotal += cch;
  1278. lpstr += ARRAY_SIZE(achHRID) - 1;
  1279. lpstrLast = lpstr;
  1280. }
  1281. }
  1282. if (cch != -1)
  1283. {
  1284. cch = _vsnprintf(
  1285. achBuf + cchTotal,
  1286. cchBuf - cchTotal,
  1287. lpstrLast,
  1288. valMarker);
  1289. }
  1290. free (buf);
  1291. return (cch == -1) ? -1 : cchTotal + cch;
  1292. }
  1293. #endif