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.

871 lines
19 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. dbgmsgp.cxx
  6. Abstract:
  7. Debug Library
  8. Author:
  9. Steve Kiraly (SteveKi) 10-Dec-1995
  10. Revision History:
  11. --*/
  12. #include "precomp.hxx"
  13. #pragma hdrstop
  14. TDebugMsg::
  15. TDebugMsg(
  16. VOID
  17. ) : m_eLevel(static_cast<EDebugLevel>(0)),
  18. m_eBreak(static_cast<EDebugLevel>(0)),
  19. m_pDeviceRoot(NULL),
  20. m_pstrPrefix(NULL),
  21. m_pBuiltinDeviceRoot(NULL)
  22. {
  23. }
  24. TDebugMsg::
  25. ~TDebugMsg(
  26. VOID
  27. )
  28. {
  29. }
  30. BOOL
  31. TDebugMsg::
  32. Valid(
  33. VOID
  34. ) const
  35. {
  36. return !!m_pBuiltinDeviceRoot;
  37. }
  38. VOID
  39. TDebugMsg::
  40. Disable(
  41. VOID
  42. )
  43. {
  44. m_eLevel = static_cast<EDebugLevel>( m_eLevel | kDbgNone );
  45. m_eBreak = static_cast<EDebugLevel>( m_eBreak | kDbgNone );
  46. }
  47. VOID
  48. TDebugMsg::
  49. Enable(
  50. VOID
  51. )
  52. {
  53. m_eLevel = static_cast<EDebugLevel>( m_eLevel & ~kDbgNone );
  54. m_eBreak = static_cast<EDebugLevel>( m_eBreak & ~kDbgNone );
  55. }
  56. BOOL
  57. TDebugMsg::
  58. Type(
  59. IN EDebugLevel eLevel
  60. ) const
  61. {
  62. return !(m_eLevel & kDbgNone) && ((m_eLevel & eLevel) || (eLevel & kDbgAlways));
  63. }
  64. BOOL
  65. TDebugMsg::
  66. Break(
  67. IN EDebugLevel eLevel
  68. ) const
  69. {
  70. return m_eBreak & eLevel;
  71. }
  72. /*++
  73. Routine Name:
  74. Initialize
  75. Routine Description:
  76. Arguments:
  77. Return Value:
  78. None.
  79. --*/
  80. VOID
  81. TDebugMsg::
  82. Initialize(
  83. IN LPCTSTR pszPrefix,
  84. IN UINT uDevice,
  85. IN INT eLevel,
  86. IN INT eBreak
  87. )
  88. {
  89. if (!m_pBuiltinDeviceRoot)
  90. {
  91. BOOL bRetval = FALSE;
  92. //
  93. // Set the debug message and break level.
  94. //
  95. m_eLevel = static_cast<EDebugLevel>(eLevel & ~kDbgPrivateMask);
  96. m_eBreak = static_cast<EDebugLevel>(eBreak & ~kDbgPrivateMask);
  97. //
  98. // Set the global device flags.
  99. //
  100. if (!Globals.DebugDevices)
  101. {
  102. Globals.DebugDevices = uDevice & (kDbgNull | kDbgDebugger | kDbgFile);
  103. }
  104. //
  105. // Set the character type to current compiled type.
  106. //
  107. m_eLevel = static_cast<EDebugLevel>(m_eLevel | Globals.CompiledCharType);
  108. //
  109. // Set the prefix string.
  110. //
  111. m_pstrPrefix = INTERNAL_NEW TDebugString(pszPrefix ? pszPrefix : kstrPrefix);
  112. //
  113. // Set the prefix string.
  114. //
  115. if (m_pstrPrefix && m_pstrPrefix->bValid() && m_pstrPrefix->bCat( _T(":")))
  116. {
  117. //
  118. // Set the additional format strings.
  119. //
  120. m_pstrFileInfoFormat = INTERNAL_NEW TDebugString(kstrFileInfoFormat);
  121. m_pstrTimeStampFormatShort = INTERNAL_NEW TDebugString(kstrTimeStampFormatShort);
  122. m_pstrTimeStampFormatLong = INTERNAL_NEW TDebugString(kstrTimeStampFormatLong);
  123. m_pstrThreadIdFormat = INTERNAL_NEW TDebugString(kstrThreadIdFormat);
  124. if( m_pstrFileInfoFormat && m_pstrFileInfoFormat->bValid() &&
  125. m_pstrTimeStampFormatShort && m_pstrTimeStampFormatShort->bValid() &&
  126. m_pstrTimeStampFormatLong && m_pstrTimeStampFormatLong->bValid() &&
  127. m_pstrThreadIdFormat && m_pstrThreadIdFormat->bValid() )
  128. {
  129. //
  130. // Attach the default debug devices.
  131. //
  132. if(Attach(NULL, kDbgDebugger, NULL, &m_pBuiltinDeviceRoot) &&
  133. Attach(NULL, kDbgFile, kstrDefaultLogFileName, &m_pBuiltinDeviceRoot) &&
  134. Attach(NULL, kDbgNull, NULL, &m_pBuiltinDeviceRoot))
  135. {
  136. bRetval = TRUE;
  137. }
  138. else
  139. {
  140. ErrorText( _T("Error: TDebugMsg::Initialize - A default debug device failed to attach!\n") );
  141. }
  142. }
  143. else
  144. {
  145. ErrorText( _T("Error: TDebugMsg::Initialize - format string failed construction!\n") );
  146. }
  147. }
  148. else
  149. {
  150. ErrorText( _T("Error: TDebugMsg::Initialize - Debug prefix string failed allocation!\n") );
  151. }
  152. //
  153. // If we failed then unregister, cleanup.
  154. //
  155. if (!bRetval)
  156. {
  157. Destroy();
  158. }
  159. }
  160. else
  161. {
  162. ErrorText( _T("Error: TDebugMsg::Initialize already initalized!\n") );
  163. }
  164. }
  165. /*++
  166. Routine Name:
  167. Destroy
  168. Routine Description:
  169. Destroys the internal state of this class, this function
  170. does the same work the destructor would.
  171. Arguments:
  172. None.
  173. Return Value:
  174. None.
  175. --*/
  176. VOID
  177. TDebugMsg::
  178. Destroy(
  179. VOID
  180. )
  181. {
  182. //
  183. // Release the debug device.
  184. //
  185. while( m_pDeviceRoot )
  186. {
  187. TDebugNodeDouble *pNode = m_pDeviceRoot;
  188. pNode->Remove( &m_pDeviceRoot );
  189. TDebugFactory::Dispose( static_cast<TDebugDevice *>( pNode ) );
  190. }
  191. //
  192. // Release the builtin debug device.
  193. //
  194. while( m_pBuiltinDeviceRoot )
  195. {
  196. TDebugNodeDouble *pNode = m_pBuiltinDeviceRoot;
  197. pNode->Remove( &m_pBuiltinDeviceRoot );
  198. TDebugFactory::Dispose( static_cast<TDebugDevice *>( pNode ) );
  199. }
  200. //
  201. // Release the string objects.
  202. //
  203. INTERNAL_DELETE m_pstrPrefix;
  204. INTERNAL_DELETE m_pstrFileInfoFormat;
  205. INTERNAL_DELETE m_pstrTimeStampFormatShort;
  206. INTERNAL_DELETE m_pstrTimeStampFormatLong;
  207. INTERNAL_DELETE m_pstrThreadIdFormat;
  208. //
  209. // Indicate we are not registered.
  210. //
  211. m_eLevel = static_cast<EDebugLevel>(0);
  212. m_eBreak = static_cast<EDebugLevel>(0);
  213. m_pDeviceRoot = NULL;
  214. m_pBuiltinDeviceRoot = NULL;
  215. m_pstrPrefix = NULL;
  216. m_pstrFileInfoFormat = NULL;
  217. m_pstrTimeStampFormatShort = NULL;
  218. m_pstrTimeStampFormatLong = NULL;
  219. m_pstrThreadIdFormat = NULL;
  220. }
  221. /*++
  222. Routine Name:
  223. Attach
  224. Routine Description:
  225. Attach debug device to list of output devices.
  226. Arguments:
  227. uDevice - Type of debug device to use.
  228. pszConfiguration - Pointer to configuration string.
  229. Return Value:
  230. TRUE debug device attached, FALSE if error occurred.
  231. --*/
  232. BOOL
  233. TDebugMsg::
  234. Attach(
  235. IN HANDLE *phDevice,
  236. IN UINT uDevice,
  237. IN LPCTSTR pszConfiguration,
  238. IN TDebugNodeDouble **ppDeviceRoot
  239. )
  240. {
  241. BOOL bRetval = FALSE;
  242. //
  243. // Get access to the debug factory.
  244. //
  245. TDebugFactory DebugFactory;
  246. //
  247. // If we failed to create the debug factory then exit.
  248. //
  249. if (DebugFactory.bValid())
  250. {
  251. //
  252. // Create the specified debug device using the factory.
  253. //
  254. TDebugDevice *pDebugDevice = DebugFactory.Produce(uDevice,
  255. pszConfiguration,
  256. m_eLevel & kDbgUnicode);
  257. //
  258. // Check if the debug device was created ok.
  259. //
  260. if (pDebugDevice)
  261. {
  262. //
  263. // Place this device on the debug device list.
  264. //
  265. if (ppDeviceRoot)
  266. {
  267. pDebugDevice->Insert(ppDeviceRoot);
  268. }
  269. else
  270. {
  271. pDebugDevice->Insert(&m_pDeviceRoot);
  272. }
  273. //
  274. // Copy back the pointer to the debug device.
  275. //
  276. if (phDevice)
  277. {
  278. *phDevice = (HANDLE)pDebugDevice;
  279. }
  280. //
  281. // Successfully attached debug device.
  282. //
  283. bRetval = TRUE;
  284. }
  285. else
  286. {
  287. ErrorText( _T("Error: TDebugMsg::bAttach - Debug device creation failed!\n") );
  288. }
  289. }
  290. else
  291. {
  292. ErrorText( _T("Error: TDebugMsg::bAttach - Debug factory creation failed!\n") );
  293. }
  294. return bRetval;
  295. }
  296. /*++
  297. Routine Name:
  298. Detach
  299. Routine Description:
  300. Detach the debug device from the device stream.
  301. Arguments:
  302. phDevice - Pointer to debug device handle.
  303. Return Value:
  304. None.
  305. --*/
  306. VOID
  307. TDebugMsg::
  308. Detach(
  309. IN HANDLE *phDevice
  310. )
  311. {
  312. //
  313. // We silently ignore non initialized devices, or null pointers.
  314. //
  315. if (phDevice && *phDevice)
  316. {
  317. //
  318. // Get a usable pointer.
  319. //
  320. TDebugDevice *pDebugDevice = (TDebugDevice *)*phDevice;
  321. //
  322. // Remove this device from the debug device list.
  323. //
  324. pDebugDevice->Remove( &m_pDeviceRoot );
  325. //
  326. // Dispose of the device.
  327. //
  328. TDebugFactory::Dispose( pDebugDevice );
  329. //
  330. // Mark this device as released.
  331. //
  332. *phDevice = NULL;
  333. }
  334. else
  335. {
  336. ErrorText( _T("Error: TDebugMsg::vDetach - non initialized or null pointer!\n") );
  337. }
  338. }
  339. /*++
  340. Routine Name:
  341. Msg
  342. Routine Description:
  343. This function is public overloaded function for
  344. sending the message to the output devices.
  345. Arguments:
  346. eLevel - requested message level
  347. pszFile - pointer to file name where message was called
  348. uLine - line number where message was called
  349. pszModulePrefix - message defined module prefix, used as an override
  350. pszMessage - pointer to post formated message string
  351. Return Value:
  352. None.
  353. --*/
  354. VOID
  355. TDebugMsg::
  356. Msg(
  357. IN UINT eLevel,
  358. IN LPCTSTR pszFile,
  359. IN UINT uLine,
  360. IN LPCTSTR pszModulePrefix,
  361. IN LPSTR pszMessage
  362. ) const
  363. {
  364. if (pszMessage)
  365. {
  366. if (Type(static_cast<EDebugLevel>(eLevel)))
  367. {
  368. StringTrait StrMessage;
  369. StrMessage.pszNarrow = pszMessage;
  370. eLevel = eLevel & ~kDbgUnicode;
  371. Output(static_cast<EDebugLevel>(eLevel), pszFile, uLine, pszModulePrefix, StrMessage);
  372. if (Break(static_cast<EDebugLevel>(eLevel)))
  373. {
  374. DebugBreak();
  375. }
  376. }
  377. INTERNAL_DELETE [] pszMessage;
  378. }
  379. }
  380. /*++
  381. Routine Name:
  382. Msg
  383. Routine Description:
  384. This function is public overloaded function for
  385. sending the message to the output devices.
  386. Arguments:
  387. eLevel - requested message level
  388. pszFile - pointer to file name where message was called
  389. uLine - line number where message was called
  390. pszModulePrefix - message defined module prefix, used as an override
  391. pszMessage - pointer to post formated message string
  392. Return Value:
  393. None.
  394. --*/
  395. VOID
  396. TDebugMsg::
  397. Msg(
  398. IN UINT eLevel,
  399. IN LPCTSTR pszFile,
  400. IN UINT uLine,
  401. IN LPCTSTR pszModulePrefix,
  402. IN LPWSTR pszMessage
  403. ) const
  404. {
  405. if (pszMessage)
  406. {
  407. if (Type(static_cast<EDebugLevel>(eLevel)))
  408. {
  409. StringTrait StrMessage;
  410. StrMessage.pszWide = pszMessage;
  411. eLevel = eLevel | kDbgUnicode;
  412. Output(static_cast<EDebugLevel>(eLevel), pszFile, uLine, pszModulePrefix, StrMessage);
  413. if (Break(static_cast<EDebugLevel>(eLevel)))
  414. {
  415. DebugBreak();
  416. }
  417. }
  418. INTERNAL_DELETE [] pszMessage;
  419. }
  420. }
  421. /********************************************************************
  422. Private member functions.
  423. ********************************************************************/
  424. /*++
  425. Routine Name:
  426. Output
  427. Routine Description:
  428. Outputs the messages to the list of registred
  429. debug devices.
  430. Arguments:
  431. eLevel - requested message level
  432. pszFile - pointer to file name where message was called
  433. uLine - line number where message was called
  434. pszModulePrefix - message defined module prefix, used as an override
  435. pszMessage - pointer to post formated message string
  436. Return Value:
  437. None.
  438. --*/
  439. VOID
  440. TDebugMsg::
  441. Output(
  442. IN EDebugLevel eLevel,
  443. IN LPCTSTR pszFileName,
  444. IN UINT uLine,
  445. IN LPCTSTR pszModulePrefix,
  446. IN StringTrait &strMsg
  447. ) const
  448. {
  449. TDebugString strFinal;
  450. //
  451. // Build the final output string.
  452. //
  453. if (BuildFinalString(strFinal,
  454. eLevel,
  455. pszModulePrefix,
  456. pszFileName,
  457. uLine,
  458. strMsg))
  459. {
  460. //
  461. // Calculate the byte count (less the null terminator) of the final string.
  462. //
  463. UINT uByteCount = (m_eLevel & kDbgUnicode)
  464. ? strFinal.uLen() * sizeof(WCHAR)
  465. : strFinal.uLen() * sizeof(CHAR);
  466. LPBYTE pByte = reinterpret_cast<LPBYTE>(const_cast<LPTSTR>(static_cast<LPCTSTR>(strFinal)));
  467. {
  468. //
  469. // Create interator on built in device list.
  470. //
  471. TDebugNodeDouble::Iterator Iter(m_pBuiltinDeviceRoot);
  472. //
  473. // Output this string to all the built in debug devices.
  474. //
  475. for( Iter.First(); !Iter.IsDone(); Iter.Next() )
  476. {
  477. if (static_cast<TDebugDevice *>(Iter.Current())->eGetDebugType() & Globals.DebugDevices)
  478. {
  479. static_cast<TDebugDevice *>(Iter.Current())->bOutput(uByteCount, pByte);
  480. }
  481. }
  482. }
  483. {
  484. //
  485. // Create interator on device list.
  486. //
  487. TDebugNodeDouble::Iterator Iter(m_pDeviceRoot);
  488. //
  489. // Output this string to all the registered debug devices.
  490. //
  491. for( Iter.First(); !Iter.IsDone(); Iter.Next() )
  492. {
  493. static_cast<TDebugDevice *>(Iter.Current())->bOutput( uByteCount, pByte);
  494. }
  495. }
  496. }
  497. else
  498. {
  499. ErrorText(_T("Error: TDebugMsg::vOutput - failed to build format string.\n"));
  500. }
  501. }
  502. /*++
  503. Routine Name:
  504. BuildFinalString
  505. Routine Description:
  506. This routing build the actual string that will be sent to the
  507. debug output devices.
  508. Arguments:
  509. strFinal - string refrence where to return the finale output string.
  510. eLevel - debug message level.
  511. pszModulePrefix - per message prefix string, can be null.
  512. pszFileName - file name were the message was requested.
  513. uLine - line number were message was requested.
  514. StrMsg - post formated message string.
  515. Return Value:
  516. TRUE final string was build successfully, FALSE error occurred.
  517. --*/
  518. BOOL
  519. TDebugMsg::
  520. BuildFinalString(
  521. IN TDebugString &strFinal,
  522. IN EDebugLevel eLevel,
  523. IN LPCTSTR pszModulePrefix,
  524. IN LPCTSTR pszFileName,
  525. IN UINT uLine,
  526. IN StringTrait &StrMsg
  527. ) const
  528. {
  529. LPCTSTR pszFormat;
  530. TDebugString strArg0;
  531. TDebugString strArg1;
  532. TDebugString strArg2;
  533. TDebugString strArg3;
  534. UINT eFlags = m_eLevel | eLevel;
  535. if (!(eFlags & kDbgNoPrefix))
  536. {
  537. (VOID)strArg0.bUpdate(pszModulePrefix ? pszModulePrefix : *m_pstrPrefix);
  538. }
  539. if (!(eFlags & kDbgNoFileInfo))
  540. {
  541. (VOID)GetParameter(eFlags & (kDbgFileInfo | kDbgFileInfoLong), strArg1, pszFileName, uLine);
  542. }
  543. (VOID)GetParameter(eFlags & (kDbgFileInfo | kDbgFileInfoLong), strArg1, pszFileName, uLine);
  544. (VOID)GetParameter(eFlags & (kDbgTimeStamp | kDbgTimeStampLong), strArg2, NULL, 0);
  545. (VOID)GetParameter(eFlags & kDbgThreadId, strArg3, NULL, 0);
  546. if ((eLevel & kDbgUnicode) == (m_eLevel & kDbgUnicode))
  547. {
  548. pszFormat = _T("%s%s%s%s %s");
  549. }
  550. else
  551. {
  552. pszFormat = _T("%s%s%s%s %S");
  553. }
  554. (VOID)strFinal.bFormat( pszFormat,
  555. static_cast<LPCTSTR>(strArg0),
  556. static_cast<LPCTSTR>(strArg1),
  557. static_cast<LPCTSTR>(strArg2),
  558. static_cast<LPCTSTR>(strArg3),
  559. StrMsg.pszByte);
  560. return strFinal.bValid();
  561. }
  562. /*++
  563. Routine Name:
  564. GetParameter
  565. Routine Description:
  566. This function get the parameter for the additinal information
  567. displayed in a format string. The flags passed to the message
  568. class and to the message function are used a guide.
  569. Arguments:
  570. eFlags - Flags indicating what parameter to get.
  571. strString - place were to return resultant string.
  572. pszFileName - pointer to file name to format if requested.
  573. uLine - line number for file name format.
  574. Return Value:
  575. TRUE parmeter was returned in strString, FALSE error.
  576. --*/
  577. BOOL
  578. TDebugMsg::
  579. GetParameter(
  580. IN UINT eFlags,
  581. IN OUT TDebugString &strString,
  582. IN LPCTSTR pszFileName,
  583. IN UINT uLine
  584. ) const
  585. {
  586. BOOL bRetval = TRUE;
  587. if (eFlags & kDbgFileInfo)
  588. {
  589. bRetval = strString.bFormat(*m_pstrFileInfoFormat, StripPathFromFileName(pszFileName), uLine);
  590. }
  591. if (eFlags & kDbgFileInfoLong)
  592. {
  593. bRetval = strString.bFormat(*m_pstrFileInfoFormat, pszFileName, uLine);
  594. }
  595. if (eFlags & kDbgTimeStamp)
  596. {
  597. bRetval = strString.bFormat(*m_pstrTimeStampFormatShort, GetTickCount());
  598. }
  599. if (eFlags & kDbgTimeStampLong)
  600. {
  601. TCHAR szBuffer[MAX_PATH];
  602. SYSTEMTIME Time;
  603. GetSystemTime(&Time);
  604. bRetval = SystemTimeToTzSpecificLocalTime(NULL, &Time, &Time) &&
  605. GetTimeFormat(LOCALE_USER_DEFAULT, 0, &Time, NULL, szBuffer, COUNTOF(szBuffer)) &&
  606. strString.bFormat(*m_pstrTimeStampFormatLong, szBuffer);
  607. }
  608. if (eFlags & kDbgThreadId)
  609. {
  610. bRetval = strString.bFormat(*m_pstrThreadIdFormat, GetCurrentThreadId());
  611. }
  612. return bRetval;
  613. }
  614. /*++
  615. Routine Name:
  616. SetMessageFieldFormat
  617. Routine Description:
  618. This routing allows individual parts of the format string
  619. to have a custom format string specifier.
  620. Arguments:
  621. Field - specified which format field to change.
  622. pszFormat - new format string, the caller must know the correct type.
  623. Return Value:
  624. None.
  625. --*/
  626. VOID
  627. TDebugMsg::
  628. SetMessageFieldFormat(
  629. IN UINT eField,
  630. IN LPTSTR pszFormat
  631. )
  632. {
  633. //
  634. // Set the new format string.
  635. //
  636. if (eField & kDbgFileInfo)
  637. {
  638. m_pstrFileInfoFormat->bUpdate(pszFormat);
  639. }
  640. if (eField & kDbgFileInfoLong)
  641. {
  642. m_pstrFileInfoFormat->bUpdate(pszFormat);
  643. }
  644. if (eField & kDbgTimeStamp)
  645. {
  646. m_pstrTimeStampFormatShort->bUpdate(pszFormat);
  647. }
  648. if (eField & kDbgTimeStampLong)
  649. {
  650. m_pstrTimeStampFormatLong->bUpdate(pszFormat);
  651. }
  652. if (eField & kDbgThreadId)
  653. {
  654. m_pstrThreadIdFormat->bUpdate(pszFormat);
  655. }
  656. //
  657. // If any of the format strings were cleared then
  658. // reset them back to the default value.
  659. //
  660. if (m_pstrFileInfoFormat->bEmpty())
  661. {
  662. m_pstrFileInfoFormat->bUpdate(kstrFileInfoFormat);
  663. }
  664. if (m_pstrTimeStampFormatShort->bEmpty())
  665. {
  666. m_pstrTimeStampFormatShort->bUpdate(kstrTimeStampFormatShort);
  667. }
  668. if (m_pstrTimeStampFormatLong->bEmpty())
  669. {
  670. m_pstrTimeStampFormatLong->bUpdate(kstrTimeStampFormatLong);
  671. }
  672. if (m_pstrThreadIdFormat->bEmpty())
  673. {
  674. m_pstrThreadIdFormat->bUpdate(kstrThreadIdFormat);
  675. }
  676. }