从另一个线程触发COM事件 [英] Firing a COM Event From Another Thread

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

问题描述

我已经使用ATL创建了一个进程中的COM对象(DLL)。注意,这是一个对象,而不是一个控件(所以没有窗口或用户界面。)我的问题是,我试图从第二个线程触发一个事件,我得到一个灾难性故障(0x8000FFFF)。如果我从我的主线程触发事件,那么我不会得到错误。第二个线程调用 CoInitializeEx ,但这没有什么区别。我使用的公寓线程模型,但切换到Free Threaded并没有帮助。

I have created an in-process COM object (DLL) using ATL. Note that this is an object and not a control (so has no window or user-interface.) My problem is that I am trying to fire an event from a second thread and I am getting a 'Catastrophic failure' (0x8000FFFF). If I fire the event from my main thread, then I don't get the error. The second thread is calling CoInitializeEx but this makes no difference. I am using the Apartment threading model but switching to Free Threaded doesn't help.

我试图从第二个线程这样做的事实显然是至关重要的。有没有一个简单的方法来做到这一点,或者我要实现一些隐藏窗口的消息?

The fact I am trying to do this from a second thread is obviously crucial. Is there an easy way to do this or am I going to have to implement some hidden-window form of messaging?

例如,在我的主对象的源文件: / p>

For example, in my main object's source file:

STDMETHODIMP MyObject::SomeMethod(...)
{
  CreateThread(NULL, 0, ThreadProc, this, 0, NULL);
  // Succeeds with S_OK
  FireEvent(L"Hello, world!");
  return S_OK;
}

DWORD WINAPI ThreadProc(LPVOID param)
{
  CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  MyObject* comObject = reinterpret_cast<MyObject*>(param);
  // Fails with 0x8000FFFF
  comObject->FireEvent(L"Hello, world!");
}

void MyObject::FireEvent(BSTR str)
{
  ...
  // Returns 0x8000FFFF if called from ThreadProc
  // Returns S_OK if called from SomeMethod
  pConnection->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
}


推荐答案

COM基础

在STA中,你的对象存在于一个线程上。这个线程是它创建的,它的方法被执行,它的事件被触发。 STA确保没有同时执行你的对象的两个方法(因为它们必须在Thread上执行,所以这是一个很好的结果)。

In STA your object lives on a single thread (The Thread). This thread is the one it's created on, it's methods are executed on and it's events are fire on. The STA makes sure that no two methods of your object are executed simultaneously (because they have to be executed on The Thread so this is a nice consequence).

这不是意味着您的对象无法从其他线程访问。这是通过为除Thread之外的每个线程创建对象的代理来完成的。在主题中,您通过 CoMarshalInterThreadInterfaceInStream 在另一个线程上,您解压缩 CoGetInterfaceAndReleaseStream < a>实际上在另一个线程上创建代理。这个代理使用消息泵同步调用到你的对象,仍然在线程上执行的调用,所以线程必须是自由的(不忙)执行从另一个线程的调用。

This does not mean that your object can't be accessed from other threads. This is done by creating proxies of your object for every thread other than The Thread. On The Thread you pack an IUnknown with CoMarshalInterThreadInterfaceInStream and on the other thread you unpack with CoGetInterfaceAndReleaseStream which actually creates the proxy on the other thread. This proxy uses the message pump to sync calls to you object, calls that are still executed on The Thread, so The Thread has to be free (not busy) to executed a call from another thread.

在你的情况下,你希望你的对象能够在一个线程上执行方法,并在另一个线程上引发事件。所以这个发生在MTA中,所以你的对象必须存在于MTA中,所以你的类必须是自由的。线程属于正好一个公寓,所以线程不能同时在MTA和STA。如果你的对象住在MTA每当一个STA对象试图使用它,它将不得不创建一个代理。所以你得到一个微小的开销。

In your case you want your object to be able to execute methods on one thread and rise events on another thread. So this has to happen in MTA, so your object has to live in MTA, so your class has to be free-threaded. Threads belong to exactly one apartment, so a thread can not be in MTA and STA simultaneously. If your object lives in MTA whenever an STA object tries to use it, it will have to create a proxy. So you get a slight overhead.

我想是你正在想一些非常聪明的技术卸载你的主线程,并做一些异步事件,它不会飞到最后:-))如果你考虑它有一个侦听器在这第二个[工人]线程...

What I guess is that you are thinking of some very clever "technique" to offload your main thread, and do some "async" events, which will not fly in the end :-)) If you think about it there has to a listener on this second [worker] thread...

Btw,这

MyObject* comObject = reinterpret_cast<MyObject*>(param);

只能在MTA中执行。

这篇关于从另一个线程触发COM事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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