Detailed description of ATL interface ing macros [3]

Source: Internet
Author: User
3. For com_interface_entry_tear_off (IID, x), refer to the ATL routines beeper and commap.

The purpose of using this macro is to put some rarely used interfaces in a single component for implementation.
This component is created only when this interface is found, and is released when its reference count is reduced to 0. Me
We know that components in ATL are implemented through multi-inheritance. Every time an interface is inherited, the system will
One more virtual function table pointer. With this macro, you can save this virtual function table pointer for each component instance.
(A pointer of 4 bytes does not seem to contain much)
Let's take a look at its typical usage:
Class ctearoff1: // This class is specifically used to implement the itearoff1 split interface.
Public idispatchimpl,
Public ccomtearoffobjectbase // External Object
Ctearoff1 (){}
~ Ctearoff1 (){}
Begin_com_map (ctearoff1)
Com_interface_entry (itearoff1)
End_com_map ()
Hresult stdmethodcalltype get_name (BSTR * pbstrname)
* Pbstrname =: sysallocstring (L "itearoff1 ");
Return s_ OK;

Class couter: Public... // The component we really want to implement
Begin_com_map (couter)
Com_interface_entry_tear_off (iid_itearoff1, ctearoff1)
End_com_map ()
Ctearoff1 implements the tear-Off Interface itearoff1, And the implementation method is no different from other components. The only difference
It inherits from ccomtearoffobjectbase. The definition of ccomtearoffobjectbase is as follows:
Class ccomtearoffobjectbase: Public ccomobjectrootex
Typedef owner _ ownerclass;
Ccomobject * m_powner;
Ccomtearoffobjectbase () {m_powner = NULL ;}
We have seen a familiar class ccomobject, which is the real generation class of components. From the above definition
We can see that the main function of ccomtearoffobjectbase is to include a pointing External Object (Here we
(Ccomobject) pointer. Its functions will be shown later.
We continue to use our old method to follow up on its execution process. Assume that pouter is what we have obtained

Iouter interface pointer of the component.
Run pouter-> QueryInterface (iid_itearoff1, (void **) & ptear1 );
Function stack 1:
7. ctearoff1: _ internalqueryinterface (...)
6. ATL: ccominternalcreator> ::
Createinstance (...)
5. ATL: ccomobjectrootbase: _ creator (...)
4. ATL: atlinternalqueryinterface (...)
3. ATL: ccomobjectrootbase: internalqueryinterface (...)
2. couter: _ internalqueryinterface (...)
1. ATL: ccomobject: QueryInterface (...)

1--4: these codes have been met many times. We should focus on the core code:
Atlinline atlapi atlinternalqueryinterface (void * pthis,
Const _ atl_intmap_entry * pentries, refiid IID, void ** ppvobject)
While (pentries-> pfunc! = NULL)
Bool bblind = (pentries-> piid = NULL );
If (bblind | inlineisequalguid (* (pentries-> piid), IID ))
If (pentries-> pfunc = _ atl_simplemapentry) // offset
// If it is a simple interface ,....
Else // actual function call
Hresult hres = pentries-> pfunc (pthis,
IID, ppvobject, pentries-> DW );
If (hres = s_ OK | (! Bblind & failed (hres )))
Return hres;
Pentries ++;
Return e_nointerface;
After itearoff1 is found in the couter interface ing array, it is executed because it is not a simple interface
Pentries-> pfunc (....). Let's take a look at the definition of com_interface_entry_tear_off:
# Define com_interface_entry_tear_off (IID, x )/
{& IID ,/
(DWORD) & _ ccomcreatordata </ccominternalcreator <ccomtearoffobject <x>/
>: Data ,/
_ Creator },
I don't quite understand. We still got the route.
5: The original _ creator is a static member function of ccomobjectrootbase. It is a base class of couter,
Therefore, you can write in this way without compiling errors. Let's take a look at its implementation:
Static hresult winapi _ creator (void * PV, refiid IID, void ** ppvobject, DWORD)
_ Atl_creatordata * PCD = (_ atl_creatordata *) dw;
Return PCD-> pfunc (PV, IID, ppvobject );
Struct _ atl_creatordata
_ Atl_creatorfunc * pfunc;
Typedef hresult (winapi _ atl_creatorfunc) (void * PV, refiid riid,
Lpvoid * GMM );
_ Atl_creatordata _ ccomcreatordata: Data =
{Creator: createinstance };
The source code is listed. You can understand it as much as I have to say. Continue Routing
6: after a large circle, we should call ccominternalcreator <...>: createinstance
Class ccominternalcreator
Static hresult winapi createinstance (void * PV, refiid riid, lpvoid * PQ)
Atlassert (* GMM = NULL );
Hresult hres = e_outofmemory;
T1 * P = NULL;
Atltry (P = new T1 (PV ))
If (P! = NULL)
P-> setvoid (PV );
P-> internalfinalconstructaddref ();
Hres = p-> finalconstruct ();
P-> internalfinalconstructrelease ();
If (hres = s_ OK)
Hres = p-> _ internalqueryinterface (riid, GMM );
If (hres! = S_ OK)
Delete P;
Return hres;
Like most of the Creator classes we have seen, it also has only one static createinstance function. Now
We can finally create our split component. It is not ctearoff1, it is also packaged by a layer, yes
Ccomtearoffobject! Now let's take a look at what its constructor has done:
Ccomtearoffobject (void * PV)
Atlassert (m_powner = NULL );
M_powner = reinterpret_cast *> (PV );
M_powner-> addref ();
Do you still remember that ctearoff1 is inherited from ccomtearoffobjectbase? This base class contains a member change
M_powner. Now it is assigned a pointer to its external object.
7. Now the component that implements the split interface is created, and the rest queries itearoff1 in ctearoff1
The work is already repetitive and will not be repeated.

Run ptear1-> QueryInterface (itearoff1, (void **) & ptear2)
A component that implements a split interface may contain multiple split interfaces. Let's check its query process.
Function stack 2:
4 ..............
3. couter: _ internalqueryinterface (...)
2. ATL: ccomobject: QueryInterface (...)
1. ATL: ccomtearoffobject: QueryInterface (...)

1: stdmethod (QueryInterface) (refiid IID, void ** ppvobject)
Return m_powner-> QueryInterface (IID, ppvobject );
Do you still remember that the split component we created is ccomtearoffobject? Query now
Is its member functions. Its implementation is very simple. In fact, it does nothing, just giving it out.
The local object (ccomobject. Remember that m_powner assigned values in the constructor.
Are you feeling a little bad? Haha
2, 3:
Sure enough, now we don't have to look at it any more. The rest will be repeated. We are calling the first query operation.
Everything. This process is very simple, but it also implies one point: Every query of a component that implements a split Interface
A new instance will be called once you query its interface !!! In the above example, the final results are ptear2 and ptear1.
It is different !! This is obviously a waste!
In the next section, we will introduce a macro that can solve this problem!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.