Basic principles of connectable objects and connection point mechanisms
In order to provide greater interaction between component objects and customers, component objects also need to actively communicate with customers. Component objects communicate with customers via an outgoing interface. If a component object defines one or more outgoing interfaces, this component object is called a connectable point object.
The so-called exit is also a COM interface. Each outgoing interface contains a set of member functions, each member function represents an event, a notification or a request. However, these interfaces are implemented in the customer's event receiver (SINK), so the interface is called. The event receiver is also a COM object.
Connectable objects must implement an iconnectionPointContainer interface to manage all outlines. Each outgoing interface corresponds to a connection point object, the connection point object implements an iconnectionPoint interface. Customers are establishing a connection with the connectable object through the iconnectionPoint interface. Each connection is described with a ConnectData structure.
ConnectData contains two members: IUNKNOWN * PUNK and DWORD DWCOOKIE. The PUNK corresponds to the iUnknown interface pointer to the client's event receiver; DWCookie is a 32-bit integer generated by the connection point object to uniquely identify this connection.
With an enumerator interface IENUMCONNECTIONPOINTS implemented by a connectable object, customers can access all connection points for the connected object. But to get the IEnumConnectionPoints interface pointer, you have to pass the IconnectionPointContainer :: EnumConnectionPoints (IEnumConnectionPoints **) function, this function returns the enumerator interface pointer.
Through another enumerator interface IEnumConnections implemented with an accessible object, all connections on a connection point cannot be accessed regardless of customer or connection objects. The IenumConnections interface pointer can be obtained through the IconnectionPoint :: EnumConnections function.
In summary, a connectable object must implement four interfaces: IconnectionPointContainer, IconnectionPoint, IEnumConnectionPoints, IEnumConnections. For the definition of these four interfaces, please read the MSDN document.
The process of connecting to objects and customer communication now is now briefly described. In the following example, the connectable object Connobject defines the interface IEventSink, and the interface is corresponding to this interface, which implements a connection point object SampleConnpoint (this object implements the connection point interface IconnectionPoint corresponding to the interface, the interface ID is IID_IEventsink).
After the customer acquiring a pointer to the IUnknown interface of an object can be connected m_pIUnknown call m_pIUnknown-> QueryInterface (IID_IConnectionPointContainer, (void **) & pConnPtCont); If the call succeeds, pConnPtCont IConnectionPointContainer interface pointer stored in the object can be connected. If the call is unsuccessful, it indicates that the object is not a connectable object. Call PConnptCont-> FindConnectionPoint (IID_IEventsink, & PConnpt). If you call the success, PConnPt will store the connection point interface IconnectionPoint pointer implemented corresponding to the connection point object Sample Connection Objects IeventSink; if the call is unsuccessful, it means that the connectable object does not support the interface Ieventsink. Call PConnpt-> Advise (PIEventSink, & M_DWCookie) to establish a connection to the event receiver (EventSink) and the connection point. The PIEventSink is a pointer to the client event receiver iUnknown interface. This pointer passes this function to the connectable object to connect to the client to initiate communication to the customer; m_dwcookie is a connection ID, this value is saved by the client, customer This value is also disconnected. Connectable objects can call the method in the client event receiver through the connection point. After the client is successfully established, the connection point has been saved in the connection point and can call PConnpt-> getConnections () to get. Customer calls PConnpt-> Unadvise (m_dwcookie) to cancel the connection, and call the PConnpt-> Release () release the connection point object. Programming instance
A connectivity object is now implemented with an MFC and then writes an extremely simple customer and time receiver.
It should be noted that the MFC implements the IConnectionPointContainer and the IEnumConnectionPoints interface through the CCMDTarget class. In addition, the IconnectionPoint interface is implemented by the CConnectionPoint class.
Connectable object connobject
In this object, realize a general COM interface IeventServer, customers can use this interface
Method DOSMETHING () makes something, but the main thing is that the object will trigger an event here. SampleConnpoint
Implement the connection point object.
Write in Guids.h:
// {EE888B01-EA9C-11D3-97B5-5254AB191930}
Static const Iid CLSID_CONNOBJECT = // Component ID
{0xEE888B01, 0XEA9C, 0x11D3, {0x97, 0xB5, 0x52, 0x54, 0xAb, 0x19, 0x19, 0x30}}
// {EE888B02-EA9C-11D3-97B5-5254AB191930}
Static const IID_IEventServer = // General COM interface, customer uses this interface method
// DOSMETHING ()
{0xee888B02, 0xEA9C, 0x11D3, {0x97, 0xB5, 0x52, 0x54, 0xAb, 0x19, 0x19, 0x30}};
{EE888B03-EA9C-11D3-97B5-5254AB191930}
Static const IID_IEventsink = // Connection point interface ID implemented
{0xee888B03, 0xEA9C, 0X11D3, {0x97, 0xAb, 0x52, 0x54, 0xAb, 0x19, 0x19, 0x30}}; 2. Write in IconNobject.h
#include "guids.h"
// Declare the IeventServer interface
Declare_Interface_ (IeventServer, IUNKNOWN)
{
STDMETHOD () PURE
}
// Declare an interface, this interface will be implemented by the customer's event receiver
Declare_Interface_ (Ieventsink, IunkNown)
{
STDMETHOD () PURE
}
3. Add the base class ccmdtarget class cconnobject. Plus #include "iconnobject.h" in class declaration file cconnobject1.h, write in class declaration:
protected:
......
// Declare the nested class for the IeventServer interface
Begin_INTERFACE_PART (Event Server, IeventServer)
STDMETHOD (DOSMETHING) ();
END_INTERFACE_PART (EventServer)
Declare_interface_map ()
// Declare the nested class for the connection point
Begin_Connection_Part (Cconnobject, SampleConnpoint)
Connection_iid (IID_IEventsink)
END_CONNECTION_PART (SAMPLECONNPOINT)
Declare_connection_map ()
Declare_olecreate (cconnobject)
Description: begin_connection_part and end_connection_part macro declares the nested class SampleConnpoint for the connection point, and is based on the CConnectionPoint class. If you need to overload the member function of the CConnectionPoint class or add your own member function, you can declare it in these two macro. Here Connection_iid macro heavy loads the cconnectionpoint :: getiid () function. Use the declare_connection-map () macro connection point mapping table.
4. Write in the implementation file of class cconnobject
Implement_olecreate (cconnobject, "connobject",
0xEE888B01, 0XEA9C, 0X11D3, 0X97, 0XB5, 0X52, 0X54, 0XAb, 0x19, 0x19, 0x30);
Begin_Interface_map (cconnobject, ccmdtarget)
Interface_part (cconnobject, IID_IEventServer, EventServer)
Interface_part (cconnobject, IID_ICONNECTIONPOINTCONTAINER, CONNPTCONTAINER)
END_INTERFACE_MAP ()
Begin_Connection_map (cconnobject, ccmdtarget)
Connection_part (cconnobject, IID_IEventsink, SampleConnpoint)
END_CONNECTION_MAP ()
Description:. A must be written in the interface map INTERFACE_PART (CConnObject, IID_IConnectionPointContainer, ConnPtContainer) to implement the interface IConnectionPointContainer noted, CCmdTarget-type embedded IConnectionPointContainer talented ConnPtContainer class to implement an interface, and recorded by m_xConnPtContainer..
B. Implement the connection point mapping with begin_connection_map and end_connection_map .connection_part defines classes that implement the connection point .5. Writes in cconnobject :: cconnobject ():
EnableConnections ();
6. Implement IeventServer interface
The IeventServer interface is based on IUNKNOWN interface, and the method of implementing the iUnknown interface is not described here. Write in the implementation file:
StdMethodimp
Cconnobject :: XeventServer :: DOSMETHING ()
{
// DOSMETHING
Method_Prologue (Cconnobject, EventServer)
PTHIS-> FireEvent ();
Return S_OK;
}
The DOSMETHING () method can provide the customer's service. Here, the connectionable object is a function of triggering a client event receiver here. The FireEvent () function is a function of the special trigger event implemented by the Connobject class. The code is as follows:
Void cconnobject :: FireEvent ()
{
/ / Get the connection pointing queue on the connection point
Const CPTRARRAY * PCONNECTIONS = m_xsampleconnpoint.getConnections ();
Assert (PConnections! = NULL);
Int cconnections = pConnections-> getSize ();
Ieventsink * pieventsink;
/ / Touch events for each connection
For (INT i = 0; i { / / Get customer event receiver interface pointer Pieventsink = (iEventsink *) (PConnections-> Getat (i)); Assert (PIEVENTSINK! = NULL); // Call the customer event receptacle event handler // This function is an interface definition, implemented by the customer event receiver. PIEVENTSINK-> EventHandle (); } } Customer Event Receiver (SINK) The event receiver is also a COM object, or it can be implemented with a nested class, but it is just an internal pair of customers. Like, there is no CLSID and class. The following example is a dialog program, and the dialog has three buttons: "Connect" (idc_connect), "Disable" (IDC_Disconnect), "Event" (IDC_Event). Create a dialog-based engineering: ConnClient. Add #include "iconnobject.h" in CConnclientdlg, then declare the event receiver nested class in the dialog class declaration: Begin_Interface_part (Eventsink, IeventSink) stdmethod (EventHandle) () ; END_INTERFACE_PART (EventSink) while variables declared several private: private: LPCONNECTIONPOINTCONTAINER pConnPtCont; // // IConnectionPointContainer recording component object interface pointer LPCONNECTIONPOINT pConnPt; // record junction interface pointer DWORD m_dwCookie; // record the connection identifier IUnknown * m_pIUnknown; / / recording component to implement an event pointer to the IUnknown interface objects receiver: STDMETHODIMP_ (ULONG) CConnClientDlg :: XEventSink :: AddRef () {return 1;} STDMETHODIMP_ (ULONG) CConnClientDlg :: XEventSink :: Release () {return 0;} STDMETHODIMP CConnClientDlg :: XEventSink :: QueryInterface (REFIID riid, void ** ppvObj) {METHOD_PROLOGUE (CConnClientDlg, EventSink) if (IsEqualIID (riid, IID_IUnknown) || IsEqualIID (riid, IID_IEventSink)) {* ppvObj = this; AddRef () Return S_OK;} else} stdmethodimp cconnclientdlg :: Xeventsink :: EventHandle () // This function will be called {:: AfxMessageBox ("Source object notification to the event receiver!" ); RETURN S_OK;} Initialize the COM library and create component object instances in cconnclientdlg :: OnInitdi Alog () Write: hResult HRESULT; HRESULT = :: Coinitialize (NULL); if (Failed (HRESULT)) {:: AFXMessageBox ("Can't initialize the COM library!"); return false;} m_piunknown = null; hResult = :: CoCreateInstance (CLSID_ConnObject, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **) & m_pIUnknown); if (FAILED (hResult)) {m_pIUnknown = NULL; :: AfxMessageBox ( "ConnObject not create objects!"); return FALSE;} m_dwCookie = 0; // Preset connection identifier is 0 Click event processing function void cconnclientdlg :: onConnect () {if (m_dwcookie! = 0) {Return;} f (m_piunknown! = null) {hResult hresult; hResult = m_piunknown-> queryinterface (IID_ICONNECTIONPOINTCONTAINER, (Void **) & PConnptCont); if (FAILED (hResult)) {:: AfxMessageBox ( "not acquired object IConnectionPointContainer Interface!"); return;} ASSERT (pConnPtCont = NULL!); hResult = pConnPtCont-> FindConnectionPoint (IID_IEventSink, & pConnPt); if (FAILED ( HRESULT)) {PConnptCont-> release () ;: AFXMessageBox ("IeventSink connection point interface!"); return;} assert (PConnpt! = null); // Get Event Receiver Pointer iUnknown * PIEventsink; M_XEventsink.QueryInterface (IID_IUNKNOWN, (Void **) & PIEventSink; // Pass the event receiver pointer to the connectivity object if (succeeded (pieventsink, & m_dwcookie)) {: : AFXMessageBox ("" "" "");} else {:: afxMessageBox ("Cannot connect to Connobject!");} PConnpt-> release (); pconnptcont-> release (); return; }} The above code establishes a connection with the connection point of the connectable object. Writing button "Disconnect" (idc_disconnect) Click Processing function is as follows: void cconnclientdlg :: Ondisconnect () {if (m_dwcookie == 0) {Return;} PCONNPT- > Unadvise (m_dwcookie); pconnpt-> release (); PConnptCont-> Release (); m_dwcookie = 0;} Writing button "Event" Click Processing Function: Void Cconnclientdlg :: Onevent () {ix (m_piunknown! = Null) {IeventServer * PIEventServer; HRESULT HR esult; hResult = m_pIUnknown-> QueryInterface (IID_IEventServer, (void **) & pIEventServer); if (FAILED (hResult)) {:: AfxMessageBox ( "not get IEventServer Interface!"); return;} pIEventServer-> DoSomething (); }} Here, the customer calls the service DOSMETHING () provided by the client, and as seen earlier, the component object will trigger an event that is handled by the Customer Event Receiver (cconnclientdlg :: Xeventsink :: EventHandle ()) in this function. . When exiting the application: void cconclientdlg :: oncancel () { m_piunknown-> release (); :: Couninitialize (); CDIALOG :: oncancel (); } After running the program, first click "Connection", then click the "Event" button, then the MessageBox will pop up, and "the source object is notified to the event receiver!". summary It is because there is a mechanism for connectivity objects, and the two-way communication of the client and component object is realized, making component objects have an event mechanism. This technology similar to "Server Push" is in a distributed application system It is very important.