From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- public/sdk/inc/stdobj.hxx | 432 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 432 insertions(+) create mode 100644 public/sdk/inc/stdobj.hxx (limited to 'public/sdk/inc/stdobj.hxx') diff --git a/public/sdk/inc/stdobj.hxx b/public/sdk/inc/stdobj.hxx new file mode 100644 index 000000000..6832ce55c --- /dev/null +++ b/public/sdk/inc/stdobj.hxx @@ -0,0 +1,432 @@ +//+--------------------------------------------------------------------------- +// +// Microsoft Windows +// Copyright (C) Microsoft Corporation, 1992 - 1992. +// +// File: stdobj.hxx +// +// Contents: Standard component object support +// +// History: 3-June-93 MikeSe Created +// +// Notes: The contents of this file provide a standard infrastructure +// for implementing (aggregatable) component objects, an amalgam +// or work done by JohnEls and DonCl. +// +// The infrastructure supplies implementations of all the IUnknown +// methods (both controlling and private), leaving the developer +// to provide only the following: +// +// - initialisation +// - destruction +// - non-IUnknown methods of supported interfaces. +// +// The infrastructure assumes a static class factory object +// (probably although not necessarily implemented using +// CStdClassFactory) and a static description of the interfaces +// supported or delegated through member variables. +// +// Summary of usage: +// +// 1. Declare your class as inheriting from CStdComponentObject. +// Within the class definition, invoke the DECLARE_DELEGATED_UNKNOWN +// macro to declare the required IUnknown methods. Do not include +// IUnknown explicitly in the list of interface supported. +// +// 2. Use the BEGIN_CLASS, SUPPORTS(_EX), DELEGATES* +// and END_CLASS macros to initialise the static class factory +// and class descriptor for the class. This can be placed in any +// convenient source file. +// +// These macros assume the following naming conventions, for +// an implementation class named : +// +// - the class factory class is named CF. +// - the class factory instance is named gcfFactory +// - the class id for the class is named CLSID_ +// - the class descriptor for the class is named gcdDescriptor +// +// If you do not adhere to these conventions you will need to +// duplicate the effect of the BEGIN_CLASS macro by hand, or +// provide #define's of the above names to the actual names. +// +// 3. Implement class initialisation. A two-phase approach is used. +// Any failure-free initialisation can be performed in the +// constructor for the class, which *must* also invoke +// the CStdComponentObject constructor, either through the +// INIT_CLASS macro or an equivalent. +// +// If any of the initialisation is failure prone, provide an +// implementation of the _InitInstance method which performs +// this initialisation and returns an appropriate result code +// in the contract of IClassFactory::CreateInstance. +// +// 4. Implement a destructor for your class, if you have any shutdown +// requirements. The destructor should not assume that your +// _InitInstance method (if any) has been called. +// +// 5. Implement the CreateInstance method for your class factory +// (or _CreateInstance if using CStdClassFactory). This should +// issue a 'new' on your class, and then invoke the (inherited) +// InitInstance method. +// +// If you are using CStdClassFactory, you can use the +// IMPLEMENT_CLASSFACTORY macro (defined in common\ih\stdclass.hxx) +// to implement the _CreateInstance method, or in any case +// you can look at the macro to get an idea of the general structure +// you must follow. +// +//---------------------------------------------------------------------------- + +#ifndef __STDOBJ_HXX__ +#define __STDOBJ_HXX__ + +#include +#include +#include + +//+------------------------------------------------------------------------- +// +// Class: ITFDELTA +// +// Purpose: Defines an interface supported or delegated to. +// +// Notes: if piid is non-NULL +// - a ulDelta with bit 31 set indicates a natively supported +// interface, and (ulDelta&0x7FFFFFFF) gives the value which +// must be added to the object's this pointer in order to +// transform into the required interface pointer. +// [in other words, the equivalent of doing (IFoo*)this] +// - a ulDelta with bit 30 set indicates an interface pointer +// which can be loaded directly from a member variable +// at the offset (ulDelta&0x3FFFFFFF) from the object's this +// pointer. +// - otherwise ulDelta indicates an offset from the object's +// this pointer to a member variable containing an IUnknown +// pointer (a delegatee) which can be QI'd to get the interface +// specified by piid. +// if piid is NULL, +// - ulDelta == 0x80000000L indicates the end of the table +// for the class. +// - otherwise, ulDelta gives the offset to an "else" delegatee +// member variable. (See the DELEGATE_ELSE macro below). +// +//-------------------------------------------------------------------------- + +class ITFDELTA +{ +public: + const IID * piid; + ULONG ulDelta; +}; + +#define ITF_SUPPORTED 0x80000000L +#define ITF_NO_QI 0x40000000L +#define ITF_END 0x80000000L + +#define NOTDELEGATED(ulDelta) ((ulDelta & ITF_SUPPORTED)!=0) +#define QIREQUIRED(ulDelta) ((ulDelta & ITF_NO_QI)==0) +#define GETDELTA(ulDelta) (ulDelta & 0x3FFFFFFFL) +#define MEMBEROFFSET(c,m) ((ULONG)&(((c *)0)->m)) + +//+--------------------------------------------------------------------------- +// +// Macros: SUPPORTS, SUPPORTS_EX, DELEGATES_DIRECT, DELEGATES_QI, +// DELEGATES_ANY, END_INTERFACES +// +// These macros are used to declare ITFDELTA structures of various kinds. +// They are intended to be used in conjunction with the BEGIN_CLASS and +// END_CLASS macros (see below) and may not work correctly if used +// otherwise. +// +// SUPPORTS is used to specify an interface that is supported directly +// on the specified class. +// +// SUPPORTS_EX is used when an interface is inherited through more than one +// parent, and you need to express which one to use. +// SUPPORTS_EX(CFoo, IFoo, IPersist) says to use the IPersist inherited from +// IFoo (as opposed to the one inherited from IPersistFile, say). +// +// DELEGATES_DIRECT specifies a member variable of the class which contains an +// interface pointer to the specified interface. +// IE: DELEGATES_DIRECT(CFoo,IFoo,_pmem) implies that _pmem is of type IFoo*. +// +// DELEGATES_QI is similar, except it specifies that the interface must be +// obtained by issuing a QueryInterface on the pointer in the member variable. +// (Thus the member variable can be of any type deriving from IUnknown). The +// QueryInterface operation is permitted to fail. +// +// DELEGATES_ANY is similar to DELEGATES_QI except that any interface may +// be requested from the referred to member variable. Thus it is a kind of +// catchall. +// +// END_INTERFACES marks the end of the list. It is not used when END_CLASS +// (see below) is used. +// +// Do not put semicolons at the ends of these statements. +// +// The built-in implementation of QueryInterface processes the ITFDELTA array +// in the class descriptor in order, stopping as soon as the requested interface +// is obtained. Thus DELEGATES_ANY entries, of which there may be several, +// will normally appear last. +// +// If an interface which is part of a derivation chain is supported (eg: +// IPersistStream, deriving from IPersist) then all the interfaces, except +// IUnknown, must be listed. (i.e both IPersist and IPersistStream). +// +//---------------------------------------------------------------------------- + +#define SUPPORTS(clsname, itfname) \ + { \ + &IID_##itfname, \ + ((ULONG)((VOID *) ((itfname *)(clsname *) ITF_SUPPORTED))) \ + }, + +#define SUPPORTS_EX(clsname, itfprimary, itfname) \ + { \ + &IID_##itfname, \ + ((ULONG)(VOID *)(itfname *)((itfprimary *)((clsname *) ITF_SUPPORTED))) \ + }, + +#define DELEGATES_DIRECT(clsname, itfname, iunkptr) \ + { \ + &IID_##itfname, \ + MEMBEROFFSET(clsname, iunkptr)|ITF_NO_QI \ + }, + +#define DELEGATES_QI(clsname, itfname, iunkptr) \ + { \ + &IID_##itfname, \ + MEMBEROFFSET(clsname, iunkptr) \ + }, + +#define DELEGATES_ANY(clsname, iunkptr) \ +{ \ + NULL, \ + MEMBEROFFSET(clsname, iunkptr) \ +}, + +#define END_INTERFACES \ + { \ + NULL, \ + ITF_END \ + } + +//+------------------------------------------------------------------------- +// +// Class: CLASSDESCRIPTION +// +// Purpose: Static description of class required by infrastructure. +// +// Notes: When creating a CLASSDESCRIPTOR, use the SUPPORTS etc. +// macros to declare the entries in the aitfd array (or +// better still, use BEGIN_CLASS etc to create the whole +// descriptor). +// +//-------------------------------------------------------------------------- + +class CLASSDESCRIPTOR +{ +public: + const CLSID * pcls; // the class id + char * pszClassName; // for object tracking, the + // printable name of the class + IClassFactory * pcf; // the class factory for the + // class, assumed static + +#pragma warning ( disable: 4200 ) // valid use of open struct + ITFDELTA aitfd[]; // supported/delegated interfaces +#pragma warning ( default: 4200 ) +}; + +//+------------------------------------------------------------------------- +// +// Macro: CLASSFACTORY_NAME, CLASSDESCRIPTOR_NAME +// +// Purpose: These macros generate the standard names for the class factory +// and class descriptor instances for a class. +// +// Notes: +// +//-------------------------------------------------------------------------- + +#define CLASSFACTORY_NAME(cls) gcf##cls##Factory +#define CLASSDESCRIPTOR_NAME(cls) gcd##cls##Descriptor + +//+------------------------------------------------------------------------- +// +// Macro: BEGIN_CLASS +// +// Purpose: Declare the class factory and the first part of the +// class descriptor. +// +// Notes: This macro is usually followed by zero or more ITFDELTA +// declaration macros (SUPPORTS, etc) and then END_CLASS. +// +//-------------------------------------------------------------------------- + +#define BEGIN_CLASS(cls) \ + cls##CF CLASSFACTORY_NAME(cls); \ + \ + CLASSDESCRIPTOR CLASSDESCRIPTOR_NAME(cls) = { \ + &CLSID_##cls, \ + #cls, \ + (IClassFactory*)&gcf##cls##Factory, \ + { + +//+------------------------------------------------------------------------- +// +// Macro: END_CLASS +// +// Purpose: Complete the declaration of the class descriptor. +// +// Notes: +// +//-------------------------------------------------------------------------- + +#define END_CLASS \ + END_INTERFACES \ + } \ +}; + +//+------------------------------------------------------------------------- +// +// Class: CStdComponentObject +// +// Purpose: Standard base class from which to derive aggregatable component +// classes. +// +// Interface: CStdComponentObject [constructor] +// InitInstance [second phase initialisation, +// do not override]. +// ~CStdComponentObject [virtual destructor] +// _InitInstance [virtual, override to provide +// class-specific second phase +// initialisation]. +// _QueryInterface [virtual, override to provide last +// ditch QueryInterface operation ]. +// +// Notes: "Last ditch" QI operation means anything which cannot be +// described in a static ITFDELTA. The _QueryInterface method +// (if provided) is invoked only if the requested interface +// cannot be satisfied via the ITFDELTA table. +// +// The order of the method declarations is important, because +// it allows us to safely cast a CStdComponentObject to an IUnknown +// without actually deriving from it. +// +//-------------------------------------------------------------------------- + +class CStdComponentObject: INHERIT_TRACKING +{ +private: + // + // pseudo-IUnknown methods + // + + STDMETHOD(PrimaryQueryInterface) (REFIID riid, void** ppv); + STDMETHOD_(ULONG,PrimaryAddRef) (void); + STDMETHOD_(ULONG,PrimaryRelease) (void); + + // + // Two-phase constructor. + // + +protected: + CStdComponentObject ( const CLASSDESCRIPTOR * pcd ); +public: + HRESULT InitInstance ( + IUnknown* punkOuter, + REFIID riid, + void** ppv ); + + // + // Destructor + // + + virtual ~CStdComponentObject(void); + +protected: + + // Override the following method to provide last-ditch QueryInterface + // behaviour. + STDMETHOD(_QueryInterface) ( REFIID riid, void** ppv ); + + // Override the following method to provide class-specific failure-prone + // initialisation. Status codes returned must be in the set defined + // as valid for IClassFactory::CreateInstance. + STDMETHOD(_InitInstance) ( void ); + + const CLASSDESCRIPTOR* _pcd; + IUnknown* _punkControlling; + +}; + +//+------------------------------------------------------------------------- +// +// Macro: DECLARE_DELEGATED_UNKNOWN +// +// Synopsis: Implements IUnknown methods that simply delegate to the +// corresponding methods on the controlling IUnknown object. +// +// Note: Use this macro when declaring a subclass of CStdComponentObject. +// Invoke it anywhere within the public portion of your class +// definition. If you sub-subclass, you must invoke this macro +// at each level. EG: +// +// class CMyMain: CStdComponentObject, IFoo +// +// class CMySub: CMyMain, IBar +// +// then both CMyMain and CMySub must DECLARE_DELEGATED_UNKNOWN. +// +//-------------------------------------------------------------------------- + +#define DECLARE_DELEGATED_UNKNOWN \ + \ +STDMETHOD(QueryInterface) (REFIID riid, void** ppv) \ +{ \ + return _punkControlling->QueryInterface(riid, ppv); \ +}; \ + \ +STDMETHOD_(ULONG,AddRef) () \ +{ \ + return _punkControlling->AddRef(); \ +}; \ + \ +STDMETHOD_(ULONG,Release) () \ +{ \ + return _punkControlling->Release(); \ +}; + +//+------------------------------------------------------------------------- +// +// Macro: INIT_CLASS +// +// Purpose: Call constructor of base class correctly. +// +// Notes: This macro should be invoked in the initialisation +// phase of the constructor for the component class +// deriving from CStdComponentObject, viz: +// +// CMyClass::CMyClass () +// :INIT_CLASS(CMyClass) +// other initialisations +// {... +// +// Use of this macro requires the class descriptor to +// be named according to the convention described previously. +// If this is not so (eg: you didn't use BEGIN_CLASS) you +// must write your own equivalent invocation. +// +// If you sub-subclass, you must declare the constructor +// for the subclass appropriately, so that the class descriptor +// for the sub-subclass can be passed through to CStdComponentObject. +// +//-------------------------------------------------------------------------- + +#define INIT_CLASS(cls) CStdComponentObject ( &CLASSDESCRIPTOR_NAME(cls) ) + +#endif // of ifndef __STDOBJ_HXX__ + + -- cgit v1.2.3