1. In fact, the component class get the interface mapping table is the first GetInterfaceMap () static member function
Get an InterfaceMap structure variable, the second value of this variable is the entry of the interface mapping table.
The first value of InterfaceMap saves the _getBaseInterfaceMap function pointer of the base class.
When the interface is not found in the component class, pass _getBaseInterfaceMap
Get the foundation of InterfaceMap, thereby obtaining the interface mapping table inlet of the base class ....
This is continuously traced..
Through these macros, we implemented interface mapping tables and provided in the class level.
Method. This way, component classes can be locate the query and address of the interface through this table.
However, there is still a big problem here.
We said that any interface must implement AddRef, Release, QueryInterface.
(Note 2: In fact, the definition of the interface has changed after Idispatch appears, you can put any
The combination of methods and data is achieved as an interface.) ... You haven't seen anything about this here ..
Yes, there is still a "big conspiracy" .... About this
#define interface_part (THECLASS, IID, LOCALCLASS) /
{& IID, Offsetof (THECLASS, M_X ## localclass)}, /
// Fill the interface shot table
Stand out ....
In actual engineering, the default above LocalClass will be replaced by Dispatch.
What is DISPATCH? In fact, in CDK1.0, COM development does not have to be above these macros.
Where you can clearly see the essence of the problem, no way, the time has changed, and the situation in front of
Discuss it ...
The location of the Dispatch is specified in the nested class of the interface ...
Then there is no doubt that dispatch is nested. But you said, where is this?
In fact, in the ccmdtarget, there is such a piece:
Struct xdispatch
{
DWORD M_VTBL; // Place-Holder for iDispatch VTABLE
#ifndef _AFX_NO_NESTED_DERIVATION
SIZE_T M_NOFFSET;
#ENDIF
} m_xdispatch;
It will become a nested class that implements the interface.
How can this be a nested class? It does n'thing ... Simply structured ...
Internally, there is the same virtual table vTable assignment behavior, which is this behavior makes m_xdispatch thoroughly
Changed, this behavior of this behavior is EnableAutomation () in the component class constructor.
code show as below:
Void ccmdtarget :: enableautomation ()
{
Assert (GetDispatchMap ()! = Null); // Must Have Declare_Dispatch_map
// Construct an COLEDISPATCHIMPL Instance Just To Get To The VTable
ColedispatchImpl dispatch;
// vTable Pointer SHOULD BE Already Set To Same or Null
Assert (m_xdispatch.m_vtbl == null ||
* (DWORD *) & dispatch == m_xdispatch.m_vtbl);
// sizeof (ColedispatchImpl) Should Be Just A DWORD (VTable Pointer)
Assert (sizeof (m_xdispatch) == sizeof (COLEDISPATCHIMPL));
// copy the vtable (AND Other data) to make sure it is initialized
m_xdispatch.m_vtbl = * (dword *) & dispatch;
* (COLEDISPATCHIMPL *) & m_xdispatch = dispatch;}
Part 2 deep into ccmdtarget to see the implementation of the three elements of COM
The reason why us go deep into ccmdtarget
I don't think it is just to implement it.
We want to know a great scene of MFC to COM: polymerization
How is it implemented?
Don't say two words, put out the frame:
PUBLIC:
// data used when ccmdtarget is Made Ole Aware
Long m_dwref;
LPUNKNOWN M_POUTERUNKNOWN; // External Controlling Unknown if! = NULL
DWORD M_XINNERUNKNOWN; // Place-Holder for Inner Controlling Unknown
PUBLIC:
// Advanced Operations
Void enableaggregation (); // call to enable aggregation
Void externaldisconnect (); // forcibly disconnect
LPunknown getControllingunkNown ();
// Get Controlling iUnknown for aggregate cree
// THESE VERSIONS DO NOT DELEGATE TO M_POUTERUNKNOWN
DWORD INTERQUERYINTERFACE (const void *, lpvoid * ppvobj);
DWORD INTERNALADDREF ();
DWORD INTERNALESE ();
// THESE VERSIONS DELEGATE TO M_POUTERUNKNOWN
DWORD EXTERNALQUERYINTERFACE (const void *, lpvoid * ppvobj);
DWORD EXTERNALADDREF ();
DWORD EXTERNALRELEASE ();
//Mplementation Helpers
LPunknown GetInterface; Const Void *);
LPunkNown QueryAggregates (const void *);
// Advanced Overrideables for Implementation
Virtual bool oncreateaggregates ();
Virtual lpunknown getInterfaceHook (const void *);
From the above statement, you can find:
Here, two standard interface methods are declared.
ExternalXX corresponds to the entrustment IUnknown in the COM model
And INTERNALXX corresponds to non-entrusting IUNKNOWN
With these two interface methods, the achievement of aggregation is OK ....
For details on aggregation, for details, please refer to relevant special
Books, no more details here.
The foundation structure of the interface is completed by Part1 and Part 2.
Part3 -------- Class factory
Needless to say, COM objects are created in need of class.
-------------------------------------------------- -------------------------------------------------- -----
Declare_olecreate (csam) macroblock
-------------------------------------------------- ---------------------------
#define declare_olecreate (Class_name) /
PUBLIC: /
Static AFX_Data ColeObjectFactory Factory; /
// Define the class factory object ...
Static Afx_Data Const Guid Guid; /
// Component Class GUID
-------------------------------------------------- -------------------------------------------------- ------------
Implement_olecreate macroblock
-------------------------------------------------- ----------------
#define import_olecreate (Class_name, External_Name, L, W1, W2, B1, /
B2, B3, B4, B5, B6, B7, B8) /
AFX_DATADEF COLEOBJECTFAACTORY CLASS_NAME :: Factory (class_name :: Guid, /
Runtime_class (class_name), false, _t (external_name)); /
/ / What to pay attention to is external_name: progid
AFX_COMDAT const AFX_DATADEF GUID CLASS_NAME :: Guid = /
{L, W1, W2, {B1, B2, B3, B4, B5, B6, B7, B8}}; /
// Give the CLSID of the component class to the member variable GUID of the component class.
-------------------------------------------------- -------------------------------------------------- -------
Implement_olecreate (CSAM, "MFCcom.sam",
0x43d242f9, 0x4f7e, 0x4cbb, 0xae, 0xDa, 0x77, 0x8d, 0xa1, 0x16, 0xD0, 0xD9)
Description: We know that when you create a component class object, you first get the current state by the app core.
Remove the class factory table from the middle, get the corresponding class factory object pointer according to CLSID. It is here
Associate information such as class and CLSID, ProID.
PART4 ------- Automation
In fact, automation is also a great subject. Automation technology enhances the environmental adaptability of components.
For automation components in the MFC, because the default interface is DISPINTERFACE, it is
Accessions use distribution means. Unlike your consciousness, always keep in mind through vtable [_index]
To access the method. In the process of using the component, first get the idispatch interface, then call IDispatch
Method GetidsOfNames gets the token (ID) of the method of Programmers hopes, finally passed
Idispatch's method invoke is executed. This technology allows scripts and macro environments to use COM
Objects, but for environments with pre-compilation, it will make the performance of the component system
Discount. Because it is more than one intermediate layer repeatedly called.
About Dispatch support, basically constructing the principle of thinking with
The above INTERFACE.
-------------------------------------------------- -------------------------------------------------- -------------------
Declare_dispatch_map ()
Begin_Dispatch_map (csam, ccmdtarget) [. CPP]
DISP_PROPERTY_NOTIFY (CSAM, "Fook", M_fook, OnfookChanged, VT_R4)
DISP_FUNCTION (CSAM, "Post", POST, VT_R4, VTS_NONE)
END_DISPATCH_MAP ()
Mobility ------------------------------------------------ -------------------- # IFDEF_AFXDLL
#define declare_dispatch_map () /
PRIVATE: /
Static const AFX_DISPMAP_ENTRY _DISPATCHENTRIES []; /
Static uint _dispatchentrycount; /
Static DWORD _DWSTOCKPROPMASK; /
protected: /
Static AFX_DATA const AFX_DISPMAP DispatchMap; /
Static const AFX_DISPMAP * PASCAL _GETBASPASPATCHMAP (); /
Virtual const AFX_DISPMAP * getDispatchMap () const; /
#ELSE
#define declare_dispatch_map () /
PRIVATE: /
Static const AFX_DISPMAP_ENTRY _DISPATCHENTRIES []; /
Static uint _dispatchentrycount; /
Static DWORD _DWSTOCKPROPMASK; /
protected: /
Static AFX_DATA const AFX_DISPMAP DispatchMap; /
Virtual const AFX_DISPMAP * getDispatchMap () const; /
#ENDIF
-------------------------------------------------- ----
#ifdef _AFXDLL
#define begin_dispatch_map (Theclass, BaseClass) /
Const Afx_Dispmap * pascal theclass :: _ getBaseDispatchMap () /
{RETURN & BASECLASS :: DispatchMap;} /
Const Afx_Dispmap * Theclass :: getDispatchmap () const /
{RETURN & THECLASS :: DispatchMap;} /
AFX_COMDAT const AFX_DISPMAP THECLASS :: DispatchMap = /
{& THECLASS :: _ getBasedispatchMap, & theclass :: _ dispatchentries [0], /
& theclass :: _ dispatchentrycount, & thermlass :: _ dwstockpropmask}; /
AFX_COMDAT uint theclass :: _ dispatchentrycount = (uint) -1; /
AFX_COMDAT DWORD THECLASS :: _ DWSTOCKPROPMASK = (DWORD) -1; /
AFX_COMDAT const AFX_DISPMAP_ENTRY THECLASS :: _ dispatchentries [] = /
{/
#ELSE
#define begin_dispatch_map (Theclass, BaseClass) /
Const Afx_Dispmap * Theclass :: getDispatchmap () const /
{RETURN & THECLASS :: DispatchMap;} /
AFX_COMDAT const AFX_DISPMAP THECLASS :: DispatchMap = /
{& Baseclass :: DispatchMap, & Theclass :: _ dispatchentries [0], / & theclass :: _ dispatchentrycount, & thermlass :: _ dwstockpropmask}; /
AFX_COMDAT uint theclass :: _ dispatchentrycount = (uint) -1; /
AFX_COMDAT DWORD THECLASS :: _ DWSTOCKPROPMASK = (DWORD) -1; /
AFX_COMDAT const AFX_DISPMAP_ENTRY THECLASS :: _ dispatchentries [] = /
{/
#ENDIF
#define end_dispatch_map () /
{VTS_NONE, DISPID_UNKNOWN, VTS_NONE, VT_VOID, /
(AFX_PMSG) NULL, (AFX_PMSG) NULL, (SIZE_T) -1, AfxDispcustom}}; /
The way the idea is the same as the above interface map. Here is not detailed here.
About Automation Question, I think two days, specialize in writing an article.
Because Automation is indeed a wide range of technologies, what can I say?
Difficult, but there are many details, and the general discussion is unclear.
The structure that appears in the above macro is needed:
Struct AFX_DISPMAP_ENTRY
{
LPCTSTSTR LPSZNAME; // Method or attribute name
Long ldispid; // Interface distribution ID (May Be Dispid_Unknown)
LPCSTR LPSZPARAMS; // Parameters
Word vt; // Return value type or attribute type
AFX_PMSG PFN; // Normal Member On OR, ONGET
AFX_PMSG PFNSET; // Special Member for Onset
Size_t npropoffset; // offset, this place is the core
AFX_DISPMAP_FLAGS FLAGS; // Flags (E.G. Stock / Custom)
}
Struct AFX_DISPMAP
{
#ifdef _AFXDLL
Const AFX_DISPMAP * (PASCAL * PFNGETBASEMAP) ();
#ELSE
Const AFX_DISPMAP * PBASEMAP;
#ENDIF
Const AFX_DISPMAP_ENTRY * LPENTRIES;
Uint * LpenTryCount;
DWORD * LPSTOCKPROPMASK; / / Do you use a spare name
}
In summary, even when the component class finds an interface, the method or change attribute is executed in the way, it is not performed directly.
Part 5 ------- Component Terrace: Several core functions
Naturally, the use of components is not always, starting from the call interface query function,
The program is started to find and create the process:
NO1.
ColeObjectFactory :: registerall ();
When the application is initialized, call. Where is the purpose? None is the registered factory.
(This place, I think it is loaded with all kinds of works.
Because you can directly use the class factory pointer in the pointer chain directly)
NO2.
AFX_MANAGE_STATE (AFXGETSTATICModuleState ());
In the core of the CWINAPP object developed by MFC
In the component, AFX_Manage_State (AFXGETSTAICMODULESTATE ());
You must call before the specific operation because it masters all the information.
In ATL, CCOMMODEL objects, coordinated inside.
Everything is scheduled by the CCOMMODEL object.
NO3.
AFXDLLGETCLASSOBJECT (RCLSID, RIID, PPV); you want to get the desired interface pointer, which is necessary to get the steps of the class pointer.
Getting the factory pointer is AFXDLLGETCLASSOBJECT (RCLSID, RIID, PPV);
Completed, it must be called before use
AFX_MANAGE_STATE (AFXGETSTATICModuleState ());
To monitor the status,
code show as below:
Scode AFXAPI AFXDLLGETCLASSOBJECT (Refclsid Rclsid, Refiid Riid, LPVOID * PPV)
{
* ppv = NULL;
DWORD LDATA1 = rclsid.data1;
// Search Factories Defined in the Application
AFX_MODULE_STATE * PModuleState = AFXGETMODULESTATE ();
AfxlockGlobals (crit_ObjectFactoryList);
For (ColeObjectFactory * pFactory = PModuleState-> m_factorylist;
Pfactory! = null; pfactory = pfactory-> m_pnextfactory)
{
IF (pfactory-> m_bregistered! = 0 &&
LDATA1 == PFactory-> m_clsid.data1 &&
((DWORD *) & rclsid) [1] == ((DWORD *) & pfactory-> m_clsid) [1] &&
((DWORD *) & rclsid) [2] == ((DWORD *) & pfactory-> m_clsid) [2] &&
((DWORD *) & rclsid) [3] == ((DWORD *) & pfactory-> m_clsid) [3])
{
// Found Suitable Class Factory - Query for Correct Interface
Scode SC = PFactory-> InternalQueryInterface (& RIID, PPV);
AFXUNLOCKGLOBALS (crit_ObjectFactoryList);
Return SC;
}
}
AFXUNLOCKGLOBALS (crit_ObjectFactoryList);
#ifdef _AFXDLL
AfxlockGlobals (crit_dynlinklist);
// Search Factories Defined in Extension DLLS
For (cdynlinklibrary * pdll = pmodulestate-> m_libraryList; pdll! = null;
PDLL = PDLL-> M_PNEXTDLL)
{
FOR (PFactory = PDLL-> m_factorylist;
Pfactory! = null; pfactory = pfactory-> m_pnextfactory)
{
IF (pfactory-> m_bregistered! = 0 &&
LDATA1 == PFactory-> m_clsid.data1 &&
((DWORD *) & rclsid) [1] == ((DWORD *) & pfactory-> m_clsid) [1] && ((dword *) & rclsid) [2] == ((DWORD *) & pfactory-> m_clsid) [2 ] &&
((DWORD *) & rclsid) [3] == ((DWORD *) & pfactory-> m_clsid) [3])
{
// Found Suitable Class Factory - Query for Correct Interface
Scode SC = PFactory-> InternalQueryInterface (& RIID, PPV);
AfXunlockGlobals (crit_dynlinklist);
Return SC;
}
}
}
AfXunlockGlobals (crit_dynlinklist);
#ENDIF
// Factory Not Registered - Return Error
Return Class_e_classNotavailable;
}
Code brief description:
First, when the component exports the function DllgetClassObject via CLSID and IID, first
The program environment will be monitored, then call AFXDLLGETCLASSOBJECT, and AfxdllgetClassObject
The internal operation is like this, which will be maintained in the global information maintained (
There are also registered types of customs, resource handles, etc., according to CLSID search
The corresponding class is searching in the extended DLL referenced by this DLL.
OK! Basically, the MFC's basic support of COM is through the above macro.
Realize ...
-------------------------------------------------- ----------------------------------
Treatment of ATL
-------------------------------------------------- ----------------------------------
Solemnly declare:
Allow copy, modification, delivery, or other behavior
However, it is not allowed for any commercial use.
Written at 1/4/2003
Last modified: 1/4/2003
By Tomhornson (@) Hotmail.com
-------------------------------------------------- ----------------------------------