2009-04-22 4 views
-1

Ich schreibe eine Anwendung, die eine COM-Bibliothek verwendet. Ich habe eine Klassenbibliothek, die die Aufrufe an die COM-Bibliothek umschließt und einige weitere Funktionen hinzufügt. Eventuell wird dies als Windows-Dienst ausgeführt. Für jetzt teste ich es mit einem Winforms-Test-Kabelbaum.Dienst löst eine Ausnahme aus, wenn versucht wird, eine COM-Bibliothek aufzurufen

Wenn die Klassenbibliothek vom Test-Kabelbaum erstellt wird, scheint alles in Ordnung zu sein. Die Probleme beginnen, wenn ich versuche, es als Dienst auszuführen. Es ist OK erstellt und sogar der erste Aufruf der COM ist in Ordnung. Das COM-Objekt löst dann ein Ereignis aus, das ich handhabe und reagiere auf das Ergebnis in dem Fall, dass ich eine andere Funktion in der COM-Bibliothek aufruft. Die Funktion wird erfolgreich in dem Fall aufgerufen wird, wenn ich es von der Testumgebung laufen, aber wenn es als Dienst ausgeführt wird eine Ausnahme ausgelöst:

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))."

Ich kann sehen, dass es Threadingprobleme. Im Fall des Testkabelbaums erfolgen alle diese Aufrufe im Hauptthread und im Fall des Windows-Dienstes befinden sich sowohl die Service-OnStart-Überschreibung als auch der COM-Ereignishandler in verschiedenen Threads. Ich habe verschiedene Dinge ohne Erfolg versucht. Irgendwelche Vorschläge?

+0

Können Sie einige Beispielcode? –

Antwort

1

Auf einige COM-Komponenten muss nur von STA-Threads zugegriffen werden. Ist dies der Fall für deine ist, Sie Ihre COM-Arbeit in einem STA-Thread tun können, etwa so:

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

Dies kann nicht die beste Verwendung von Fäden sein (ein neuer Thread für jeden Anruf) für Ihre Situation, aber es ist ein Ausgangspunkt.

+0

@ Jeremy Lew: Es ist auch völlig nicht erforderlich. Beim Erstellen eines RCW platziert die CLR das Objekt in einem eigenen Thread, wenn die Erstellung in einem Nicht-STA-Thread stattfindet. Sie pumpen auch keine Nachrichten im STA-Thread, was ein MUSS für den Umgang mit STA COM-Objekten ist. – casperOne

+0

Das sind einige gute Punkte. Es bleibt mir immer noch unklar, warum es funktioniert, wenn es von Winforms gestartet wird und nicht wenn es vom Service gestartet wird. –

0

Wird der Win-Dienst unter demselben Benutzerkonto wie die Winforms-Anwendung ausgeführt?

+0

Es läuft als LocalSystem. –

+0

Ich habe es gerade als Benutzer versucht und das Ergebnis ist ziemlich das Gleiche. –

0

Es ist jetzt gelöst. Ich musste die Fäden neu anordnen. Jetzt sind das COM-Objekt und alle Aufrufe desselben im selben Thread und es gibt keine Threading-Probleme. Noch ist die Frage, wie im gemeinsamen Fall damit umzugehen ist, unklar.

-1

Ich habe gerade das Projekt geschlossen und es wieder geöffnet und Fehler behoben

Verwandte Themen