我对C#编组线程之间的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的线程模型总是让我感到困惑:/
答案 0 :(得分:3)
看起来你正在使用Stephen Toub的StaTaskScheduler
作为一些“有状态”逻辑的一部分,其中你的COM对象生活在StartNew
边界。如果是这种情况,请确保在同一StaTaskScheduler
STA线程上创建并使用这些对象,而不在其外部。那么你根本不必担心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的“公寓”中,并从那里访问它:
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
提供的事件,请检查: