关于COM多线程和STA/MTA的问题
你好,我是 COM 的初学者。我想在 STA 和 MTA 模式下测试 COM dll。我的第一个问题是:COM 对象是否可能同时支持 STA 和 MTA?
现在我想象下面的 STA 代码片段:
// this is the main thread
m_IFoo;
CoInitializeEx(STA); // initialize COM in main thread
CreateInstance(m_IFoo);
m_IFoo->Bar();
CreateThread(ThreadA);
// start ThreadA
// this is secondary thread
ThreadA()
{
CoInitializeEx(STA);
m_IFoo->Buz(); // call m_IFoo's method directly
}
这段代码可以工作吗?我是否遗漏了任何基本的东西?我知道主线程需要一个窗口消息循环来执行来自其他线程的调用。我需要做些什么吗?
现在我继续测试 MTA。如果我只是将上面代码中的“STA”替换为“MTA”,可以吗?
另一个问题是:由于带有GUI的线程必须是STA,所以我无法在GUI线程中初始化和测试MTA?
预先感谢并为我对 COM 和线程的幼稚感到抱歉。
Hi I am a beginner in COM. I want to test a COM dll in both STA and MTA modes. My first question is: is it possible a COM object supports both STA and MTA?
Now I imagine the STA code snippet below:
// this is the main thread
m_IFoo;
CoInitializeEx(STA); // initialize COM in main thread
CreateInstance(m_IFoo);
m_IFoo->Bar();
CreateThread(ThreadA);
// start ThreadA
// this is secondary thread
ThreadA()
{
CoInitializeEx(STA);
m_IFoo->Buz(); // call m_IFoo's method directly
}
Will this code work? Am I missing any fundamental things? I know the main thread needs a window message loop to let calls from other threads be executed. Do I have to do anything about it?
Now I move on to test MTA. If I merely replace "STA" with "MTA" in the above code, will it work?
Another question is: As a thread with GUI must be STA, I cannot initialize and test MTA in a GUI thread?
Thanks in advance and sorry for me being naive on COM and threading.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的代码不是合法的 COM,因为您直接从一个 STA 向另一个 STA 传递指针,这是 COM 不允许的。
在COM中,接口指针具有“公寓亲和性”,它们只能在公寓内使用。要将指针从一个 STA 传递到另一个 STA,或者在 STA 和 MTA 之间传递,必须将指针“编组”到安全的表示形式,然后由接收线程取消编组。
最简单的方法是使用 全局接口表;您在一个线程中向其注册接口并返回一个 DWORD,然后在另一个线程中使用它来返回另一个线程可以使用的接口版本。
如果两个线程都是 MTA,则可以避免这样做。虽然 STA 是每个线程一个 - 每个 STA 线程都有自己的公寓 - MTA 由所有 MTA 线程共享。这意味着 MTA 线程可以在它们之间自由传递 COM 指针。 (但如果将指针传递给 STA 线程或从 STA 线程传递指针,它们仍然需要封送。)
一般来说,您不会在 STA 或 MTA 之间更改代码,通常在一开始就决定一次。如果线程有UI,那么它需要消息循环,并且通常是STA。如果没有 UI,您可能会决定使用 MTA。但是,一旦您做出决定并编写代码,以后就很少会更改为另一个,因为选择一个或另一个具有影响代码的不同要求和假设;从 STA 更改为 MTA 或反之亦然,您必须仔细检查代码并查看是否需要更改指针分配等内容。
Your code is not legal COM, because you are passing a pointer directly from one STA to another, which COM doesn't allow.
In COM, interface pointers have "apartment affinity", they can only be used within an apartment. To pass a pointer from one STA to another, or between STA and MTA, you have to 'marshal' the pointer to a safe representation, which is then unmarshaled by the receiving thread.
The simplest way to do this is using the Global Interface Table; you register the interface with it in one thread and get back a DWORD, which you then use in the other thread to get back a version of the interface that the other thread can use.
If both threads are MTA, you can avoid doing this. While STA are one-per-thread - each STA thread has its own aparment - the MTA is shared by all MTA threads. This means that MTA threads can pass COM pointers between themselves freely. (But they still need to marshal if passing pointers to or from STA threads.)
Generally speaking, you don't change code between STA or MTA, you usually decide this once at the outset. If the thread has UI, then it needs a message loop, and is usually STA. If there's no UI, you may decide to use MTA. But once you make that decision and write your code, it's rare to change to the other later, since picking one or the other has different requirements and assumptions that affect the code; change from STA to MTA or vice versa and you'd have to carefully review the code and see if things like pointer assignments needed to be changed.
能否从“MTA”切换到“STA”以及这种切换的后果将取决于对象在系统注册表中的注册方式。为了使对象能够“支持”这两种情况而不进行编组,它必须将 ThreadingModel 设置为 Both。
请参阅这个很好的答案< /a> -
Both
表示“Free
或Apartment
,具体取决于调用者如何初始化 COM”。这正是您想要的。至于使用“STA”模式 - 是的,trace对象所属必须通过调用
GetMessage()
、TranslateMesage()
和来运行消息循环循环中的 DispatchMessage()
。无论如何,对象方法不会直接从第二个线程调用 - 它们将通过代理。请参阅这篇非常好的文章了解详细信息解释。Being able to switch from "MTA" to "STA" and consequences of such switch will depend on how the object is registered in system registry. In order for the object to "support" both cases without marshalling it has to have
ThreadingModel
set toBoth
.Please see this great answer -
Both
means "eitherFree
orApartment
depending on how the caller initializes COM". That's exactly what you want.As to using the "STA" mode - yes, the tread object belongs to will have to run the message loop by calling
GetMessage()
,TranslateMesage()
andDispatchMessage()
in a loop. Anyway the objects methods won't be called directly from the second thread - they will go through the proxy. Please see this very good article for thorough explanation.