2009-04-22 16 views
-1

私はCOMライブラリを使用するアプリケーションを作成しています。 COMライブラリに呼び出しをラップし、いくつかの機能を追加するクラスライブラリがあります。最終的にこれはWindowsサービスとして実行されます。今のところ私はWinformsテストハーネスを使ってテストします。COMライブラリを呼び出すときにサービスが例外をスローする

テストハーネスによってクラスライブラリが作成されると、すべて正常に動作しているようです。問題はサービスとして実行しようとすると始まります。それはOKで作成され、COMへの最初の呼び出しでさえOKです。次に、COMオブジェクトは、処理するイベントを発生させ、イベントの結果に応答して、COMライブラリの別の関数を呼び出します。

System.InvalidCastException occurred Message="Unable to cast COM object of type '' to interface type ''. This operation failed because the QueryInterface call on the COM component for the interface with IID '{350ADD2A-18CB-4D9C-BE28-48D53F14E6FB}' failed due to the following error: The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))."

私はスレッド問題があることがわかります。私はテストハーネスからそれを実行するが、サービスとして実行しているときに例外がスローされたときの機能は、ケースで正常に起動されます。テストハーネスの場合、この呼び出しはすべてメインスレッドで発生し、Windowsサービスの場合はService OnStartのオーバーライドとCOMイベントハンドラの両方が別のスレッド上にあります。私は成功していない別のものを試してきました。助言がありますか?

+0

サンプルコードを提供できますか? –

答えて

1

一部のCOMコンポーネントには、STAスレッドのみがアクセスする必要があります。これはあなたのためのケースであれば、 あなたのCOMの仕事はそうのようなSTAスレッドで実行できます。

RunInSTAThread(() => com_object.DoSomething()); 

private static void RunInSTAThread(ThreadStart thread_start) 
     { 
      Exception threadEx = null; 
      ThreadStart wrapped_ts =() => 
             { 
              try 
              { 
               thread_start(); 
              } 
              catch (Exception ex) 
              { 
               MethodInfo preserveStackTrace = 
                typeof(Exception).GetMethod("InternalPreserveStackTrace", 
                       BindingFlags.Instance | BindingFlags.NonPublic); 
               preserveStackTrace.Invoke(ex, null); 
               threadEx = ex; 
              } 
             }; 
      Thread thread = new Thread(wrapped_ts); 
      thread.SetApartmentState(ApartmentState.STA); 
      thread.Start(); 
      thread.Join(); 
      if (threadEx != null) 
      { 
       throw threadEx; 
      } 
     } 

これは、あなたの状況についてのスレッド(すべての呼び出しのための新しいスレッド)を最大限に活用できない場合がありしかしそれは出発点です。

+0

@Jeremy Lew:これはまったく必要ではありません。 RCWを作成するとき、STA以外のスレッドで作成された場合、CLRはオブジェクトを自身のスレッドに配置します。また、STA COMオブジェクトを処理するためのMTAであるSTAスレッド上にメッセージをポンピングしていません。 – casperOne

+0

これは良い点です。 Winformsから起動したときに、なぜサービスから起動したときに動作しないのかは、まだわかりません。 –

0

WinサービスがWinformsアプリケーションと同じユーザーアカウントで実行されていますか?

+0

LocalSystemとして実行しています。 –

+0

私はUserとして試しましたが、結果はほぼ同じです。 –

0

これで解決しました。私はスレッドを再配置しなければならなかった。 COMオブジェクトとそのすべての呼び出しは同じスレッド上にあり、スレッド間の問題はありません。 それでも普通のケースでそれをどう対処するかという疑問は不明のままです。

-1

私はプロジェクトを閉じてもう一度開いてエラーを解決しました

関連する問題