Add an interface to the derived class of ccmdtarget

xiaoxiao2021-03-06  72

Adding an implementation of an interface to a class, which is a common requirement, especially in event notifications, more common in connection points. Many classes in the MFC Class library have such a need, such as class ColeControl, a lot of interfaces. The MFC's own method is used in nested classes and defines several macro to simplify the process. With the same way, we can also easily add an interface to an interface in your own class. The CCMDTarget implements the default implementation of the three functions of IUNKNOWN in the CCMDTarget. The general MFC classes are inherited from ccmdTarget, so it is a way to add interfaces to CCMDTARGETs.

For example, there is a class CSampleView inherited from CVIEW. Now add a new interface IMYTEST to it, which only has an empty method TEST (). The addition process is as follows:

(1) Add the following code to the CSampleView class definition:

Declare_interface_map () // Declaration Interface Mapping Begin_Interface_part (TestInterface, ImyTest) // Declaration Implementation Interface ImyTest Nested STDMETHOD (TEST) (); end_interface_part (FontNotify2)

(2) Add the following code to the CSAMPLEVIEW class:

BEGIN_INTERFACE_MAP (CSampleView, CCmdTarget) INTERFACE_PART (CSampleView, IID_IMyTest, TestInterface) END_INTERFACE_MAP () STDMETHODIMP_ (ULONG) CSampleView :: XTestInterface :: AddRef () {METHOD_PROLOGUE_EX (CSampleView, TestInterface) return (ULONG) pThis-> ExternalAddRef ();} STDMETHODIMP_ (ULONG) CSampleView :: XTestInterface :: Release () {METHOD_PROLOGUE_EX (CSampleView, TestInterface) return (ULONG) pThis-> ExternalRelease ();} STDMETHODIMP CSampleView :: XTestInterface :: QueryInterface (REFIID iid, LPVOID FAR * ppvObj) {METHOD_PROLOGUE_EX (CSampleView, TestInterface) return (HRESULT) pThis-> ExternalQueryInterface (& iid, ppvObj);} STDMETHODIMP CSampleView :: XTestInterface :: Test () {METHOD_PROLOGUE_EX (CSampleView, TestInterface) // do something you like return S_OK;}

Uncover the mystery of macro, see what it is. The following is a simplified version.

(1) DECLARE_INTERFACE_MAP

struct AFX_INTERFACEMAP_ENTRY {const void * piid; // the interface id (IID) (NULL for aggregate) size_t nOffset; // offset of the interface vtable from m_unknown}; struct AFX_INTERFACEMAP {const AFX_INTERFACEMAP * (PASCAL * pfnGetBaseMap) (); / / NULL is root class const AFX_INTERFACEMAP_ENTRY * pEntry; // map for this class}; #define DECLARE_INTERFACE_MAP () / private: / static const AFX_INTERFACEMAP_ENTRY _interfaceEntries []; / protected: / static AFX_DATA const AFX_INTERFACEMAP interfaceMap; / static const AFX_INTERFACEMAP * PASCAL _GetBaseInterfaceMap (); / virtual const AFX_INTERFACEMAP * GetInterfaceMap () const; / (2) begin_interface_part / end_interface_part

#define begin_interface_part (localclass, baseclass) /// defines a nested class x ## localclass: public baseclass / {/ public: / stdmethod_ (ulong, addref) (); / stdmethod_ (ulong, release) (); / STDMETHOD (REFIID IID, LPVOID * PPVOBJ); / #define end_interface_part (localclass) /} m_x ## localclass; / friend class x ## localclass; /

(3) Begin_Interface_map / interface_part / end_interface_map

#define offsetof (s, m) (size_t) & (((s *) 0) -> m) #define BEGIN_INTERFACE_MAP (theClass, theBase) / const AFX_INTERFACEMAP * PASCAL theClass :: _ GetBaseInterfaceMap () / {return & theBase :: interfaceMap ;} / const AFX_INTERFACEMAP * theClass :: GetInterfaceMap () const / {return & theClass :: interfaceMap;} / AFX_COMDAT const AFX_DATADEF AFX_INTERFACEMAP theClass :: interfaceMap = / {& theClass :: _ GetBaseInterfaceMap, & theClass :: _ interfaceEntries [0],}; / AFX_COMDAT const AFX_DATADEF AFX_INTERFACEMAP_ENTRY theClass :: _ interfaceEntries [] = / {/ #define INTERFACE_PART (theClass, iid, localClass) / {& iid, offsetof (theClass, m_x ## localClass)}, / #define END_INTERFACE_MAP () / {NULL, ( SIZE_T) -1} /}; / (4) Method_Prologue_ex

#define METHOD_PROLOGUE_EX (theClass, localClass) / METHOD_PROLOGUE (theClass, localClass) / #define METHOD_PROLOGUE (theClass, localClass) / theClass * pThis = / ((theClass *) ((BYTE *) this - offsetof (theClass, m_x ## localClass )))))); / AFX_MANAGE_STATE (PTHIS-> m_pmodulestate) / pthis; // Avoid Warning from Compiler /

The biggest role of Method_Prologue is to get a PTHIS pointer. This macro is used in a member function of nested classes, and PTHIS is a pointer of its parent class, which is also a CSAMPLEVIEW of this pointer.

These macros are very similar to the message mapping in the MFC, which is very detailed in the "In-Shar-out MFC" in Houjie. I also don't want to draw a snake. Its basic thinking is to put the objects of each nested class (that is, the M_x start variable) in an array, so that the pointer to these interfaces can be obtained when QueryInterface, the so-called interface pointer is the nested object address.

It is also possible to simply explain its structure (not accurate, only illustrating the meaning): ccmdtarget contains three functions: ExternalAddref, ExternalRelease, ExternalQueryInterface. This way we don't have to implement the iUnknown interface, as long as you simply call the function of the parent class, it is very convenient. The execution of the ExternalQueryInterface is the first interface to find the query in the subclass. If you find it, return it to your interface pointer. If you can't find GetBaseInterfacemap to the parent class, you can push it. The same is the same as the message mapping. If you are interested, you will go to the next source code.

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

New Post(0)