2013-04-19 11 views
6

Ho un componente esterno (C++), che voglio chiamare dal mio codice C#.C# STAThread COMException

Il codice è qualcosa di simile:

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

Quindi il problema è che, alla prima chiamata che sta funzionando bene, il componente esterno chiamato, sono tornato risultato.

Ma quando provo a chiamarlo in un altro thread, ho ottenuto un'eccezione: System.InvalidCastException: impossibile eseguire il cast dell'oggetto COM di tipo 'System .__ ComObject' .... Sono sicuro che questa eccezione è stata lanciata, a causa dello STAThread. Perché se rimuovo l'attributo [STAThread] dalla funzione Main, lo stesso avviene con la prima chiamata del componente esterno, che ha funzionato correttamente.

Come posso chiamare questo componente esterno da un altro thread per eliminare questa eccezione?

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

Altra cosa folle si verifica ora. Quando avvio il programma da Visual Studio con F5, il problema si verifica anche nella prima chiamata, ma quando eseguo direttamente il file binario .exe, funziona (dall'altro thread non lo è :(). If I commutare la build da Debug per rilasciare e partire da Visual Studio con F5, la prima chiamata a lavorare di nuovo.

Perché succede?

Grazie per voi aiuto in anticipo!

migliori saluti, Zoli

+0

Cosa succede quando si esegue l'intero lavoro (creare un'istanza COM ed eseguire il metodo) in una discussione creata come STA?È possibile che questo oggetto COM sia contrassegnato come STA nel Registro di sistema e non funzioni correttamente tra diversi appartamenti COM (da MTA a STA o da STA a MTA) a causa di un errore nel modo in cui è stato codificato. –

+0

Ho la stessa eccezione :(. Ma la funzione Main è STA, dove viene creato il thread Anche il thread è impostato su STA, quindi non capisco –

+0

Ciò potrebbe essere dovuto a un bug nel componente. tutto è fatto in un singolo thread STA, dovrebbe funzionare –

risposta

2

Il threading non è mai un piccolo dettaglio. Se il codice non è esplicitamente documentato per supportare il threading quindi le probabilità del 99% sono che non lo supporta.

E chiaramente questo componente non supporta la filettatura. La creazione di un altro thread STA non è la soluzione magica, è pur sempre un thread diverso. InvalidCastException ti dice che manca anche il supporto proxy/stub necessario per effettuare il marshal delle chiamate da un thread di lavoro, come quello che stai cercando di creare. Necessario per rendere le chiamate thread-safe al codice che non siano thread-safe. Anche se hai violato il contratto per uno [STAThread], deve pompare un loop di messaggi. È il ciclo di messaggi che consente di effettuare chiamate da un thread di lavoro a un componente che non è thread-safe. Ottieni un ciclo di messaggi da Application.Run().

Qui si ferma il dollaro. Non è thread-safe, punto. Anche se correggi il thread principale o chiedi al fornitore o all'autore di fornirti il ​​proxy/stub, non hai ancora realizzato ciò che hai deciso di fare, in realtà non verrà eseguito sul thread di lavoro che hai creato. Così deve assomigliare a questo:

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

che crea l'oggetto sullo stesso thread che si fanno le chiamate da così è thread-safe. C'è ancora il problema che questo thread di lavoro non pompa un ciclo di messaggi, i componenti COM tendono a fare affidamento su questo. Scoprirai se si tratta di un problema o meno da deadlock o eventi che non vengono eseguiti. Se ha già funzionato bene nel tuo programma di test quando lo hai chiamato dal thread principale, probabilmente stai bene non pompando.

+0

Molto buono descrizione, grazie per l'aiuto! :) Ora sta funzionando nel mio programma di test. Metterò nell'ambiente reale, e spero che tutto andrà bene :). –

Problemi correlati