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
16 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1996-2000 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // ExcOper.cpp
  7. //
  8. // Abstract:
  9. // Implementation of exception classes.
  10. //
  11. // Author:
  12. // David Potter (davidp) May 20, 1996
  13. //
  14. // Revision History:
  15. //
  16. // Notes:
  17. // TraceTag.h and resource.h are pulled from the project directory.
  18. //
  19. // stdafx.h must disable some W4 warnings.
  20. //
  21. // TraceTag.h must define TraceError.
  22. //
  23. // resource.h must define IDS_ERROR_MSG_ID, and the string must be
  24. // defined something like "\n\nError ID: %d (%08.8x)." in the resource file.
  25. //
  26. // IDP_NO_ERROR_AVAILABLE must defined as a string for displaying when
  27. // no error code is available.
  28. //
  29. // EXC_AppMessageBox(LPCTSTR...) and EXC_AppMessageBox(UINT...) must be
  30. // defined and implemented.
  31. //
  32. // EXC_GetResourceInstance must be defined and implemented to return the
  33. // resource instance handle of the application or DLL.
  34. //
  35. /////////////////////////////////////////////////////////////////////////////
  36. #include <string.h>
  37. #include "ExcOper.h"
  38. #include "TraceTag.h"
  39. #include "resource.h"
  40. #ifdef _DEBUG
  41. #define new DEBUG_NEW
  42. #undef THIS_FILE
  43. static char THIS_FILE[] = __FILE__;
  44. #endif
  45. /////////////////////////////////////////////////////////////////////////////
  46. // class CException
  47. /////////////////////////////////////////////////////////////////////////////
  48. #ifndef __AFX_H__
  49. /////////////////////////////////////////////////////////////////////////////
  50. //++
  51. //
  52. // CException::ReportError
  53. //
  54. // Routine Description:
  55. // Report an error from the exception. Overriding to get a bigger
  56. // error message buffer.
  57. //
  58. // Arguments:
  59. // nType [IN] Type of message box.
  60. // nError [IN] ID of a mesage to display if exception has no message.
  61. //
  62. // Return Value:
  63. // Return value from MessageBox.
  64. //
  65. //--
  66. /////////////////////////////////////////////////////////////////////////////
  67. int CException::ReportError( UINT nType /* = MB_OK */, UINT nError /* = 0 */ )
  68. {
  69. TCHAR szErrorMessage[128];
  70. int nDisposition;
  71. UINT nHelpContext;
  72. if ( GetErrorMessage(szErrorMessage, sizeof( szErrorMessage ) / sizeof( TCHAR ), &nHelpContext ) )
  73. {
  74. nDisposition = EXC_AppMessageBox( szErrorMessage, nType, nHelpContext );
  75. } // if: error message retrieved successfully
  76. else
  77. {
  78. if ( nError == 0 )
  79. {
  80. nError = IDP_NO_ERROR_AVAILABLE;
  81. } // if: no error code
  82. nDisposition = EXC_AppMessageBox( nError, nType, nHelpContext );
  83. } // else: error retrieving error message
  84. return nDisposition;
  85. } //*** CException::ReportError()
  86. #endif // __AFX_H__
  87. /////////////////////////////////////////////////////////////////////////////
  88. // class CExceptionWithOper
  89. /////////////////////////////////////////////////////////////////////////////
  90. #ifdef __AFX_H__
  91. IMPLEMENT_DYNAMIC(CExceptionWithOper, CException)
  92. #endif // __AFX_H__
  93. /////////////////////////////////////////////////////////////////////////////
  94. //++
  95. //
  96. // CExceptionWithOper::ReportError
  97. //
  98. // Routine Description:
  99. // Report an error from the exception. Overriding to get a bigger
  100. // error message buffer.
  101. //
  102. // Arguments:
  103. // nType [IN] Type of message box.
  104. // nError [IN] ID of a mesage to display if exception has no message.
  105. //
  106. // Return Value:
  107. // Return value from MessageBox.
  108. //
  109. //--
  110. /////////////////////////////////////////////////////////////////////////////
  111. int CExceptionWithOper::ReportError(
  112. UINT nType /* = MB_OK */,
  113. UINT nError /* = 0 */
  114. )
  115. {
  116. TCHAR szErrorMessage[EXCEPT_MAX_OPER_ARG_LENGTH * 3];
  117. int nDisposition;
  118. UINT nHelpContext;
  119. if ( GetErrorMessage( szErrorMessage, sizeof( szErrorMessage ) / sizeof( TCHAR ), &nHelpContext ) )
  120. {
  121. nDisposition = EXC_AppMessageBox( szErrorMessage, nType, nHelpContext );
  122. } // if: error message retrieved successfully
  123. else
  124. {
  125. if ( nError == 0 )
  126. {
  127. nError = IDP_NO_ERROR_AVAILABLE;
  128. } // if: no error code
  129. nDisposition = EXC_AppMessageBox( nError, nType, nHelpContext );
  130. } // else: error retrieving error message
  131. return nDisposition;
  132. } //*** CExceptionWithOper::ReportError()
  133. /////////////////////////////////////////////////////////////////////////////
  134. //++
  135. //
  136. // CExceptionWithOper::ReportError
  137. //
  138. // Routine Description:
  139. // Report an error from the exception. This method should be used from
  140. // all threads except the main thread.
  141. //
  142. // Arguments:
  143. // pfnMsgBox [IN] Message box function pointer.
  144. // dwParam [IN] Parameter to pass to the message box function.
  145. // nType [IN] Type of message box.
  146. // nError [IN] ID of a mesage to display if exception has no message.
  147. //
  148. // Return Value:
  149. // Return value from MessageBox.
  150. //
  151. //--
  152. /////////////////////////////////////////////////////////////////////////////
  153. int CExceptionWithOper::ReportError(
  154. PFNMSGBOX pfnMsgBox,
  155. DWORD dwParam,
  156. UINT nType /* = MB_OK */,
  157. UINT nError /* = 0 */
  158. )
  159. {
  160. TCHAR szErrorMessage[EXCEPT_MAX_OPER_ARG_LENGTH * 3];
  161. int nDisposition;
  162. UINT nHelpContext;
  163. ASSERT( pfnMsgBox != NULL );
  164. if ( GetErrorMessage( szErrorMessage, sizeof( szErrorMessage ) / sizeof( TCHAR ), &nHelpContext ) )
  165. {
  166. nDisposition = (*pfnMsgBox)( dwParam, szErrorMessage, nType, nHelpContext );
  167. } // if: error message retrieved successfully
  168. else
  169. {
  170. if ( nError == 0 )
  171. {
  172. nError = IDP_NO_ERROR_AVAILABLE;
  173. } // if: no error code
  174. CString strMsg;
  175. strMsg.LoadString( nError );
  176. nDisposition = (*pfnMsgBox)( dwParam, strMsg, nType, nHelpContext );
  177. } // else: error retrieving error message
  178. return nDisposition;
  179. } //*** CExceptionWithOper::ReportError( pfnMsgBox )
  180. /////////////////////////////////////////////////////////////////////////////
  181. //++
  182. //
  183. // CExceptionWithOper::ReportError
  184. //
  185. // Routine Description:
  186. // Report an error from the exception. This method should be used from
  187. // all threads except the main thread.
  188. //
  189. // Arguments:
  190. // hwndParent [IN] Parent window.
  191. // nType [IN] Type of message box.
  192. // nError [IN] ID of a mesage to display if exception has no message.
  193. //
  194. // Return Value:
  195. // Return value from MessageBox.
  196. //
  197. //--
  198. /////////////////////////////////////////////////////////////////////////////
  199. int CExceptionWithOper::ReportError(
  200. HWND hwndParent,
  201. UINT nType /* = MB_OK */,
  202. UINT nError /* = 0 */
  203. )
  204. {
  205. ASSERT(hwndParent != NULL);
  206. TCHAR szErrorMessage[EXCEPT_MAX_OPER_ARG_LENGTH * 3];
  207. int nDisposition;
  208. UINT nHelpContext;
  209. if ( GetErrorMessage( szErrorMessage, sizeof( szErrorMessage ) / sizeof( TCHAR ), &nHelpContext ) )
  210. {
  211. nDisposition = EXC_AppMessageBox( hwndParent, szErrorMessage, nType, nHelpContext );
  212. } // if: error message retrieved successfully
  213. else
  214. {
  215. if ( nError == 0 )
  216. {
  217. nError = IDP_NO_ERROR_AVAILABLE;
  218. } // if: no error code
  219. CString strMsg;
  220. strMsg.LoadString( nError );
  221. nDisposition = EXC_AppMessageBox( hwndParent, szErrorMessage, nType, nHelpContext );
  222. } // else: error retrieving error message
  223. return nDisposition;
  224. } //*** CExceptionWithOper::ReportError( pfnMsgBox )
  225. /////////////////////////////////////////////////////////////////////////////
  226. //++
  227. //
  228. // CExceptionWithOper::SetOperation
  229. //
  230. // Routine Description:
  231. // Constructor.
  232. //
  233. // Arguments:
  234. // idsOperation [IN] String ID for operation occurring during exception.
  235. // pszOperArg1 [IN] 1st argument to operation string.
  236. // pszOperArg2 [IN] 2nd argument to operation string.
  237. //
  238. // Return Value:
  239. // None.
  240. //
  241. //--
  242. /////////////////////////////////////////////////////////////////////////////
  243. void CExceptionWithOper::SetOperation(
  244. IN UINT idsOperation,
  245. IN LPCTSTR pszOperArg1,
  246. IN LPCTSTR pszOperArg2
  247. )
  248. {
  249. m_idsOperation = idsOperation;
  250. if ( pszOperArg1 == NULL )
  251. {
  252. m_szOperArg1[0] = _T('\0');
  253. } // if: first argument not specified
  254. else
  255. {
  256. ::_tcsncpy( m_szOperArg1, pszOperArg1, (sizeof( m_szOperArg1 ) / sizeof( TCHAR )) - 1 );
  257. m_szOperArg1[(sizeof( m_szOperArg1 ) / sizeof( TCHAR ))- 1] = _T('\0');
  258. } // else: first argument specified
  259. if ( pszOperArg2 == NULL )
  260. {
  261. m_szOperArg2[0] = _T('\0');
  262. } // if: second argument not specified
  263. else
  264. {
  265. ::_tcsncpy( m_szOperArg2, pszOperArg2, (sizeof( m_szOperArg2 ) / sizeof( TCHAR )) - 1 );
  266. m_szOperArg2[(sizeof( m_szOperArg2 ) / sizeof( TCHAR )) - 1] = _T('\0');
  267. } // else: second argument specified
  268. } //*** CExceptionWithOper::SetOperation()
  269. /////////////////////////////////////////////////////////////////////////////
  270. //++
  271. //
  272. // CExceptionWithOper::FormatWithOperation
  273. //
  274. // Routine Description:
  275. // Get the error message represented by the exception.
  276. //
  277. // Arguments:
  278. // lpszError [OUT] String in which to return the error message.
  279. // nMaxError [IN] Maximum length of the output string.
  280. // pszMsg [IN] Message to format with the operation string.
  281. //
  282. // Return Value:
  283. // None.
  284. //
  285. //--
  286. /////////////////////////////////////////////////////////////////////////////
  287. void CExceptionWithOper::FormatWithOperation(
  288. OUT LPTSTR lpszError,
  289. IN UINT nMaxError,
  290. IN LPCTSTR pszMsg
  291. )
  292. {
  293. DWORD dwResult;
  294. TCHAR szOperation[EXCEPT_MAX_OPER_ARG_LENGTH];
  295. TCHAR szFmtOperation[EXCEPT_MAX_OPER_ARG_LENGTH * 3];
  296. ASSERT( lpszError != NULL );
  297. ASSERT( nMaxError > 0 );
  298. // Format the operation string.
  299. if ( m_idsOperation )
  300. {
  301. void * rgpvArgs[2] = { m_szOperArg1, m_szOperArg2 };
  302. // Load the operation string.
  303. dwResult = ::LoadString( EXC_GetResourceInstance(), m_idsOperation, szOperation, (sizeof( szOperation ) / sizeof( TCHAR )) );
  304. ASSERT( dwResult != 0 );
  305. // Format the operation string.
  306. ::FormatMessage(
  307. FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  308. szOperation,
  309. 0,
  310. MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ),
  311. szFmtOperation,
  312. sizeof( szFmtOperation ) / sizeof( TCHAR ),
  313. (va_list *) rgpvArgs
  314. );
  315. szFmtOperation[(sizeof( szFmtOperation ) / sizeof( TCHAR )) - 1] = _T('\0');
  316. // Format the final error message.
  317. if ( pszMsg != NULL )
  318. {
  319. ::_sntprintf( lpszError, nMaxError - 1, _T("%s\n\n%s"), szFmtOperation, pszMsg );
  320. } // if: additional message specified
  321. else
  322. {
  323. ::_tcsncpy(lpszError, szFmtOperation, nMaxError - 1);
  324. } // else: no additional message specified
  325. lpszError[nMaxError - 1] = _T('\0');
  326. } // if: operation string specified
  327. else
  328. {
  329. if ( pszMsg != NULL )
  330. {
  331. ::_tcsncpy( lpszError, pszMsg, nMaxError - 1 );
  332. lpszError[nMaxError - 1] = _T('\0');
  333. } // if: additional message specified
  334. else
  335. {
  336. lpszError[0] = _T('\0');
  337. } // if: no additional message specified
  338. } // else: no operation string specified
  339. } //*** CExceptionWithOper::FormatWithOperation()
  340. //***************************************************************************
  341. /////////////////////////////////////////////////////////////////////////////
  342. // class CNTException
  343. /////////////////////////////////////////////////////////////////////////////
  344. #ifdef __AFX_H__
  345. IMPLEMENT_DYNAMIC( CNTException, CExceptionWithOper )
  346. #endif // __AFX_H__
  347. /////////////////////////////////////////////////////////////////////////////
  348. //++
  349. //
  350. // CNTException::FormatErrorMessage
  351. //
  352. // Routine Description:
  353. // Format the error message represented by the exception.
  354. //
  355. // Arguments:
  356. // lpszError [OUT] String in which to return the error message.
  357. // nMaxError [IN] Maximum length of the output string.
  358. // pnHelpContext [OUT] Help context for the error message.
  359. // bIncludeID [IN] Include the ID in the message.
  360. //
  361. // Return Value:
  362. // TRUE Message available.
  363. // FALSE No message available.
  364. //
  365. //--
  366. /////////////////////////////////////////////////////////////////////////////
  367. BOOL CNTException::FormatErrorMessage(
  368. LPTSTR lpszError,
  369. UINT nMaxError,
  370. PUINT pnHelpContext,
  371. BOOL bIncludeID
  372. )
  373. {
  374. DWORD dwResult;
  375. TCHAR szNtMsg[1024];
  376. // Format the NT status code.
  377. ::FormatErrorMessage( m_sc, szNtMsg, sizeof( szNtMsg ) / sizeof( TCHAR ) );
  378. // Format the message with the operation string.
  379. FormatWithOperation( lpszError, nMaxError, szNtMsg );
  380. // Add the error ID.
  381. if ( bIncludeID )
  382. {
  383. UINT nMsgLength = _tcslen( lpszError );
  384. TCHAR szErrorFmt[EXCEPT_MAX_OPER_ARG_LENGTH];
  385. if ( nMsgLength - 1 < nMaxError )
  386. {
  387. dwResult = ::LoadString( EXC_GetResourceInstance(), IDS_ERROR_MSG_ID, szErrorFmt, (sizeof( szErrorFmt ) / sizeof( TCHAR )) );
  388. ASSERT( dwResult != 0 );
  389. ::_sntprintf( &lpszError[nMsgLength], nMaxError - nMsgLength - 1, szErrorFmt, m_sc, m_sc );
  390. } // if: there is room for the error ID
  391. } // if: error ID should be included
  392. return TRUE;
  393. } //*** CNTException::FormatErrorMessage()
  394. //***************************************************************************
  395. /////////////////////////////////////////////////////////////////////////////
  396. // Global Functions
  397. /////////////////////////////////////////////////////////////////////////////
  398. static CNTException gs_nte( ERROR_SUCCESS, NULL, NULL, NULL, FALSE );
  399. static CExceptionWithOper gs_ewo( NULL, NULL, NULL, FALSE );
  400. /////////////////////////////////////////////////////////////////////////////
  401. //++
  402. //
  403. // ThrowStaticException
  404. //
  405. // Purpose:
  406. // Throw the static NT Exception.
  407. //
  408. // Arguments:
  409. // sc [IN] NT status code.
  410. // idsOperation [IN] String ID for operation occurring during exception.
  411. // pszOperArg1 [IN] 1st argument to operation string.
  412. // pszOperArg2 [IN] 2nd argument to operation string.
  413. //
  414. // Returns:
  415. // None.
  416. //
  417. //--
  418. /////////////////////////////////////////////////////////////////////////////
  419. void ThrowStaticException(
  420. IN SC sc,
  421. IN UINT idsOperation,
  422. IN LPCTSTR pszOperArg1,
  423. IN LPCTSTR pszOperArg2
  424. )
  425. {
  426. gs_nte.SetOperation( sc, idsOperation, pszOperArg1, pszOperArg2 );
  427. TraceError( gs_nte );
  428. throw &gs_nte;
  429. } //*** ThrowStaticException()
  430. /////////////////////////////////////////////////////////////////////////////
  431. //++
  432. //
  433. // ThrowStaticException
  434. //
  435. // Purpose:
  436. // Throw the static Cluster Administrator Exception.
  437. //
  438. // Arguments:
  439. // idsOperation [IN] String ID for operation occurring during exception.
  440. // pszOperArg1 [IN] 1st argument to operation string.
  441. // pszOperArg2 [IN] 2nd argument to operation string.
  442. //
  443. // Returns:
  444. // None.
  445. //
  446. //--
  447. /////////////////////////////////////////////////////////////////////////////
  448. void ThrowStaticException(
  449. IN UINT idsOperation,
  450. IN LPCTSTR pszOperArg1,
  451. IN LPCTSTR pszOperArg2
  452. )
  453. {
  454. gs_ewo.SetOperation( idsOperation, pszOperArg1, pszOperArg2 );
  455. TraceError( gs_ewo );
  456. throw &gs_ewo;
  457. } //*** ThrowStaticException()
  458. /////////////////////////////////////////////////////////////////////////////
  459. //++
  460. //
  461. // FormatErrorMessage
  462. //
  463. // Routine Description:
  464. // Format the error message represented by the exception.
  465. //
  466. // Arguments:
  467. // sc [IN] Status code.
  468. // lpszError [OUT] String in which to return the error message.
  469. // nMaxError [IN] Maximum length of the output string.
  470. //
  471. // Return Value:
  472. // TRUE Message available.
  473. // FALSE No message available.
  474. //
  475. //--
  476. /////////////////////////////////////////////////////////////////////////////
  477. BOOL FormatErrorMessage(
  478. DWORD sc,
  479. LPTSTR lpszError,
  480. UINT nMaxError
  481. )
  482. {
  483. DWORD _cch;
  484. // Format the NT status code from the system.
  485. _cch = FormatMessage(
  486. FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  487. NULL,
  488. sc,
  489. MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ),
  490. lpszError,
  491. nMaxError,
  492. 0
  493. );
  494. if ( _cch == 0 )
  495. {
  496. Trace( g_tagError, _T("Error %d getting message from system for error code %d"), GetLastError(), sc );
  497. // Format the NT status code from NTDLL since this hasn't been
  498. // integrated into the system yet.
  499. _cch = FormatMessage(
  500. FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS,
  501. GetModuleHandle( _T("NTDLL.DLL") ),
  502. sc,
  503. MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ),
  504. lpszError,
  505. nMaxError,
  506. 0
  507. );
  508. if ( _cch == 0 )
  509. {
  510. #ifdef _DEBUG
  511. DWORD _sc = GetLastError();
  512. _sc=_sc;
  513. Trace( g_tagError, _T("Error %d getting message from NTDLL.DLL for error code %d"), _sc, sc );
  514. #endif
  515. lpszError[0] = _T('\0');
  516. } // if: error formatting status code from NTDLL
  517. } // if: error formatting status code from system
  518. return TRUE;
  519. } //*** FormatErrorMessage()