用c++ (ATL, MFC或纯c++)处理COM事件,实现Java互操作
visual studio - Handling COM events in C++ (ATL, MFC or pure C++) for Java interop
我目前正在尝试构建一个c++库(DLL文件),与COM组件接口,使其在Java中可用。我的想法是,我将构建一个非常小的c++ DLL,其中包含一个"包装"在COM组件周围的类,然后使用SWIG导出它。我使用了#import语句:
#import "ComponentName.dll"
调用CoInitialize()并创建组件的实例(通过由Visual Studio生成的IComponentNamePtr类)。这对所有普通的COM方法调用都有效,这很好。
然而,我不知道如何让事件工作。我看到有一个IComponentNameEventsPtr补充了主要的"智能指针"类,但我不知道该怎么做才能让它工作
我已经尝试了以下所有事件的工作:
- 纯c++ —我不知道该怎么做。我尝试创建一个从IComponentNameEvents类继承的新类,为所有抽象函数制作存根,并覆盖函数,除了函数没有标记为虚拟,所以没有工作。 MFC
- 本;我无法得到调用AfxOleInit正确工作。谷歌告诉我,当从DLL调用时,调用失败,因为它假设OLE已经初始化。我不太确定如何解决这个问题。每次我试图创建COM组件的实例时,我的库都会崩溃(我认为是因为COM没有正确初始化)
- ATL 本;我不知道如何在ATL中进行项目。我可以创建类(通过"简单ATL"向导,然后是"实现接口"向导),但不知道如何使用它。我在MSDN上阅读了Using IDispEventImpl,但不知道如何使用该方法生成的类。我是否需要通过ATL来使用COM对象(或者我可以使用#import自动生成的类)?如何"附加"事件侦听器类?
- 我读事件处理在COM使用event_receiver属性(新的Visual c++统一事件模型的一部分)。最初,我不知道如何将其与通过#import语句创建的COM组件的使用相结合。我终于弄清楚了(并且在页面上提到了!),我需要在#import语句上使用"embedded_idl"标志,但这破坏了其他事情(我在.tlh文件中得到了一堆"期望类型规范接近"的错误)
有人知道怎么做吗?最简单的方法是什么?我的背景是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;
-
你需要在#import行后面加上"embedded_idl"
#import "ComponentName.dll" embedded_idl
-
如果组件中嵌入了任何结构,您可能会由于VisualStudio中的错误而得到一些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()之前解除所有事件的挂钩,否则会得到错误。
- Android NDK传感器向事件队列报告奇怪的间隔
- 从文本文件中读取时钟时间和事件时间并进行处理
- WMI检测进程创建事件-c++
- EvtExportLogneneneba API正在将远程计算机的事件日志保存到远程PC本身.如何将其保存到主机
- 处理闪烁窗口事件
- C++Builder中的OnClick事件签名存在问题
- 跟踪滚动条上的鼠标事件
- 什么是事件表 (wxWidgets)?
- 如何在 MFCaptureEngine 中获取"Camera removed"事件
- 给定顺序中的事件处理
- 当服务中的事件被触发时,如何将响应从服务发送回客户端?
- 在 C++/CLI 中将 .NET 事件从一个 DLL 引发到另一个 DLL
- 如何创建事件驱动的 SDL2 应用程序
- Windows 进程间同步类似事件?
- 如何从C++端挂接到 QML 项的 onClick 事件
- 如何通过多类"Union variable" (sfml) 使用轮询事件
- 如何在Qt 4.8中阻止/忽略/丢弃早于特定超时的用户输入事件
- C++ 信号和插槽不工作:插槽不响应事件
- 在虚幻引擎中触发C++ dll的事件
- 具有Qt事件循环的可移植通用共享库设置