ATL interface mapping macro detailed [5]

zhaozj2021-02-16  74

Four .com_interface_entry_cached_tear_off (IID, X, PUNK) This macro and the top section of the COM_ITERFACE_ENTRY_TEAR_OFF macro are the most important differences, and new objects will not be created when querying other interfaces in the split object. Let's take a look at its typical usage:

class CTearOff2: public IDispatchImpl , public CComTearOffObjectBase {public: CTearOff2 () {} ~ CTearOff2 () {} BEGIN_COM_MAP (CTearOff2) COM_INTERFACE_ENTRY (ITearOff2) END_COM_MAP () HRESULT STDMETHODCALLTYPE get_Name (BSTR * pbstrName ) {* pbstrName = :: SysAllocString (L "ITearOff2"); return S_OK;}}; class COuter: public .... {public: BEGIN_COM_MAP (COuter) COM_INTERFACE_ENTRY_CACHED_TEAR_OFF (IID_ITearOff2, CTearOff2, m_pUnkTearOff2.p) .... .. End_com_map () ccomptr m_punktearoff2; .....};

CTearoff2 implements the split interface ITEAROFF2. Its class definition is the same as the CTearoff1 seen by the previous section, regardless of which division interface is the same, different places lies in couter. A member variable m_punktearoff2 is added to a parameter of the macro in the COUTER.

We continue to track its internal execution with the old way, assuming that the POUTER is the components that have been obtained have interface IOUTER pointers.

Perform Pouter-> Queryinterface (IID_ITEAROFF2, (Void **) & PTEAR1);

Function Stack 1:

9.ctearoff2 :: _ internalQueryinterface (...) 8.atl :: ccomcachedtearoffObject :: queryinterface (...) 9.atl :: ccomcachedtearoffObject :: queryinterface (... ) 8.atl :: ccomcreator > :: createinstance () 7.atl :: ccomobjectRootBase :: _ cache (...) 5.couter :: _ cache (...) 5.atl :: : AtlinternalQueryinterface (...) 4.atl :: ccomobjectrootbase :: InternalQueryInterface (...) 3, couter :: _ internalQueryinterface (...) 2.atl :: ccomobject :: queryinterface (...) 1 .Ctestdlg :: onbutton1 () line 187 22 bytes

Explanation:

1: Pouter-> QueryInterface (IID_ITEAROFF2, (Void **) & PTEAR1);

2-5: This code saw many times, no need to talk, now the program is executed

HRESULT HRES = Pentries-> PFUNC (PTHIS, IID, PPVObject, Pentries-> DW); It seems that we have to see this macro definition to know what PFUNC is performing.

#define com_interface_entry_cached_tear_off (IID, X, PUNK) /

{& IID, /

(DWORD) & _ CCOMCACHEDATA

CCMCREATOR >, / /

(DWORD) OFFSTOF (_CommapClass, PUNK) /

? gt ;:: data, /

_Cache},

The definition of the macro we came in the previous section is not too the same, or then track it first.

6: It turns out in Begin_COM_MAP also defined _cache functions:

Static HRESULT WINAPI _CACHE (Void * PV, Refiid IID, VOID ** PPVObject, DWORD DW) /

{/

......

HRESULT HRES = CComobject HRES = CComobjectRootBase :: _ Cache (PV, IID, PPVObject, DW); /

......

} /

7: Take a look at CComobjectRootBase :: _ cache source code:

