ATL interface mapping macro detailed [2]

zhaozj2021-02-16  81

5:

CCMCREATOR :: CreateInstance (Void * PV, Refiid Riid, LPVOID * PPV) {T1 * P = NULL; ATLTRY (P = New T1 (PV)) // Create Class Factory object if (p! = Null) {P-> SetVoid (PV); P-> InternalFinalConstructAddref (); hres = p-> finalconstruct (); p-> infinalconstructrelease (); if (hres == s_ok) hres = p-> queryinterface (riid, ppv); if (HRES ! = S_OK) Delete P;}}

Note that the T1 here is ccomobjectcached , this is the template parameter we give CComcreator. We have seen our familiar operators 'new'! Until now we have finally created a component of the component. But I haven't finished, continue to go down, what do you do in Setvoid (PV)?

Void ccomclassfactory :: setvoid (void * pv) {m_pfncreateInstance = (_tl_creatorfunc *) PV;}

Everyone still remember that we used to pass CMYOBJECT :: _ CreatorClass :: CreateInstance as a parameter to Pentry-> PfNgetClassObject (...), then we don't understand what is going on, now it is clear! It turns out that the class is a factory that needs it to create a component object! Although we just guess this from literally, it is actually as it is expected, in CCOMCLASSFAACTORY: CREATEINSTANCE (...), we have seen M_PFNCREATEINSTANCE (Punkouter, Riid, PPVOBJ); now everything is already Understand, ATLs have been opened for us to create a class, and we have opened it. The rest of the process of creating components is already our very familiar process!

But now, now we need to query an IUNKNOWN pointer for the class object, this pointer exists in the PENTRY-> PCF seen in front.

6:

STDMETHOD (REFIID IID, VOID ** PPVObject) {return_internalQueryInterface (IID, PPVObject);}

Now calling ccomobjectcached :: queryinterface, as for this class, we don't need to know now, I am very tired, huh, huh.

7:

HRESULT _INTERNALQUERYINTERFACE (Refiid IID, Void ** PPVObject) / {Return InternalQueryInterface (this, _Getentries (), IID, PPVObject);}

All classes of _internalqueryinterface (...) are defined in Begin_COM_MAP. CCOMOBJECTCACHED does not have a begin_com_map macro, so call now CCOMCLASSFAACTory. Note that the THIS pointer and interface mapping array _Getentries () is passed to INTERNALQUERYINTERFACE (), which is the basis for implementing queries (...). Define a static interface mapping array in Begin_COM_MAP (X): _TL_INTMAP_ENTRY _ENTRIES [];

Each interface mapping macro is actually an increase in an array. An interface map macro includes three parts: the IID number of the interface, the offset value (most of the time), the function that needs to be executed, does not have other functions for the general interface. _Getentries () is returning to this array. There are still some details of the issue.

8:

static HRESULT WINAPI InternalQueryInterface (void * pThis, const _ATL_INTMAP_ENTRY * pEntries, REFIID iid, void ** ppvObject) {... HRESULT hRes = AtlInternalQueryInterface (pThis, pEntries, iid, ppvObject); ...}

Co-call now CComObjectRootBase :: InternalQueryinterface (...)

9: Now we finally arrived at QueryInterface's nose.

AtlinternalQueryInterface (...) is the end point of the entire query process, which traverses the interface mapping table and makes the corresponding action according to each item. There are many kinds of news maps in ATL, there are many ways, but now we don't care about those, now we have to do it is to find an iUnknown interface, which is easy, we don't even need to traverse interface mapping tables.

ATLINLINE ATLAPI AtlInternalQueryInterface (void * pThis, const _ATL_INTMAP_ENTRY * pEntries, REFIID iid, void ** ppvObject) {ATLASSERT (pEntries-> pFunc == _ATL_SIMPLEMAPENTRY); if (ppvObject == NULL) return E_POINTER; * ppvObject = NULL; if ( Inlineisequalunknown (IID)) // USE First Interface {iUnknown * punk = (iUnknown *) ((int) PTHIS PENTRIES-> DW); punk-> addref (); * ppVObject = punk; return s_ok;} ... // There is also a lot of piles, but now you can't use it, save some space}

Here is a provision that the first interface of the interface mapping table must be _ATL_SIMPLEENTRY. As for why this requirement, and pthis pentries-> DW, let's talk later, it is also a bunch of problems. In short, we are now having easy access to the class objects we need and the iUnknown pointer.

4: I think we can get back to the first step, but in atl :: atlmodulegetclassobject, stop, look at its source code, but also query the iClassFactory pointer by the iUnknown pointer you just received. . It is also the same call, just as in step 6 to 9, we will make the same call. Note that in step 9, we are no longer the iUnknown pointer, so we need to see the code I have not listed, but this is left to the next function stack and look at 1: Finally finally All operations of the creation of a class object have been completed, and now we have to do is the process of creating components of the CreateInstance (...) function we are familiar with the Create of the Capture Factory. As we see, now OLE starts calling ccomclassfactory :: createInstance (), we haven't forgotten, and the CreateInstance () function for creating components has been reserved in the class factory object, which is already very clear.

2. Don't repeat it, see step 4.

3. Don't repeat it, see step 4.

4. If we continue to route, our stack can be very long, but this is just a repeated mood. I didn't continue to go, I was very tired, hehe.

Function call stack 2:

0: .......... 5.atl :: atlinternalQueryinterface (...) 4.atl :: ccomobjectrootbase :: InternalQueryinterface (...) 3.cmyObject :: _ InternalQueryinterface (...) 2.atl :: ccomobject :: queryinterface (...) 1.punk-> queryinterface (IID_IMYOBJECT, (Void **) & PMYObject; (client)

Explain as follows:

1. We query the iMyObject pointer through the iUnknown interface pointer of the components that have just been obtained. This is the pointer we really need.

2. Remember that we said that the ATL really created components is not CMYObject, but ccomobject, ccomaggobject or ccompolyobile, here we create ccomobject. So we must call CComobject :: queryinterface (...), and indeed CComobject Implement this function.

STDMETHOD (QueryInterface) (Refiid IID, Void ** PPVObject)

{RETURN _INTERNALQUERYINTERFACE (IID, PPVObject);

It is just simply call _internalQueryInterface (...), we also said that only the begin_com_map macro will be _internalQueryinterface (...), so now do it to its parent class cMyObject, so Call CMYOBJECT: :: _ interfaceQueryInterface (...)

3. In the future, we are already very familiar, but also to say it again, huh, huh

4. This call is also very familiar, don't say more.

5. Now we will query is a non-iunknown interface, so let's take a look at the code we have not listed before.

Atlinline Atlapi AtlinternalQueryInterface (Void * Pthis, Const _Tr_INTMAP_ENTRY * PENTRIES, REFIID IID, VOID ** PPVObject) {// Make sure the first item of the interface map is a simple interface // If you query the iUnknown interface, perform the appropriate operation // below will be traversed Interface mapping table, trying to find the corresponding interface while (pentries-> pfunc! = Null) {bool bblind = (pentries-> piid == null); if (bblind || Inlineisequalguid (* (Pentries-> PIID), IID) ) {// _ATL_SIMPLEMAPENTRY indicates a simple interface if (Pentries-> PFUNC == _ATL_SIMPLEMAPENTRY) // offset {atlassert (! BBLIND); IUNKNOWN * PUNK = (IUNKNOWN *) ((int) PTHIS PENTRIES-> DW); Punk-> addRef (); * pPVObject = punk; return s_ok;} Else // If not a simple interface, you need to perform the corresponding function {HRESULT HRES = Pentries-> Pfunc (PTHIS, IID, PPVObject, Pentries-> DW ); If (hres == s_ok || (! BBLIND && Failed (HRES))) Return HRES;}}} } Return E_NOINTERFACE;}} The logic of the function is very clear, only two points may not understand, one is (iUnknown *) ((int) pTHIS PENTRIES-> DW) What is the meaning, the other is Pentries-> PFUNC to the end Do something. The previous problem will tell in COM_ITERFACE_ENTRY2, and the latter problem will explain the different types of interfaces later. The meal is always a bit to eat, huh, huh. Now we just need to care about how our iMyObject is found. Look at its macro We will unwind the com_interface_entry (iMyObject) to follow:

{& _ATL_IIDOF (IMYObject), // Get iMyObject's IID Value OffsetOfClass (iMyObject, CMYObject), // Define Offset_SimpleMapenTry}, // Indicates that it is a simple interface

We will also stay again later for OffsetOfClass (ImyObject, CMYOBJECT). According to this structure, we can easily get the IMYOBJECT interface pointer.

0: OK, IT is over. Return it in turn.

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

New Post(0)