292 lines
12 KiB
C++
292 lines
12 KiB
C++
|
/**********************************************************************/
|
||
|
/** 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_
|