When C # is called in C ++ to develop COM components, general interface calls are easy to implement, but it is not easy to respond to events in COM components in C ++. Because the events in C # Use the delegate mechanism, but C ++ does not have the delegate mechanism, the corresponding implementation cannot be achieved. What should we do?
Although there is no delegate type in C ++, C ++ can develop the ATL component and use event ing, can we use this mechanism to implement it? After constantly searching for materials and making some efforts, we finally achieved our goal. Please refer.
Trigger Event is output internally by the COM component encapsulated by C #, and Event Reponse: 10000 is output after the C ++ Event is triggered by the COM component. How can this problem be implemented? Let's first look at the COM component code of C:
IPaint Interface
using System;using System.Collections.Generic;using System.Linq;using System.Runtime.InteropServices;using System.Text;namespace ComEvent{ [Guid("7EEDF2D8-836C-4294-90A0-7A144ADC93F9")] [InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface IPaint { [DispId(1)] void Draw(int count); }}
IEvent Interface
using System;using System.Collections.Generic;using System.Linq;using System.Runtime.InteropServices;using System.Text;namespace ComEvent{ [Guid("7FE32A1D-F239-45ad-8188-89738C6EDB6F")] [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface IEvent { [DispId(20)] void DrawEvent(int count); }}
Paint implementation
Using System; using System. collections. generic; using System. linq; using System. runtime. interopServices; using System. text; namespace ComEvent {[Guid ("76BBA445-7554-4308-8487-322BAE955527"), ClassInterface (ClassInterfaceType. none), ComDefaultInterface (typeof (IPaint), ComSourceInterfaces (typeof (IEvent), ComVisible (true)] public class Paint: IPaint {public delegate void DrawDelegate (int count ); // pay attention to the event Must be the same as the name defined by IEvent, and must be public event DrawDelegate DrawEvent; # region IPaint member public void Draw (int count) {Console. writeLine ("Trigger Event"); OnDraw (count);} public void OnDraw (int count) {try {if (DrawEvent = null) {Console. writeLine ("Event is NULL! ") ;}Else {DrawEvent (count) ;}} catch (Exception ex) {Console. WriteLine (ex. Message) ;}# endregion }}
Description
1. The GUID in the Code must be different and can be generated using the GUID generator. Note the value of DsidpId in the IEvent interface. I suffered a huge loss in implementation.
2. The IEvent interface type of the event interface is InterfaceIsIDispatch.
3. in the implemented class, you need to add references to the exposed COM interface, that is, ComDefaultInterface (typeof (IPaint) and ComSourceInterfaces (typeof (IEvent )), note that typeof is followed by our custom interface.
4. since painting does not inherit the IEvent interface, but it requires a corresponding DrawEvent event to be triggered in painting, we need to define a delegate similar to DrawEvent in IEvent to correspond in painting, public delegate void DrawDelegate (int count) and public event DrawDelegate DrawEvent;
5. To use the COM component, You need to configure the project attributes. See the following figure.
Compile the COM component. At this time, the Output will generate three files: ComEvent. dll, ComEvent. pdb, and ComEvent. tlb, where ComEvent. tlb is used when C ++ calls the COM component.
The following is the implementation code of the C ++ call.
ComCall_CPlusPlus.cpp
// ComCall_CPlusPlus.cpp: defines the entry point of the console application. // # Include "stdafx. h "# import ".. \ Output \ ComEvent. tlb "using namespace ComEvent; ATL: CComModule _ Module; class EventReceiver: public IDispEventImpl <0, EventReceiver, & (_ uuidof (ComEvent: IEvent )), & (_ uuidof (ComEvent ::__ ComEvent), 1, 0> {public: STDMETHOD (DrawEventResponse) (int count); BEGIN_SINK_MAP (eventventresponer) SINK_ENTRY_EX (0, (_ uuidof (ComEvent: IEvent), 20, DrawEventResponse) END_SINK_MAP ()}; STDMETHODIMP EventReceiver: DrawEventResponse (int count) {printf ("Event Reponse: % d \ n ", count); return S_ OK;} int _ tmain (int argc, _ TCHAR * argv []) {CoInitialize (NULL); ComEvent :: IPaintPtr pPaint (_ uuidof (ComEvent: Paint); _ Module. init (NULL, (HINSTANCE) GetModuleHandle (NULL); EventReceiver * pReceiver = new EventReceiver; HRESULT hresult = pReceiver-> DispEventAdvise (ppainting); pPaint-> Draw (10000 ); pReceiver-> DispEventUnadvise (pPaint); _ Module. term (); CoUninitialize (); return 0 ;}
Stdafx. h
// Stdafx. h: include files in the standard system, // or include files that are frequently used but not frequently changed // include files specific to the project // # pragma once # include "targetver. h "# include
# Include
# Include // Add extern CComModule _ Module; // Add # include // Add // TODO: reference other header files required by the program here
Description
1. ATL Module reference: Add atlbase. h, extern CComModule _ Module and atlcom. h to stdafx. h, and Add ATL: CComModule _ Module to ComCall_CPlusPlus.CPP;
2. Define an event receiver class that inherits from the ATL template interface IDispEventImpl. The first parameter in the template of IDispEventImpl is 0, the second is the name of the event receiving Class eventcycler, and the third parameter is the pointer to the event Interface ID (use & (_ uuidof (ComEvent :: (IEvent). The fourth parameter is the pointer to the class ID (Calculated using & (_ uuidof (ComEvent: :__ ComEvent). The fifth parameter is 1, the sixth parameter is 0.
3. Add a reference to the ComEvent namespace.
4. Event ing DrawEventResponse. BEGIN_SINK_MAP, SINK_ENTRY_EX, and END_SINK_MAP must be in one group to map events.
The parameter of BEGIN_SINK_MAP is EventReceiver.
SINK_ENTRY_EX the first parameter is 0, and the second parameter is the ID of the event interface (Calculated using _ uuidof (ComEvent: IEvent, this value must be consistent with the event ID used by IDispEventImpl), and the fourth parameter is the DispId of the event (that is, the value 20 defined when the COM component is defined. It must be this value, otherwise, an error occurs. The fifth parameter is the implementation of DrawEventResponse.
5. initialize COM and release the instance: CoInitialize (NULL) and CoUninitialize () must be paired
6. ATL implementation _ Module. Init
7. ATL mount and cancel events pReceiver-> DispEventAdvise (pPaint) and pReceiver-> DispEventUnadvise (pPaint ).
The following is the JAVA implementation code.
package com.event;import com.jacob.activeX.ActiveXComponent;import com.jacob.com.Dispatch;import com.jacob.com.DispatchEvents;import com.jacob.com.Variant;public class ComEventExample {public static void main(String[] args) {ActiveXComponent dotnetCom = new ActiveXComponent("ComEvent.Paint");Dispatch test = (Dispatch) dotnetCom.getObject();SensorEvents se = new SensorEvents();DispatchEvents de = new DispatchEvents(test, se); Dispatch.call(test, "Draw", new Variant(10000));}}
package com.event;import com.jacob.com.Variant;public class SensorEvents {public void DrawEvent(Variant[] i) {System.out.println("this is java event executed "+i[0]);}}
Be sure to pay attention to the reference of the jacob. jar package.
This is the running result of JAVA.
Download http://download.csdn.net/detail/xxdddail/6710307