问题描述
我很困惑关于C#元素的COM对象之间的线程。为此,我有一个应用程序以任务并行方式加载一组文件。我正在使用加载文件使用COM对象。一旦COM对象被加载,我将对象存储在一个中央列表中。
I'm getting very confused about whether C# marshal's COM objects between threads. To this end I have an application which is loading a set of files in a task parallel fashion. I'm using the StaTaskScehduler to load the files using the COM object. Once the COM object is loaded I am storing the object in a central list.
然后,我再次尝试对这些数据执行一些处理,再次使用STATaskScheduler。然而在这一点上我遇到了一个问题。我收到以下异常:
I then later try to perform some processing on this data, again using the STATaskScheduler. However at this point I hit a problem. I receive an exception as follows:
An unhandled exception of type 'System.Runtime.InteropServices.InvalidComObjectException' occurred in MadCat.exe
Additional information: COM object that has been separated from its underlying RCW cannot be used
现在我的理解是,我收到这个错误,因为对象没有编组到新线程。我认为这是C#为你做的吗?
Now my understanding is that I receive this error because the object hasn't been marshalled into the new thread. I thought this was something C# does for you?
如何在一个线程中创建一个公寓线程COM对象,然后从另一个线程使用它?
How can I create an apartment threaded COM object in one thread and then use it from another thread?
我在这里叫错了树吗?我应该不使用Sta公寓的线程?我可以保证对象永远不会同时从多个线程访问。任何想法非常感激。
Am I barking up the wrong tree here? Should I not even be using the Sta apartment for my threads? I can guarantee that the object is never access from multiple threads simultaneously. Any thoughts much appreciated.
编辑 :COM对象的定义如下:
Edit: The COM object is defined as follows:
[
coclass,
threading( apartment ),
vi_progid( [Namespace.Class] ),
progid( [Namespace.Class].6 ),
version( 6.0 ),
uuid( GUID_C[Class] ),
helpstring( [Class]" Class" )
]
所以通过我的理解,这是一个公寓线程对象,对吧?我刚刚尝试使用一个修改的任务调度程序,不设置公寓状态(默认情况下MTA)。然后,这个对象似乎工作,当我在一个线程中创建它,并使用它从另一个。这是安全的还是会回来咬我吗?
So by my understanding this is an apartment threaded object, right? I've just tried using a modified task scheduler that doesn't set the apartment state (MTA by default?). This object then does seem to work when I create it in one thread and use it from another. Is this safe or will it come back to bite me some other way?
COM的线程模型总是困扰我的地狱:/
COM's threading model has always confused the hell out of me :/
推荐答案
您似乎正在使用Stephen Toub的作为一些有状态逻辑的一部分, $ c> StartNew 边界。如果是这样,请确保您在同一个 StaTaskScheduler
STA线程上创建和使用这些对象,而不在其他地方。然后你不必担心COM封送。不用说,你应该创建 StaTaskScheduler
只有一个线程,即 numberOfThreads:1
。
It appears you're using Stephen Toub's StaTaskScheduler
as a part of some "stateful" logic, where your COM objects live across StartNew
boundaries. If that's the case, make sure you create and use these objects on the same StaTaskScheduler
STA thread and nowhere outside it. Then you wouldn't have to worry about COM marshaling at all. Needless to say, you should create StaTaskScheduler
with only one thread, i.e., numberOfThreads:1
.
这是我的意思:
var sta = new StaTaskScheduler(numberOfThreads:1);
var comObjects = new { Obj = (ComObject)null };
Task.Factory.StartNew(() =>
{
// create COM object
comObjects.Obj = (ComObject)Activator.CreateInstance(
Type.GetTypeFromProgID("Client.ProgID"));
}, CancellationToken.None, TaskCreationOptions.None, sta);
//...
for(int i=0; i<10; i++)
{
var result = await Task.Factory.StartNew(() =>
{
// use COM object
return comObjects.Obj.Method();
}, CancellationToken.None, TaskCreationOptions.None, sta);
}
如果 Obj.Method()
返回另一个COM对象,你应该保持结果在同一StaTaskScheduler的公寓,并从那里访问它:
If Obj.Method()
returns another COM objects, you should keep the result in the same StaTaskScheduler's "apartment" and access it from there, too:
var comObjects = new { Obj = (ComObject)null, Obj2 = (AnotherComObject)null };
//...
await Task.Factory.StartNew(() =>
{
// use COM object
comObjects.Obj2 = comObjects.Obj.Method();
}, CancellationToken.None, TaskCreationOptions.None, sta);
如果您还需要处理 Obj
,请检查:
If you also need to handle events sourced by Obj
, check this:
- 。
- StaTaskScheduler and STA thread message pumping.
这篇关于C#在线程之间编组COM对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!