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.

636 lines
24 KiB

  1. /*******************************************************************************
  2. * SPDebug.h *
  3. *-----------*
  4. * Description:
  5. * This header file contains debug output services for SAPI5
  6. *-------------------------------------------------------------------------------
  7. * Copyright (c) Microsoft Corporation. All rights reserved.
  8. *******************************************************************************/
  9. #pragma once
  10. #include <TCHAR.h>
  11. #include <crtdbg.h>
  12. #ifdef ASSERT_WITH_STACK
  13. #include "AssertWithStack.h"
  14. #endif
  15. const TCHAR g_szSpDebugKey[] = _T("SPDebug");
  16. const TCHAR g_szSpDebugFuncTraceReportMode[] = _T("FuncTraceMode");
  17. const TCHAR g_szSpDebugFuncTraceReportFile[] = _T("FuncTraceFile");
  18. const TCHAR g_szSpDebugParamInfoReportMode[] = _T("ParamInfoMode");
  19. const TCHAR g_szSpDebugParamInfoReportFile[] = _T("ParamInfoFile");
  20. const TCHAR g_szSpDebugDumpInfoReportMode[] = _T("DumpInfoMode");
  21. const TCHAR g_szSpDebugDumpInfoReportFile[] = _T("DumpInfoFile");
  22. const TCHAR g_szSpDebugAssertReportMode[] = _T("AssertMode");
  23. const TCHAR g_szSpDebugAssertReportFile[] = _T("AssertFile");
  24. const TCHAR g_szSpDebugHRFailReportMode[] = _T("HRFailMode");
  25. const TCHAR g_szSpDebugHRFailReportFile[] = _T("HRFailFile");
  26. const TCHAR g_szSpDebugAssertSettingsReReadEachTime[] = _T("AssertSettingsReReadEachTime");
  27. const TCHAR g_szSpDebugServerOnStart[] = _T("DebugServerOnStart");
  28. const TCHAR g_szSpDebugClientOnStart[] = _T("DebugClientOnStart");
  29. const TCHAR g_szSpDebugLog[] = _T("c:\\spdebug.log");
  30. #ifdef _DEBUG
  31. class CSpDebug
  32. {
  33. public:
  34. CSpDebug()
  35. {
  36. m_mutex = NULL;
  37. m_reportModePrev = -1;
  38. m_hfilePrev = NULL;
  39. Read();
  40. }
  41. ~CSpDebug()
  42. {
  43. if (m_mutex != NULL)
  44. {
  45. CloseHandle(m_mutex);
  46. }
  47. }
  48. BOOL FuncTrace(BOOL fEnter = TRUE)
  49. {
  50. return fEnter
  51. ? Enter(_CRT_WARN, m_FuncTraceMode, m_szFuncTraceFile)
  52. : Leave();
  53. }
  54. BOOL ParamInfo(BOOL fEnter = TRUE)
  55. {
  56. return fEnter
  57. ? Enter(_CRT_WARN, m_ParamInfoMode, m_szParamInfoFile)
  58. : Leave();
  59. }
  60. BOOL DumpInfo(BOOL fEnter = TRUE)
  61. {
  62. return fEnter
  63. ? Enter(_CRT_WARN, m_DumpInfoMode, m_szDumpInfoFile)
  64. : Leave();
  65. }
  66. BOOL Assert(BOOL fEnter = TRUE)
  67. {
  68. if (m_fAssertSettingsReReadEachTime)
  69. Read();
  70. return fEnter
  71. ? Enter(_CRT_ASSERT, m_AssertMode, m_szAssertFile)
  72. : Leave();
  73. }
  74. BOOL HRFail(BOOL fEnter = TRUE)
  75. {
  76. return fEnter
  77. ? Enter(_CRT_WARN, m_HRFailMode, m_szHRFailFile)
  78. : Leave();
  79. }
  80. BOOL DebugServerOnStart()
  81. {
  82. return m_fDebugServerOnStart;
  83. }
  84. BOOL DebugClientOnStart()
  85. {
  86. return m_fDebugClientOnStart;
  87. }
  88. private:
  89. void Read()
  90. {
  91. HKEY hkeyDebug;
  92. RegCreateKeyEx(
  93. HKEY_CLASSES_ROOT,
  94. g_szSpDebugKey,
  95. 0,
  96. NULL,
  97. 0,
  98. KEY_READ | KEY_WRITE,
  99. NULL,
  100. &hkeyDebug,
  101. NULL);
  102. if (hkeyDebug == NULL)
  103. {
  104. RegCreateKeyEx(
  105. HKEY_CLASSES_ROOT,
  106. g_szSpDebugKey,
  107. 0,
  108. NULL,
  109. 0,
  110. KEY_READ,
  111. NULL,
  112. &hkeyDebug,
  113. NULL);
  114. }
  115. DWORD dw = sizeof(m_fAssertSettingsReReadEachTime);
  116. if (RegQueryValueEx(
  117. hkeyDebug,
  118. g_szSpDebugAssertSettingsReReadEachTime,
  119. NULL,
  120. NULL,
  121. LPBYTE(&m_fAssertSettingsReReadEachTime),
  122. &dw) != ERROR_SUCCESS)
  123. {
  124. m_fAssertSettingsReReadEachTime = FALSE;
  125. RegSetValueEx(
  126. hkeyDebug,
  127. g_szSpDebugAssertSettingsReReadEachTime,
  128. NULL,
  129. REG_DWORD,
  130. LPBYTE(&m_fAssertSettingsReReadEachTime),
  131. sizeof(m_fAssertSettingsReReadEachTime));
  132. }
  133. ReadFor(
  134. hkeyDebug,
  135. g_szSpDebugFuncTraceReportMode,
  136. g_szSpDebugFuncTraceReportFile,
  137. &m_FuncTraceMode,
  138. m_szFuncTraceFile,
  139. 0,
  140. g_szSpDebugLog);
  141. ReadFor(
  142. hkeyDebug,
  143. g_szSpDebugParamInfoReportMode,
  144. g_szSpDebugParamInfoReportFile,
  145. &m_ParamInfoMode,
  146. m_szParamInfoFile,
  147. 0,
  148. g_szSpDebugLog);
  149. ReadFor(
  150. hkeyDebug,
  151. g_szSpDebugDumpInfoReportMode,
  152. g_szSpDebugDumpInfoReportFile,
  153. &m_DumpInfoMode,
  154. m_szDumpInfoFile,
  155. _CRTDBG_MODE_DEBUG,
  156. g_szSpDebugLog);
  157. ReadFor(
  158. hkeyDebug,
  159. g_szSpDebugAssertReportMode,
  160. g_szSpDebugAssertReportFile,
  161. &m_AssertMode,
  162. m_szAssertFile,
  163. _CRTDBG_MODE_WNDW,
  164. g_szSpDebugLog);
  165. ReadFor(
  166. hkeyDebug,
  167. g_szSpDebugHRFailReportMode,
  168. g_szSpDebugHRFailReportFile,
  169. &m_HRFailMode,
  170. m_szHRFailFile,
  171. _CRTDBG_MODE_DEBUG,
  172. g_szSpDebugLog);
  173. dw = sizeof(m_fDebugServerOnStart);
  174. if (RegQueryValueEx(
  175. hkeyDebug,
  176. g_szSpDebugServerOnStart,
  177. NULL,
  178. NULL,
  179. LPBYTE(&m_fDebugServerOnStart),
  180. &dw) != ERROR_SUCCESS)
  181. {
  182. m_fDebugServerOnStart = FALSE;
  183. RegSetValueEx(
  184. hkeyDebug,
  185. g_szSpDebugServerOnStart,
  186. NULL,
  187. REG_DWORD,
  188. LPBYTE(&m_fDebugServerOnStart),
  189. sizeof(m_fDebugServerOnStart));
  190. }
  191. dw = sizeof(m_fDebugClientOnStart);
  192. if (RegQueryValueEx(
  193. hkeyDebug,
  194. g_szSpDebugClientOnStart,
  195. NULL,
  196. NULL,
  197. LPBYTE(&m_fDebugClientOnStart),
  198. &dw) != ERROR_SUCCESS)
  199. {
  200. m_fDebugClientOnStart = FALSE;
  201. RegSetValueEx(
  202. hkeyDebug,
  203. g_szSpDebugClientOnStart,
  204. NULL,
  205. REG_DWORD,
  206. LPBYTE(&m_fDebugClientOnStart),
  207. sizeof(m_fDebugClientOnStart));
  208. }
  209. RegCloseKey(hkeyDebug);
  210. }
  211. void ReadFor(
  212. HKEY hkey,
  213. const TCHAR * pszModeValueName,
  214. const TCHAR * pszFileValueName,
  215. DWORD * pdwModeValue,
  216. TCHAR * pszFileValue,
  217. DWORD dwDefaultModeValue,
  218. const TCHAR * pszDefaultFileValue)
  219. {
  220. DWORD dw = sizeof(*pdwModeValue);
  221. if (RegQueryValueEx(
  222. hkey,
  223. pszModeValueName,
  224. NULL,
  225. NULL,
  226. LPBYTE(pdwModeValue),
  227. &dw) != ERROR_SUCCESS)
  228. {
  229. *pdwModeValue = dwDefaultModeValue;
  230. RegSetValueEx(
  231. hkey,
  232. pszModeValueName,
  233. NULL,
  234. REG_DWORD,
  235. LPBYTE(pdwModeValue),
  236. sizeof(*pdwModeValue));
  237. }
  238. dw = MAX_PATH;
  239. if (RegQueryValueEx(
  240. hkey,
  241. pszFileValueName,
  242. NULL,
  243. NULL,
  244. LPBYTE(pszFileValue),
  245. &dw) != ERROR_SUCCESS)
  246. {
  247. _tcscpy(pszFileValue, pszDefaultFileValue);
  248. RegSetValueEx(
  249. hkey,
  250. pszFileValueName,
  251. NULL,
  252. REG_SZ,
  253. LPBYTE(pszFileValue),
  254. MAX_PATH);
  255. }
  256. }
  257. BOOL Enter(int reportType, DWORD &reportMode, TCHAR * pszFile)
  258. {
  259. if (reportMode != 0)
  260. {
  261. // We'll hold the mutex, until the caller also calls Leave
  262. if (m_mutex == NULL)
  263. {
  264. m_mutex = CreateMutex(NULL, FALSE, _T("SpDebug"));
  265. }
  266. WaitForSingleObject(m_mutex, INFINITE);
  267. m_reportType = reportType;
  268. m_reportModePrev = _CrtSetReportMode(reportType, reportMode);
  269. if (reportMode & _CRTDBG_MODE_FILE)
  270. {
  271. HANDLE hfile = CreateFile(
  272. pszFile,
  273. GENERIC_READ | GENERIC_WRITE,
  274. FILE_SHARE_READ,
  275. NULL,
  276. OPEN_ALWAYS,
  277. 0,
  278. NULL);
  279. SetFilePointer(hfile, 0, NULL, FILE_END);
  280. m_hfilePrev = (_HFILE)_CrtSetReportFile(reportType, (_HFILE)hfile);
  281. }
  282. return TRUE;
  283. }
  284. return FALSE;
  285. }
  286. BOOL Leave()
  287. {
  288. int reportMode = _CrtSetReportMode(m_reportType, m_reportModePrev);
  289. if (reportMode & _CRTDBG_MODE_FILE)
  290. {
  291. CloseHandle((_HFILE)_CrtSetReportFile(m_reportType, (_HFILE)m_hfilePrev));
  292. }
  293. ReleaseMutex(m_mutex);
  294. return TRUE;
  295. }
  296. private:
  297. HANDLE m_mutex;
  298. int m_reportType;
  299. int m_reportModePrev;
  300. _HFILE m_hfilePrev;
  301. BOOL m_fAssertSettingsReReadEachTime;
  302. DWORD m_FuncTraceMode;
  303. TCHAR m_szFuncTraceFile[MAX_PATH + 1];
  304. DWORD m_ParamInfoMode;
  305. TCHAR m_szParamInfoFile[MAX_PATH + 1];
  306. DWORD m_DumpInfoMode;
  307. TCHAR m_szDumpInfoFile[MAX_PATH + 1];
  308. DWORD m_AssertMode;
  309. TCHAR m_szAssertFile[MAX_PATH + 1];
  310. DWORD m_HRFailMode;
  311. TCHAR m_szHRFailFile[MAX_PATH + 1];
  312. BOOL m_fDebugServerOnStart;
  313. BOOL m_fDebugClientOnStart;
  314. };
  315. inline CSpDebug *PSpDebug()
  316. {
  317. static CSpDebug debug;
  318. return &debug;
  319. }
  320. class CSpFuncTrace
  321. {
  322. public:
  323. CSpFuncTrace(PCHAR pFuncName)
  324. {
  325. m_pFuncName = pFuncName;
  326. if (PSpDebug()->FuncTrace())
  327. {
  328. _RPT1( _CRT_WARN, "\nEntering Function: %s\n", m_pFuncName );
  329. PSpDebug()->FuncTrace(FALSE);
  330. }
  331. }
  332. ~CSpFuncTrace()
  333. {
  334. if (PSpDebug()->FuncTrace())
  335. {
  336. _RPT1( _CRT_WARN, "Leaving Function: %s\n", m_pFuncName );
  337. PSpDebug()->FuncTrace(FALSE);
  338. }
  339. }
  340. private:
  341. PCHAR m_pFuncName;
  342. };
  343. #endif // _DEBUG
  344. //=== User macros ==============================================================
  345. #ifdef _DEBUG
  346. #define SPDBG_FUNC(name) \
  347. CSpFuncTrace functrace(name)
  348. #if defined(ASSERT_WITH_STACK) && !defined(_WIN64)
  349. #define SPDBG_REPORT_ON_FAIL(hr) \
  350. do \
  351. { \
  352. HRESULT _hr = (hr); \
  353. if (FAILED(_hr) && PSpDebug()->HRFail()) \
  354. { \
  355. SYSTEMTIME sysTime; \
  356. GetLocalTime(&sysTime); \
  357. CHAR pszHrWithTime[100]; \
  358. sprintf(pszHrWithTime, "%lX\n\n%d.%d.%d %02d:%02d:%02d", \
  359. _hr, \
  360. sysTime.wMonth,sysTime.wDay,sysTime.wYear, \
  361. sysTime.wHour,sysTime.wMinute,sysTime.wSecond); \
  362. PCHAR pszStack = \
  363. (PCHAR)_alloca( \
  364. cchMaxAssertStackLevelStringLen * \
  365. cfrMaxAssertStackLevels + 1); \
  366. GetStringFromStackLevels(0, 10, pszStack); \
  367. _RPT4(_CRT_WARN, \
  368. "%s(%d): Failed HR = %s\n\n%s\n", \
  369. __FILE__, \
  370. __LINE__, \
  371. pszHrWithTime, \
  372. pszStack); \
  373. PSpDebug()->HRFail(FALSE); \
  374. } \
  375. } while (0)
  376. #else // ASSERT_WITH_STACK & !_WIN64
  377. #define SPDBG_REPORT_ON_FAIL(hr) \
  378. do \
  379. { \
  380. HRESULT _hr = (hr); \
  381. if (FAILED(_hr) && PSpDebug()->HRFail()) \
  382. { \
  383. _RPT3(_CRT_WARN, "%s(%d): Failed HR = %lX\n", __FILE__, __LINE__, (_hr) );\
  384. PSpDebug()->HRFail(FALSE); \
  385. } \
  386. } while (0)
  387. #endif // ASSERT_WITH_STACK
  388. #define SPDBG_ASSERT(expr) \
  389. do \
  390. { \
  391. if (!(expr)) \
  392. { \
  393. if (PSpDebug()->Assert()) \
  394. { \
  395. _ASSERTE( expr ); \
  396. PSpDebug()->Assert(FALSE); \
  397. } \
  398. } \
  399. } \
  400. while (0)
  401. #define SPDBG_VERIFY(expr) \
  402. SPDBG_ASSERT(expr)
  403. #define SPDBG_PMSG0(format) \
  404. do \
  405. { \
  406. if (PSpDebug()->ParamInfo()) \
  407. { \
  408. _RPT0(_CRT_WARN, format); \
  409. PSpDebug()->ParamInfo(FALSE); \
  410. } \
  411. } while (0)
  412. #define SPDBG_PMSG1(format, arg1) \
  413. do \
  414. { \
  415. if (PSpDebug()->ParamInfo()) \
  416. { \
  417. _RPT1(_CRT_WARN, format, arg1); \
  418. PSpDebug()->ParamInfo(FALSE); \
  419. } \
  420. } while (0)
  421. #define SPDBG_PMSG2(format, arg1, arg2) \
  422. do \
  423. { \
  424. if (PSpDebug()->ParamInfo()) \
  425. { \
  426. _RPT2(_CRT_WARN, format, arg1, arg2); \
  427. PSpDebug()->ParamInfo(FALSE); \
  428. } \
  429. } while (0)
  430. #define SPDBG_PMSG3(format, arg1, arg2, arg3) \
  431. do \
  432. { \
  433. if (PSpDebug()->ParamInfo()) \
  434. { \
  435. _RPT3(_CRT_WARN, format, arg1, arg2, arg3); \
  436. PSpDebug()->ParamInfo(FALSE); \
  437. } \
  438. } while (0)
  439. #define SPDBG_PMSG4(format, arg1, arg2, arg3, arg4) \
  440. do \
  441. { \
  442. if (PSpDebug()->ParamInfo()) \
  443. { \
  444. _RPT4(_CRT_WARN, format, arg1, arg2, arg3, arg4); \
  445. PSpDebug()->ParamInfo(FALSE); \
  446. } \
  447. } while (0)
  448. #define SPDBG_DMSG0(format) \
  449. do \
  450. { \
  451. if (PSpDebug()->DumpInfo()) \
  452. { \
  453. _RPT0(_CRT_WARN, format); \
  454. PSpDebug()->DumpInfo(FALSE); \
  455. } \
  456. } while (0)
  457. #define SPDBG_DMSG1(format, arg1) \
  458. do \
  459. { \
  460. if (PSpDebug()->DumpInfo()) \
  461. { \
  462. _RPT1(_CRT_WARN, format, arg1); \
  463. PSpDebug()->DumpInfo(FALSE); \
  464. } \
  465. } while (0)
  466. #define SPDBG_DMSG2(format, arg1, arg2) \
  467. do \
  468. { \
  469. if (PSpDebug()->DumpInfo()) \
  470. { \
  471. _RPT2(_CRT_WARN, format, arg1, arg2); \
  472. PSpDebug()->DumpInfo(FALSE); \
  473. } \
  474. } while (0)
  475. #define SPDBG_DMSG3(format, arg1, arg2, arg3) \
  476. do \
  477. { \
  478. if (PSpDebug()->DumpInfo()) \
  479. { \
  480. _RPT3(_CRT_WARN, format, arg1, arg2, arg3); \
  481. PSpDebug()->DumpInfo(FALSE); \
  482. } \
  483. } while (0)
  484. #define SPDBG_DMSG4(format, arg1, arg2, arg3, arg4) \
  485. do \
  486. { \
  487. if (PSpDebug()->DumpInfo()) \
  488. { \
  489. _RPT4(_CRT_WARN, format, arg1, arg2, arg3, arg4); \
  490. PSpDebug()->DumpInfo(FALSE); \
  491. } \
  492. } while (0)
  493. #define SPDBG_RETURN(hr) \
  494. { \
  495. HRESULT __hr = (hr); \
  496. if (FAILED(__hr)) \
  497. { \
  498. SPDBG_REPORT_ON_FAIL(__hr); \
  499. } \
  500. return __hr; \
  501. }
  502. #define SPDBG_DEBUG_SERVER_ON_START() \
  503. { \
  504. if (PSpDebug()->DebugServerOnStart()) \
  505. { \
  506. if (MessageBox( \
  507. GetDesktopWindow(), \
  508. _T("Attach Debugger to the SAPI Server process?"), \
  509. _T("SAPI"), \
  510. MB_YESNO) == IDYES) \
  511. { \
  512. USES_CONVERSION; \
  513. TCHAR szCommand[MAX_PATH + 1]; \
  514. wsprintf( \
  515. szCommand, \
  516. _T("msdev -p %d"), \
  517. GetCurrentProcessId()); \
  518. system(T2A(szCommand)); \
  519. } \
  520. } \
  521. }
  522. #define SPDBG_DEBUG_CLIENT_ON_START() \
  523. { \
  524. if (PSpDebug()->DebugClientOnStart()) \
  525. { \
  526. TCHAR szModule[MAX_PATH + 1]; \
  527. szModule[0] = '\0'; \
  528. TCHAR * pszSapiServer = \
  529. _T("sapisvr.exe"); \
  530. GetModuleFileName( \
  531. NULL, \
  532. szModule, \
  533. MAX_PATH); \
  534. if ((_tcslen(szModule) <= \
  535. _tcslen(pszSapiServer) || \
  536. _tcsicmp( \
  537. szModule + \
  538. _tcslen(szModule) - \
  539. _tcslen(pszSapiServer), \
  540. pszSapiServer) != 0) && \
  541. MessageBox( \
  542. GetDesktopWindow(), \
  543. _T("Attach Debugger to the SAPI Client process?"), \
  544. _T("SAPI"), \
  545. MB_YESNO) == IDYES) \
  546. { \
  547. USES_CONVERSION; \
  548. TCHAR szCommand[MAX_PATH + 1]; \
  549. wsprintf( \
  550. szCommand, \
  551. _T("msdev -p %d"), \
  552. GetCurrentProcessId()); \
  553. system(T2A(szCommand)); \
  554. } \
  555. } \
  556. }
  557. #else // _DEBUG
  558. #define SPDBG_FUNC(name)
  559. #define SPDBG_REPORT_ON_FAIL(hr)
  560. #define SPDBG_ASSERT(expr)
  561. #define SPDBG_VERIFY(expr) (expr)
  562. #define SPDBG_PMSG0(format)
  563. #define SPDBG_PMSG1(format, arg1)
  564. #define SPDBG_PMSG2(format, arg1, arg2)
  565. #define SPDBG_PMSG3(format, arg1, arg2, arg3)
  566. #define SPDBG_PMSG4(format, arg1, arg2, arg3, arg4)
  567. #define SPDBG_DMSG0(format)
  568. #define SPDBG_DMSG1(format, arg1)
  569. #define SPDBG_DMSG2(format, arg1, arg2)
  570. #define SPDBG_DMSG3(format, arg1, arg2, arg3)
  571. #define SPDBG_DMSG4(format, arg1, arg2, arg3, arg4)
  572. #define SPDBG_RETURN(hr) return (hr)
  573. #define SPDBG_DEBUG_SERVER_ON_START()
  574. #define SPDBG_DEBUG_CLIENT_ON_START()
  575. #endif // _DEBUG