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.

984 lines
33 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. vs_debug.hxx
  5. Abstract:
  6. Various defines for general usage
  7. Author:
  8. Adi Oltean [aoltean] 07/09/1999
  9. Revision History:
  10. Name Date Comments
  11. aoltean 07/09/1999 Created
  12. aoltean 08/11/1999 Adding throw specification
  13. aoltean 09/03/1999 Adding DuplicateXXX functions
  14. aoltean 09/09/1999 dss -> vss
  15. aoltean 09/20/1999 Adding ThrowIf, Err, Msg, MsgNoCR, etc.
  16. --*/
  17. #ifndef __VSS_DEBUG_HXX__
  18. #define __VSS_DEBUG_HXX__
  19. #if _MSC_VER > 1000
  20. #pragma once
  21. #endif
  22. ////////////////////////////////////////////////////////////////////////
  23. // Standard foo for file name aliasing. This code block must be after
  24. // all includes of VSS header files.
  25. //
  26. #ifdef VSS_FILE_ALIAS
  27. #undef VSS_FILE_ALIAS
  28. #endif
  29. #define VSS_FILE_ALIAS "INCDEBGH"
  30. //
  31. ////////////////////////////////////////////////////////////////////////
  32. ////////////////////////////////////////////////////////////////////////
  33. // Global constants
  34. //
  35. // @const x_nVssMsgBufferSize | Maximum buffer size in Tracer operations
  36. const x_nVssMsgBufferSize = 512;
  37. const x_nVssNumericBufferSize = 30;
  38. const x_nVssGuidBufferSize = 60;
  39. const x_nVssMaxDebugArgs = 10;
  40. const WCHAR x_wszEventLogVssSourceName[] = L"VSS";
  41. /////////////////////////////////////////////////////////////////////////////
  42. // Declared classes
  43. //
  44. //
  45. // @class CVssFunctionTracer | This structure is used for tracing, debugging, treating HRESULTS
  46. // in a C++ function, especially a COM server method.
  47. //
  48. struct CVssDebugInfo
  49. {
  50. // Constructors& destructors
  51. private:
  52. CVssDebugInfo();
  53. public:
  54. CVssDebugInfo(
  55. LPCWSTR wszFile,
  56. LPCSTR szFileAlias, // Five character alias, see file drivers\volsnap\filealias.xls for mappings
  57. ULONG ulLine,
  58. DWORD dwLevel,
  59. DWORD dwIndent = 0
  60. );
  61. CVssDebugInfo(
  62. const CVssDebugInfo& original
  63. );
  64. ~CVssDebugInfo() ;
  65. // Operations
  66. public:
  67. // This is used to add an numeric-type argument
  68. CVssDebugInfo operator << ( IN INT nArgument );
  69. // This is used to add an numeric-type argument.
  70. // It will be represented in hexadecimal format.
  71. CVssDebugInfo operator << ( IN HRESULT hrArgument );
  72. // This is used to add an numeric-type argument.
  73. // It will be represented in hexadecimal format.
  74. CVssDebugInfo operator << ( IN LONGLONG llArgument );
  75. // This is used to add an numeric-type argument.
  76. CVssDebugInfo operator << ( IN GUID hrArgument );
  77. // This is used to add an string-type argument
  78. CVssDebugInfo operator << ( IN LPCWSTR wszArgument );
  79. public:
  80. LPCWSTR m_wszFile;
  81. LPCSTR m_szFileAlias;
  82. ULONG m_ulLine;
  83. DWORD m_dwLevel;
  84. DWORD m_dwIndent;
  85. // Optional argument list
  86. LPWSTR m_ppwszStrings[x_nVssMaxDebugArgs];
  87. WORD m_wNumStrings;
  88. bool m_bOutOfMemoryOccured;
  89. mutable bool m_bStringsOwnership;
  90. };
  91. #define VSSDBG_COORD CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_COORD, 0)
  92. #define VSSDBG_SWPRV CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_SWPRV, 0)
  93. #define VSSDBG_TESTPRV CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_TESTPRV, 0)
  94. #define VSSDBG_VSSTEST CVssDebugInfo(__WFILE__, "TST--", __LINE__, DEBUG_TRACE_VSS_TEST, 0)
  95. #define VSSDBG_VSSDEMO CVssDebugInfo(__WFILE__, "TSD--", __LINE__, DEBUG_TRACE_VSS_DEMO, 0)
  96. #define VSSDBG_EXCEPT CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_CATCH_EXCEPTIONS, 0)
  97. #define VSSDBG_GEN CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_GEN, 0)
  98. #define VSSDBG_XML CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_XML, 0)
  99. #define VSSDBG_WRITER CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_WRITER, 0)
  100. #define VSSDBG_IOCTL CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_IOCTL, 0)
  101. #define VSSDBG_SHIM CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_SHIM, 0)
  102. #define VSSDBG_SQLLIB CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_SQLLIB, 0)
  103. #define VSSDBG_VSSADMIN CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_ADMIN, 0)
  104. #define VSSDBG_STSWRITER CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_STSWRITER, 0)
  105. #define VSSDBG_SQLWRITER CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_SQLWRITER, 0)
  106. #define VSS_STANDARD_CATCH(FT) \
  107. catch( HRESULT CaughtHr ) { \
  108. FT.hr = CaughtHr; \
  109. FT.Trace( VSSDBG_EXCEPT, L"HRESULT EXCEPTION CAUGHT: hr: 0x%x", FT.hr ); \
  110. } \
  111. catch( ... ) { \
  112. FT.hr = E_UNEXPECTED; \
  113. FT.Trace( VSSDBG_EXCEPT, L"UNKNOWN EXCEPTION CAUGHT, returning hr: 0x%x", FT.hr ); \
  114. }
  115. //
  116. // @class CVssFunctionTracer | This class is used for tracing, debugging, treating HRESULTS
  117. // in a C++ function, especially a COM server method.
  118. //
  119. class CVssFunctionTracer
  120. {
  121. class CVssOutputBuffer
  122. {
  123. private:
  124. // Must be under 512 in order to make
  125. // the lookaside allocation algortihm work efficiently!
  126. enum { nVssMsgBufferSize = 400 };
  127. WCHAR* m_pwszBuffer;
  128. public:
  129. CVssOutputBuffer() { m_pwszBuffer = new WCHAR[nVssMsgBufferSize + 1]; }
  130. ~CVssOutputBuffer() { delete m_pwszBuffer; }
  131. INT GetBufferSize() { return nVssMsgBufferSize; };
  132. WCHAR * GetBuffer() { return m_pwszBuffer; };
  133. bool IsBufferValid() { return (m_pwszBuffer != NULL); };
  134. };
  135. // Constructors and destructors
  136. private:
  137. CVssFunctionTracer();
  138. CVssFunctionTracer(const CVssFunctionTracer&);
  139. public:
  140. CVssFunctionTracer(
  141. IN CVssDebugInfo dbgInfo,
  142. IN const WCHAR* pwszFunctionName
  143. );
  144. ~CVssFunctionTracer();
  145. // Attributes
  146. public:
  147. _declspec(property(get=GetHr,put=SetHr)) HRESULT hr;
  148. // Implementation
  149. inline HRESULT GetHr() { return m_hr; };
  150. inline void SetHr( HRESULT hr ) { m_hr = hr; };
  151. inline bool HrFailed() { return FAILED(m_hr); };
  152. inline bool HrSucceeded() { return SUCCEEDED(m_hr); };
  153. // Operations
  154. public:
  155. //
  156. // Traces.
  157. //
  158. void inline __cdecl Trace( CVssDebugInfo dbgInfo, const WCHAR* pwszMsgFormat, ...);
  159. void inline TraceBuffer( CVssDebugInfo dbgInfo, DWORD dwBufferSize, PBYTE pbBuffer );
  160. void inline __cdecl Throw(
  161. CVssDebugInfo dbgInfo, // Caller debugging info
  162. HRESULT hrToBeThrown, // The new HR to be thrown
  163. const WCHAR* pwszMsgFormat, // Message that will be displayed if throw needed
  164. ... // Additional arguments
  165. ) throw(HRESULT);
  166. void inline __cdecl ThrowIf(
  167. BOOL bThrowNeeded, // Throw an HR if and only if bThrowNeeded is TRUE.
  168. CVssDebugInfo dbgInfo, // Caller debugging info
  169. HRESULT hrToBeThrown, // The new HR to be thrown
  170. const WCHAR* pwszMsgFormat, // Message that will be displayed if throw needed
  171. ... // Additional arguments
  172. ) throw(HRESULT);
  173. //
  174. // Messages displayed at the console (only for test and demo purpose).
  175. //
  176. void __cdecl Msg(
  177. const WCHAR* pwszMsgFormat, // Message that will be displayed
  178. ...
  179. );
  180. void __cdecl MsgNoCR(
  181. const WCHAR* pwszMsgFormat, // Message that will be displayed
  182. ...
  183. );
  184. void __cdecl Err(
  185. CVssDebugInfo dbgInfo, // Caller debugging info
  186. HRESULT hrToBeThrown, // The new HR to be thrown
  187. const WCHAR* pwszMsgFormat, // Error message that will be displayed
  188. ...
  189. );
  190. //
  191. // Informative message boxes (only for test and demo purpose).
  192. //
  193. void __cdecl MsgBox(
  194. const WCHAR* pwszMsgTitle, // Title of the Message box
  195. const WCHAR* pwszMsgFormat, // Message that will be displayed
  196. ...
  197. );
  198. void __cdecl ErrBox(
  199. CVssDebugInfo dbgInfo, // Caller debugging info
  200. HRESULT hrToBeThrown, // The new HR to be thrown
  201. const WCHAR* pwszMsgFormat, // Error message that will be displayed
  202. ...
  203. );
  204. // Trace the corresponding COM error
  205. void TraceComError();
  206. // Log the attempt of starting VSS
  207. void LogVssStartupAttempt();
  208. // Put a new entry in the Error Log.
  209. void __cdecl LogError(
  210. IN DWORD dwEventID, // The ID of the event
  211. IN CVssDebugInfo dbgInfo, // Caller debugging info
  212. IN WORD wType = EVENTLOG_ERROR_TYPE // Entry type
  213. );
  214. void __cdecl TranslateError(
  215. IN CVssDebugInfo dbgInfo,
  216. IN HRESULT hr,
  217. IN LPCWSTR wszRoutine
  218. );
  219. void inline __cdecl CheckForError(
  220. IN CVssDebugInfo dbgInfo,
  221. IN LPCWSTR wszRoutine
  222. )
  223. {
  224. if (HrFailed())
  225. TranslateError(dbgInfo, m_hr, wszRoutine);
  226. }
  227. // check for an error on an internal call. Do not log E_UNEXPECTED
  228. // errors
  229. void inline __cdecl CheckForErrorInternal(
  230. IN CVssDebugInfo dbgInfo,
  231. IN LPCWSTR wszRoutine
  232. )
  233. {
  234. if (HrFailed())
  235. {
  236. if (m_hr == E_UNEXPECTED)
  237. throw E_UNEXPECTED;
  238. else
  239. TranslateError(dbgInfo, m_hr, wszRoutine);
  240. }
  241. }
  242. void __cdecl TranslateGenericError
  243. (
  244. IN CVssDebugInfo dbgInfo, // Caller debugging info
  245. IN HRESULT hr,
  246. IN LPCWSTR wszErrorTextFormat,
  247. IN ...
  248. );
  249. void __cdecl LogGenericWarning
  250. (
  251. IN CVssDebugInfo dbgInfo, // Caller debugging info
  252. IN LPCWSTR wszErrorTextFormat,
  253. IN ...
  254. );
  255. BOOL IsDuringSetup() { return g_cDbgTrace.IsDuringSetup(); };
  256. BOOL IsInSoftwareProvider() { return m_dwLevel == DEBUG_TRACE_VSS_SWPRV; };
  257. //
  258. // Calls CoCreate in a cycle and performs special logging
  259. //
  260. void CoCreateInstanceWithLog(
  261. IN CVssDebugInfo dbgInfo, // Caller debugging info
  262. IN CLSID ServerClassID,
  263. IN LPCWSTR ServerName,
  264. IN DWORD dwContext,
  265. IN IID InterfaceID,
  266. OUT IUnknown ** ppUnknown
  267. );
  268. // Attributes
  269. public:
  270. HRESULT m_hr;
  271. // Internal Data
  272. private:
  273. const WCHAR* m_pwszFunctionName;
  274. LPCSTR m_szFileAlias;
  275. ULONG m_ulLine;
  276. DWORD m_dwLevel; // At entry time
  277. DWORD m_dwIndent; // At entry time
  278. };
  279. ///////////////////////////////////////////////////////////////////////////////////////
  280. // Class implementations
  281. //
  282. ///////////////////////////////////////////////////////////////////////////////////////
  283. // CVssDebugInfo
  284. inline CVssDebugInfo::CVssDebugInfo(
  285. LPCWSTR wszFile,
  286. LPCSTR szFileAlias,
  287. ULONG ulLine,
  288. DWORD dwLevel,
  289. DWORD dwIndent
  290. ):
  291. m_wszFile(wszFile),
  292. m_szFileAlias(szFileAlias),
  293. m_ulLine(ulLine),
  294. m_dwIndent(dwIndent),
  295. m_dwLevel(dwLevel),
  296. m_wNumStrings(0),
  297. m_bOutOfMemoryOccured(false),
  298. m_bStringsOwnership(true)
  299. {
  300. for (WORD wIndex = 0; wIndex < x_nVssMaxDebugArgs; wIndex++)
  301. m_ppwszStrings[wIndex] = NULL;
  302. }
  303. inline CVssDebugInfo::CVssDebugInfo(
  304. const CVssDebugInfo& original
  305. )
  306. {
  307. m_wszFile = original.m_wszFile; // We suppose that this is a constant string.
  308. m_szFileAlias = original.m_szFileAlias; // We suppose that this is a constant string.
  309. m_ulLine = original.m_ulLine;
  310. m_dwIndent = original.m_dwIndent;
  311. m_dwLevel = original.m_dwLevel;
  312. m_wNumStrings = original.m_wNumStrings;
  313. m_bOutOfMemoryOccured = original.m_bOutOfMemoryOccured;
  314. // Transfer the strings ownership.
  315. // This will work even if the ownership is already transferred
  316. m_bStringsOwnership = original.m_bStringsOwnership;
  317. original.m_bStringsOwnership = false;
  318. // Transfer the strings
  319. for (WORD wIndex = 0; wIndex < x_nVssMaxDebugArgs; wIndex++)
  320. m_ppwszStrings[wIndex] = original.m_ppwszStrings[wIndex];
  321. }
  322. inline CVssDebugInfo::~CVssDebugInfo()
  323. {
  324. if (m_bStringsOwnership) {
  325. for (WORD wIndex = 0; wIndex < x_nVssMaxDebugArgs; wIndex++) {
  326. if ( m_ppwszStrings[wIndex] != NULL ) {
  327. ::CoTaskMemFree(m_ppwszStrings[wIndex]);
  328. m_ppwszStrings[wIndex] = NULL;
  329. }
  330. }
  331. }
  332. }
  333. // This is used to add an numeric-type argument
  334. inline CVssDebugInfo CVssDebugInfo::operator << ( IN INT nArgument )
  335. {
  336. // Converting the number into a string
  337. WCHAR wszBuffer[x_nVssNumericBufferSize + 1];
  338. ::_snwprintf(wszBuffer, x_nVssNumericBufferSize, L"%d", nArgument);
  339. return (*this) << wszBuffer;
  340. }
  341. // This is used to add an HRESULT-type argument
  342. inline CVssDebugInfo CVssDebugInfo::operator << ( IN HRESULT hrArgument )
  343. {
  344. // Converting the number into a string
  345. WCHAR wszBuffer[x_nVssNumericBufferSize + 1];
  346. ::_snwprintf(wszBuffer, x_nVssNumericBufferSize, L"0x%08lx", hrArgument);
  347. return (*this) << wszBuffer;
  348. }
  349. // This is used to add an LONGLONG-type argument
  350. inline CVssDebugInfo CVssDebugInfo::operator << ( IN LONGLONG llArgument )
  351. {
  352. // Converting the number into a string
  353. WCHAR wszBuffer[x_nVssNumericBufferSize + 1];
  354. ::_snwprintf(wszBuffer, x_nVssNumericBufferSize,
  355. WSTR_LONGLONG_FMT, LONGLONG_PRINTF_ARG(llArgument) );
  356. return (*this) << wszBuffer;
  357. }
  358. // This is used to add an GUID-type argument
  359. inline CVssDebugInfo CVssDebugInfo::operator << ( IN GUID guidArgument )
  360. {
  361. // Converting the number into a string
  362. WCHAR wszBuffer[x_nVssGuidBufferSize + 1];
  363. ::_snwprintf(wszBuffer, x_nVssGuidBufferSize, WSTR_GUID_FMT, GUID_PRINTF_ARG(guidArgument));
  364. return (*this) << wszBuffer;
  365. }
  366. // This is used to add an string-type argument
  367. inline CVssDebugInfo CVssDebugInfo::operator << ( IN LPCWSTR wszArgument )
  368. {
  369. if (wszArgument == NULL) {
  370. BS_ASSERT(false);
  371. return (*this);
  372. }
  373. if (m_bOutOfMemoryOccured)
  374. return (*this);
  375. // We cannot add more strings if we do not have the ownership...
  376. if (!m_bStringsOwnership) {
  377. BS_ASSERT(false);
  378. return (*this);
  379. }
  380. if (m_wNumStrings >= x_nVssMaxDebugArgs) {
  381. BS_ASSERT(false); // Improper usage (putting too many arguments)
  382. return (*this);
  383. }
  384. // Storing into the actual list of arguments. We might have an allocation error here.
  385. LPWSTR wszFormattedValue = (LPWSTR)::CoTaskMemAlloc(sizeof(WCHAR)*(1 + ::wcslen(wszArgument)));
  386. if (wszFormattedValue == NULL) {
  387. m_bOutOfMemoryOccured = true;
  388. return (*this);
  389. }
  390. ::wcscpy(wszFormattedValue, wszArgument);
  391. m_ppwszStrings[m_wNumStrings++] = wszFormattedValue;
  392. return (*this);
  393. }
  394. ///////////////////////////////////////////////////////////////////////////////////////
  395. // CVssFunctionTracer
  396. inline CVssFunctionTracer::CVssFunctionTracer(
  397. IN CVssDebugInfo dbgInfo,
  398. IN const WCHAR* pwszFunctionName
  399. )
  400. {
  401. m_hr = S_OK;
  402. m_pwszFunctionName = pwszFunctionName;
  403. m_szFileAlias = dbgInfo.m_szFileAlias;
  404. m_ulLine = dbgInfo.m_ulLine;
  405. m_dwLevel = dbgInfo.m_dwLevel;
  406. m_dwIndent = dbgInfo.m_dwIndent;
  407. if ( g_cDbgTrace.IsTracingEnabled() && g_cDbgTrace.GetTraceEnterExit() )
  408. {
  409. g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine,
  410. m_dwIndent, m_dwLevel, m_pwszFunctionName, TRUE );
  411. // The reason that I not allow putting here custom-defined arguments is that
  412. // if the caller put wrong references it can easily generate an AV.
  413. // And, at this point, there is no NT exceptions treatment at the caller side.
  414. g_cDbgTrace.PrintEnterExit(L"");
  415. g_cDbgTrace.PostPrint( m_dwIndent );
  416. }
  417. }
  418. inline CVssFunctionTracer::~CVssFunctionTracer()
  419. {
  420. if ( g_cDbgTrace.IsTracingEnabled() && g_cDbgTrace.GetTraceEnterExit() )
  421. {
  422. g_cDbgTrace.PrePrint( L"", 0UL, m_dwIndent, m_dwLevel, m_pwszFunctionName, FALSE );
  423. g_cDbgTrace.PrintEnterExit(L"hr: 0x%08x", m_hr);
  424. g_cDbgTrace.PostPrint( m_dwIndent );
  425. }
  426. }
  427. void inline __cdecl CVssFunctionTracer::Trace( CVssDebugInfo dbgInfo, const WCHAR* pwszMsgFormat, ...)
  428. // WARNING: This function do NOT clear the ft.hr field!
  429. {
  430. if ( !g_cDbgTrace.IsTracingEnabled() )
  431. return;
  432. CVssOutputBuffer buffer;
  433. if (buffer.IsBufferValid())
  434. {
  435. va_list marker;
  436. va_start( marker, pwszMsgFormat );
  437. _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), pwszMsgFormat, marker );
  438. va_end( marker );
  439. g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine,
  440. dbgInfo.m_dwIndent, dbgInfo.m_dwLevel );
  441. g_cDbgTrace.Print( L"%s: %s", m_pwszFunctionName, buffer.GetBuffer() );
  442. g_cDbgTrace.PostPrint( dbgInfo.m_dwIndent );
  443. }
  444. };
  445. void inline CVssFunctionTracer::TraceBuffer( CVssDebugInfo dbgInfo, DWORD dwBufferSize, PBYTE pbBuffer )
  446. {
  447. // WARNING: This function do NOT clear the ft.hr field!
  448. if ( !g_cDbgTrace.IsTracingEnabled() )
  449. return;
  450. const nBytesPerSubgroup = 4;
  451. const nSubgroupsPerGroup = 2;
  452. const nGroupsCount = 2;
  453. const nSubgroupSize = 3*nBytesPerSubgroup + 1; // Add a space between subgroups
  454. const nGroupSize = nSubgroupSize*nSubgroupsPerGroup + 1; // Add a space between groups
  455. const nLineSize = nGroupSize*nGroupsCount + 1; // Add the zero character.
  456. WCHAR wszPrintedBufferLine[nLineSize];
  457. WCHAR wszPrintedBufferLineInChr[nLineSize];
  458. WCHAR wszDigits[] = L"0123456789ABCDEF";
  459. // Print each line
  460. for (DWORD dwBufferOffset = 0; dwBufferOffset < dwBufferSize; )
  461. {
  462. int nLineOffset = 0;
  463. int nLineOffsetChr = 0;
  464. // Print each group in the line
  465. for (int nGroupIndex = 0; nGroupIndex < nGroupsCount; nGroupIndex++)
  466. {
  467. // Print each subgroup in the group
  468. for (int nSubgroupIndex = 0; nSubgroupIndex < nSubgroupsPerGroup; nSubgroupIndex++)
  469. {
  470. // Print each byte in the subgroup
  471. for (int nByteIndex = 0; nByteIndex < nBytesPerSubgroup; nByteIndex++)
  472. {
  473. if (dwBufferOffset < dwBufferSize)
  474. {
  475. BYTE bChar = pbBuffer[dwBufferOffset];
  476. wszPrintedBufferLineInChr[nLineOffsetChr++] =
  477. ( bChar >= 0x20 && bChar < 0x7F )? (WCHAR)bChar: L'.';
  478. wszPrintedBufferLine[nLineOffset++] = wszDigits[pbBuffer[dwBufferOffset] / 0x10];
  479. wszPrintedBufferLine[nLineOffset++] = wszDigits[pbBuffer[dwBufferOffset++] % 0x10];
  480. wszPrintedBufferLine[nLineOffset++] = L' '; // Print an additional space after each group
  481. }
  482. else
  483. {
  484. wszPrintedBufferLineInChr[nLineOffsetChr++] = L'#';
  485. wszPrintedBufferLine[nLineOffset++] = L'#';
  486. wszPrintedBufferLine[nLineOffset++] = L'#';
  487. wszPrintedBufferLine[nLineOffset++] = L' '; // Print an additional space after each group
  488. }
  489. }
  490. wszPrintedBufferLine[nLineOffset++] = L' '; // Print a space after each subgroup
  491. }
  492. wszPrintedBufferLine[nLineOffset++] = L' '; // Print an additional space after each group
  493. }
  494. // Put hte termination characters
  495. wszPrintedBufferLineInChr[nLineOffsetChr++] = L'\0';
  496. wszPrintedBufferLine[nLineOffset++] = L'\0';
  497. BS_ASSERT( nLineOffset == nLineSize );
  498. g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine,
  499. dbgInfo.m_dwIndent, dbgInfo.m_dwLevel );
  500. g_cDbgTrace.Print( L"%s %s", wszPrintedBufferLine, wszPrintedBufferLineInChr );
  501. g_cDbgTrace.PostPrint( dbgInfo.m_dwIndent );
  502. }
  503. };
  504. void inline __cdecl CVssFunctionTracer::Throw(
  505. CVssDebugInfo dbgInfo, // Caller debugging info
  506. HRESULT hrToBeThrown, // The new HR to be thrown
  507. const WCHAR* pwszMsgFormat, // Message that will be displayed if throw needed
  508. ... // Additional arguments
  509. ) throw(HRESULT)
  510. {
  511. if ( g_cDbgTrace.IsTracingEnabled() )
  512. {
  513. if (pwszMsgFormat != NULL)
  514. {
  515. CVssOutputBuffer buffer;
  516. if (buffer.IsBufferValid())
  517. {
  518. va_list marker;
  519. va_start( marker, pwszMsgFormat );
  520. _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), pwszMsgFormat, marker );
  521. va_end( marker );
  522. g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine,
  523. dbgInfo.m_dwIndent, dbgInfo.m_dwLevel );
  524. g_cDbgTrace.Print( L"%s: %s", m_pwszFunctionName, buffer.GetBuffer() );
  525. g_cDbgTrace.PostPrint( dbgInfo.m_dwIndent );
  526. }
  527. }
  528. g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine,
  529. dbgInfo.m_dwIndent, DEBUG_TRACE_CATCH_EXCEPTIONS );
  530. g_cDbgTrace.Print( L"%s: Throwing HRESULT code 0x%08lx. "
  531. L"Previous HRESULT code = 0x%08lx", m_pwszFunctionName, hrToBeThrown, m_hr );
  532. g_cDbgTrace.PostPrint( DEBUG_TRACE_CATCH_EXCEPTIONS );
  533. }
  534. m_hr = hrToBeThrown;
  535. throw( ( HRESULT )m_hr );
  536. };
  537. void inline __cdecl CVssFunctionTracer::ThrowIf(
  538. BOOL bThrowNeeded, // Throw an HR if and only if bThrowNeeded is TRUE.
  539. CVssDebugInfo dbgInfo, // Caller debugging info
  540. HRESULT hrToBeThrown, // The new HR to be thrown
  541. const WCHAR* pwszMsgFormat, // Message that will be displayed if throw needed
  542. ... // Additional arguments
  543. ) throw(HRESULT)
  544. // WARNING: This function clears the ft.hr field if no errors !
  545. // Also if bThrowNeeded == false then the m_hr is reset to S_OK !
  546. {
  547. if (!bThrowNeeded)
  548. {
  549. m_hr = S_OK;
  550. return;
  551. }
  552. if ( g_cDbgTrace.IsTracingEnabled() )
  553. {
  554. if (pwszMsgFormat != NULL)
  555. {
  556. CVssOutputBuffer buffer;
  557. if (buffer.IsBufferValid())
  558. {
  559. va_list marker;
  560. va_start( marker, pwszMsgFormat );
  561. _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), pwszMsgFormat, marker );
  562. va_end( marker );
  563. g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine,
  564. dbgInfo.m_dwIndent, dbgInfo.m_dwLevel );
  565. g_cDbgTrace.Print( L"%s: %s", m_pwszFunctionName, buffer.GetBuffer() );
  566. g_cDbgTrace.PostPrint( dbgInfo.m_dwIndent );
  567. }
  568. }
  569. g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine,
  570. dbgInfo.m_dwIndent, DEBUG_TRACE_CATCH_EXCEPTIONS );
  571. g_cDbgTrace.Print( L"%s: %s HRESULT code 0x%08lx. "
  572. L"Previous HRESULT code = 0x%08lx",
  573. bThrowNeeded? L"Throwing": L"Tracing",
  574. m_pwszFunctionName, hrToBeThrown, m_hr );
  575. g_cDbgTrace.PostPrint( DEBUG_TRACE_CATCH_EXCEPTIONS );
  576. }
  577. m_hr = hrToBeThrown;
  578. throw( ( HRESULT )m_hr );
  579. };
  580. //
  581. // Messages displayed at the console (only for test and demo purpose).
  582. //
  583. void inline __cdecl CVssFunctionTracer::Msg(
  584. const WCHAR* pwszMsgFormat, // Message that will be displayed
  585. ...
  586. )
  587. {
  588. USES_CONVERSION;
  589. _ASSERTE(pwszMsgFormat);
  590. CVssOutputBuffer buffer;
  591. if (buffer.IsBufferValid())
  592. {
  593. va_list marker;
  594. va_start( marker, pwszMsgFormat );
  595. _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), pwszMsgFormat, marker );
  596. va_end( marker );
  597. wprintf( L"%s\n", W2CT(buffer.GetBuffer()) );
  598. }
  599. }
  600. void inline __cdecl CVssFunctionTracer::MsgNoCR(
  601. const WCHAR* pwszMsgFormat, // Message that will be displayed
  602. ...
  603. )
  604. {
  605. USES_CONVERSION;
  606. _ASSERTE(pwszMsgFormat);
  607. CVssOutputBuffer buffer;
  608. if (buffer.IsBufferValid())
  609. {
  610. va_list marker;
  611. va_start( marker, pwszMsgFormat );
  612. _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), pwszMsgFormat, marker );
  613. va_end( marker );
  614. wprintf( L"%s", W2CT(buffer.GetBuffer()) );
  615. }
  616. }
  617. void inline __cdecl CVssFunctionTracer::Err(
  618. CVssDebugInfo dbgInfo, // Caller debugging info
  619. HRESULT hrToBeThrown, // The new HR to be thrown
  620. const WCHAR* pwszMsgFormat, // Error message that will be displayed
  621. ...
  622. )
  623. {
  624. USES_CONVERSION;
  625. _ASSERTE(pwszMsgFormat);
  626. CVssOutputBuffer buffer;
  627. if (buffer.IsBufferValid())
  628. {
  629. va_list marker;
  630. va_start( marker, pwszMsgFormat );
  631. _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), pwszMsgFormat, marker );
  632. va_end( marker );
  633. // Message box
  634. CVssOutputBuffer buffer2;
  635. if (!buffer2.IsBufferValid())
  636. throw(E_OUTOFMEMORY);
  637. _snwprintf(buffer2.GetBuffer(), buffer2.GetBufferSize(), L"%s(%ld)\n%s @ [%08lx,%08lx], PID=%ld, TID=%ld\n%s",
  638. dbgInfo.m_wszFile, dbgInfo.m_ulLine,
  639. m_pwszFunctionName, dbgInfo.m_dwIndent, dbgInfo.m_dwLevel,
  640. GetCurrentProcessId(), GetCurrentThreadId(),
  641. buffer.GetBuffer()
  642. );
  643. ::MessageBoxW( NULL, buffer2.GetBuffer(), L"Error", MB_OK);
  644. if ( g_cDbgTrace.IsTracingEnabled() )
  645. {
  646. g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine,
  647. dbgInfo.m_dwIndent, dbgInfo.m_dwLevel );
  648. g_cDbgTrace.Print( L"%s: %s", m_pwszFunctionName, buffer2.GetBuffer() );
  649. g_cDbgTrace.PostPrint( dbgInfo.m_dwIndent );
  650. }
  651. wprintf( L"Error: %s\n", W2CT(buffer2.GetBuffer()) );
  652. }
  653. if (hrToBeThrown)
  654. {
  655. m_hr = hrToBeThrown;
  656. throw( ( HRESULT )m_hr );
  657. }
  658. }
  659. //
  660. // Informative message boxes (only for test and demo purpose).
  661. //
  662. void inline __cdecl CVssFunctionTracer::MsgBox(
  663. const WCHAR* pwszMsgTitle, // Title of the Message box
  664. const WCHAR* pwszMsgFormat, // Message that will be displayed
  665. ...
  666. )
  667. {
  668. USES_CONVERSION;
  669. _ASSERTE(pwszMsgTitle);
  670. _ASSERTE(pwszMsgFormat);
  671. CVssOutputBuffer buffer;
  672. if (buffer.IsBufferValid())
  673. {
  674. va_list marker;
  675. va_start( marker, pwszMsgFormat );
  676. _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), pwszMsgFormat, marker );
  677. va_end( marker );
  678. ::MessageBox(NULL, W2CT(buffer.GetBuffer()), W2CT(pwszMsgTitle), MB_OK);
  679. }
  680. }
  681. void inline __cdecl CVssFunctionTracer::ErrBox(
  682. CVssDebugInfo dbgInfo, // Caller debugging info
  683. HRESULT hrToBeThrown, // The new HR to be thrown
  684. const WCHAR* pwszMsgFormat, // Error message that will be displayed
  685. ...
  686. )
  687. {
  688. USES_CONVERSION;
  689. _ASSERTE(pwszMsgFormat);
  690. CVssOutputBuffer buffer;
  691. if (buffer.IsBufferValid())
  692. {
  693. va_list marker;
  694. va_start( marker, pwszMsgFormat );
  695. _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), pwszMsgFormat, marker );
  696. va_end( marker );
  697. if ( g_cDbgTrace.IsTracingEnabled() )
  698. {
  699. g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine,
  700. dbgInfo.m_dwIndent, dbgInfo.m_dwLevel );
  701. g_cDbgTrace.Print( L"%s: %s", m_pwszFunctionName, buffer.GetBuffer() );
  702. g_cDbgTrace.PostPrint( dbgInfo.m_dwIndent );
  703. }
  704. ::MessageBox(NULL, W2CT(buffer.GetBuffer()), L"Error", MB_OK);
  705. }
  706. if (hrToBeThrown)
  707. {
  708. m_hr = hrToBeThrown;
  709. throw( ( HRESULT )m_hr );
  710. }
  711. }
  712. /*++
  713. Routine Description:
  714. Traces the COM error description. Can be called after automation COM calls
  715. (for example XML or COM+ related)
  716. --*/
  717. void inline CVssFunctionTracer::TraceComError()
  718. {
  719. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssFunctionTracer::TraceComError");
  720. CComPtr<IErrorInfo> pErrorInfo;
  721. HRESULT hr2 = ::GetErrorInfo(0, &pErrorInfo);
  722. if (SUCCEEDED(hr2)) {
  723. if (pErrorInfo != NULL) {
  724. BSTR bstrDescription;
  725. HRESULT hr3 = pErrorInfo->GetDescription(&bstrDescription);
  726. if (SUCCEEDED(hr3)) {
  727. ft.Trace(VSSDBG_GEN, L"Error info description: %s", bstrDescription);
  728. ::SysFreeString(bstrDescription);
  729. } else
  730. ft.Trace(VSSDBG_GEN, L"Warning: Error getting error description = 0x%08lx", hr3);
  731. }
  732. }
  733. else
  734. ft.Trace(VSSDBG_GEN, L"Warning: Error getting error info = 0x%08lx", hr2);
  735. }
  736. void inline __cdecl CVssFunctionTracer::LogError(
  737. IN DWORD dwEventID, // The ID of the event
  738. IN CVssDebugInfo dbgInfo, // Caller debugging info
  739. IN WORD wType // By default it is EVENTLOG_ERROR_TYPE
  740. )
  741. {
  742. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssFunctionTracer::LogError");
  743. try
  744. {
  745. LPCWSTR ppwszStrings[x_nVssMaxDebugArgs];
  746. CHAR szFileLine[32];
  747. CHAR szTemp[34]; // Max length of string from _ultoa()
  748. // Create the four lines of binary data output in the data section of the event log message.
  749. // First the Caller debugging info:
  750. ::strncpy( szFileLine, dbgInfo.m_szFileAlias, 8 );
  751. ::_ultoa( dbgInfo.m_ulLine, szTemp, 10 );
  752. ::strncpy( szFileLine + 8, szTemp, 8 ); // strncpy has the nice property of zeroing out unuse chars.
  753. // Now info on the ft at point of construction:
  754. ::strncpy( szFileLine + 16, m_szFileAlias, 8 );
  755. ::_ultoa( m_ulLine, szTemp, 10 );
  756. ::strncpy( szFileLine + 24, szTemp, 8 ); // strncpy has the nice property of zeroing out unuse chars.
  757. // Fill out the strings that are given as arguments
  758. WORD wNumStrings = dbgInfo.m_wNumStrings;
  759. for( WORD wIndex = 0; wIndex < dbgInfo.m_wNumStrings; wIndex++ )
  760. ppwszStrings[wIndex] = const_cast<LPCWSTR>(dbgInfo.m_ppwszStrings[wIndex]);
  761. // Get a handle to use with ReportEvent()
  762. HANDLE hEventSource = ::RegisterEventSourceW(
  763. NULL, // IN LPCWSTR lpUNCServerName,
  764. x_wszEventLogVssSourceName // IN LPCWSTR lpSourceName
  765. );
  766. if (hEventSource == NULL)
  767. ft.Throw( VSSDBG_SHIM, E_UNEXPECTED, L"Error on RegisterEventSourceW 0x%08lx", GetLastError());
  768. // Write to event log.
  769. BOOL bRet = ::ReportEventW(
  770. hEventSource, // IN HANDLE hEventLog,
  771. wType, // IN WORD wType,
  772. 0, // IN WORD wCategory,
  773. dwEventID, // IN DWORD dwEventID,
  774. NULL, // IN PSID lpUserSid,
  775. wNumStrings, // IN WORD wNumStrings,
  776. sizeof( szFileLine ), // IN DWORD dwDataSize,
  777. ppwszStrings, // IN LPCWSTR *lpStrings,
  778. szFileLine // IN LPVOID lpRawData
  779. );
  780. if ( !bRet )
  781. ft.Trace( VSSDBG_SHIM, L"Error on ReportEventW 0x%08lx", GetLastError());
  782. // Close the handle to the event log
  783. bRet = ::DeregisterEventSource( hEventSource );
  784. if ( !bRet )
  785. ft.Throw( VSSDBG_SHIM, E_UNEXPECTED, L"Error on DeregisterEventSource 0x%08lx", GetLastError());
  786. }
  787. VSS_STANDARD_CATCH(ft)
  788. }
  789. //
  790. // Set the file alias to unknown in case a module doesn't set it's alias.
  791. //
  792. #undef VSS_FILE_ALIAS
  793. #define VSS_FILE_ALIAS "UNKNOWN"
  794. #endif // __VSS_DEBUG_HXX__