在 C++ 中处理 C# COM 事件
Posted
技术标签:
【中文标题】在 C++ 中处理 C# COM 事件【英文标题】:Handle C# COM events in C++ 【发布时间】:2012-06-11 00:42:45 【问题描述】:我已经设法创建了一个带有事件的 C# COM 对象。请在下面找到代码,
[Guid("1212674-38748-45434")]
public interface ICalculator
int Add(int Num1, int Num2);
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("3453674234-84444-84784")]
public interface ICalculatorEvents
[DispId(1)]
void Completed(int Result);
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(ICalculatorEvents))]
[Guid("87457845-945u48-4954")]
public class Calculator : ICalculator
public delegate void CompletedDelegate(int result);
public event CompletedDelegate Completed;
public Add(int Num1, int Num2)
int Result = Num1 + Num2;
if(Completed != null)
Completed(Result);
我已经在 C++ 控制台应用程序中导入了这个 COM 对象,并且能够调用“Add()”方法。我不确定如何在我的 C++ 应用程序中处理“已完成”事件。你能就此提出建议吗?每当发生此事件时,我都希望在控制台中显示结果值。
请在下面找到 C++ 应用程序的代码。事件“已完成”永远不会在这里处理。这进入了一个无限循环。
#import "Calculator.tlb"
using namespace Calculator;
int Flag = 0;
class HandleEvent : public ICalculatorEvent
public:
HandleEvent(void);
~HandleEvent(void);
HRESULT __stdcall QueryInterface(const IID &, void **);
ULONG __stdcall AddRef(void) return 1;
ULONG __stdcall Release(void) return 1;
HRESULT __stdcall Completed(int Result);
;
HandleEvent::HandleEvent(void)
HRESULT HandleEvent::Completed(int Result)
printf("Addition Completed, Result: %d", Result);
Flag = 1;
HRESULT HandleEvent::QueryInterface(const IID & iid,void ** pp)
if (iid == __uuidof(ICalculatorEvent) || iid == __uuidof(IUnknown))
*pp = this;
AddRef();
return S_OK;
return E_NOINTERFACE;
int _tmain(int argc, _TCHAR* argv[])
CoInitialize(NULL);
Flag = 0;
ICalculatorPtr pCalc(__uuidof(Calculator));
pCalc->Add(5, 6);
do
while(Flag == 0);
CoUninitialize ();
return 0;
提前致谢。
【问题讨论】:
我认为您 Completed 事件对象不会被调用,因为它始终为空。哪个类实现了ICalculatorEvents接口? ICalculatorEvents 在 C++ 应用程序中实现。请在下面找到 C++ 代码, 对不起,我无法在评论中添加代码。所以我已将此添加到我的第一篇文章中。谢谢 在 _tmain() 函数中,pCalc->Add() 应该如何知道应该调用哪个 ICalculatorEvent 实现的对象?这里没有 EventHandler 对象。如果有,在 Add() 方法中,完成委托不指向任何方法。 我假设在 Add 方法中调用事件时会调用 HandleEvent::Completed(int Result) 方法?我对 COM 完全陌生,我想我想在这里理解一些东西。 【参考方案1】:如果您想使用委托,则无需声明接口。像这样更改 _tmain() 函数:
int _tmain(int argc, _TCHAR* argv[])
CoInitialize(NULL);
Flag = 0;
EventHandler evh ;
ICalculatorPtr pCalc(__uuidof(Calculator));
pCalc->Completed = &evh.Completed() ;
pCalc->Add(5, 6);
do
while(Flag == 0);
CoUninitialize ();
return 0;
如果你想使用接口试试这个。
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(ICalculatorEvents))]
[Guid("87457845-945u48-4954")]
public class Calculator : ICalculator
public ICalculatorEvents callbackObject ;
public Add(int Num1, int Num2)
int Result = Num1 + Num2;
if(callbackObject != null)
callbackObject.Completed(Result);
并将 _tmain() 方法更改为此。
int _tmain(int argc, _TCHAR* argv[])
CoInitialize(NULL);
Flag = 0;
EventHandler evh ;
ICalculatorPtr pCalc(__uuidof(Calculator));
pCalc->callbackObject = &evh ;
pCalc->Add(5, 6);
do
while(Flag == 0);
CoUninitialize ();
return 0;
【讨论】:
“EventHandler”应该是某个全局类还是您自己定义的? VS2019 告诉我“标识符未定义”。我需要包含一些标题吗?【参考方案2】:我发现 C++ 客户端中的 COM 初始化应该使用
CoInitializeEx(NULL, COINIT_MULTITHREADED);
用于来自 C# (.NET) COM 服务器的异步事件处理,否则 C++ 客户端仅在 CoUninitialize() 调用后接收事件。
事件处理类:
class EventWrapper : public IDispEventSimpleImpl<1, EventWrapper, &DIID_RumCardCOMEvents >
public:
// now you need to declare a sink map - a map of methods handling the events
BEGIN_SINK_MAP(EventWrapper)
SINK_ENTRY_INFO(1, DIID_RumCardCOMEvents, 0x1, isCardInserted, &cardInserted)
SINK_ENTRY_INFO(1, DIID_RumCardCOMEvents, 0x2, isCardRemoved, &cardRemoved)
// event interface id (can be more than 1)---+ | | |
// must match dispid of your event -----------------+ | |
// method which handles the event ------------------------+ |
// type information for event, see below --------------------------------------+
END_SINK_MAP()
// declare the type info object. You will need one for each method with different signature.
// it will be defined in the .cpp file, as it is a static member
static _ATL_FUNC_INFO cardInserted; // 'placeholder' object to carry event information (see below)
static _ATL_FUNC_INFO cardRemoved; // 'placeholder' object to carry event information (see below)
// method which handles the event
STDMETHOD (isCardInserted)(unsigned char type)
// usually it is defined it in the .cpp file
cout << "isCardInserted: " << (int)type << endl;
return 0;
STDMETHOD (isCardRemoved)()
// usually it is defined it in the .cpp file
cout << "isCardRemoved" << endl;
return 0;
;
主要:
int main()
CoInitializeEx(NULL, COINIT_MULTITHREADED);
try
EventWrapper ev;
ev.DispEventAdvise(/*COM interface*/);
// receiving events
ev.DispEventUnadvise(/*COM interface*/);
catch (_com_error& e)
cout << "Exception: " << e.ErrorMessage() << endl;
CoUninitialize();
return 0;
【讨论】:
什么是“&DIID_RumCardCOMEvents”? RumCardCOMEvents 是您的 COM 事件接口吗? “DIID”部分从何而来? 是的,是COM事件接口,不好意思不记得了,太久远了。以上是关于在 C++ 中处理 C# COM 事件的主要内容,如果未能解决你的问题,请参考以下文章