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.

794 lines
19 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. Debugex.cpp
  5. Abstract:
  6. Implementation of the CDebug class.
  7. Author:
  8. Eran Yariv (EranY) Jul, 1999
  9. Revision History:
  10. --*/
  11. #include <windows.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <tchar.h>
  15. #include <time.h>
  16. #include "debugex.h"
  17. #include <faxreg.h> // We're reading the default mask from HKLM\REGKEY_FAX_CLIENT\REGVAL_DBGLEVEL_EX
  18. #include <faxutil.h> // For the DEBUG_FAX_TAPI_MSG, DEBUG_VER_MSG, DEBUG_WRN_MSG, and DEBUG_ERR_MSG constants
  19. #ifdef _DEBUG
  20. #define new DEBUG_NEW
  21. #undef THIS_FILE
  22. static char THIS_FILE[] = __FILE__;
  23. #endif
  24. #ifdef ENABLE_FRE_LOGGING
  25. #define ENABLE_LOGGING
  26. #endif
  27. #ifdef DEBUG
  28. #define ENABLE_LOGGING
  29. #endif
  30. #ifdef ENABLE_LOGGING
  31. //////////////////////////////////////////////////////////////////////
  32. // Static variables
  33. //////////////////////////////////////////////////////////////////////
  34. HANDLE CDebug::m_shLogFile = INVALID_HANDLE_VALUE;
  35. LONG CDebug::m_sdwIndent = 0;
  36. DWORD CDebug::m_sDbgMask = DEFAULT_DEBUG_MASK;
  37. DWORD CDebug::m_sFmtMask = DEFAULT_FORMAT_MASK;
  38. BOOL CDebug::m_sbMaskReadFromReg = FALSE;
  39. BOOL CDebug::m_sbRegistryExist = FALSE;
  40. BOOL CDebug::m_sbFlush = TRUE;
  41. //////////////////////////////////////////////////////////////////////
  42. // Construction/Destruction
  43. //////////////////////////////////////////////////////////////////////
  44. CDebug::~CDebug()
  45. /*++
  46. Routine name : CDebug::~CDebug
  47. Routine description:
  48. Destructor
  49. Author:
  50. Eran Yariv (EranY), Jul, 1999
  51. Arguments:
  52. None.
  53. Return Value:
  54. None.
  55. --*/
  56. {
  57. DWORD dwLastError = GetLastError ();
  58. Unindent ();
  59. switch (m_ReturnType)
  60. {
  61. case DBG_FUNC_RET_UNKNOWN:
  62. DbgPrint (FUNC_TRACE, NULL, 0, TEXT("}"));
  63. break;
  64. case DBG_FUNC_RET_HR:
  65. //
  66. // We have the return HRESULT
  67. //
  68. if (NOERROR == *m_phr)
  69. {
  70. DbgPrint (FUNC_TRACE, NULL, 0, TEXT("} (NOERROR)"));
  71. }
  72. else if (S_FALSE == *m_phr)
  73. {
  74. DbgPrint (FUNC_TRACE, NULL, 0, TEXT("} (S_FALSE)"));
  75. }
  76. else
  77. {
  78. DbgPrint (FUNC_TRACE, NULL, 0, TEXT("} (0x%08X)"), *m_phr);
  79. }
  80. break;
  81. case DBG_FUNC_RET_DWORD:
  82. //
  83. // We have the return DWORD
  84. //
  85. if (ERROR_SUCCESS == *m_pDword)
  86. {
  87. DbgPrint (FUNC_TRACE, NULL, 0, TEXT("} (ERROR_SUCCESS)"));
  88. }
  89. else
  90. {
  91. DbgPrint (FUNC_TRACE, NULL, 0, TEXT("} (%ld)"), *m_pDword);
  92. }
  93. break;
  94. case DBG_FUNC_RET_BOOL:
  95. //
  96. // We have the return BOOL
  97. //
  98. if (*m_pBool)
  99. {
  100. DbgPrint (FUNC_TRACE, NULL, 0, TEXT("} (TRUE)"));
  101. }
  102. else
  103. {
  104. DbgPrint (FUNC_TRACE, NULL, 0, TEXT("} (FALSE)"));
  105. }
  106. break;
  107. default:
  108. DbgPrint (ASSERTION_FAILED,
  109. TEXT(__FILE__),
  110. __LINE__,
  111. TEXT("ASSERTION FAILURE!!!"));
  112. {
  113. DebugBreak();
  114. }
  115. break;
  116. }
  117. SetLastError (dwLastError);
  118. }
  119. //////////////////////////////////////////////////////////////////////
  120. // Implementation
  121. //////////////////////////////////////////////////////////////////////
  122. void
  123. CDebug::EnterModuleWithParams (
  124. LPCTSTR lpctstrModule,
  125. LPCTSTR lpctstrFormat,
  126. va_list arg_ptr
  127. )
  128. {
  129. DWORD dwLastError = GetLastError ();
  130. if (!m_sbMaskReadFromReg)
  131. {
  132. ReadMaskFromReg ();
  133. }
  134. lstrcpyn (m_tszModuleName,
  135. lpctstrModule,
  136. ARR_SIZE (m_tszModuleName) - 1);
  137. m_tszModuleName[ARR_SIZE(m_tszModuleName)-1] = TEXT('\0');
  138. TCHAR szArgs[1024] = {0};
  139. _vsntprintf(szArgs, ARR_SIZE(szArgs)-1, lpctstrFormat, arg_ptr);
  140. TCHAR szBuf[1024] = {0};
  141. _sntprintf (szBuf, ARR_SIZE(szBuf) - 1, TEXT("%s (%s)"), m_tszModuleName, szArgs);
  142. DbgPrint (FUNC_TRACE, NULL, 0, szBuf);
  143. DbgPrint (FUNC_TRACE, NULL, 0, TEXT("{"));
  144. Indent ();
  145. SetLastError (dwLastError);
  146. }
  147. void
  148. CDebug::EnterModule (
  149. LPCTSTR lpctstrModule
  150. )
  151. {
  152. DWORD dwLastError = GetLastError ();
  153. if (!m_sbMaskReadFromReg)
  154. {
  155. ReadMaskFromReg ();
  156. }
  157. lstrcpyn (m_tszModuleName,
  158. lpctstrModule,
  159. ARR_SIZE (m_tszModuleName) - 1);
  160. m_tszModuleName[ARR_SIZE(m_tszModuleName)-1] = TEXT('\0');
  161. DbgPrint (FUNC_TRACE, NULL, 0, m_tszModuleName);
  162. DbgPrint (FUNC_TRACE, NULL, 0, TEXT("{"));
  163. Indent ();
  164. SetLastError (dwLastError);
  165. }
  166. //*****************************************************************************
  167. //* Name: OpenLogFile
  168. //* Author: Mooly Beery (MoolyB), May, 2000
  169. //*****************************************************************************
  170. //* DESCRIPTION:
  171. //* Creates a log file which accepts the debug output
  172. //*
  173. //* PARAMETERS:
  174. //* [IN] LPCTSTR lpctstrFilename:
  175. //* the filename which will be created in the temporary folder
  176. //*
  177. //* RETURN VALUE:
  178. //* FALSE if the operation failed.
  179. //* TRUE is succeeded.
  180. //* Comments:
  181. //* this function should be used together with CloseLogFile()
  182. //*****************************************************************************
  183. BOOL CDebug::OpenLogFile(LPCTSTR lpctstrFilename)
  184. {
  185. TCHAR szFilename[MAX_PATH] = {0};
  186. TCHAR szTempFolder[MAX_PATH] = {0};
  187. TCHAR szPathToFile[MAX_PATH] = {0};
  188. if (!lpctstrFilename)
  189. {
  190. DbgPrint (ASSERTION_FAILED,
  191. TEXT(__FILE__),
  192. __LINE__,
  193. TEXT("Internat error - bad Filename"));
  194. DebugBreak();
  195. return FALSE;
  196. }
  197. // first expand the filename
  198. if (ExpandEnvironmentStrings(lpctstrFilename,szFilename,MAX_PATH)==0)
  199. {
  200. return FALSE;
  201. }
  202. // is this is a file description or a complete path to file
  203. if (_tcschr(szFilename,_T('\\'))==NULL)
  204. {
  205. // this is just the file's name, need to add the temp folder to it.
  206. if (GetTempPath(MAX_PATH,szTempFolder)==0)
  207. {
  208. return FALSE;
  209. }
  210. _tcsncpy(szPathToFile,szTempFolder,MAX_PATH-1);
  211. _tcsncat(szPathToFile,szFilename,MAX_PATH-_tcslen(szPathToFile)-1);
  212. }
  213. else
  214. {
  215. // this is the full path to the log file, use it.
  216. _tcsncpy(szPathToFile,szFilename,MAX_PATH-1);
  217. }
  218. m_shLogFile = ::SafeCreateFile(
  219. szPathToFile,
  220. GENERIC_WRITE,
  221. FILE_SHARE_WRITE | FILE_SHARE_READ,
  222. NULL,
  223. OPEN_ALWAYS,
  224. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
  225. NULL);
  226. if (m_shLogFile==INVALID_HANDLE_VALUE)
  227. {
  228. return FALSE;
  229. }
  230. SetLogFile(m_shLogFile);
  231. // no sense to open the file and not enable printing to it.
  232. m_sFmtMask |= DBG_PRNT_TO_FILE;
  233. return TRUE;
  234. }
  235. //*****************************************************************************
  236. //* Name: CloseLogFile
  237. //* Author: Mooly Beery (MoolyB), May, 2000
  238. //*****************************************************************************
  239. //* DESCRIPTION:
  240. //* Closes the log file which accepts the debug output
  241. //*
  242. //* PARAMETERS:
  243. //*
  244. //* RETURN VALUE:
  245. //*
  246. //* Comments:
  247. //* this function should be used together with OpenLogFile()
  248. //*****************************************************************************
  249. void CDebug::CloseLogFile()
  250. {
  251. if (m_shLogFile!=INVALID_HANDLE_VALUE)
  252. {
  253. ::CloseHandle(m_shLogFile);
  254. m_shLogFile = INVALID_HANDLE_VALUE;
  255. }
  256. }
  257. //*****************************************************************************
  258. //* Name: SetLogFile
  259. //* Author: Mooly Beery (MoolyB), May, 2000
  260. //*****************************************************************************
  261. //* DESCRIPTION:
  262. //* redirects the debug output to the file whose handle is given
  263. //*
  264. //* PARAMETERS:
  265. //* [IN] HANDLE hFile:
  266. //* the handle of the file which will accept the debug output
  267. //*
  268. //* RETURN VALUE:
  269. //* the previous handle
  270. //*
  271. //* Comments:
  272. //* this function should be used only in cases the OpenLogFile is
  273. //* insufficient and a different file location/type is required
  274. //* otherwise, don't manipulate the handle yourself, just use the
  275. //* pair OpenLogFile / CloseLogFile
  276. //*****************************************************************************
  277. HANDLE CDebug::SetLogFile(HANDLE hFile)
  278. {
  279. HANDLE OldHandle = m_shLogFile;
  280. m_shLogFile = hFile;
  281. return OldHandle;
  282. }
  283. void CDebug::DbgPrint (
  284. DbgMsgType type,
  285. LPCTSTR lpctstrFileName,
  286. DWORD dwLine,
  287. LPCTSTR lpctstrFormat,
  288. ...
  289. )
  290. /*++
  291. Routine name : CDebug::DbgPrint
  292. Routine description:
  293. Print to debug (with file and line number)
  294. Author:
  295. Eran Yariv (EranY), Jul, 1999
  296. Arguments:
  297. type [in] - Type of message
  298. lpctstrFileName [in] - Location of caller
  299. dwLine [in] - Line of caller
  300. lpctstrFormat [in] - printf format string
  301. ... [in] - optional parameters
  302. Return Value:
  303. None.
  304. --*/
  305. {
  306. va_list arg_ptr;
  307. va_start(arg_ptr, lpctstrFormat);
  308. Print (type, lpctstrFileName, dwLine, lpctstrFormat, arg_ptr);
  309. va_end (arg_ptr);
  310. }
  311. void CDebug::Trace (
  312. DbgMsgType type,
  313. LPCTSTR lpctstrFormat,
  314. ...
  315. )
  316. /*++
  317. Routine name : CDebug::DbgPrint
  318. Routine description:
  319. Trace to debug
  320. Author:
  321. Eran Yariv (EranY), Jul, 1999
  322. Arguments:
  323. type [in] - Type of message
  324. lpctstrFormat [in] - printf format string
  325. ... [in] - optional parameters
  326. Return Value:
  327. None.
  328. --*/
  329. {
  330. va_list arg_ptr;
  331. va_start(arg_ptr, lpctstrFormat);
  332. Print (type, NULL, 0, lpctstrFormat, arg_ptr);
  333. va_end (arg_ptr);
  334. }
  335. void CDebug::Print (
  336. DbgMsgType type,
  337. LPCTSTR lpctstrFileName,
  338. DWORD dwLine,
  339. LPCTSTR lpctstrFormat,
  340. va_list arg_ptr
  341. )
  342. /*++
  343. Routine name : CDebug::Print
  344. Routine description:
  345. Print to debug
  346. Author:
  347. Eran Yariv (EranY), Jul, 1999
  348. Mooly Beery (MoolyB), Jun, 2000
  349. Arguments:
  350. type [in] - Type of message
  351. lpctstrFileName [in] - Location of caller
  352. dwLine [in] - Line of caller
  353. lpctstrFormat [in] - printf format string
  354. arg_ptr [in] - optional parameters list
  355. Return Value:
  356. None.
  357. --*/
  358. {
  359. if (!(type & m_sDbgMask))
  360. {
  361. //
  362. // This type of debug message is masked out
  363. //
  364. return;
  365. }
  366. TCHAR szMsg [2000]={0};
  367. TCHAR szBuf [1000]={0};
  368. TCHAR szTimeBuff[10]={0};
  369. TCHAR szDateBuff[10]={0};
  370. DWORD dwLastError = GetLastError();
  371. DWORD dwInd = 0;
  372. // Time stamps
  373. if (m_sFmtMask & DBG_PRNT_TIME_STAMP)
  374. {
  375. dwInd += _stprintf(&szMsg[dwInd],
  376. TEXT("[%-8s %-8s] "),
  377. _tstrdate(szDateBuff),
  378. _tstrtime(szTimeBuff));
  379. }
  380. // Thread ID
  381. if (m_sFmtMask & DBG_PRNT_THREAD_ID)
  382. {
  383. dwInd += _stprintf(&szMsg[dwInd],
  384. TEXT("[0x%04x] "),
  385. GetCurrentThreadId());
  386. }
  387. // Message type
  388. if (m_sFmtMask & DBG_PRNT_MSG_TYPE)
  389. {
  390. dwInd += _stprintf(&szMsg[dwInd],
  391. TEXT("[%s] "),
  392. GetMsgTypeString(type));
  393. }
  394. // Now comes the actual message
  395. _vsntprintf(szBuf, ARR_SIZE(szBuf)-1, lpctstrFormat, arg_ptr);
  396. int i;
  397. i = _sntprintf( &szMsg[dwInd],
  398. ARR_SIZE(szMsg) - dwInd - 1,
  399. TEXT("%*c%s "),
  400. m_sdwIndent * _DEBUG_INDENT_SIZE,
  401. TEXT(' '),
  402. szBuf);
  403. if (i > 0)
  404. {
  405. dwInd += i;
  406. }
  407. else
  408. {
  409. //
  410. // No more room
  411. //
  412. szMsg[ARR_SIZE(szMsg)-1]=TEXT('\0');
  413. goto OutputString;
  414. }
  415. // filename & line number
  416. if (m_sFmtMask & DBG_PRNT_FILE_LINE)
  417. {
  418. if (lpctstrFileName && dwLine)
  419. {
  420. //
  421. // Protect from overrun.
  422. //
  423. i = _sntprintf( &szMsg[dwInd],
  424. ARR_SIZE(szMsg)-dwInd-2, // 2 for '\n' and '\0'
  425. TEXT("(%s %ld)"),
  426. lpctstrFileName,
  427. dwLine);
  428. if (i > 0)
  429. {
  430. dwInd += i;
  431. }
  432. else
  433. {
  434. //
  435. // No more room
  436. //
  437. szMsg[ARR_SIZE(szMsg)-1]=TEXT('\0');
  438. goto OutputString;
  439. }
  440. }
  441. }
  442. _sntprintf( &szMsg[dwInd], ARR_SIZE(szMsg)-dwInd-1, TEXT("\n"));
  443. szMsg[ARR_SIZE(szMsg)-1]=TEXT('\0');
  444. OutputString:
  445. // standard output?
  446. if (m_sFmtMask & DBG_PRNT_TO_STD)
  447. {
  448. OutputDebugString(szMsg);
  449. }
  450. // file output?
  451. if (m_sFmtMask & DBG_PRNT_TO_FILE)
  452. {
  453. if (m_shLogFile!=INVALID_HANDLE_VALUE)
  454. {
  455. OutputFileString(szMsg);
  456. }
  457. }
  458. SetLastError (dwLastError);
  459. } // CDebug::Print
  460. void
  461. CDebug::Unindent()
  462. /*++
  463. Routine name : CDebug::Unindent
  464. Routine description:
  465. Move indention one step backwards
  466. Author:
  467. Eran Yariv (EranY), Jul, 1999
  468. Arguments:
  469. Return Value:
  470. None.
  471. --*/
  472. {
  473. if (InterlockedDecrement(&m_sdwIndent)<0)
  474. {
  475. DbgPrint (ASSERTION_FAILED,
  476. TEXT(__FILE__),
  477. __LINE__,
  478. TEXT("Internat error - bad indent"));
  479. DebugBreak();
  480. }
  481. } // CDebug::Unindent
  482. void CDebug::SetDebugMask(DWORD dwMask)
  483. {
  484. m_sbMaskReadFromReg = TRUE;
  485. m_sDbgMask = dwMask;
  486. }
  487. void CDebug::SetFormatMask(DWORD dwMask)
  488. {
  489. m_sbMaskReadFromReg = TRUE;
  490. m_sFmtMask = dwMask;
  491. }
  492. DWORD CDebug::ModifyDebugMask(DWORD dwAdd,DWORD dwRemove)
  493. {
  494. if (!m_sbMaskReadFromReg)
  495. {
  496. // first let's read the requested debug mask & format
  497. ReadMaskFromReg();
  498. }
  499. m_sDbgMask |= dwAdd;
  500. m_sDbgMask &= ~dwRemove;
  501. return m_sDbgMask;
  502. }
  503. DWORD CDebug::ModifyFormatMask(DWORD dwAdd,DWORD dwRemove)
  504. {
  505. if (!m_sbMaskReadFromReg)
  506. {
  507. // first let's read the requested debug mask & format
  508. ReadMaskFromReg();
  509. }
  510. m_sFmtMask |= dwAdd;
  511. m_sFmtMask &= ~dwRemove;
  512. return m_sFmtMask;
  513. }
  514. void CDebug::SetDebugFlush(BOOL fFlush)
  515. {
  516. m_sbFlush = fFlush;
  517. }
  518. BOOL CDebug::DebugFromRegistry()
  519. {
  520. if (!m_sbMaskReadFromReg)
  521. {
  522. // first let's read the requested debug mask & format
  523. ReadMaskFromReg();
  524. }
  525. return m_sbRegistryExist;
  526. }
  527. BOOL CDebug::ReadMaskFromReg()
  528. {
  529. BOOL bRes = FALSE;
  530. HKEY hkey = NULL;
  531. DWORD dwRegValue;
  532. DWORD dwRegType;
  533. DWORD dwRes;
  534. DWORD dwRegSize = sizeof (dwRegValue);
  535. if (m_sbMaskReadFromReg)
  536. {
  537. //
  538. // Debug & Format mask already read.
  539. //
  540. goto end;
  541. }
  542. m_sbMaskReadFromReg = TRUE;
  543. m_sDbgMask = DEFAULT_DEBUG_MASK;
  544. m_sFmtMask = DEFAULT_FORMAT_MASK;
  545. dwRes = RegOpenKeyEx (HKEY_LOCAL_MACHINE, REGKEY_FAX_CLIENT, 0, KEY_READ, &hkey);
  546. if (ERROR_SUCCESS != dwRes)
  547. {
  548. goto end;
  549. }
  550. dwRes = RegQueryValueEx (hkey,
  551. REGVAL_DBGLEVEL_EX,
  552. NULL,
  553. &dwRegType,
  554. (LPBYTE)&dwRegValue,
  555. &dwRegSize);
  556. if (ERROR_SUCCESS != dwRes)
  557. {
  558. goto end;
  559. }
  560. if (REG_DWORD != dwRegType)
  561. {
  562. //
  563. // Expecting only a DWORD value
  564. //
  565. goto end;
  566. }
  567. m_sDbgMask = dwRegValue;
  568. dwRes = RegQueryValueEx (hkey,
  569. REGVAL_DBGFORMAT_EX,
  570. NULL,
  571. &dwRegType,
  572. (LPBYTE)&dwRegValue,
  573. &dwRegSize);
  574. if (ERROR_SUCCESS != dwRes)
  575. {
  576. goto end;
  577. }
  578. if (REG_DWORD != dwRegType)
  579. {
  580. //
  581. // Expecting only a DWORD value
  582. //
  583. goto end;
  584. }
  585. m_sFmtMask = dwRegValue;
  586. bRes = TRUE;
  587. m_sbRegistryExist = TRUE;
  588. end:
  589. if (hkey)
  590. {
  591. RegCloseKey (hkey);
  592. }
  593. return bRes;
  594. } // CDebug::ReadMaskFromReg
  595. BOOL CDebug::OutputFileString(LPCTSTR szMsg)
  596. {
  597. BOOL bRes = FALSE;
  598. //
  599. // Attempt to add the line to a log file
  600. //
  601. #ifdef UNICODE
  602. char sFileMsg[2000];
  603. int Count = WideCharToMultiByte(
  604. CP_ACP,
  605. 0,
  606. szMsg,
  607. -1,
  608. sFileMsg,
  609. sizeof(sFileMsg)/sizeof(sFileMsg[0]),
  610. NULL,
  611. NULL
  612. );
  613. if (Count==0)
  614. {
  615. return bRes;
  616. }
  617. #else
  618. const char* sFileMsg = szMsg;
  619. #endif
  620. DWORD dwFilePointer = ::SetFilePointer(m_shLogFile,0,NULL,FILE_END);
  621. if (dwFilePointer==INVALID_SET_FILE_POINTER)
  622. {
  623. return bRes;
  624. }
  625. DWORD dwNumBytesWritten = 0;
  626. DWORD dwNumOfBytesToWrite = strlen(sFileMsg);
  627. if (!::WriteFile(m_shLogFile,sFileMsg,dwNumOfBytesToWrite,&dwNumBytesWritten,NULL))
  628. {
  629. return bRes;
  630. }
  631. if (dwNumBytesWritten!=dwNumOfBytesToWrite)
  632. {
  633. return bRes;
  634. }
  635. if (m_sbFlush)
  636. {
  637. if (!::FlushFileBuffers(m_shLogFile))
  638. {
  639. return bRes;
  640. }
  641. }
  642. bRes = TRUE;
  643. return bRes;
  644. }
  645. LPCTSTR CDebug::GetMsgTypeString(DWORD dwMask)
  646. {
  647. switch (dwMask)
  648. {
  649. case ASSERTION_FAILED: return _T("ERR");
  650. case DBG_MSG:
  651. case FUNC_TRACE: return _T(" ");
  652. case DBG_WARNING: return _T("WRN");
  653. case MEM_ERR:
  654. case COM_ERR:
  655. case RESOURCE_ERR:
  656. case STARTUP_ERR:
  657. case GENERAL_ERR:
  658. case EXCEPTION_ERR:
  659. case RPC_ERR:
  660. case WINDOW_ERR:
  661. case FILE_ERR:
  662. case SECURITY_ERR:
  663. case REGISTRY_ERR:
  664. case PRINT_ERR:
  665. case SETUP_ERR:
  666. case NET_ERR: return _T("ERR");
  667. default: return _T("???");
  668. }
  669. }
  670. #endif