static HRESULT WINAPI _Cache (void * pv, REFIID iid, void ** ppvObject, DWORD dw) {HRESULT hRes = E_NOINTERFACE; _ATL_CACHEDATA * pcd = (_ATL_CACHEDATA *) dw; IUnknown ** pp = (IUnknown **) ((DWORD) PV PCD-> dwoffsetvar; if (* pp == null) hres = pcd-> PFUNC (PV, IID_IUNKNOWN, (VOID **) PP); if (* pp! = null) hres = (* pp) - > Queryinterface (IID, ppvobject); return hres;}

The key to the problem is DW, DW is passed from Pentries-> DW. We have to look at the macro definition

(DWORD) & _ CCMCAMCHEDATA >, / (dword) Offsetof (_Commapclass, punk) /> :: data, /

What means.

Template

_TL_CacheData _ccomcachedata :: data = {dwvar, creator :: createinstance};

CCOMCREATOR We have seen its definition in front, it only has a member function

CreateInstance template class CComCachedTearOffObject: public IUnknown, public CComObjectRootEx {public:. Typedef contained _BaseClass; CComCachedTearOffObject (void * pv): m_contained (((contained :: _ OwnerClass *) pv) -> GetControllingUnknown ()) {m_contained.m_pOwner = reinterpret_cast *> (pv);} CComContainedObject m_contained;}; CComCachedTearOffObject is on a macro and the macro key speak different location Because it contains an object of CCOMCONTAINEDOBJECT. The role of this object is in the query.

Let's take a look at the definition of Offsetof:

#define offsetof (s, m) (SIZE_T) & ((S *) 0) -> M)

For DWORD OFFSTOF (_CommapClass, punk) is the offset value in the _CommapClass class.

Let's take a look at _ATL_CACHEDDATA.

Struct _tl_cachedata {DWORD DWOFFSETVAR; _TL_CREATORFUNC * PFUNC;}; typedef hResult (WinAPI _TL_CREATORFUNC) (Void * PV, REFIID RIID, LPVOID * PPV);

It should be noted that the parameter DW from the _Cached () function is the variable of the _TL_CACHEDATA structure, so it is known that the PV PCD-> DWOFFSetVar is the offset value of the m_punktearoff2 defined in class couter, So IUNKNOWN ** PP is a pointer pointing to a pointer to M_PUNKTEAROFF2.

PDC-> PFUNC () will call CCOMCREATOR > :: CreateInstance

8: CCOMCREATOR :: CreateInstance will create a CCOMCACHEDTEAROFFOBJECT <> object instance. Its constructor is defined as follows:

CComCachedTearOffObject (void * pv): m_contained (((contained :: _ OwnerClass *) pv) -> GetControllingUnknown ()) {ATLASSERT (m_contained.m_pOwner == NULL); m_contained.m_pOwner = reinterpret_cast * > (pv);

Here Contained is CTEAROFF2, Contained :: _ OwnerClass is the couter, you can see M_Contained to save the pointer of the external object.

9: After the object is created, the interface item ITEAROFF2 will be queried.

STDMETHOD (QueryInterface) ({// If it is iUnknown, ..., return IUNKNWON interface pointer else hres = m_contained._internalQueryinterface (IID, PPVObject); .....} Attention, here The query work is handed over to M_Contained, that is, a CCOMCONTAINEDOBJECT object. But now the IUNKNOWN pointer is now, don't forget, we also define an iunknown pointer in the couter, now query is it! !

8: After a series of decall, back to _Cache (), now continue to check the ITEAROFF2 interface. Yes ITEAROFF2 is queried according to the iUnknown pointer we just queried. So once again entered atl :: ccomcachedtearoffObject :: queryinterface (...), but this will call M_Contained._internalQueryInterface (...).

9: Because the base class of ccomcontainedObject m_contained is ctearoff2, CTEAROFF2 :: _ InternalQueryinterface will be called (...)

The rest of the operation is nothing special, and only general query operations.

Perform PTEAR1-> QueryInterface (ITEAROFF2, (Void **) & PTEAR2);

Function Stack 2:

12.ATL :: AtlInternalQueryInterface (...) 11.ATL :: CComObjectRootBase :: InternalQueryInterface (...) 10.CTearOff2 :: _ InternalQueryInterface (...) 9.ATL :: CComCachedTearOffObject :: QueryInterface (. .) 8.Atl :: ccomobjectrootbase :: _ cache (...) 7.couter :: _ cache (...) 6.atl :: atlinternalQueryinterface (...) 5.atl :: ccomobjectRootbase :: interNalQueryInterface ........................................................................................................................................................................................................................................................... ... CCOMCONTAINEDOBJECT :: queryinterface (...)

Explanation:

1: The first step may make us confused, why do ccomcontainedObject :: queryinterface

In the previous section, executing atl :: ccomtearoffObject :: queryinterface (...), so we naturally guess, here should be executed is the function of ccomcachedtearoffObject. But let's take a look at the definition of ccomcachedtearoffObject:

template class CComCachedTearOffObject: public IUnknown, public CComObjectRootEx {...}; no original CComCachedTearOffObject (CTearOff2 is here) contained in the class inherits from, and is inherited from CTearOff1 CComTearOffObject of! So the PTEAR1 we just got will not be the object of CCOMCHEDTEAROFFOBJECT. In fact, ccomcontainedObject is inherited from ctearoff2, and query the ITEAROFF2 interface in step 9 in the above function stack, the work is handed over to m_contained, this is a ccomcontainedObject object, so I actually query ITEAROFF2 pointing Is CCOMCONTAINEDOBJECT object. So now the execution will be ccomcontainedObject :: queryinterface (...)! ! !

STDMETHOD (QueryInterface) (REFIID iid, void ** ppvObject) {HRESULT hr = OuterQueryInterface (iid, ppvObject); if (! FAILED (hr) && _GetRawUnknown () = m_pOuterUnknown) hr = _InternalQueryInterface (iid, ppvObject); return hr; } //? m_pouterunknown

2:

HRESULT OUTERQUERYINTERFACE (REFIID IID, VOID ** PPVObject) {Return M_PouterunkNown-> Queryinterface (IID, PPVObject);}

Turn the query work to the external object, that is, COUTER.

First, the functionality of the second step is the same as that of the previous section, is handed over to the external object to process, and the difference between the following 3-8: Query process in couter is different, we can Jump to step 8

Static HRESULT WINAPI _CACHE (Void * Pv, Refiid IID, Void ** PPVObject, DWORD DW) {.... if (* pp == null) hres = pcd-> pfunc (PV, IID_IUNKNOWN, (Void **) PP ); If (* pp! = Null) hres = (* pp) -> queryinterface (IID, ppvobject); return hres;}

I still remember that we define an iUTerOwn pointer m_punktearoff2, we created a CTEAROFF2 object when I first queryed the ITEAROFF2 interface, and queried an IUnknown pointer to it. Now it works, in _Cache Judgment If m_punktearoff2 does not equal empty, it indicates that CTEAROFF2 has been created, but it is directly used to use it to query the interface.

9: So now call CCOMCachedTearoffObject :: queryinterface (...), in step 9 in the last function stack, we have seen this queryinterface code, which handed the query work to M_Contained._internalQueryInterface (.), because there is no Begin_COM_MAP macro in ccomcontainedObject, so there is no define _interQueryInterface (), so actually calling the functions of the class it contains, that is, ctearoff2 :: _ internalQueryinterface (...) 10- 12: The following work is very simple, no longer described.

to sum up:

COM_TERFACE_ENTRY_CACHED_TEAR_OFF is a relatively troublesome macro, which is different from the macro described in the previous section is that the process of creating a split interface object is only once. If the object has been created, the next query is not the interface of the object. Create a new split object. To achieve this, it contains an IUNKNOWN pointer in the external object and queries this IUNKNOWN pointer when you first create a split object, so you can know if this pointer is empty, you can know if this split object has been created, thus Decide whether a new split object is created and the other interfaces within the split object are queried. It is particularly important to note that there are actually two objects being created, one is ccomcachedtearoffObject , the other is CCOMCONTAINEDOBJECT . And the second object is implemented inside the first object, and the real query work is also handed over to the second object. COUTER:: M_PUNKTEAROFF2 is an iUnknown pointer for an object. When you use it to query itemoff2, it is actually handed over to its internal object M_Contained, which can be seen very clear on the 8th, 9 steps.

I finally finished this macro, I feel that this macro may be the most complicated in the ATL interface map macro, in fact it does not use the true function of CCOMCONTAINEDObject. I feel that this macro may not be so troublesome.

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

New Post(0)