C#在线程之间编组COM对象

我对C#marshal在线程之间是否有COM对象感到非常困惑。 为此,我有一个应用程序,它以任务并行方式加载一组文件。 我正在使用StaTaskScehduler使用COM对象加载文件。 加载COM对象后,我将对象存储在中央列表中。

然后,我再次使用STATaskScheduler尝试对此数据执行一些处理。 但是在这一点上我遇到了一个问题。 我收到如下例外情况:

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#为你做的事情?

如何在一个线程中创建一个公寓线程COM对象,然后从另一个线程使用它?

我在这里吠叫错了吗? 我甚至不能使用Sta公寓作为我的主题吗? 我可以保证对象永远不会同时从多个线程访问。 任何想法都非常感激。

编辑 :COM对象定义如下:

 [ coclass, threading( apartment ), vi_progid( [Namespace.Class] ), progid( [Namespace.Class].6 ), version( 6.0 ), uuid( GUID_C[Class] ), helpstring( [Class]" Class" ) ] 

所以根据我的理解,这是一个公寓线程对象,对吗? 我刚刚尝试使用未设置公寓状态的修改任务调度程序(默认为MTA?)。 当我在一个线程中创建它并从另一个线程中使用它时,这个对象似乎确实有效。 这样安全还是会回来咬我一些其他方式?

COM的线程模型一直困扰着我:/

看起来你正在使用Stephen Toub的StaTaskScheduler作为一些“有状态”逻辑的一部分,其中你的COM对象存在于StartNew边界之间。 如果是这种情况,请确保在同一个StaTaskScheduler STA线程上创建并使用这些对象, StaTaskScheduler在其外部。 那么你根本不用担心COM编组。 不用说,您应该只使用一个线程创建StaTaskScheduler ,即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的“apartment”中,并从那里访问它:

 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采购的事件,请检查:

  • StaTaskScheduler和STA线程消息泵送 。
Interesting Posts