1

System.Timers.TimermyTimerを使用する Visual Studio アドインがあります。
N 秒ごとに myTimer が起動し、次のコードを実行します。

foreach(Window window in DTE2.Windows)
{
    TextDocument td = window.Document.Object("TextDocument") as TextDocument;
    // do stuff with td...  
}

これは別のスレッドから呼び出されるため、次のいずれかのエラーが発生することがあります。

  • 非管理対象サーバーで IEnumVARIANT の QI が失敗しました。
    foreach 行の EnvDTE.Windows.GetEnumerator()
    で (DTE2.Windows のウィンドウ ウィンドウ)

  • アプリケーションは、別のスレッド用にマーシャリングされたインターフェースを呼び出しました。(HRESULT からの例外: 0x8001010E (RPC_E_WRONG_THREAD)) TextDocument td = window.Document.Object("TextDocument") as TextDocument; 行
    の EnvDTE.Window.get_Document()で。

COM オブジェクトが関係しているため、別のスレッドでこの列挙子にアクセスする適切な方法は何ですか?
ある種の COM スレッド マーシャリングですか?
他の何か?

4

1 に答える 1

2

スレッド セーフではないオブジェクト モデルを保護しようとする COM に違反しています。Visual Studio オートメーション インターフェイスのような複雑なオブジェクト モデルは決してありません。COM は、バックグラウンド スレッドで行われた呼び出しを STA スレッドに自動的にマーシャリングすることによって、これを実行しようとします。これは、すべて同じメソッドを持つ元の COM インターフェイスのレプリカであるプロキシを介して行われますが、STA スレッドでメソッドを実行するインターフェイスへの呼び出しをマーシャリングします。

このプロキシにはスレッド アフィニティがあり、それを作成したスレッドでのみ使用できます。DTE2 が問題です。DTE2 インターフェイス インスタンスを作成する前に拡張コードが実行された場合、DTE2 はプロキシではなく「実際の」インターフェイス ポインターになります。次に、Timer が Elapsed イベント用に作成するようなワーカー スレッドで使用すると、爆弾が発生します。DTE2 が最初にコードによって作成された場合、通常の方法で実行される拡張コードを爆撃します。

DTE2.DTE で問題が解決するかもしれませんが、確かではありません。最終的には何も修正されません。とにかく、コードは常に Visual Studio STA スレッドで実行されます。System.Timer.Timer を使用しないでください。System.Windows.Forms.Timer のような同期タイマーを使用してください。

于 2010-12-22T14:56:33.243 に答える