ATL COM:从其他线程访问事件方法 [英] ATL COM: Access Event Methods From Other Thread

查看:175
本文介绍了ATL COM:从其他线程访问事件方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在实现一个COM接口到现有的VS2010 C ++ MFC应用程序。 COM接口交互的大部分部分工作得很好,但我很困惑如何从另一个线程触发COM事件,COM接口运行/定义的线程。应用程序是多线程的,其中一个主线程运行COM接口并处理GUI更改(线程1 ),一个线程从C库接收传入消息(线程2 )。

I'm implementing a COM interface to an existing VS2010 C++ MFC-application. Most parts of the COM interface interaction works great, but I am confused of how to trigger COM events from another thread that the one where the COM interface is running / defined. The application is multi-threaded with one main thread running the COM interface and handling GUI changes (thread 1) and one thread to receive incoming messages from a C-library (thread 2).

对于线程2中收到的某些消息,我想通过发送COM事件通知COM客户端。我阅读了许多主题(从另一个主题触发COM事件)的用户)和 CoMarshalInterThreadInterfaceInStream / CoGetInterfaceAndReleaseStream 。使用Google我似乎找不到任何使用这些方法,对我有意义;我只是不明白如何实现这些功能,如果他们真的会帮助我。

For certain messages received in thread 2 I want to notify the COM clients by sending a COM event. I have read many threads (Firing COM Event From Another Thread is one of them) and CoMarshalInterThreadInterfaceInStream / CoGetInterfaceAndReleaseStream is mentioned. Using Google I can't seem to find any usage of these methods that makes any sense to me; I just don't understand how to implement these functions and if they really will help me.

相关代码部分:

TestCOM.idl:(接口定义)

 interface ITestCOM: IDispatch
{
    [id(1), helpstring("method Test")] HRESULT Test();
};

dispinterface _ITestCOMEvents
{
    properties:
    methods:
        [id(1), helpstring("event ExecutionOver")] HRESULT TestEvent();
};

coclass TestAppCOM
{
    [default] interface ITestCOM;
    [default, source] dispinterface _ITestCOMEvents;
};

ITestCOMEvents_CP.h (VS生成的连接点/事件类) / p>

ITestCOMEvents_CP.h (VS generated class for Connection Points / events)

template<class T>
class CProxy_ITestCOMEvents : 
   public ATL::IConnectionPointImpl<T, &__uuidof(_ITestCOMEvents)>
{
public:
    HRESULT Fire_TestEvent()
    {
       HRESULT hr = S_OK;
       T * pThis = static_cast<T *>(this);
       int cConnections = m_vec.GetSize();
       for (int iConnection = 0; iConnection < cConnections; iConnection++)
       {
          pThis->Lock();
          CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
          pThis->Unlock();
...

TestCOM.h 方法和CProxy_ITestCOMEvents类)

TestCOM.h (class implementing the methods and CProxy_ITestCOMEvents class)

class ATL_NO_VTABLE CTestCOM :
   public CComObjectRootEx<CComMultiThreadModel>,
   public CComCoClass<CTestCOM, &CLSID_TestCOM>,
   public IConnectionPointContainerImpl<CTestCOM>,
   public CProxy_ITestCOMEvents<CTestCOM>,
   public IDispatchImpl<IMecAppCOM, &IID_ITestCOM, &LIBID_TestLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
   static CTestCOM * p_CTestCOM;

CTestCOM()
{
    p_CTestCOM = this;
}

Incoming.CPP

case INCOMING_EVENT_1:
// Trigger Fire_TestEvent in thread 1
// CTestCOM::p_CTestCOM->Fire_TestEvent(); trigger event on thread 2



在上面的代码中,您可以找到我当前的解决方法,创建一个指针对象p_CTestCOM,它将允许在线程1上运行的任何类触发COM事件。线程2可以访问该对象,但它会在线程2中触发它,这将不工作。为了解决这一点,Incoming.CPP中定义的所有方法都可以向使用p_CTestCOM访问和发送COM事件的线程1发送消息(使用PostMessage())。这将工作,但我相信必须有一个更好(和更安全)的解决方案,更准确地遵循COM设计原则。

In the code above you can find my current workaround for this problem which is to create a pointer object p_CTestCOM that will allow any class running on thread 1 to trigger the COM events. Thread 2 can access that object but it would trigger it in thread 2, which wouldn't work. To solve this all methods defined in Incoming.CPP could post a message (using PostMessage()) to thread 1 which would use p_CTestCOM to access and send the COM event. This would work, but I am sure there must be a better (and safer) solution that more accurately follows the COM design principles.

我有人可以散发一些光非常感谢!

I someone could shed some light I would be most grateful!

推荐答案

Roman R.提供了一些不错的选择,但有一个更好的选择,IMO:到触发事件的线程。作为建议侦听器通常在ATL项目中的 IConnectionPointImpl 类中完成,你只需要修改默认 IConnectionPointImpl 为您做编组(例如通过 GIT ,这是更简单的封送API)。

Roman R. provides some good options but there is a better alternative, IMO: you can marshal the listeners to the thread which fires the event. As advising the listeners is typically done inside IConnectionPointImpl class in an ATL project, you 'just' need to modify the default IConnectionPointImpl to do the marshalling for you (e.g. via GIT which is simpler that marshaling API).

最大的优点是代码的其余部分几乎与以前一样,所以没有需要消息传递或同步 - 只有生成的* CP.h文件需要更新。

The big advantage is that the rest of the code remains almost the same as before, so no message passing or synchronization is needed - only the generated *CP.h file needs to be updated.

这个实现在Microsoft知识库文章KB280512中讨论,似乎被删除现在,但有一个 PJ Naughter改进的实施,您可以使用它替换默认实现。

The implementation is discussed in Microsoft knowledge base article KB280512 which seems to be removed now, but there is an improved implementation by PJ Naughter which you can use to replace the default implementation.

这是我的版本使用,基于缺少的知识库文章。
用法很简单,只需重命名生成的CP.h中的类文件,并修改 m_vec.GetAt 零件,如我链接的gist中所述。

Here's the version that I use, based on the missing KB article. The usage is simple, just rename the class in the generated CP.h file and modify m_vec.GetAt parts, as described in the gist I have linked.

这篇关于ATL COM:从其他线程访问事件方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