5

C# がスレッド間で COM オブジェクトをマーシャリングするかどうかについて非常に混乱しています。この目的のために、一連のファイルをタスク並列方式でロードするアプリケーションがあります。COM オブジェクトを使用してファイルをロードするためにStaTaskScehdulerを使用しています。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

COMオブジェクトが境界StaTaskSchedulerを越えて存在する「ステートフル」ロジックの一部として、Stephen Toub'sを使用しているようです。StartNewその場合は、これらのオブジェクトを同じStaTaskSchedulerSTA スレッド上で作成して使用し、それ以外の場所で使用しないようにしてください。そうすれば、COM マーシャリングについてまったく心配する必要がなくなります。言うまでもなく、StaTaskSchedulerスレッドは 1 つだけで作成する必要があります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);
}

が別の COM オブジェクトを返す場合Obj.Method()は、結果を同じ 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 に答える