2010-02-01 4 views
7

Sono nuovo a 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'oggetto creato in STA che non è thread-safe.Impossibile chiamare l'oggetto COM creato da STAThread da altri thread STA

MyCalcServer classe qui creata utilizzando Oggetto semplice ATL. Le impostazioni utilizzate sono le stesse in this article:

  • modello di threading: Appartamento
  • Aggregazione: No
  • Interfaccia: personalizzato

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

Tuttavia, questo risulta sempre in InvalidCastException (E_NOINTERFACE) generato all'interno del codice t1. Ho anche provato a cambiare ApartmentState in MTA senza successo.

Unable to cast COM object of type 'MyCOMLib.MyCalcServerClass' to interface type 'MyCOMLib.IMyCalcServer'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{B005DB8C-7B21-4898-9DEC-CBEBE175BB21}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

Qualcuno potrebbe spiegare cosa sto facendo male qui?

+0

Forse il JIT pensa che tu non stia usando "istanza" e lo rilasci in anticipo. prova a mettere Marshal.ReleaseComObject (istanza) dopo i join. – adrianm

+0

@adrianm Ancora non funziona, ma grazie per questo – Gant

+0

Prova a cambiare la prima riga in MyCOMLib.IMyCalcServer instance = new MyCOMLib.MyCalcServer(); Penso che solo le interfacce (non le classi) possono essere inserite tra i thread. – adrianm

risposta

3

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

+2

Il wrapper .Net esegue automaticamente il marshalling tra i thread (altrimenti il ​​finalizzatore non funzionerebbe). Se il marshal automatico non ha funzionato, l'errore sarebbe E_WRONG_THREAD (8001010E) – adrianm

1

Sono riuscito a ottenere questa risoluzione.

Siccome sono nuovo a COM, non so molto su Proxy/Stub e 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 le informazioni da questa pagina utile: Why would I want to merge Proxy/Stub code with my DLL project.

Proxy/stubs providing standard marshaling for your component. In many cases a DLL-based component may not need proxy/stub because it is running in the same context of its client, and this option may seem useless at first. However, COM uses the marshaling process to synchronize access to a component in multi-threaded situations. So, a DLL-based component will need a proxy/stub DLL in at least two cases:

  • It's running a multi-threaded client and needs to pass interface pointer between apartments (STA to STA or MTA to STA).

  • DCOM can provide a surrogate process for a DLL-based component so that it can be accessed in a distributed environment. In this case a proxy/stub is needed to marshal between machines.

By merging the proxy/stub code with your implementation, you don't have to distribute two DLLs, just the one.

Io segnerò @ risposta di Dewfy come accettare come lui ha fatto luce sul tema Proxy.