5

我对 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 的线程模型总是让我很困惑:/

4

1 回答 1

4

看来您正在使用 Stephen ToubStaTaskScheduler作为一些“有状态”逻辑的一部分,您的 COM 对象跨越StartNew边界。如果是这种情况,请确保在同一个StaTaskSchedulerSTA 线程上创建和使用这些对象,而不是在它之外的任何地方。那么你就完全不用担心 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,请检查:

于 2014-07-16T13:24:14.687 回答