Ccomobjectrootobjectbase provides an internal implementation of interface query in table-driven mode, that is, internalqueryinterface (). Therefore, when creating an ATL-Based Com class, you must create a ing table containing all the Implemented interfaces.
1. begin_com_map, end_com_map, com_interface_entry, and com_interface_entry2 macros
ATL provides
Begin_com_map,
End_com_map,
Com_interface_entry
Com_interface_entry2
These four macros are used to create an interface ing table.
Assume that a class cclassa inherits the iinta and iintb interfaces, the interface ing table of this class is created as follows:
Class cclassa: Public ccomobjectrootex <ccomsinglethreadmode>
{
Begin_com_map (cclassa)
Com_interface_entry (iinta)
Com_interface_entry (iintb)
End_com_map ()
......
};
While, when cclassb inherits iintc and iintd, both iintc and iintd inherit from the idispatch interface. At this time, if the client program is querying the idispatch interface, the idispatch interface pointer returned by QueryInterface cannot determine whether it belongs to iintc or iintd. In this case, you need to specify the default point of the idispatch interface pointer. The com_interface_entry2 () macro is used to complete this function. The following code points the request to the idispatch interface to the iintd idispatch interface pointer by default.
Class cclassb: Public ccomobjectrootex <ccomsinglethreadmode>
{
Begin_com_map (cclassa)
Com_interface_entry (iintc)
Com_interface_entry (iintd)
Com_interface_entry2 (idispatch, iintd)
End_com_map ()
......
};
2. Implementation and functions of the interface ing table
You can get the following code by using the macro extension in cclassb, which is slightly simplified:
Class cclassb: Public ccomobjectrootex <ccomsinglethreadmode>
{
// Begin_com_map (cclassb)
Public:
Typedef cclassb _ commapclass;
Static hresult _ cache (void * PV, refiid IID, void * ppvobject, dword_ptr DW)
{
_ Commapclass * P = (_ commapclass *) PV;
P-> lock ();
Hresult hres = ccomobjectrootbase: _ cache (PV, IID, ppvobject, DW );
P-> unlock ();
Return hres;
}
Iunknown * _ getrawunknown ()
{Return (iunknown *) (int_ptr) This ++ _ getentries ()-> DW );}
Hresult _ internalqueryinterface (refiid IID, void ** ppvobj)
{Return internalqueryinterface (this, _ getentries (), IID, ppvobj );}
Const static ATL: _ atl_intmap_entry * _ getentries ()
{
Static const ATL: _ atl_intmap_entry _ entries [] =
{
// Com_interface_entry (iintc)
{& _ Atl_iidof (iintc ),
Offsetofclass (iintc, _ commapclass ),
_ Atl_simplemapentry
},
// Com_interface_entry (iintd)
{& _ Atl_iidof (iintd ),
Offsetofclass (iintd, _ commapclass ),
_ Atl_simplemapentry
},
// Com_interface_entry2 (idispatch, iintd)
{& _ Atl_iidof (iintd ),
Reinterpret_cast <dword_ptr> (static_cast <idispatch *> (
Static_cast <iintd *> (reinterpret_cast <_ commapclass *> (8)-8,
_ Atl_simplemapentry
},
// End_com_map ()
{Null, 0, 0}
};
Return & _ entries;
}
Virtual ulong addref () = 0;
Virtual ulong release () = 0;
Hresult QueryInterface (refiid, void *) = 0; (# how to add the order of the three functions ?)
};
According to the above Code, the key to the role of begin_com_map () and other macros is to provide a static _ getentries () method to obtain a static COM interface ing table created in this method. Where, when the base class (or interface) is the parent class (or interface) of the derived class (or interface), The offsetofclass (base, derived) macro is used to return the base interface (or Class) the pointer offset value in the class relative to the derived pointer in the virtual table of the derived class. The _ atl_simplemapentry constant represents the second member DW of the _ atl_intmap_entry structure, which represents the offset value between the base and the derived pointer. The main difference between com_interface_entry2 and com_interface_entry is the calculation of the Offset Value.
In addition, the end_com_map () macro declares the addref () and release () Methods of iunknown as pure virtual functions. From this we can see that the iunknown interface method is destined to have the subclass implementation of this class.
3. Conclusion
Each Atl-based COM object must first create a static interface ing table, which is created by the begin_com_map, end_com_map, com_interface_entry, and com_interface_entry2 macros. They create an interface ing table and an interface ing table to obtain functions, and declare iunknown methods as pure virtual functions, which will be implemented by their derived classes.