Compile COM connection point events in VC
A typical solution in COM is to let the client object instantiate the server object and then call these objects. However, without a special mechanism, it is difficult for these server objects to redirect and callback to client objects. The COM connection point provides this special mechanism to implement bidirectional communication between the server and the client. Using the connection point, the server can call the client when some events occur on the server.
Principles include:
With the connection point, the server can define an interface to specify the events it can trigger. When an event is triggered on the server, the client to perform the operation will register with the server. Then, the client provides the implementation of the interface defined by the server.
The client can register with the server through some standard mechanisms. Com provides iconnectionpointcontainer and iconnectionpoint interfaces for this purpose.
The COM connection point Server Client can be written using C ++ and C # managed code. The C ++ client registers an instance of the class, which provides the implementation of the receiver interface. The hosting client registers a single event Delegate and creates a single receiver based on each event notification method. For details, refer to the interoperability section of C.
I. Programming of connection points
1. Use ATL to create a component program.
2. Add ATL simple object and support connection point events.
NOTE: If there is no current connection point event, you can manually add it in the. IDL file. For example
[
UUID (57ccb7a5-f3b6-4990-91cd-33a82e1aaa46 ),
Helpstring ("ifunevent dispinterface ")
]
Dispinterface _ ifunevent
{
Properties:
// The Event interface does not have any attributes
Methods:
[ID (1), helpstring ("method onresult")] hresult onresult ([out, retval] Long * retval );
[ID (2), helpstring ("method ONTYPE")] hresult ONTYPE ([in] Long ntype );
}
3. Because connection point events are supported, A _ xxxevent source interface is automatically generated. We add the method to be triggered.
4. Select the event object under the component. In the displayed dialog box, select Add method. You can add more methods...
5. Implementation Method (in fact, the component only declares the method, which is implemented only when the customer calls it ). Select components/classes, right-click them, and select implement connection... in the pop-up menu ....
The cproxy_xxxevent class is generated automatically. The fire function is implemented in the class.
6. Complete other interface functions of the component.
The connection points of components are easy to write. The key is how to monitor and receive events on the client. It is easy to implement in. net. But it is complicated in VC.
2. Connect to the client (VC)
1. Include the header file "_ I. H" and introduce the "Project. TLB" Ole library file. For example:
# Include "atldemo_ I .h"
# Import "atldemo. TLB" named_guids raw_interfaces_only
2. Create a class: Derived from _ ixxxevent. (Xxx indicates the actual event name)
Overload each virtual function of the implementation class. If _ ixxxevent is an iunkown interface, you only need to overload the QueryInterface, addref, and release functions; if _ ixxxevent is a bidirectional interface, you need to reload the three functions of the iunkown interface and the four functions of the idispatch interface.
Implement the event function by using the function, using sink_entry_info to implement event ing, and using the event ID in the invoke function.
Event ing using sink_entry_info
For example:
Begin_sink_map (ceventsink)
Sink_entry_info (1, diid _ inew01events, dispid_msg, MSG, & msginfo)
End_sink_map ()
I have defined an MSF function in the component, so the message is hashed here. Then implement the MSG method.
3. How to call
3.1 Use Project Support COM and afxoleinit or coinitialize/UN coinitialize
3.2 obtain the Component Interface
3.3 get the connection point container and find the connection point.
3.4 use advise to send a listening object to the component, so that the event will respond when the event occurs. When not in use, unadvise is used to disconnect the connection point event. Afxconnectionadvice is also used to send the listening object to the component interface.
3.5 release resources.
The Code is as follows:
# Pragma once
# Include "atldemo_ I .h"
# Import "atldemo. TLB" named_guids raw_interfaces_only
Class cskin: Public _ ifunevent
{
Public:
Cskin (void );
~ Cskin (void );
PRIVATE:
DWORD m_dwrefcount;
Public:
Stdmethodimp fire_ontype (long ntype)
{
Cstring strtemp;
Strtemp. Format (_ T ("the result is % d"), ntype );
Afxmessagebox (strtemp );
Return s_ OK ;;
}
Hresult stdmethodcalltype QueryInterface (refiid IID, void ** ppvobject)
{
If (IID = diid _ ifunevent)
{
M_dwrefcount ++;
* Ppvobject = (void *) This;
Return s_ OK;
}
If (IID = iid_iunknown)
{
M_dwrefcount ++;
* Ppvobject = (void *) This;
Return s_ OK;
}
Return e_nointerface;
}
Ulong stdmethodcalltype addref ()
{
M_dwrefcount ++;
Return m_dwrefcount;
}
Ulong stdmethodcalltype release ()
{
Ulong L;
L = m_dwrefcount --;
If (0 = m_dwrefcount)
{
Delete this;
}
Return L;
}
Hresult stdmethodcalltype gettypeinfocount (
/* [Out] */_ RPC _ out uint * pctinfo)
{
Return s_ OK;
}
Hresult stdmethodcalltype gettypeinfo (
/* [In] */uint itinfo,
/* [In] */lcid,
/* [Out] */_ RPC _ deref_out_opt itypeinfo ** pptinfo)
{
Return s_ OK;
}
Hresult stdmethodcalltype getidsofnames (
/* [In] */_ RPC _ in refiid riid,
/* [Size_is] [in] */_ RPC _ in_ecount_full (cnames) lpolestr * rgsznames,
/* [Range] [in] */uint cnames,
/* [In] */lcid,
/* [Size_is] [out] */_ RPC _ out_ecount_full (cnames) dispid * rgdispid)
{
Return s_ OK;
}
/* [Local] */hresult stdmethodcalltype invoke (
/* [In] */dispid dispidmember,
/* [In] */refiid riid,
/* [In] */lcid,
/* [In] */word wflags,
/* [Out] [in] */dispparams * pdispparams,
/* [Out] */variant * pvarresult,
/* [Out] */partition info * ppartition info,
/* [Out] */uint * puargerr)
{
Switch (dispidmember) // based on different dispidmember, complete different callback functions and ID numbers of the event Functions
{
Case 2:
{
// 1st Param: [in] Long lvalue.
Variant varlvalue;
Long lvalue = 0;
Variantinit (& varlvalue );
Variantclear (& varlvalue );
Varlvalue = (pdispparams-> rgvarg) [0];
Lvalue = v_i4 (& varlvalue );
Fire_ontype (lvalue );
}
Break;
Default: break;
}
Return s_ OK;
}
};
# Include "stdafx. H"
# Include "skin. H"
Cskin: cskin (void)
{
M_dwrefcount = 0;
}
Cskin ::~ Cskin (void)
{
}
Implementation:
Coinitialize (null );
Ccomptr <ifun> pfun;
Hresult hR = pfun. cocreateinstance (clsid_fun );
If (HR! = S_ OK)
{
Return;
}
Iconnectionpointcontainer * pcpc;
HR = pfun-> QueryInterface (iid_iconnectionpointcontainer, (void **) & pcpc );
If (! Succeeded (HR ))
{
Return;
}
Iconnectionpoint * PCP;
HR = pcpc-> findconnectionpoint (diid _ ifunevent, & PCP );
If (! Succeeded (HR ))
{
Return;
}
Pcpc-> release ();
Iunknown * psinkunk;
Cskin * psink = new cskin ();
HR = psink-> QueryInterface (iid_iunknown, (void **) & psinkunk );
DWORD dwadvise;
HR = PCP-> advise (psinkunk, & dwadvise); // the receiver is associated with the connection point
Long C = 0;
Pfun-> Add (1, 5, & C );
// PCP-> unadvise (dwadvise) // disconnect the connection point event
PCP-> release ();
Pfun. Release ();
Couninitialize ();
References:
COM connection points by Alex C. punnen:
Http://www.codeproject.com/KB/COM/connectionpoint.aspx
COM Component Design and Application
Http://www.vckbase.com/document/viewdoc? Id = 1525
Code for compiling and calling COM connection points in VC
Http://download.csdn.net/source/3437607