2013-04-19 10 views
6

私はC#コードから呼び出したい外部コンポーネント(C++)を持っています。C#STAThread COMException

コードはこのようなものです:

using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 

namespace dgTEST 
{ 
    class Program 
    { 
     [STAThread] 
     static void Main(string[] args) 
     { 
      ExtComponentCaller extCompCaller = new ExtComponentCaller(); 
      result = extCompCaller.Call(input); 

      Thread t = new Thread(new ThreadStart(() => 
      { 
       try 
       { 
        result = extCompCaller.Call(input); 
       } 
       catch (Exception ex) 
       { 
        Console.WriteLine(ex.ToString()); 
       } 
      })); 

      t.SetApartmentState(ApartmentState.STA); 
      t.Start(); 
      t.Join(); 
     } 
    } 
} 

だから、問題は最初の呼び出しで、それは、よく呼ばれる外部コンポーネントを働いている、ということですが、私は結果を戻りました。

しかし、他のスレッドで呼び出そうとすると例外が発生します。 System.InvalidCastException: 'System .__ ComObject'タイプのCOMオブジェクトをキャストすることができません。 STAThreadのためにこの例外がスローされていると確信しています。 Main関数から[STAThread]属性を削除すると、外部コンポーネントの最初の呼び出しで同じことが起こるため、正常に動作しました。

この例外を取り除くために、この外部コンポーネントをほかのスレッドから呼び出す方法はありますか?

更新-------------

その他のクレイジーなことが発生しました。 F5でVisual Studioからプログラムを起動すると、問題は最初の呼び出しでも発生しますが、バイナリ.exeファイルを直接実行すると、別のスレッドからは正常に動作しています:() F5、再び作業の最初の呼び出しを使用してVisual Studioからそれを解放して開始するデバッグからビルドを切り替える。

なぜそれが起こるのでしょうか?あなたのための

おかげで、事前に役立つ!

よろしく、 Zoli

+0

STAとしてマークを付けて作成したスレッドで作業全体(COMインスタンスを作成してメソッドを実行)を実行するとどうなりますか?このCOMオブジェクトがレジストリ内のSTAとしてマークされ、異なるCOMアパートメント(MTAからSTAまたはSTAからMTAへ)でうまく動作しない可能性があります。 –

+0

私は同じ例外があります:(。 メイン関数はスレッドが作成されるSTAです。スレッドもSTAに設定されていますので、わかりません –

+0

これはコンポーネントの不具合の可能性があります。 –

答えて

2

スレッディングは決して細かいことではありません。 99%の確率はそれをサポートしていないということです。

明らかに、このコンポーネントはスレッディングをサポートしていません。別のSTAスレッドを作成することは魔法の解決策ではなく、まだ別のスレッドです。 InvalidCastExceptionは、作成しようとしているワーカースレッドからの呼び出しをマーシャリングするために必要なプロキシ/スタブサポートも欠落していることを示しています。スレッドセーフではないコードに対してスレッドセーフな呼び出しを行うために必要です。 [STAThread]の契約を破ったとしても、メッセージループをポンピングする必要があります。ワーカースレッドからスレッドセーフではないコンポーネントへの呼び出しを可能にするのはメッセージループです。 Application.Run()からメッセージループを取得します。

これはバックが停止する場所です。スレッドセーフな期間ではありません。あなたのメインスレッドを修正したり、プロキシ/スタブを提供するようにベンダーや著者に依頼しても、やるべきことはまだ達成されていません。作成したワーカースレッドでは実際には実行されません。だから、次のようになります。それは、スレッドセーフであるから、あなたが電話をかけることが同じスレッド上のオブジェクトを作成します

static void Main(string[] args) 
    { 
     Thread t = new Thread(new ThreadStart(() => 
     { 
      ExtComponentCaller extCompCaller = new ExtComponentCaller(); 
      result = extCompCaller.Call(input); 
     })); 

     t.SetApartmentState(ApartmentState.STA); 
     t.Start(); 
     t.Join(); 
    } 

を。このワーカースレッドがメッセージループをポンピングしないという問題はまだありますが、COMコンポーネントはそれに頼っている傾向があります。デッドロックや実行されないイベントから問題があるかどうかを確認します。あなたがメインスレッドから呼び出されたときにテストプログラムで既にうまくいっていれば、おそらくポンピングしていなくても問題ありません。

+0

非常に良い説明、助けてくれてありがとう! :) これは私のテストプログラムで動作しています。私は実際の環境に入れて、すべてがうまくいくことを願っています:)。 –

関連する問題