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.

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