Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

583 lines
19 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1999
  5. //
  6. // File: mmcerror.cpp
  7. //
  8. // Contents: Class definitions for mmc error support code.
  9. //
  10. // History: 15-Jul-99 VivekJ Created
  11. //
  12. //--------------------------------------------------------------------------
  13. #pragma once
  14. #ifndef _MMCERROR_H
  15. #define _MMCERROR_H
  16. #include "baseapi.h" // for MMCBASE_API
  17. #include "stddbg.h" // for ASSERT, COMPILETIME_ASSERT
  18. /*+-------------------------------------------------------------------------*
  19. * WHY NAMESPACES ?
  20. * We had problems trying to use "modified" SC when implementing
  21. * com classes supporting ISupportErrorInfo.
  22. * we had:
  23. * [global version] - class CS
  24. * [local version ] - a template class _SC, derived from SC and typedef'ed to SC.
  25. * That was not only confusing to us - IDE debugger was also confused and crashing.
  26. *
  27. * The solution for that was to separate real types used for implementing.
  28. * Thus to have typedef'ed definitions both in global and local scope.
  29. * Plus (to avoid dealing with _SC and __SC and have better IDE support)
  30. * we have used namespaces mmcerror and comerror, so we endup with this:
  31. * - mmcerror::SC defining main functionality
  32. * - comerror::SC (derived from mmcerror::SC) defining modified functionality
  33. * - global SC - typedef of mmcerror::SC
  34. * - local SC - typedef of comerror::SC
  35. *+-------------------------------------------------------------------------*/
  36. namespace mmcerror {
  37. /*+-------------------------------------------------------------------------*
  38. * class SC
  39. *
  40. * PURPOSE: The definition of a status code. Contains two members, a facility
  41. * and an error code. This is a class rather
  42. * than a typedef to avoid accidental casts to and from HRESULTS.
  43. *
  44. * SC's hold information about an error: The source of the error,
  45. * and the error code itself. These are stored in
  46. * different bit fields within the SC.
  47. *
  48. * NOTE: Do not add any virtual functions or member variables to this class.
  49. * This could potentially wreak havoc on MMC performance.
  50. *
  51. *+-------------------------------------------------------------------------*/
  52. class MMCBASE_API SC
  53. {
  54. public:
  55. typedef long value_type;
  56. private:
  57. enum facility_type
  58. {
  59. FACILITY_WIN = 1, // Defined by the system
  60. FACILITY_MMC = 2, // these map directly to an UINT.
  61. FACILITY_HRESULT = 3, // these map directly to an HRESULT
  62. };
  63. public:
  64. /*
  65. * Constructor. Default copy construction and assignment are sufficient.
  66. * If they are ever insufficient, that is a clear indication that this
  67. * class has become heavier than is acceptable for its pervasive pass-by-
  68. * value usage.
  69. */
  70. SC (HRESULT hr = S_OK);
  71. // equality operators
  72. bool operator==(const SC &rhs) const;
  73. bool operator==(HRESULT hr) const;
  74. bool operator!=(const SC &rhs) const;
  75. bool operator!=(HRESULT hr) const;
  76. SC& operator= (HRESULT hr) {MakeSc(FACILITY_HRESULT, hr); return (*this);}
  77. SC& FromWin32(value_type value) {MakeSc(FACILITY_WIN, value); return (*this);}
  78. SC& FromMMC(value_type value) {MakeSc(FACILITY_MMC, value); return (*this);}
  79. void Clear() {MakeSc(FACILITY_HRESULT, S_OK); }
  80. HRESULT ToHr() const;
  81. value_type GetCode() const {return m_value;}
  82. // get the error message in a preallocated buffer
  83. void GetErrorMessage(UINT maxLength, /*[OUT]*/ LPTSTR szMessage) const;
  84. static void SetHinst(HINSTANCE hInst);
  85. static void SetHWnd(HWND hWnd);
  86. static DWORD GetMainThreadID() {return s_dwMainThreadID;}
  87. static void SetMainThreadID(DWORD dwThreadID);
  88. operator bool() const;
  89. operator ! () const;
  90. bool IsError() const {return operator bool();}
  91. static HINSTANCE GetHinst() {ASSERT(s_hInst); return s_hInst;}
  92. static HWND GetHWnd() {return s_hWnd;}
  93. DWORD GetHelpID();
  94. static LPCTSTR GetHelpFile();
  95. void Throw() throw(SC);
  96. void Throw(HRESULT hr) throw();
  97. void FatalError() const; // ends the application.
  98. SC& FromLastError();
  99. // does the same trace like in ~SC(); does not change contents.
  100. void Trace_() const;
  101. void TraceAndClear() { Trace_(); Clear(); }
  102. private:
  103. void MakeSc(facility_type facility, value_type value){m_facility = facility, m_value = value;}
  104. // accessor functions
  105. facility_type GetFacility() const {return m_facility;}
  106. private:
  107. operator HRESULT() const; // this is to prevent automatic conversions to HRESULTs by way of bool's.
  108. private:
  109. facility_type m_facility;
  110. value_type m_value; // the error code.
  111. static HINSTANCE s_hInst; // the module that contains all error messages.
  112. static HWND s_hWnd; // the parent HWnd for the error boxes.
  113. static DWORD s_dwMainThreadID; // The main thread ID of MMC.
  114. // debug specific behavior
  115. #ifdef DBG // Debug SC's hold a pointer to the name of the function they are declared in.
  116. public:
  117. void SetFunctionName(LPCTSTR szFunctionName);
  118. LPCTSTR GetFunctionName() const;
  119. void SetSnapinName (LPCTSTR szSnapinName) { m_szSnapinName = szSnapinName;}
  120. LPCTSTR GetSnapinName() const { return m_szSnapinName;}
  121. void CheckCallingThreadID();
  122. ~SC();
  123. // SC shouldn't pass the function name around - it's something personal.
  124. // These will prevent doing so:
  125. SC& operator = (const SC& other);
  126. SC(const SC& other);
  127. private:
  128. LPCTSTR m_szFunctionName;
  129. LPCTSTR m_szSnapinName;
  130. static UINT s_CallDepth;
  131. #endif // DBG
  132. };
  133. } // namespace mmcerror
  134. // see "WHY NAMESPACES ?" comment at the top of file
  135. typedef mmcerror::SC SC;
  136. //############################################################################
  137. //############################################################################
  138. //
  139. // the module that contains all the localized strings
  140. //
  141. //############################################################################
  142. //############################################################################
  143. MMCBASE_API HINSTANCE GetStringModule();
  144. //############################################################################
  145. //############################################################################
  146. //
  147. // Functions to format and display an error
  148. //
  149. //############################################################################
  150. //############################################################################
  151. //
  152. // Functions to get an error string from a given SC
  153. //
  154. void MMCBASE_API FormatErrorIds( UINT idsOperation, SC sc, UINT maxLength, /*[OUT]*/ LPTSTR szMessage);
  155. void MMCBASE_API FormatErrorString(LPCTSTR szOperation, SC sc, UINT maxLength, /*[OUT]*/ LPTSTR szMessage, BOOL fShort = FALSE);
  156. void MMCBASE_API FormatErrorShort(SC sc, UINT maxLength, /*[OUT]*/ LPTSTR szMessage);
  157. //
  158. // Error Boxes - These will eventually allow to user to suppress more error messages
  159. //
  160. int MMCBASE_API MMCErrorBox(UINT idsOperation, UINT fuStyle = MB_ICONSTOP | MB_OK);
  161. int MMCBASE_API MMCErrorBox(UINT idsOperation, SC sc, UINT fuStyle = MB_ICONSTOP | MB_OK);
  162. int MMCBASE_API MMCErrorBox(LPCTSTR szOperation, SC sc, UINT fuStyle = MB_ICONSTOP | MB_OK);
  163. int MMCBASE_API MMCErrorBox( SC sc, UINT fuStyle = MB_ICONSTOP | MB_OK);
  164. int MMCBASE_API MMCErrorBox(LPCTSTR szMessage, UINT fuStyle = MB_ICONSTOP | MB_OK);
  165. //
  166. // Message Boxes - These cannot be suppressed
  167. //
  168. // This #define eventually will change so that MessageBox's are different and cannot be suppressed
  169. #define MMCMessageBox MMCErrorBox
  170. //############################################################################
  171. //############################################################################
  172. //
  173. // Debug macros
  174. //
  175. //############################################################################
  176. //############################################################################
  177. #ifdef DBG
  178. MMCBASE_API void TraceError(LPCTSTR sz, const SC& sc);
  179. MMCBASE_API void TraceErrorMsg(LPCTSTR szFormat, ...);
  180. MMCBASE_API void TraceSnapinError(LPCTSTR szError, const SC& sc);
  181. #define DECLARE_SC(_sc, _func) SC _sc; sc.SetFunctionName(_func);
  182. // This define is used only within the SC class
  183. #define INCREMENT_CALL_DEPTH() ++s_CallDepth
  184. #define DECREMENT_CALL_DEPTH() --s_CallDepth
  185. ///////////////////////////////////////////////////////////////////////
  186. // MMC public interfaces (for snapins) should use this macro as this //
  187. // does some initial error checks and more can be added later. //
  188. ///////////////////////////////////////////////////////////////////////
  189. #define DECLARE_SC_FOR_PUBLIC_INTERFACE(_sc, _func) SC _sc;\
  190. sc.SetFunctionName(_func);\
  191. sc.SetSnapinName(GetSnapinName());\
  192. sc.CheckCallingThreadID();
  193. #define IMPLEMENTS_SNAPIN_NAME_FOR_DEBUG() tstring _szSnapinNameForDebug;\
  194. LPCTSTR GetSnapinName()\
  195. {\
  196. return _szSnapinNameForDebug.data();\
  197. };\
  198. void SetSnapinName(LPCTSTR sz)\
  199. {\
  200. _szSnapinNameForDebug = sz;\
  201. };
  202. #else
  203. #define TraceError ;/##/
  204. #define TraceSnapinError ;/##/
  205. #define DECLARE_SC(_sc, _func) SC _sc;
  206. // This define is used only within the SC class
  207. #define INCREMENT_CALL_DEPTH()
  208. #define DECREMENT_CALL_DEPTH()
  209. #define DECLARE_SC_FOR_PUBLIC_INTERFACE(_sc, _func) SC _sc;
  210. #define IMPLEMENTS_SNAPIN_NAME_FOR_DEBUG()
  211. #endif
  212. //############################################################################
  213. //############################################################################
  214. //
  215. // Parameter validation
  216. //
  217. //############################################################################
  218. //############################################################################
  219. /*+-------------------------------------------------------------------------*
  220. *
  221. * ScCheckPointers
  222. *
  223. * PURPOSE: Checks to make sure that all specified parameters are non-NULL
  224. *
  225. * PARAMETERS:
  226. * const void * pv1 :
  227. *
  228. * RETURNS:
  229. * inline SC: S_OK if no error, E_INVALIDARG if any of the pointers are NULL
  230. *
  231. *
  232. * NOTE: Do not replace with a single function and optional parameters; that
  233. * is inefficient.
  234. *+-------------------------------------------------------------------------*/
  235. inline SC ScCheckPointers(const void * pv1, HRESULT err = E_INVALIDARG)
  236. {
  237. return (NULL == pv1) ? err : S_OK;
  238. }
  239. inline SC ScCheckPointers(const void * pv1, const void *pv2, HRESULT err = E_INVALIDARG)
  240. {
  241. return ( (NULL == pv1) || (NULL == pv2) ) ? err : S_OK;
  242. }
  243. inline SC ScCheckPointers(const void * pv1, const void * pv2, const void * pv3, HRESULT err = E_INVALIDARG)
  244. {
  245. return ( (NULL == pv1) || (NULL == pv2) || (NULL == pv3) ) ? err : S_OK;
  246. }
  247. inline SC ScCheckPointers(const void * pv1, const void * pv2, const void * pv3, const void * pv4, HRESULT err = E_INVALIDARG)
  248. {
  249. return ( (NULL == pv1) || (NULL == pv2) || (NULL == pv3) || (NULL == pv4) ) ? err : S_OK;
  250. }
  251. inline SC ScCheckPointers(const void * pv1, const void * pv2, const void * pv3, const void * pv4, const void * pv5, HRESULT err = E_INVALIDARG)
  252. {
  253. return ( (NULL == pv1) || (NULL == pv2) || (NULL == pv3) || (NULL == pv4) || (NULL == pv5) ) ? err : S_OK;
  254. }
  255. inline SC ScCheckPointers(const void * pv1, const void * pv2, const void * pv3, const void * pv4, const void * pv5, const void* pv6, HRESULT err = E_INVALIDARG)
  256. {
  257. return ( (NULL == pv1) || (NULL == pv2) || (NULL == pv3) || (NULL == pv4) || (NULL == pv5) || (NULL == pv6)) ? err : S_OK;
  258. }
  259. // see "WHY NAMESPACES ?" comment at the top of file
  260. namespace mmcerror {
  261. /*+-------------------------------------------------------------------------*
  262. * SC::SC
  263. *
  264. * Constructor for SC.
  265. *
  266. * Default copy construction and assignment are sufficient. If they are
  267. * ever insufficient, that is a clear indication that this class has become
  268. * heavier than is acceptable for its pervasive pass-by-value usage.
  269. *--------------------------------------------------------------------------*/
  270. inline SC::SC (HRESULT hr /* =S_OK */)
  271. #ifdef DBG
  272. : m_szFunctionName(NULL), m_szSnapinName(NULL)
  273. #endif // DBG
  274. {
  275. /*
  276. * This assert will fail if SC's ever derive from a non-trivial base
  277. * class (i.e. one that has members or virtual functions), or defines
  278. * virtual functions of its own. Don't do that! SC's must remain
  279. * extremely lightweight.
  280. */
  281. COMPILETIME_ASSERT (offsetof (SC, m_facility) == 0);
  282. INCREMENT_CALL_DEPTH();
  283. MakeSc (FACILITY_HRESULT, hr);
  284. }
  285. /*+-------------------------------------------------------------------------*
  286. * SC::operator==
  287. *
  288. *
  289. * PURPOSE: Determines whether two SC's are equivalent.
  290. *
  291. *+-------------------------------------------------------------------------*/
  292. inline bool
  293. SC::operator==(const SC &rhs) const
  294. {
  295. return ( (m_facility == rhs.m_facility) &&
  296. (m_value == rhs.m_value) );
  297. }
  298. inline bool
  299. SC::operator==(HRESULT hr) const
  300. {
  301. return ( (m_facility == FACILITY_HRESULT) &&
  302. (m_value == hr) );
  303. }
  304. inline bool
  305. SC::operator!=(const SC &rhs) const
  306. {
  307. return !operator==( rhs );
  308. }
  309. inline bool
  310. SC::operator!=(HRESULT hr) const
  311. {
  312. return !operator==( hr );
  313. }
  314. // this version compares an hr to an SC.
  315. inline
  316. operator == (HRESULT hr, const SC & sc)
  317. {
  318. return (sc == hr);
  319. }
  320. #ifdef DBG
  321. /*+-------------------------------------------------------------------------*
  322. *
  323. * SC::GetFunctionName
  324. *
  325. * PURPOSE: Sets the debug function name to the supplied string.
  326. *
  327. * PARAMETERS:
  328. *
  329. * RETURNS:
  330. * LPCTSTR The function name.
  331. *
  332. *+-------------------------------------------------------------------------*/
  333. inline LPCTSTR SC::GetFunctionName() const
  334. {
  335. return m_szFunctionName;
  336. }
  337. /*+-------------------------------------------------------------------------*
  338. *
  339. * SC::CheckCallingThreadID
  340. *
  341. * PURPOSE: Check if the method was called on main thread.
  342. *
  343. * PARAMETERS:
  344. *
  345. * RETURNS:
  346. * inline void
  347. *
  348. *+-------------------------------------------------------------------------*/
  349. inline void SC::CheckCallingThreadID()
  350. {
  351. ASSERT(-1 != GetMainThreadID());
  352. if (GetMainThreadID() == ::GetCurrentThreadId())
  353. return;
  354. TraceSnapinError(_T(", method called from wrong thread"), (*this));
  355. return;
  356. }
  357. /*+-------------------------------------------------------------------------*
  358. *
  359. * SC::~SC
  360. *
  361. * PURPOSE: Destructor - Debug mode only. Does a trace if an error occurred.
  362. *
  363. *+-------------------------------------------------------------------------*/
  364. inline SC::~SC()
  365. {
  366. DECREMENT_CALL_DEPTH();
  367. Trace_();
  368. }
  369. #endif // DBG
  370. /*+-------------------------------------------------------------------------*
  371. *
  372. * SC::Trace_()
  373. *
  374. * PURPOSE: Does a trace if an error occurred. Does nothing in release mode
  375. * It is very convenient when we want to register, but ignore the error -
  376. * Simply doing sc.Trace_(); sc.Clear(); does all we need.
  377. *
  378. *+-------------------------------------------------------------------------*/
  379. inline void SC::Trace_() const
  380. {
  381. #ifdef DBG
  382. if (IsError())
  383. {
  384. // Distinguish between snapin error & MMC error using the
  385. // snapin name variable.
  386. if (m_szSnapinName != NULL)
  387. {
  388. TraceSnapinError(_T(""), *this);
  389. }
  390. else if (m_szFunctionName != NULL)
  391. {
  392. TraceError(m_szFunctionName, *this);
  393. }
  394. }
  395. #endif // DBG
  396. }
  397. /*+-------------------------------------------------------------------------*
  398. *
  399. * SC::operator bool
  400. *
  401. * PURPOSE: Returns a value indicating whether the SC holds an error code
  402. *
  403. * PARAMETERS: None
  404. *
  405. * RETURNS:
  406. * bool : true if error, else false
  407. *
  408. *+-------------------------------------------------------------------------*/
  409. inline SC::operator bool() const
  410. {
  411. if(GetCode()==0)
  412. return false; // quick exit if no error
  413. return (GetFacility()==FACILITY_HRESULT) ? FAILED(GetCode()) : true;
  414. }
  415. inline SC::operator !() const
  416. {
  417. return (!operator bool());
  418. }
  419. } // namespace mmcerror
  420. /*+-------------------------------------------------------------------------*
  421. *
  422. * ScFromWin32
  423. *
  424. * PURPOSE: Creates an SC with the facility set to Win32.
  425. *
  426. * PARAMETERS:
  427. * SC::value_type code :
  428. *
  429. * RETURNS:
  430. * inline SC
  431. *
  432. *+-------------------------------------------------------------------------*/
  433. inline SC ScFromWin32(SC::value_type code)
  434. {
  435. SC sc;
  436. sc.FromWin32(code);
  437. return sc;
  438. }
  439. /*+-------------------------------------------------------------------------*
  440. *
  441. * ScFromMMC
  442. *
  443. * PURPOSE: Creates an SC with the facility set to MMC.
  444. *
  445. * PARAMETERS:
  446. * SC::value_type code :
  447. *
  448. * RETURNS:
  449. * inline SC
  450. *
  451. *+-------------------------------------------------------------------------*/
  452. MMCBASE_API inline SC ScFromMMC(SC::value_type code)
  453. {
  454. SC sc;
  455. sc.FromMMC(code);
  456. return sc;
  457. }
  458. /*+-------------------------------------------------------------------------*
  459. *
  460. * HrFromSc
  461. *
  462. * PURPOSE: Converts a status code (SC) to an HRESULT. Use sparingly, as this
  463. * loses information in the conversion.
  464. *
  465. * PARAMETERS:
  466. * SC &sc: The SC to convert
  467. *
  468. * RETURNS:
  469. * inline HRESULT: The converted value.
  470. *
  471. *+-------------------------------------------------------------------------*/
  472. MMCBASE_API inline HRESULT HrFromSc(const SC &sc)
  473. {
  474. return sc.ToHr();
  475. }
  476. /*+-------------------------------------------------------------------------*
  477. *
  478. * SCODEFromSc
  479. *
  480. * PURPOSE: Converts a status code (SC) to an SCODE. Use sparingly, as this
  481. * loses information in the conversion.
  482. * On 32bit machine SCODE is same as HRESULT.
  483. *
  484. * PARAMETERS:
  485. * SC &sc: The SC to convert
  486. *
  487. * RETURNS:
  488. * inline SCODE: The converted value.
  489. *
  490. *+-------------------------------------------------------------------------*/
  491. MMCBASE_API inline SCODE SCODEFromSc(const SC &sc)
  492. {
  493. return (SCODE)sc.ToHr();
  494. }
  495. #endif //_MMCERROR_H