//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1991 - 1992. // // File: Except.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 // //---------------------------------------------------------------------------- #pragma warning(4:4509) // SEH used in function w/ _trycontext #ifndef __EXCEPT_HXX_ #define __EXCEPT_HXX_ #ifdef DISPLAY_INCLUDES #pragma message( "#include <" __FILE__ ">..." ) #endif #if defined( KERNEL ) # include # include #else // !KERNEL # include # include # include # include #endif #include const int maxExceptionSize = 256; #define DEB_BUDDY 0x10000 #define DEB_UNWIND 0x20000 // // 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 !defined( KERNEL ) //# include //# endif // !KERNEL # if (DBG == 1 || OFSDBG == 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 && OFSDBG == 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 // #if defined( WIN32 ) # if !defined( KERNEL ) # include # endif // !KERNEL #else // !WIN32 # include #endif // WIN32 class CTry; typedef void(*PFV)(); extern void terminate(); extern void unexpected(); extern PFV set_terminate(PFV terminate_fn); extern PFV set_unexpected(PFV unexpected_fn); #if DBG==1 || OFSDBG == 1 typedef BOOL (* ALLOC_HOOK)(size_t nSize); EXPORTDEF ALLOC_HOOK MemSetAllocHook( ALLOC_HOOK pfnAllocHook ); extern EXPORTDEF void WINAPI ExceptionReport( unsigned int iLine, char *szFile, char *szMsg); #endif // DBG == 1 || OFSDBG == 1 //+--------------------------------------------------------------------------- // // 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. // //---------------------------------------------------------------------------- class CException { public: EXPORTDEF CException(long lError); long GetErrorCode() { return _lError;} EXPORTDEF virtual int WINAPI IsKindOf(const char * szClass) const; protected: long _lError; }; //+--------------------------------------------------------------------------- // // 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 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(); #ifndef WIN32 void Throw(); #endif /* WIN32 */ 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 || OFSDBG == 1 exDebugOut(( DEB_ITRACE, "POP %lx %lx( %lx )\n", _StackTop, _aStack[_StackTop].GetDtor(), _aStack[_StackTop].GetThis() )); #endif // DBG || OFSDBG == 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); } EXPORTDEF CExceptionContext& APINOT _ExceptionContext(void); //---------------------------------------------------------------------------- // // Various operator new implementations // //---------------------------------------------------------------------------- EXPORTDEF int APINOT LeakCheck ( ULONG* pCount ); #if defined( KERNEL ) // // Prototype for extra operator new used in kernel to specify // resident vs. swappable heap. // void InitExceptionSystem(); void* __cdecl operator new ( size_t size, POOL_TYPE pool ); #if OFSDBG == 1 # define NEW_POOL( pool, pCounter ) new(pool, pCounter) void* __cdecl operator new ( size_t size, POOL_TYPE pool, ULONG* pCounter ); #else # define NEW_POOL( pool, pCounter ) new(pool) #endif #endif // KERNEL // // Allocation with trace context // #if OFSDBG == 1 || DBG == 1 # define NEW( pCounter ) new ( pCounter ) void* __cdecl operator new ( size_t size, ULONG* pCounter ); #else # define NEW( pCounter ) new #endif // // Prototype for extra operator new used in routines which do not // have an exception handler set up and prefer a null return on // failed allocations rather than an exception. // typedef enum _FAIL_BEHAVIOR { NullOnFail, ExceptOnFail } FAIL_BEHAVIOR ; void* __cdecl operator new ( size_t size, FAIL_BEHAVIOR FailBehavior ); #define newx new(ExceptOnFail) //+--------------------------------------------------------------------------- // // Class: CSystemException // // Purpose: Base class for system (hardware) exceptions which are // not handled by a specific exception class // // Interface: // // History: 18-Oct-91 KyleP Created. // //---------------------------------------------------------------------------- class CSystemException : public CException { public: EXPORTDEF CSystemException(ULONG ulExcept); virtual int WINAPI IsKindOf(const char * szClass) const; ULONG GetSysErrorCode() { return( _ulExcept ); } private: ULONG _ulExcept; }; //+--------------------------------------------------------------------------- // // 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(); // // The following function ***MUST*** be declared inline and // actually be ***IMPLEMENTED*** inline. It calls setjmp; // and if TryIt is a real procedure then we just set the // return for longjmp on a piece of stack that is reclaimed! // //inline int TryIt(); #ifndef WIN32 // // _jb is the setjmp buffer indicating the location that will // be longjmp'ed to when an exception occurs. // jmp_buf _jb; #endif /* WIN32 */ // // _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 || OFSDBG == 1// +++++++++++++++++++++++++++++++++++++++++++++++ # define THROW(e) \ { \ ThrowDebugException(__LINE__,__FILE__,e); \ } #else // DBG == 0 && OFSDBG == 0 ++++++++++++++++++++++++++++++++++++++++++++ # define THROW(e) \ { \ ThrowException(e, 1); \ } #endif // DBG == 0 && OFSDBG == 0 ++++++++++++++++++++++++++++++++++++++++++++ #ifdef WIN32 // ---------------------------------------------------- #define EXCEPT_VULCAN 0xE0000001 # define CALLEX( x ) \ __try \ { \ x; \ } \ __except( EXCEPTION_EXECUTE_HANDLER ) \ { \ THROW( CException( GetExceptionCode() ) ); \ } #if defined( KERNEL ) # if DBG == 1 || OFSDBG == 1// +++++++++++++++++++++++++++++++++++++++++++++++ # define RETHROW() \ ExceptionReport(__LINE__,__FILE__,"Rethrowing Exception"); \ ExRaiseStatus( EXCEPT_VULCAN ); # else // DBG == 0 && OFSDBG == 0 ++++++++++++++++++++++++++++++++++++++++++++ # define RETHROW() \ ExRaiseStatus( EXCEPT_VULCAN ); # endif // DBG == 0 && OFSDBG == 0 ++++++++++++++++++++++++++++++++++++++++++++ #else // !KERNEL # if DBG == 1 || OFSDBG == 1// +++++++++++++++++++++++++++++++++++++++++++++++ # define RETHROW() \ ExceptionReport(__LINE__,__FILE__,"Rethrowing Exception"); \ RaiseException( EXCEPT_VULCAN, 0, 0, 0 ); # else // DBG == 0 && OFSDBG == 0 ++++++++++++++++++++++++++++++++++++++++++++ # define RETHROW() \ RaiseException( EXCEPT_VULCAN, 0, 0, 0 ); # endif // DBG == 0 && OFSDBG == 0 ++++++++++++++++++++++++++++++++++++++++++++ #endif // !KERNEL #define TRY \ { \ CTry _trycontext; \ __try EXPORTDEF ULONG APINOT Unwind( struct _EXCEPTION_POINTERS * pdisp, CTry * ptry ); #if DBG == 1 || OFSDBG == 1 // +++++++++++++++++++++++++++++++++++++++++++++++ #define CATCH(class, e) \ __except( Unwind( GetExceptionInformation(), &_trycontext ) ) \ { \ CExceptionContext& _exceptioncontext = _ExceptionContext(); \ if (_exceptioncontext._exception.IsKindOf(#class)) \ { \ ExceptionReport(__LINE__,__FILE__,"Catching Exception"); \ class & e = (class &)_exceptioncontext._exception; #define AND_CATCH(class, e) \ } \ else if (_exceptioncontext._exception.IsKindOf(#class)) \ { \ ExceptionReport(__LINE__,__FILE__,"Catching Exception"); \ class & e = (class &)_exceptioncontext._exception; #else // DBG == 0 ++++++++++++++++++++++++++++++++++++++++++++ #define CATCH(class, e) \ __except( Unwind( GetExceptionInformation(), &_trycontext ) ) \ { \ CExceptionContext& _exceptioncontext = _ExceptionContext(); \ if (_exceptioncontext._exception.IsKindOf(#class)) \ { \ class & e = (class &)_exceptioncontext._exception; #define AND_CATCH(class, e) \ } \ else if (_exceptioncontext._exception.IsKindOf(#class)) \ { \ class & e = ( class &)_exceptioncontext._exception; #endif // DBG == 0 +++++++++++++++++++++++++++++++++++++++++++ #define END_CATCH \ } \ else \ { \ RETHROW(); \ } \ } \ } #else // NOT WIN32 ------------------------------------------------- #define TRY \ { \ CTry _trycontext; \ if (setjmp(_trycontext._jb) == 0) \ #if DBG == 1 || OFSDBG == 1 // ++++++++++++++++++++++++++++++++++++++++++++++++ #define CATCH(class, e) \ \ else \ { \ CExceptionContext& _exceptioncontext = _ExceptionContext(); \ if (_exceptioncontext._exception.IsKindOf(#class)) \ { \ ExceptionReport(__LINE__,__FILE__,"Catching Exception"); \ class & e = (class &)_exceptioncontext._exception; #define AND_CATCH(class, e) \ \ } \ else if (_exceptioncontext._exception.IsKindOf(#class)) \ { \ ExceptionReport(__LINE__,__FILE__,"Catching Exception"); \ class & e = (class &)_exceptioncontext._exception; #else // DBG == 0 +++++++++++++++++++++++++++++++++++++++++++++ #define CATCH(class, e) \ \ else \ { \ CExceptionContext& _exceptioncontext = _ExceptionContext(); \ if (_exceptioncontext._exception.IsKindOf(#class)) \ { \ class & e = (class &)_exceptioncontext._exception; #define AND_CATCH(class, e) \ \ } \ else if (_exceptioncontext._exception.IsKindOf(#class)) \ { \ class & e = (class &)_exceptioncontext._exception; #endif // DBG == 0 +++++++++++++++++++++++++++++++++++++++++++ #define END_CATCH \ } \ else \ { \ _exceptioncontext.Throw(); \ } \ } \ } #define RETHROW() \ _exceptioncontext.Throw() #endif // NOT WIN32 ------------------------------------------------ //+--------------------------------------------------------------------------- // // 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. // //---------------------------------------------------------------------------- #define INHERIT_UNWIND \ \ public CUnwindable #define INHERIT_VIRTUAL_UNWIND \ \ public CVirtualUnwindable #define END_MULTINHERITED_CONSTRUCTION(class, base1) \ \ base1::_Activate(sizeof(class), &class::_ObjectUnwind); // // Why such a complicated test below? Because we are nearly ready to // ship Daytona and Ole includes except.hxx but requires the macros // do nothing. We are unable to change the Ole sources this late in // the game, so you get exceptions only if you are: // a) In a Cairo build and didn't define NOEXCEPTIONS, or // b) Defined YESEXCEPTIONS in any build. // // The above would be true and interesting if anybody except OFS wanted // to use ofsNew or ofsDelete. As it is, the declarations below (and // most of the rest of this file) should be moved to the OFS project // #if ((WIN32 == 300) && !defined(NOEXCEPTIONS)) || defined(YESEXCEPTIONS) #if (OFSDBG == 1) void* __cdecl ofsNew( size_t size, FAIL_BEHAVIOR FailBehavior ); inline void* __cdecl operator new ( size_t size, FAIL_BEHAVIOR FailBehavior) { return ofsNew(size, FailBehavior); } void __cdecl ofsDelete( void * p ); inline void __cdecl operator delete ( void * p ) { ofsDelete( p ); } #endif // (OFSDBG == 1) #define INHERIT_UNWIND_IF_CAIRO : INHERIT_UNWIND #define DECLARE_UNWIND \ \ static void APINOT _ObjectUnwind(void * pthis); #if DBG == 1 || OFSDBG == 1 # 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 # define IMPLEMENT_UNWIND(class) \ \ void APINOT class::_ObjectUnwind(void * pthis) \ { \ ((class *)pthis)->class::~class(); \ } #endif // DBG #define END_CONSTRUCTION(class) \ \ _Activate( sizeof(class), &class::_ObjectUnwind ); // The following macro will (probably) need to be redefined (to null) when // compiler support for exceptions arrives. #define INLINE_UNWIND(cls) \ static void _ObjectUnwind ( void * pthis ) \ { ((cls *)pthis)->cls::~cls(); }; #else #define INHERIT_UNWIND_IF_CAIRO #define DECLARE_UNWIND #define END_CONSTRUCTION(class) #define INLINE_UNWIND(cls) #define IMPLEMENT_UNWIND(cls) #endif #endif // __EXCEPT_HXX__