用于Java互操作的C ++(ATL,MFC或纯C ++)处理COM事件
我目前正在尝试构建一个与COM组件接口的C ++库(DLL文件),以使其可用于Java。 我的想法是,我将构建一个非常小的C ++ DLL,其中包含一个围绕COM组件“包装”的类,然后使用SWIG将其导出。 通过使用#import语句,我得到了很多:
#import "ComponentName.dll"
调用CoInitialize()并创建组件的实例(通过由Visual Studio生成的IComponentNamePtr类)。 这适用于所有正常的COM方法调用,这很好。
但是,我无法弄清楚如何让事件发挥作用。 我看到有一个IComponentNameEventsPtr补充了主要的“智能指针”类,但我无法弄清楚如何才能使它工作
我已经尝试了以下所有事件以使事件有效:
有谁知道如何做到这一点? 最简单的方法是什么? 我的背景是在C#和PHP中,所以我没有太多关于在C ++中使用COM的经验。
tldr:在C ++ DLL中使用COM事件的最简单方法是什么?
在代码中实现源接口(使用任何机制,包括使用midl编译器生成纯C代码)。 在您的外部类型库(您正在使用的那个)中查找如下所示的界面:
[source] interface IOutGoing;
一旦你实现了它,使用Advise
在注册事件的对象上进行注册(使用Unadvise
注销它)
下面是一个典型用法的片段,假设你使用MIDL方式(使用ATL / MFC你必须编写更少的代码,但知道更多的宏/模板)
class CSink : public IOutGoing
{
public:
// IUnknown
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
// IOutGoing
HRESULT __stdcall GotMessage(int Message);
CSink() : m_cRef(0) { }
~CSink() { }
private:
long m_cRef;
};
IUnknown* pUnknown;
CoCreateInstance(CLSID_XXXXXXXXX, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**)&pUnknown);
IConnectionPointContainer* pConnectionPointContainer;
hr = pUnknown->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionPointContainer);
hr = pConnectionPointContainer->FindConnectionPoint(IID_IOutGoing, &pConnectionPoint);
// Instantiate the sink object.
CSink* mySink = new CSink;
// Give the connectable object a pointer to the sink.
DWORD dwCookie;
pConnectionPoint->Advise((IUnknown*)mySink, &dwCookie);
我实际上使用统一事件模型自己工作。 一些笔记从我的经验得到它的工作:
您需要初始化ATL,否则在连接事件时会发生空指针错误。 如果你不想在你的项目中使用ATL(就像我没有 - 我的项目是普通的C ++),在dllmain.cpp中这样的东西可以正常工作(用虚拟模块初始化ATL):
class CDummyModule : public CAtlDllModuleT<CDummyModule> {};
CDummyModule _Module;
您需要将“embedded_idl”添加到#import行的末尾。
#import "ComponentName.dll" embedded_idl
如果组件中嵌入了任何结构体,由于Visual Studio中的错误,您可能会遇到一些MIDL2025错误(“预计类型规范接近”)(请参阅https://connect.microsoft.com/VisualStudio/feedback/details/ 333473 / midl2025-migrating-an-attributed-com-project-to-vs-2008-pro-with-exported-structures和http://social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/ 03b78133-5eac-4754-b9af-fc864a9389a3)。 解决方案是添加:
[importidl("vsbugfix.idl")];
然后添加一个
typedef struct StructName StructName;
对于每个引发错误的结构
完成之后,您应该能够初始化COM并创建对象的实例。 丑陋的示例代码:
IComponentName blah;
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
MessageBox(NULL, "Failed to initialize COM", "Hi!", 0);
throw "Failed to initialize COM";
}
try
{
hr = blah.CreateInstance("Something.Something");
if (FAILED(hr))
{
CoUninitialize();
MessageBox(NULL, "Failed to initialize the COM library!!", "Hi!", 0);
throw "Failed to initialize the COM library";
}
}
catch (...)
{
MessageBox(NULL, "Exception occured when initialising library!", "Error", 0);
CoUninitialize();
throw "Exception occured when initialising library!";
}
一旦拥有了COM对象,就可以根据MSDN的“COM中的事件处理”文章连接事件:
__hook(&IComponentNameEvents::OnWhatever, blah, &EventHandlerClass::OnWhatever);
在调用CoUninitialize()之前,一定要解除所有事件,否则会出错。
链接地址: http://www.djcxy.com/p/81309.html上一篇: Handling COM events in C++ (ATL, MFC or pure C++) for Java interop