6

私が理解していることから、 STAを使用しているとマークされた COM コンポーネントがMTAスレッドから使​​用される場合、呼び出しは STA スレッドにマーシャリングされ、その専用スレッドから実行されるはずです。Windows クライアント アプリケーションの場合、これは UI スレッドで実行され (STA としてマークされている場合)、COM コンポーネントから私へのコールバックは、非表示のウィンドウに送信されて処理される Windows メッセージによって処理されることを意味します。 Windows メッセージ ループ。

IIS でホストされている WCF サービスで STA COM コンポーネントを使用するとどうなりますか? ワーカー プロセスの STA スレッドで Windows メッセージ ループは発生しますか? 独自のメッセージ ループを使用して独自の STA スレッドを起動できますか?

4

2 に答える 2

5

COMランタイムは、STA内のCOMオブジェクトのメソッドへの呼び出しのディスパッチを処理します。これはWindowsメッセージのディスパッチに使用されるのと同じOSメカニズムに基づいていることは間違いありませんが、これを実現することを心配する必要はありません。 COMは、内部でこれを行います。

心配する必要があるのは、COMオブジェクトがどのSTAに存在するかです。WCFサービスからCOM相互運用機能を使用してアパートメントスレッドのCOMオブジェクトをインスタンス化する場合は、注意が必要です。

これを行うスレッドがSTAスレッドでない場合、すべてのインプロセスCOMオブジェクトは、IISワーカープロセスの既定のホストSTAに存在します。これが発生することは望ましくありません。すべてのサービス操作のすべてのCOMオブジェクトは、この同じSTAに配置されます。手がかりは名前にあります-すべてのオブジェクトに対して1つのスレッドがあります-そしてそれらのメソッドへのすべての呼び出しは、アパート内の唯一のスレッドがそれらを実行するのを待ってシリアル化されます。サービスは、複数の同時クライアントを処理するように拡張されません。

特定のWCF要求を処理するためにインスタンス化するCOMオブジェクトが、他の要求用に作成されたオブジェクトとは別の独自のSTAにあることを確認する必要があります。これを行うには、大きく2つの方法があります。

  • 独自のスレッドを起動し、開始する前に指定ApartmentState.STASetApartmentState()て、特定の要求に対してCOMオブジェクトをインスタンス化します。これは、 Kevの回答のリンクでScott Seelyによって詳述されたアプローチです。彼は、各サービス操作呼び出しが新しいSTAで初期化されたスレッドで呼び出されることを保証します。これらの方針に沿った、より難しいがよりスケーラブルなソリューションは、再利用可能なSTAで初期化されたスレッドのプールを実装することです。
  • COMオブジェクトをCOM+アプリケーションでホストして、別のDllHostプロセスに存在するようにします。ここで、COM +は(と呼ばれる抽象化を通じてActivityさまざまな要求のオブジェクトをさまざまなSTAに配置します。

コールバックについて言及するとき、あなたが何を意味するのか正確にはわかりません。おそらく、COMオブジェクトのメソッドの1つへの引数としてCOMオブジェクトに渡された参照を介して、マネージコードに実装されたCOMインターフェイスでCOMメソッドが呼び出されることを意味します。そうであれば、これは正常に機能するはずです。しかし、おそらくあなたは何か他のものを意味します。その場合、おそらくあなたは明確にするために質問を修正することができます。

于 2011-03-10T13:28:19.983 に答える
3

WCF サービスの STA スレッドでメッセージを送信する必要があるか、COM オブジェクトからのコールバックを見逃していることがわかりました。

次のコードは機能しますが、Dispatcher を介して COM オブジェクトを呼び出す必要があります。

ComWrapper comWrapper;
Thread localThread;
Dispatcher localThreadDispatcher;

public Constructor()
{
   localThread = new Thread(ThreadProc)
   {
       Name = "test"
   };
   localThread.SetApartmentState(ApartmentState.STA);

   AutoResetEvent init = new AutoResetEvent(false);

   localThread.Start(init);

   init.WaitOne();
}

private void ThreadProc(object o)
{
    localThreadDispatcher = Dispatcher.CurrentDispatcher;
    ((AutoResetEvent)o).Set();

    comWrapper = new ComWrapper()

    Dispatcher.Run();

    localThreadFinished.Set();
 }

そして、次のように呼び出します。

public void UsefulComOperation()
{
    localThreadDispatcher.Invoke(new Action( () => comWrapper.UsefulOperation);
}
于 2011-05-17T09:56:56.290 に答える