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.

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