//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1991 - 1992. // // File: ciexcpt.hxx // // Contents: Macro package for C++ exception support // // Classes: CException -- The base for all exception classes // CExceptionContext -- Per-thread exception context. // CUnwindable -- Classes with destructors inherit // from this. // CTry -- Per/TRY state. // // Functions: Macros to implement TRY ... CATCH // Macros to implement unwind for classes with destructors // // History: 22-May-91 KyleP Created Interface. // 15-Aug-91 SethuR modified THROW,CATCH,AND_CATCH, // END_CATCH macros // 18-Oct-91 KyleP Win32 try/except implementation // 20-Feb-92 KyleP Fixed destruction of classes with // virtual methods. // 03-Aug-92 KyleP Kernel implementation // 13-Nov-92 KyleP Bugfix destruction of heap classes. // Added assertion checking. // 27-May-93 Mackm Added definitions for un-exceptional // operator new. // 01-Jun-93 RobBear Added definitions for alloc hooking // 30-Sep-93 KyleP DEVL obsolete // 14-Dec-93 AlexT Add NOEXCEPTIONS support // 25-Apr-95 DwightKr Native C++ exception support // 11-Map-95 DwightKr Add autocheck support // //---------------------------------------------------------------------------- #pragma warning(4:4509) // SEH used in function w/ _trycontext #pragma warning(4:4535) // _set_se_translator used w/o /EHa #pragma once #include const int maxExceptionSize = 256; #define DEB_UNWIND 0x10000 // // If EXCEPT_TEST is defined, then the exception code can be compiled // without use the the 'Win4 environment'. This is only to facilitate // testing. When EXCEPT_TEST is defined debug messages are printed // to stdout instead of the debug terminal. // // // REAL CODE -- REAL CODE -- REAL CODE -- REAL CODE // #ifndef EXCEPT_TEST # if (DBG == 1 || CIDBG == 1) // // VERY UNUSUAL SITUATION: // Out xxxDebugOut macros are designed to be inline. This causes // a problem in exceptions because the _xxxInfoLevel flag which // determines if a message should be printed is not declared in // every DLL. So. Instead of calling the macro: // // DECLARE_DEBUG(ex) // // I will: void exInlineDebugOut2(unsigned long fDebugMask, char const *pszfmt, ...); // and then export this function from OSM.DLL (or whatever DLL // exports exception handling. // # define exDebugOut( x ) exInlineDebugOut2 x # define exAssert( x ) Win4Assert( x ) # else // DBG == 0 && CIDBG == 0 # define exDebugOut( x ) # define exAssert( x ) # endif // // TEST ONLY -- TEST ONLY -- TEST ONLY -- TEST ONLY // #else // EXCEPT_TEST typedef unsigned long ULONG; typedef unsigned char BYTE; # define TRUE 1 # include # define exAssert( x ) assert( (x) ) # include inline void exInlineDebugOut( ULONG, char * msg, ... ) { va_list arglist; va_start(arglist, msg); vfprintf(stderr, msg, arglist); } # define exDebugOut( x ) exInlineDebugOut x # define _PopUpError( p1, p2, p3 ) 0xFFFFFFFF # define Win4ExceptionLevel 0xFFFFFFFF # define EXCEPT_MESSAGE 0x1 # define EXCEPT_POPUP 0x0 # define EXCEPT_BREAK 0x0 # define DEB_FORCE 0x0 # define DEB_WARN 0x0 # define DEB_ERROR 0x0 # define DEB_ITRACE 0x0 #endif // EXCEPT_TEST // // END TEST -- END TEST -- END TEST -- END TEST // //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- // // Various operator new implementations // //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- int APINOT LeakCheck ( ULONG* pCount ); BOOL ExceptDllMain( HANDLE hDll, DWORD dwReason, LPVOID lpReserved ); void* ciNew( size_t size ); __forceinline void * __cdecl operator new ( size_t size ) { void * p = ciNew( size ); // ciNew Throws -- tell the compiler about it so it doesn't generate a // check for 0. __assume( p ); return p; } BOOL ciIsValidPointer( const void * p ); void ciDelete( void * p ); // // We MUST force this to be inlined - o/w, a call to delete is made which // leads to collision in the new/delete operators. // static inline void __cdecl operator delete ( void * p ) { ciDelete( p ); } #if DBG==1 || CIDBG == 1 typedef BOOL (* ALLOC_HOOK)(size_t nSize); EXPORTDEF ALLOC_HOOK MemSetAllocHook( ALLOC_HOOK pfnAllocHook ); #endif // DBG == 1 || CIDBG == 1 // // The default is to print exception messages to debug terminal. // #if DBG == 1 || CIDBG == 1 extern "C" ULONG GetWin4ExceptionLevel(void); #endif // DBG == 1 || CIDBG == 1 //+--------------------------------------------------------------------------- //---------------------------------------------------------------------------- // // Function prototypes to be used in all implemenations (user & kernel; // native C++ exceptions & C++ exception macros) are defined here. // //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void APINOT ExceptionReport( unsigned int iLine, char *szFile, char *szMsg, long lError = long(-1) ); //+--------------------------------------------------------------------------- //---------------------------------------------------------------------------- // // Code to support native C++ exceptions in user & kernel start here. // Macros to support C++ exceptions flllow below. Native C++ exception // support is used if NATIVE_EH is defined. // //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #if defined(NATIVE_EH) void _cdecl SystemExceptionTranslator( unsigned int uiWhat, struct _EXCEPTION_POINTERS * pexcept ); #define TRANSLATE_EXCEPTIONS _se_translator_function __tf = _set_se_translator( SystemExceptionTranslator ); #define UNTRANSLATE_EXCEPTIONS _set_se_translator( __tf ); class CTranslateSystemExceptions { public: CTranslateSystemExceptions() { _tf = _set_se_translator( SystemExceptionTranslator ); } ~CTranslateSystemExceptions() { _set_se_translator( _tf ); } private: _se_translator_function _tf; }; class CException { public: CException(long lError) : _lError(lError), _dbgInfo(0) {} CException(); long GetErrorCode() { return _lError;} void SetInfo(unsigned dbgInfo) { _dbgInfo = dbgInfo; } unsigned long GetInfo(void) const { return _dbgInfo; } protected: long _lError; unsigned long _dbgInfo; }; //+--------------------------------------------------------------------------- // // Class: CCiNullClass // // Purpose: An empty class to satisfy the macros. // //---------------------------------------------------------------------------- class CCiNullClass { }; SCODE APINOT GetOleError(CException & e); SCODE APINOT GetScodeError(CException & e); #define INHERIT_UNWIND public CCiNullClass #define INHERIT_VIRTUAL_UNWIND public CCiNullClass #define DECLARE_UNWIND #define IMPLEMENT_UNWIND(class) #define END_CONSTRUCTION(class) #define INLINE_UNWIND(class) #define INLINE_TEMPL_UNWIND(class1, class2) #undef try #undef catch #define TRY try # if DBG == 1 || CIDBG == 1 //+--------------------------------------------------------------------------- // // Macro: THROW - throw a CException // QUIETTHROW - throws a CException without an exception report // // Synopsis: Throws an exception // debug, kernel & user // // History: 29-Mar-95 DwightKr Created. // //---------------------------------------------------------------------------- template inline void doThrowTempl ( unsigned int iLine, char * pszFile, int fVerbose, T & e ) { if ( fVerbose ) e.SetInfo( GetWin4ExceptionLevel() | EXCEPT_VERBOSE ); else e.SetInfo( GetWin4ExceptionLevel() & ~EXCEPT_VERBOSE ); if ( e.GetInfo() & EXCEPT_VERBOSE) ExceptionReport( iLine, pszFile, "Throwing Exception", e.GetErrorCode() ); throw e; } #define THROW( e ) \ { \ doThrowTempl( __LINE__, \ __FILE__, \ 1, \ e ); \ } #define QUIETTHROW( e ) \ { \ doThrowTempl( __LINE__, \ __FILE__, \ 0, \ e ); \ } //+--------------------------------------------------------------------------- // // Macro: RETHROW // // Synopsis: Rethrows an exception // debug, kernel & user // // History: 29-Mar-95 DwightKr Created. // //---------------------------------------------------------------------------- #define RETHROW() \ { \ if ( e.GetInfo() & EXCEPT_VERBOSE ) \ ExceptionReport( __LINE__, \ __FILE__, \ "Rethrowing Exception", \ e.GetErrorCode() ); \ throw; \ } //+--------------------------------------------------------------------------- // // Macro: CATCH // // Synopsis: catches an exception // debug, kernel & user // // History: 29-Mar-95 DwightKr Created. // //---------------------------------------------------------------------------- #define CATCH(class,e) catch( class & e ) \ { \ if ( e.GetInfo() & EXCEPT_VERBOSE) \ ExceptionReport( __LINE__, \ __FILE__, \ "Catching Exception", \ e.GetErrorCode() ); //+--------------------------------------------------------------------------- // // Macro: AND_CATCH // // Synopsis: catches an exception // debug, kernel & user // // History: 29-Mar-95 DwightKr Created. // //---------------------------------------------------------------------------- #define AND_CATCH(class,e) } CATCH(class, e) //+--------------------------------------------------------------------------- // // Macro: END_CATCH // // Synopsis: end of a try\catch block // debug, user & kernel // // History: 29-Mar-95 DwightKr Created. // //---------------------------------------------------------------------------- #define END_CATCH } # else // DBG == 0 && CIDBG == 0 //+--------------------------------------------------------------------------- // // Macro: THROW // // Synopsis: Throws an exception // retail, user & kernel // // History: 29-Mar-95 DwightKr Created. // //---------------------------------------------------------------------------- # define THROW(e) \ throw e; //+--------------------------------------------------------------------------- // // Macro: QUIETTHROW // // Synopsis: Throws an exception // retail, user & kernel // // History: 29-Mar-95 DwightKr Created. // //---------------------------------------------------------------------------- # define QUIETTHROW(e) \ throw e; //+--------------------------------------------------------------------------- // // Macro: RETHROW // // Synopsis: Rethrows an exception // retail, user & kernel // // History: 29-Mar-95 DwightKr Created. // //---------------------------------------------------------------------------- # define RETHROW() \ throw; //+--------------------------------------------------------------------------- // // Macro: CATCH // // Synopsis: catches an exception // retail, user & kernel // // History: 29-Mar-95 DwightKr Created. // //---------------------------------------------------------------------------- #define CATCH(class,e) catch( class & e ) //+--------------------------------------------------------------------------- // // Macro: AND_CATCH // // Synopsis: catches an exception // retail, user & kernel // // History: 29-Mar-95 DwightKr Created. // //---------------------------------------------------------------------------- #define AND_CATCH(class,e) catch( class & e ) //+--------------------------------------------------------------------------- // // Macro: CATCH_ALL // // Synopsis: catches all exceptions // retail, user & kernel // // History: 29-Mar-95 DwightKr Created. // //---------------------------------------------------------------------------- #define CATCH_ALL catch( ... ) //+--------------------------------------------------------------------------- // // Macro: END_CATCH // // Synopsis: end of a try\catch block // retail, user & kernel // // History: 29-Mar-95 DwightKr Created. // //---------------------------------------------------------------------------- #define END_CATCH # endif // DBG == 0 && CIDBG == 0 #else // #if defined(NATIVE_EH) #define TRANSLATE_EXCEPTIONS #define UNTRANSLATE_EXCEPTIONS //------------------------------------------------------------------ //------------------------------------------------------------------ // // Support for compilers which do NOT support native C++ exceptions // exists after this point. // //------------------------------------------------------------------ //------------------------------------------------------------------ #define EXCEPT_VULCAN 0xE0000001 typedef void(*PFV)(); extern void terminate(); extern void unexpected(); extern PFV set_terminate(PFV terminate_fn); extern PFV set_unexpected(PFV unexpected_fn); //+--------------------------------------------------------------------------- // // Class: CException // // Purpose: All exception objects (e.g. objects that are THROW) // inherit from CException. // // Interface: ~CException - Destructor // IsKindOf - Class membership query // // History: 22-May-91 KyleP Created. // // Notes: This class is a hack, until C7 can provide some support // for runtime inheritance detection (e.g. a way to generate // a mangled name). When we get this support a new // implementation of IsKindOf should be developed. The concept, // however, would remain the same: C++ exception objects are // instances of an exception class, but they are caught by class. // // A compiler can implement IsKindOf by throwing a // decorated name which uniquely identifies a class and // describes its inheritance. // // Don't do anything too fancy with subclasses of CException. // Instances of your subclass are memcpy-ed around. Having // a user defined destructor, for example, is probably a bad // idea. // // WARNING: There is an implemtation of this class in the C-runtime // package. Don't add functions to this class as they will not // exist in the native C++ support. This class exists to // support those C++ compilers which do not support native C++ // exceptions. // //---------------------------------------------------------------------------- class CException { public: EXPORTDEF CException(long lError); CException(); long GetErrorCode() { return _lError;} EXPORTDEF virtual int WINAPI IsKindOf(const char * szClass) const; void SetInfo(unsigned dbgInfo) { _dbgInfo = dbgInfo; } unsigned long GetInfo(void) const { return _dbgInfo; } #if DBG == 1 || CIDBG == 1 EXPORTDEF virtual void WINAPI Report(unsigned int iLine,char *szFile,char *szMsg); #endif // DBG == 1 || CIDBG == 1 protected: long _lError; unsigned long _dbgInfo; }; //+--------------------------------------------------------------------------- // // Class: CExceptionContext // // Purpose: Per-thread exception state and throw exception methods. // // Interface: CExceptionContext -- Constructor // ~CExceptionContext -- Destructor // Push -- Push a new element on the stack of // elements-to-be-destroyed. // Pop -- Pop an an element off the stack. // SetTop -- Set the top of stack to the specified // element. // GetTop -- Return the top element. // Throw -- Throw an exception // // History: 19-Nov-91 KyleP Fix heap unwind, multiple inheritance // 22-May-91 KyleP Created. // // Notes: There is only 1 CExceptionContext object per thread. // //---------------------------------------------------------------------------- class CTry; class CExceptionContextPool; class CExceptionContext { public: CExceptionContext(); ~CExceptionContext(); EXPORTDEF void WINAPI Reserve(void * pthis); inline void Pop(void * pthis); EXPORTDEF void WINAPI SetTop(void * pthis, ULONG cbElement, void (* pfn)(void *)); inline int GetTop(); void Unwind( CTry * ptry ); // // _pTopTry contains the head of a linked list of CTry objects, // each of which corresponds to a TRY clause. // CTry * _pTopTry; // // _pLastNew records the address of the most recent free // store allocation, _cbLastNew the size. // BYTE * _pLastNew; int _cbLastNew; int _fNewReadyForUnwind; // // _exception contains a pointer to the current exception, // if any. The character buffer following it is for storing // additional data belonging to subclasses. // CException _exception; char buffer[maxExceptionSize]; private: // // Each StackElement contains enough information to destroy a // completly constructed object, and the determine whether // objects which have not yet been fully constructed were // allocated on the heap or the stack. // class StackElement { public: BOOL IsThisEqual( void * pthis ) { return( pthis == _pthis ); } BOOL IsSizeEqual( ULONG cb ) { return( cb == _cbElement ); } BOOL IsOnStack() { return( _cbElement == 0 ); } BOOL IsOnHeap() { return( _cbElement != 0 ); } BOOL IsActive() { return( _pfn != 0 ); } void SetOnStack() { _cbElement = 0; } void SetOnHeap( ULONG size ) { _cbElement = size; } void SetThis( void * pthis ) { _pthis = pthis; } void SetDtor( void (* pfn)(void *) ) { _pfn = pfn; } void * GetDtor() { return( _pfn ); } void * GetThis() { return( _pthis ); } void Destroy() { _pfn( (BYTE *)_pthis ); } void Delete() { delete (BYTE *)_pthis; } private: void * _pthis; // This for CUnwindable void (* _pfn)(void *); // 'Static destructor' ULONG _cbElement; // 0 == On stack. > 0 = Size of class }; // // _aStack is the stack of objects-to-be-destroyed in the face // of an exception (stack unwind). // StackElement * _aStack; // // _StackTop is the index of the first free element on the stack. // int _StackTop; // // _StackSize is the maximum number of elements which can be // stored on the stack. // int _StackSize; EXPORTDEF void APINOT _Grow(); }; //+--------------------------------------------------------------------------- // // Member: CExceptionContext::Pop, public // // Synopsis: Pops the top element off the stack of objects to be destroyed. // // Effects: Pop only has an effect if the top element on the stack // is for [pthis]. // // Arguments: [pthis] -- Must correspond to the top of stack if the // element is to be popped. // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- inline void CExceptionContext::Pop(void * pthis) { // // Remove the top of stack only if it corresponds to pthis. // Thus the element will be removed only if this object was // declared on the stack (as opposed to embedded) and no // exception was encountered. // // // You should *always* find what you're looking for. No checking // for runoff. The very bottom element of the stack is a sentinel // for the case of heap objects which have been fully removed from // the stack. // exAssert( _StackTop > 0 ); if ( _aStack[_StackTop-1].IsThisEqual( pthis ) ) { // // The following assertion is hit if an unwindable object // is destroyed without END_CONSTRUCTION being called. // exAssert( _aStack[_StackTop-1].IsActive() ); _StackTop--; #if DBG == 1 || CIDBG == 1 exDebugOut(( DEB_ITRACE, "POP %lx %lx( %lx )\n", _StackTop, _aStack[_StackTop].GetDtor(), _aStack[_StackTop].GetThis() )); #endif // DBG || CIDBG == 1 } } //+--------------------------------------------------------------------------- // // Member: CExceptionContext::GetTop, public // // Returns: The index of the top of the stack of objects to be // destroyed. This is the first available element. // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- inline int CExceptionContext::GetTop() { return(_StackTop); } CExceptionContext& APINOT _ExceptionContext(void); SCODE APINOT GetOleError(CException & e); SCODE APINOT GetScodeError(CException & e); //+--------------------------------------------------------------------------- // // Class: CUnwindable, CVirtualUnwindable // // Purpose: Per-object exception state and registration/unwind methods. // // Interface: CUnwindable -- Constructor // ~CUnwindable -- Destructor // _Activate -- Activate object. // // History: 22-May-91 KyleP Created. // 13-Nov-92 KyleP Added virtual version // // Notes: CVirtualUnwindable should be used if and only if a // derived class has some other virtual method. // //---------------------------------------------------------------------------- class CUnwindable { public: inline CUnwindable(); inline ~CUnwindable(); inline void _Activate( ULONG cbElement, void (* pfn)(void *) ); }; class CVirtualUnwindable { public: inline CVirtualUnwindable(); virtual ~CVirtualUnwindable(); inline void _Activate( ULONG cbElement, void (* pfn)(void *) ); }; //+--------------------------------------------------------------------------- // // Member: CUnwindable::CUnwindable, public // // Synopsis: Initializes the link field of the object. // // Effects: Essentially sets up enough state to remember the position // of the object which inherits from CUnwindable // within the stack of objects-to-be-destroyed. // // History: 22-May-91 KyleP Created. // // Notes: This call does not fully link the object into the chain // of objects to be destroyed. See _Activate. // //---------------------------------------------------------------------------- inline CUnwindable::CUnwindable() { // // Initialize by allocating a record on the deletion stack. // _ExceptionContext().Reserve(this); } inline CVirtualUnwindable::CVirtualUnwindable() { // // Initialize by allocating a record on the deletion stack. // _ExceptionContext().Reserve(this); } //+--------------------------------------------------------------------------- // // Member: CUnwindable::~CUnwindable, public // // Synopsis: Removes this object from the stack of objects to be destroyed. // // Modifies: Per/thread exception context. // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- inline CUnwindable::~CUnwindable() { _ExceptionContext().Pop(this); } inline CVirtualUnwindable::~CVirtualUnwindable() { _ExceptionContext().Pop(this); } //+--------------------------------------------------------------------------- // // Member: CUnwindable::_Activate, public // // Synopsis: Fully link object into stack of objects to be destroyed. // // Effects: After this call, the object which inherits from // CUnwindable will be destroyed during unwind. // // If the object was declared on the heap, then it is // removed completely from the stack of objects that will // be destroyed during unwind. // // Arguments: [prealthis] -- This pointer of instance. Will differ // from this pointer of CUnwindable // if instance has a virtual method. // [cbElement] -- Size of the instance being activated. If // an element is declared on the heap and // [cbElement] is smaller than the allocation // then the element won't be deleted. // // [pfn] -- Pointer to a static destructor. [pfn] takes a // this pointer. // // Modifies: This object is now the top of the stack of objects that // will be destroyed (_exceptioncontext is modified). // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- inline void CUnwindable::_Activate( ULONG cbElement, void (* pfn)(void *)) { _ExceptionContext().SetTop(this, cbElement, pfn); } inline void CVirtualUnwindable::_Activate( ULONG cbElement, void (* pfn)(void *)) { _ExceptionContext().SetTop(this, cbElement, pfn); } //+--------------------------------------------------------------------------- // // Class: CTry // // Purpose: Containt per/TRY state. // // Interface: ~CTry - Destructor // TryIt - Setup to run the TRY body. // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- class CTry { public: inline CTry(); inline ~CTry(); // // _pPrevTry is a link to the enclosing TRY clause. // CTry * _pPrevTry; // // _StackTop was the top of the stack of objects-to-be-destroyed // when the TRY clause was entered. // int _StackTop; }; //+--------------------------------------------------------------------------- // // Member: CTry::~CTry, public // // Synopsis: Unlinks the TRY ... CATCH from the per/thread list. // // Modifies: The per/thread list of try clauses in _exceptioncontext. // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- inline CTry::~CTry() { exDebugOut(( DEB_ITRACE, "END TRY %lx (%lx)\n", _StackTop, this )); // // The destructor for CTry is called only during normal (no // exception) exit from the TRY ... CATCH or when an // exception was successfully caught in this block. // In these cases we want to unlink this CTry. // // Note that we could delete _exceptioncontext._TheException // here, which may be non-null if we caught an exception in // this TRY ... CATCH block. But why bother? That would add // additional code to the normal case. The last exception // can wait to be deleted until the next occurs. // _ExceptionContext()._pTopTry = _pPrevTry; } //+--------------------------------------------------------------------------- // // Member: CTry::CTry, public // // Synopsis: Set up to run the body of a TRY ... CATCH clause. // // Effects: Links this CTry into the chain of TRY clauses. // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- inline CTry::CTry() { CExceptionContext& _exceptioncontext = _ExceptionContext(); _pPrevTry = _exceptioncontext._pTopTry; _exceptioncontext._pTopTry = this; _StackTop = _exceptioncontext.GetTop(); exDebugOut(( DEB_ITRACE, "TRY %lx (%lx)\n", _StackTop, this )); } //+--------------------------------------------------------------------------- // // The following macros implement a TRY ... CATCH syntax similar // to that in C++. They are used as follows: // // TRY // { // // Body of try goes here... // } // CATCH(exclass, e) // { // // We get here when an exception of class exclass has // // been thrown. The variable e is declared as * exclass. // } // AND_CATCH(exclass, e) // { // // Just like CATCH. Any number of AND_CATCH can follow // // CATCH. Handlers are tried in order of appearance. // } // END_CATCH // // To throw an exception, use the THROW macro -- THROW(exclass). To // re-throw the same exception from within a catch clause use // RETHROW(). Note that RETHROW() is only valid in a CATCH/AND_CATCH. // // History: 22-May-91 KyleP Created Interface. // 15-Aug-91 SethuR modified THROW,CATCH,AND_CATCH,END_CATCH // macros // 18-Oct-91 KyleP Win32 try/except implementation // //---------------------------------------------------------------------------- extern EXPORTDEF void APINOT ThrowDebugException(unsigned int iLine, char * szFile, CException & ecE ); extern EXPORTDEF void APINOT ThrowException(CException & ecE, unsigned dummy); #if DBG == 1 || CIDBG == 1// +++++++++++++++++++++++++++++++++++++++++++++++ //+--------------------------------------------------------------------------- // // Macro: THROW // // Synopsis: Throws an exception // debug // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- # define THROW(e) \ { \ e.SetInfo( GetWin4ExceptionLevel() | EXCEPT_VERBOSE); \ ThrowDebugException( __LINE__, __FILE__, e); \ } //+--------------------------------------------------------------------------- // // Macro: QUIETTHROW // // Synopsis: Throws a quiet exception // debug // // History: 29-Mar-95 DwightKr Created. // //---------------------------------------------------------------------------- #define QUIETTHROW(e) \ { \ e.SetInfo( GetWin4ExceptionLevel() ); \ ThrowDebugException( __LINE__, __FILE__, e); \ } #else // DBG == 0 && CIDBG == 0 ++++++++++++++++++++++++++++++++++++++++++++ //+--------------------------------------------------------------------------- // // Macro: THROW // // Synopsis: Throws an exception // retail // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- # define THROW(e) \ { \ ThrowException(e, 1); \ } //+--------------------------------------------------------------------------- // // Macro: QUIETTHROW // // Synopsis: Throws a quiet exception // retail // // History: 29-Mar-95 DwightKr Created. // //---------------------------------------------------------------------------- #define QUIETTHROW(e) THROW(e) #endif // DBG == 0 && CIDBG == 0 ++++++++++++++++++++++++++++++++++++++++++++ # if DBG == 1 || CIDBG == 1// +++++++++++++++++++++++++++++++++++++++++++++++ //+--------------------------------------------------------------------------- // // Macro: RETHROW // // Synopsis: Rethrows an exception // debug, user // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- # define RETHROW() \ { \ if ( ((class CException &)_exceptioncontext._exception).GetInfo() & EXCEPT_VERBOSE ) \ ExceptionReport(__LINE__,__FILE__,"Rethrowing Exception"); \ RaiseException( EXCEPT_VULCAN, 0, 0, 0 ); \ } #else // DBG == 0 && CIDBG == 0 ++++++++++++++++++++++++++++++++++++++++++++ //+--------------------------------------------------------------------------- // // Macro: RETHROW // // Synopsis: Rethrows an exception // retail, user // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- # define RETHROW() \ RaiseException( EXCEPT_VULCAN, 0, 0, 0 ); #endif // DBG == 0 && CIDBG == 0 ++++++++++++++++++++++++++++++++++++++++++++ //+--------------------------------------------------------------------------- // // Macro: TRY // // Synopsis: Begin TRY block // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- #define TRY \ { \ CTry _trycontext; \ __try EXPORTDEF ULONG APINOT Unwind( struct _EXCEPTION_POINTERS * pdisp, CTry * ptry ); #if DBG == 1 || CIDBG == 1 // +++++++++++++++++++++++++++++++++++++++++++++++ //+--------------------------------------------------------------------------- // // Macro: CATCH // // Synopsis: Begin CATCH block // debug // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- #define CATCH(class, e) \ __except( Unwind( GetExceptionInformation(), &_trycontext ) ) \ { \ CExceptionContext& _exceptioncontext = _ExceptionContext(); \ if (_exceptioncontext._exception.IsKindOf(#class)) \ { \ class & e = (class &)_exceptioncontext._exception; \ if ( e.GetInfo() & EXCEPT_VERBOSE ) \ e.Report( __LINE__, \ __FILE__, \ "Catching Exception"); //+--------------------------------------------------------------------------- // // Macro: AND_CATCH // // Synopsis: Begin another CATCH block // debug // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- #define AND_CATCH(class, e) \ } \ else if ( _exceptioncontext._exception.IsKindOf(#class) ) \ { \ class & e = (class &)_exceptioncontext._exception; \ if ( e.GetInfo() & EXCEPT_VERBOSE ) \ e.Report( __LINE__, \ __FILE__, \ "Catching Exception"); #else // DBG == 0 ++++++++++++++++++++++++++++++++++++++++++++ //+--------------------------------------------------------------------------- // // Macro: CATCH // // Synopsis: Begin CATCH block // retail // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- #define CATCH(class, e) \ __except( Unwind( GetExceptionInformation(), &_trycontext ) ) \ { \ CExceptionContext& _exceptioncontext = _ExceptionContext(); \ if (_exceptioncontext._exception.IsKindOf(#class)) \ { \ class & e = (class &)_exceptioncontext._exception; //+--------------------------------------------------------------------------- // // Macro: AND_CATCH // // Synopsis: Begin another CATCH block // retail // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- #define AND_CATCH(class, e) \ } \ else if (_exceptioncontext._exception.IsKindOf(#class)) \ { \ class & e = ( class &)_exceptioncontext._exception; #endif // DBG == 0 +++++++++++++++++++++++++++++++++++++++++++ //+--------------------------------------------------------------------------- // // Macro: END_CATCH // // Synopsis: End of CATCH block // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- #define END_CATCH \ } \ else \ { \ RETHROW(); \ } \ } \ } //+--------------------------------------------------------------------------- // // The following macros prepare a class for stack unwinding. Any class // with a destructor should be prepared to deal with stack unwind. // The macros are used as follows: // // First, in the .hxx file... // // class CClassWithADestructor : INHERIT_UNWIND // , other inheritance // { // DECLARE_UNWIND // // // // // The rest of the class declaration goes here... // // // } // // And then in the .cxx file... // // IMPLEMENT_UNWIND(CClassWithADestructor) // // CClassWithADestructor::CClassWithADestructor(...) // { // // // // User construction activity. // // // // // // // The following should precede every return from the // // constructor. // // // // END_CONSTRUCTION(CClassWithADestructor) // } // // INHERIT_UNWIND must be the first inheritance. // // For further levels of inheritance, you do not need to inherit from // INHERIT_UNWIND (more to the point, you can't). The other macros // must be used for all levels. // // INHERIT_VIRTUAL_UNWIND must be used in place of INHERIT_UNWIND on a class // that contains virtual methods. If INHERIT_VIRTUAL_UNWIND also fails, // then find me (KyleP) and I'll try to figure out what went wrong. // // Multiple inheritance is untested. It may work, or it may not. If you // really need multiple inheritance see me (KyleP). // // History: 19-Nov-91 KyleP Added multiple-inheritance support // 22-May-91 KyleP Created Interface. // 13-Nov-92 KyleP Added support for classes with virtual // methods. // //---------------------------------------------------------------------------- //+--------------------------------------------------------------------------- // // Macro: INHERIT_UNWIND // // Synopsis: Inherit unwindable behavior // class DOES NOT contain virtual functions // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- #define INHERIT_UNWIND \ \ public CUnwindable //+--------------------------------------------------------------------------- // // Macro: INHERIT_VIRTUAL_UNWIND // // Synopsis: Inherit unwindable behavior // class contains virtual functions // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- #define INHERIT_VIRTUAL_UNWIND \ \ public CVirtualUnwindable //+--------------------------------------------------------------------------- // // Macro: INLINE_UNWIND // // Synopsis: Defines inline static destructor // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- #define INLINE_UNWIND(cls) \ static void _ObjectUnwind ( void * pthis ) \ { ((cls *)pthis)->cls::~cls(); }; //+--------------------------------------------------------------------------- // // Macro: INLINE_TEMPL_UNWIND // // Synopsis: Defines inline static destructor, used in templates // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- #define INLINE_TEMPL_UNWIND(tclass, tparam) \ static void _ObjectUnwind ( void * pthis ) \ { ((tclass *)pthis)->~tclass(); }; //+--------------------------------------------------------------------------- // // Macro: END_CONSTRUCTION // // Synopsis: Activates automatic unwinding // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- #define END_CONSTRUCTION(class) \ \ _Activate( sizeof(class), &class::_ObjectUnwind ); //+--------------------------------------------------------------------------- // // Macro: END_MULTIINHERITED_CONSTRUCTION // // Synopsis: Activates automatic unwinding // for classes with multiple inheritance // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- #define END_MULTINHERITED_CONSTRUCTION(class, base1) \ \ base1::_Activate(sizeof(class), &class::_ObjectUnwind); //+--------------------------------------------------------------------------- // // Macro: DECLARE_UNWIND // // Synopsis: Declares static destructor // Obsolete! // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- #define DECLARE_UNWIND \ \ static void APINOT _ObjectUnwind(void * pthis); #if DBG == 1 || CIDBG == 1 //+--------------------------------------------------------------------------- // // Macro: IMPLEMENT_UNWIND // // Synopsis: Defines static destructor // Obsolete! // debug // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- # define IMPLEMENT_UNWIND(class) \ \ void APINOT class::_ObjectUnwind(void * pthis) \ { \ ((class *)pthis)->class::~class(); \ } \ \ struct __Check##class \ { \ __Check##class() \ { \ if ( (CUnwindable *)((class *)10) != (CUnwindable *)10 || \ (CVirtualUnwindable *) \ ((class *)10) != (CVirtualUnwindable *)10 ) \ { \ exDebugOut(( DEB_ERROR, \ "INVALID UNWINDABLE CLASS: %s.\n", \ #class )); \ } \ } \ }; \ \ __Check##class __check_except_##class; #else // DBG == 0 //+--------------------------------------------------------------------------- // // Macro: IMPLEMENT_UNWIND // // Synopsis: Defines static destructor // Obsolete! // retail // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- # define IMPLEMENT_UNWIND(class) \ \ void APINOT class::_ObjectUnwind(void * pthis) \ { \ ((class *)pthis)->class::~class(); \ } #endif // DBG // // Use to implement unwindable templates // For intstance if you have // // template tclass // // then use // // IMPLEMENT_TEMPL_UNWIND(tclass, tparam> // //+--------------------------------------------------------------------------- // // Macro: IMPLEMENT_TEMPLATE_UNWIND // // Synopsis: Defines static destructor // Obsolete! // // History: 22-May-91 KyleP Created. // //---------------------------------------------------------------------------- #define IMPLEMENT_TEMPL_UNWIND(tclass, tparam) \ \ void APINOT tclass::_ObjectUnwind(void * pthis) \ { \ ((tclass *)pthis)->~tclass(); \ } #endif // defined(NATIVE_EH)