|
|
/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corp., 1991 **/ /**********************************************************************/
/*
base.hxx Universal base class for error cascading and debugging information
This file assumes that 0 denotes NERR_Success, the "no error" state.
FILE HISTORY beng 09-Jul-1990 created beng 17-Jul-1990 added standard comment header to BASE beng 31-Jul-1991 added FORWARDING_BASE rustanl 11-Sep-1991 Added DECLARE_OUTLINE_NEWBASE, DECLARE_MI_NEWBASE, DEFINE_MI2_NEWBASE, DEFINE_MI3_NEWBASE, and DEFINE_MI4_NEWBASE KeithMo 23-Oct-1991 Added forward references. chuckc 26-Feb-1992 made ReportError non-inline if DEBUG beng 30-Mar-1992 Added ResetError members */
#ifndef _BASE_HXX_
#define _BASE_HXX_
//
// Forward references.
//
DLL_CLASS ALLOC_BASE; DLL_CLASS BASE; DLL_CLASS FORWARDING_BASE;
DLL_CLASS ALLOC_BASE { public: void * operator new ( size_t cbSize ) ; void * operator new ( size_t cbSize, void * p ) ; void operator delete ( void * p ) ; };
/*************************************************************************
NAME: BASE (base)
SYNOPSIS: Universal base object, root of every class. It contains universal error status and debugging support.
INTERFACE: ReportError() - report an error on the object from within the object.
QueryError() - return the current error state, or 0 if no error outstanding.
operator!() - return TRUE if an error is outstanding. Typically means that construction failed.
ResetError() - restores object to pristine non-error state.
CAVEATS: This sort of error reporting is safe enough in a single- threaded system, but loses robustness when multiple threads access shared objects. Use it for constructor-time error handling primarily.
NOTES: A class which inherits BASE through a private class should use the NEWBASE macro (q.v.) in its definition; otherwise its clients will lose the use of ! and QueryError.
HISTORY: rustanl 07-Jun-1990 Created as part of LMOD beng 09-Jul-1990 Gutted, removing LMOD methods beng 17-Jul-1990 Added USHORT error methods beng 19-Oct-1990 Finally, removed BOOL error methods johnl 14-Nov-1990 Changed QueryError to be a const method beng 25-Jan-1991 Added the ! Boolean operator and NEWBASE beng 31-Jul-1991 Made FORWARDING_BASE a friend beng 05-Oct-1991 Win32 conversion beng 30-Mar-1992 Added ResetError member DavidHov 19-Nov-1992 Made ReportError inline always
*************************************************************************/
DLL_CLASS BASE : virtual public ALLOC_BASE { friend class FORWARDING_BASE;
private: APIERR _err;
protected: BASE() : _err(0) {}
VOID _ReportError ( APIERR errSet ); // Debug assistant
// Report construction failure: out/inline depending on DEBUG
VOID ReportError( APIERR errSet ) #if defined(DEBUG)
{ _ReportError( errSet ) ; } #else
{ _err = errSet; } #endif
VOID ResetError() { _err = 0; }
public: APIERR QueryError() const { return _err; } BOOL operator!() const { return (_err != 0); } };
/*************************************************************************
NAME: FORWARDING_BASE
SYNOPSIS: A BASE which forwards its errors to some other object
INTERFACE: ReportError() - report an error on the object from within the object.
QueryError() - return the current error state, or 0 if no error outstanding.
operator!() - return TRUE if an error is outstanding. Typically means that construction failed.
ResetError() - restores object to pristine non-error state.
NOTES: The canonical example of a FORWARDING object is a control within a window: if any control fails construction, the entire window fails.
HISTORY: beng 31-Jul-1991 Created beng 05-Oct-1991 Win32 conversion beng 30-Mar-1992 Added ResetError
**************************************************************************/
DLL_CLASS FORWARDING_BASE : virtual public ALLOC_BASE { private: BASE * _pbase;
protected: FORWARDING_BASE(BASE* pbase) : _pbase(pbase) {} VOID ReportError(APIERR errSet) { _pbase->ReportError(errSet); } VOID ResetError() { _pbase->ResetError(); }
public: APIERR QueryError() const { return _pbase->QueryError(); } BOOL operator!() const { return (_pbase->QueryError() != 0); } };
//
// The NEWBASE macro adds forwarding methods to a class.
// Use it when a class loses ! and QueryError through private inheritance,
// or else when a class includes FORWARDING_BASE and wants that to override
// its previous BASE inheritance.
//
#define NEWBASE(class) \
protected: \ VOID ReportError( APIERR errSet ) { class::ReportError(errSet); } \ VOID ResetError() { class::ResetError(); } \ public: \ APIERR QueryError() const { return class::QueryError(); } \ BOOL operator!() const { return (class::QueryError() != 0); }
//
// The following macro declares ReportError and QueryError as outline
// methods. Only use today is in the DECLARE_MI_NEWBASE macro.
//
#define DECLARE_OUTLINE_NEWBASE( class ) \
protected: \ VOID ResetError(); \ VOID ReportError( APIERR err ); \ public: \ APIERR QueryError() const; \ BOOL operator!() const { return (class::QueryError() != 0 ); }
//
// This macro redeclares the BASE methods for a class that
// multiply inherits from (any number of) BASE objects. Use
// appropriate macro defined below to define these methods.
//
// This macro and the definition macros below provide a
// very cheap work-around for not making BASE a virtual class.
//
#define DECLARE_MI_NEWBASE( class ) DECLARE_OUTLINE_NEWBASE( class )
//
// The following macros redefines the BASE methods for a class
// that multiply inherits from 2, 3, or 4 classes which inherit from
// BASE. If needed, MI maniacs may add more such macros in the future.
//
#define DEFINE_MI2_NEWBASE( class, parent_class0, \
parent_class1 ) \ VOID class::ReportError( APIERR err ) \ { \ parent_class0::ReportError( err ); \ parent_class1::ReportError( err ); \ } \ VOID class::ResetError() \ { \ parent_class0::ResetError(); \ parent_class1::ResetError(); \ } \ APIERR class::QueryError() const \ { \ APIERR err; \ if ( ( err = parent_class0::QueryError()) != 0 || \ ( err = parent_class1::QueryError()) != 0 ) \ { \ /* nothing */ \ } \ return err; \ }
#define DEFINE_MI3_NEWBASE( class, parent_class0, \
parent_class1, \ parent_class2 ) \ VOID class::ReportError( APIERR err ) \ { \ parent_class0::ReportError( err ); \ parent_class1::ReportError( err ); \ parent_class2::ReportError( err ); \ } \ VOID class::ResetError() \ { \ parent_class0::ResetError(); \ parent_class1::ResetError(); \ parent_class2::ResetError(); \ } \ APIERR class::QueryError() const \ { \ APIERR err; \ if ( ( err = parent_class0::QueryError()) != 0 || \ ( err = parent_class1::QueryError()) != 0 || \ ( err = parent_class2::QueryError()) != 0 ) \ { \ /* nothing */ \ } \ return err; \ }
#define DEFINE_MI4_NEWBASE( class, parent_class0, \
parent_class1, \ parent_class2, \ parent_class3 ) \ VOID class::ReportError( APIERR err ) \ { \ parent_class0::ReportError( err ); \ parent_class1::ReportError( err ); \ parent_class2::ReportError( err ); \ parent_class3::ReportError( err ); \ } \ VOID class::ResetError() \ { \ parent_class0::ResetError(); \ parent_class1::ResetError(); \ parent_class2::ResetError(); \ parent_class3::ResetError(); \ } \ APIERR class::QueryError() const \ { \ APIERR err; \ if ( ( err = parent_class0::QueryError()) != 0 || \ ( err = parent_class1::QueryError()) != 0 || \ ( err = parent_class2::QueryError()) != 0 || \ ( err = parent_class3::QueryError()) != 0 ) \ { \ /* nothing */ \ } \ return err; \ }
#endif // _BASE_HXX_
|