2013-04-19 12 views
6

Ich habe eine externe Komponente (C++), die ich von meinem C# -Code aufrufen möchte.C# STAThread COMException

Der Code ist so etwas wie diese:

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(); 
     } 
    } 
} 

Das Problem ist also, dass beim ersten Aufruf, es funktioniert gut, die externe Komponente genannt, bekam ich Ergebnis zurück. Wenn ich versuche, es in einem anderen Thread aufzurufen, habe ich eine Ausnahme: System.InvalidCastException: Kann COM-Objekt vom Typ "System. Ich bin sicher, dass diese Ausnahme wegen des STAThread geworfen wurde. Weil, wenn ich das [STAThread] -Attribut von der Hauptfunktion entferne, dasselbe mit dem ersten Anruf der externen Komponente geschieht, der gut gearbeitet wurde.

Wie kann ich diese externe Komponente von einem anderen Thread aufrufen, um diese Ausnahme loszuwerden?

UPDATE -------------

Andere verrückte Sache kommt jetzt. Wenn ich das Programm von Visual Studio mit F5 starte, tritt das Problem auch beim ersten Aufruf auf, aber wenn ich direkt die binäre .exe-Datei ausführe, funktioniert es (vom anderen Thread ist es nicht :(). Wenn ich schalten Sie den Build von Debug auf Release und es von Visual Studio mit F5, der erste Anruf wieder zu arbeiten beginnen.

Warum ist es passiert?

Dank im Voraus für Sie helfen!

mit besten Grüßen, Zoli

+0

Was passiert, wenn Sie die gesamte Arbeit (COM-Instanz erstellen und Methode ausführen) in einem Thread erstellen, den Sie als STA markieren?Es ist möglich, dass dieses COM-Objekt als STA in der Registrierung markiert ist und nicht gut über verschiedene COM-Appliances funktioniert (von MTA zu STA oder von STA zu MTA), möglicherweise aufgrund eines Fehlers in der Art, wie es codiert wurde. –

+0

Ich habe die gleiche Ausnahme :(. Aber die Hauptfunktion ist STA, wo der Thread erstellt wird. Der Thread auf STA auch eingestellt, so verstehe ich nicht. –

+0

Dies kann aufgrund eines Fehlers in der Komponente. Wann alles wird in einem einzigen STA-Thread erledigt, es sollte funktionieren –

Antwort

2

Threading ist nie ein kleines Detail.Wenn Code nicht explizit ist Um die Threading zu unterstützen, sind die 99% -Wahrscheinlichkeiten so, dass sie es nicht unterstützen.

Und natürlich unterstützt diese Komponente Threading nicht. Einen anderen STA-Thread zu erstellen ist nicht die magische Lösung, es ist immer noch ein anderer Thread. Die InvalidCastException teilt Ihnen mit, dass auch die Proxy/Stub-Unterstützung fehlt, die erforderlich ist, um Aufrufe von einem Worker-Thread wie dem, den Sie erstellen möchten, zu marshallen. Erforderlich, um threadsichere Aufrufe an Code zu tätigen, der nicht threadsicher ist. Obwohl du den Vertrag für einen [STAThread] gebrochen hast, muss er eine Nachrichtenschleife pumpen. Es ist die Nachrichtenschleife, die Aufrufe von einem Arbeitsthread an eine Komponente ermöglicht, die nicht threadsicher ist. Sie erhalten eine Nachrichtenschleife von Application.Run().

Hier stoppt der Dollar. Es ist nicht Thread-sicher, Punkt. Auch wenn Sie Ihren Hauptthread beheben oder den Hersteller oder Autor auffordern, Ihnen den Proxy/Stub zur Verfügung zu stellen, haben Sie immer noch nicht das erreicht, was Sie tun wollten. Es wird nicht auf dem von Ihnen erstellten Arbeitsthread ausgeführt. So muss es wie folgt aussehen:

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(); 
    } 

, die das Objekt auf dem gleichen Thread erstellt, dass Sie die Anrufe aus, so ist es Thread-sicher. Es gibt immer noch das Problem, dass dieser Arbeitsthread keine Nachrichtenschleife pumpt, COM-Komponenten neigen dazu, sich darauf zu verlassen. Sie werden herausfinden, ob es sich um ein Deadlock oder um Ereignisse handelt, die nicht ausgeführt werden. Wenn es in Ihrem Testprogramm bereits in Ordnung war, als Sie es aus dem Hauptthread aufgerufen haben, dann sind Sie wahrscheinlich in Ordnung, wenn Sie nicht pumpen.

+0

Sehr gut Beschreibung, danke für die Hilfe! :) Jetzt funktioniert es in meinem Testprogramm. Ich lege mich in die reale Umgebung und hoffe, dass alles gut wird :). –

Verwandte Themen