Imansible chiamare l’object COM creato da STAThread da altri thread STA

Sono nuovo di COM e sto cercando di capire la differenza tra STA e MTA. Ho provato a creare un esempio che mostra che COM può gestire le chiamate all’object creato in STA che non è thread-safe.

MyCalcServer class MyCalcServer qui viene creata utilizzando ATL Simple Object. Le impostazioni utilizzate sono le stesse di questo articolo :

  • Modello di filettatura: appartamento
  • Aggregazione: no
  • Interfaccia: personalizzata

MyCalcServer object COM MyCalcServer viene utilizzato in un altro progetto C # che è:

 class Program { [STAThread] static void Main(string[] args) { MyCOMLib.MyCalcServer instance = new MyCOMLib.MyCalcServer(); string output1; instance.ChangeValue("Gant", out output1); Console.WriteLine(output1); Thread t1 = new Thread(() => { while (true) { string output; instance.ChangeValue("Gant", out output); Console.WriteLine(output); } }); t1.SetApartmentState(ApartmentState.STA); t1.Start(); // : // also has t2 and t3 here with similar code // : t1.Join(); t2.Join(); t3.Join(); } } 

Tuttavia, questo comporta sempre InvalidCastException (E_NOINTERFACE) generato nel codice di t1. Ho anche provato a cambiare ApartmentState in MTA senza successo.

Imansible trasmettere l’object COM di tipo “MyCOMLib.MyCalcServerClass” al tipo di interfaccia “MyCOMLib.IMyCalcServer”. Questa operazione non è riuscita perché la chiamata QueryInterface sul componente COM per l’interfaccia con IID ‘{B005DB8C-7B21-4898-9DEC-CBEBE175BB21}’ non è riuscita a causa del seguente errore: Nessuna interfaccia supportata (Eccezione da HRESULT: 0x80004002 (E_NOINTERFACE)) .

Qualcuno potrebbe spiegare cosa sto facendo male qui?

Si chiede esplicitamente a COM di creare un’istanza per il thread principale, quindi si passa a un altro thread. Ovviamente in alcune circostanze è permesso (per esempio dichiarare MyCalcServer come multithread).

Ma nel tuo caso sembra necessario creare proxy per un altro thread. Nei normali client COM viene eseguito da CoMarshalInterThreadInterfaceInStream. C’è un grande articolo per chiarirlo http://www.codeproject.com/KB/COM/cominterop.aspx

Sono riuscito a ottenere questa risoluzione.

Dato che sono nuovo di COM, non so molto su Proxy / Stub e che sono necessari per il marshalling di materiale tra STA e STA. Dopo aver creato un nuovo progetto ATL e aver verificato che “Unisci proxy / stub” fosse spuntato. Il problema è svanito.

Trovo utili le informazioni di questa pagina: Perché dovrei unire il codice Proxy / Stub con il mio progetto DLL.

Proxy / stub che forniscono il marshalling standard per il componente. In molti casi, un componente basato su DLL potrebbe non richiedere proxy / stub perché è in esecuzione nello stesso contesto del suo client e questa opzione potrebbe sembrare inutile all’inizio. Tuttavia, COM utilizza il processo di marshalling per sincronizzare l’accesso a un componente in situazioni multi-thread. Quindi, un componente basato su DLL avrà bisogno di una DLL proxy / stub in almeno due casi:

  • È in esecuzione un client multi-thread e deve passare il puntatore all’interfaccia tra gli appartamenti (da STA a STA o MTA a STA).

  • DCOM può fornire un processo surrogato per un componente basato su DLL in modo che sia ansible accedervi in ​​un ambiente distribuito. In questo caso è necessario un proxy / stub per effettuare il marshalling tra le macchine.

Unendo il codice proxy / stub con la tua implementazione, non devi distribuire due DLL, solo quella.

Contrassegnerò la risposta di @ Dewfy come accettata, poiché ha fatto luce sull’argomento Proxy.