COM multiplexing in Containment and Aggregation implementation

xiaoxiao2021-03-06  37

COM review (1): CONTAINMENT and AGGREGATION implementation

Containment is a relatively simple multiplex method. of. Of course, Component B can expand the function of Component A. Component B can use the already existing Component A without any changes to Component A. ConTainment Example Implementation (Pan Aimin "COM Principles and Applications" Chapter 4) AGGREGATION compares, Component A must be able to adapt to special processing under AGGREGATION. Its core is the queryinterface function. Aggregation involves collaboration between the aggregation object and the aggregated object, reflects the true COM multiplex, and ContainMent is just the nest of the client and Component, which is the essential difference between Containment and Aggregation. Realization of Aggregation (taken from Pan Aimin "COM Principles and Applications").

Codeclass INondelegatingUnknown Component A of {public: virtual HRESULT __stdcall NondelegationQueryInterface (const IID & iid, void ** ppv) = 0; virtual ULONG __stdcall NondelegatingAddRef () = 0; virtual ULONG __stdcall NondelegationRelease () = 0;}; class CA: public ISomeInterface , public INondelegatingUnknown {protected: ULONG m_Ref; public: CA (IUnknown * pUnknownOuter); ~ CA (); public: // Delegating IUnknown virtual HRESULT __stdcall QueryInterface (const IID & iid, void ** ppv); virtual ULONG __stdcall AddRef () ; virtual ULONG __stdcall Release (); // Nondelegating IUnknown virtual HRESULT __stdcall NondelegationQueryInterface (const IID & iid, void ** ppv); virtual ULONG __stdcall NondelegatingAddRef (); virtual ULONG __stdcall NondelegationRelease (); virtual HRESULT __stdcall SomeFunction (); private: IUNKNOWN * M_PUNK nownOuter; // pointer to outer IUnknown}; // Implemention of class CACA :: CA (IUnknown * pUnknownOuter) {m_Ref = 0; g_CompANumber ; m_pUnknownOuter = pUnknownOuter;} CA :: ~ CA () {} ULONG CA: : Nondelegatingaddref () {m_ref ; return (ulong) m_ref;} Ulong Ca :: NondelegationRelease () {m_ref -; if (m_ref == 0) {g_companumber -; delete this; return 0;} return (ulong ) m_ref;} HRESULT CA :: NondelegationQueryinterface (const IID & IID, VOID ** PPV) {IF (IID == IIUNKNOWN) {* ppv = (inondlegateingunknown *) THIS; ((iUnknown *) (* ppv)) ->

AddRef (); // This is actually called NondelegationAddref ()! ! ! ! } else if (iid == iid_someinterface) {* ppv = (isomeInterface *) THIS; (isomeInterface *) (* ppv)) -> addref (); //, otherwise, here, addref (), / / If the aggregate status calls the external commit address, otherwise calls NondelegationAddref !!!} else {* ppv = null; returnif;} Return S_OK;} Ulong Ca :: addRef () {ix (m_PunknOwnouter! = Null) return m_pUnknownOuter-> AddRef (); else return NondelegatingAddRef ();} ULONG CA :: Release () {if (! m_pUnknownOuter = NULL) return m_pUnknownOuter-> Release (); else return NondelegationRelease ();} HRESULT CA :: QueryInterface (const IID & iid, void ** ppv) {if (! m_pUnknownOuter = NULL) return m_pUnknownOuter-> QueryInterface (iid, ppv); else return NondelegationQueryInterface (iid, ppv);} HRESULT CA :: SomeFunction () {printf ( " THIS IS CA :: SomeFunction! / N "); Return S_OK;} It can be seen from the above code that the aggregated object needs to implement two IUNKNOWN interfaces, Delegation UNKNOWN and Nondelegation UNKNOWN interfaces, Nondelegation Unknown is an iUnknown interface implemented in a normal manner. DELEGATION UNKNOWN passes all calls to the Nondelegation Unknown interface during use; in aggregation, it passes the interface to the external object, while the external object is controlled by the Nondelegation interface.

Aggregation of the CAFactory CreateInstance achieved:! HRESULT CAFactory :: CreateInstance (IUnknown * pUnknownOuter, const IID & iid, void ** ppv) {HRESULT hr; // iid must be IID_IUnknown for aggregating if ((pUnknownOuter = NULL) && (iid! = IID_IUnknown)) {return CLASS_E_NOAGGREGATION;} * ppv = NULL; hr = E_OUTOFMEMORY; // Create the object passing function to notify on destruction CA * pObj = new CA (pUnknownOuter);. if (NULL == pObj) return hr; // Obtain the first interface Pointer (Which Does An AddRef) HR = Pobj-> NondelegationQueryInterface (IID, PPV); if (HR! = S_OK) {// Kill The Object if Initial Creation Or Finit Failed. G_companumber -; / / Reference count g_companumber be added in constructor delete pobj;} Return HR;} MFC COM AGGREGATION Implementation: COM uses C nested classes to implement COM interface, and use interface mapping tables to simplify programming, MFC's support for COM is Start with class ccmdtarget.

#define DECLARE_INTERFACE_MAP () / private: / static const AFX_INTERFACEMAP_ENTRY _interfaceEntries []; / protected: / static const AFX_INTERFACEMAP interfaceMap; / static const AFX_INTERFACEMAP * PASCAL GetThisInterfaceMap (); / virtual const AFX_INTERFACEMAP * GetInterfaceMap () const; / struct AFX_INTERFACEMAP_ENTRY {const void * piid; // the interface id (IID) size_t nOffset (NULL for aggregate); // offset of the interface vtable from m_unknown}; struct AFX_INTERFACEMAP {#ifdef _AFXDLL const AFX_INTERFACEMAP * (PASCAL * pfnGetBaseMap) (); // NULL IS ROOT CLASS # else const AFX_INTERFACEMAP * PBASEMAP; #ENDIF const AFX_INTERFACEMAP_ENTRY * PENTRY; // map for this class}; It can be clearly seen that MFC continues to use the MAP table to implement COM interface. View the addition of the specific MAP table and the delete macro can learn more about the architecture. #define BEGIN_INTERFACE_MAP (theClass, theBase) / const AFX_INTERFACEMAP * PASCAL theClass :: GetThisInterfaceMap () / {return & theClass :: interfaceMap;} / const AFX_INTERFACEMAP * theClass :: GetInterfaceMap () const / {return & theClass :: interfaceMap;} / AFX_COMDAT const AFX_INTERFACEMAP theClass :: interfaceMap = / {& theBase :: GetThisInterfaceMap, & theClass :: _ interfaceEntries [0],}; / AFX_COMDAT const AFX_INTERFACEMAP_ENTRY theClass :: _ interfaceEntries [] = / {/ # define INTERFACE_PART (theClass, iid, localClass) / { & iid, offsetof (theClass, m_x ## localClass)}, / # define INTERFACE_AGGREGATE (theClass, theAggr) {NULL, offsetof (theClass, theAggr)}, / # define END_INTERFACE_MAP () / {NULL, (size_t) -1} / }; / Where the OFFSTOF macro can give the offset between the member variables and the classification, and the compiler calculates this constant when compiling. The interface part defines the definition using the macro begin_interface_part, init_interface_part, end_interface_part.

转载请注明原文地址:https://www.9cbs.com/read-53095.html

New Post(0)