2010-02-01 8 views
7

Ich bin neu in COM und versuche, den Unterschied zwischen STA und MTA zu verstehen. Ich habe versucht, ein Beispiel zu erstellen, das zeigen würde, dass COM Aufrufe von in STA erstellten Objekten verwalten kann, die nicht Thread-sicher sind.Kann COM-Objekt, das aus STAThread von anderen STA-Threads erstellt wird, nicht aufrufen

MyCalcServer Klasse hier wird mit ATL Simple Object erstellt. Die Einstellungen sind die gleichen wie in this article:

  • Threading Modell: Wohnung
  • Aggregation: Kein
  • Schnittstelle: Benutzerdefinierte

MyCalcServer COM-Objekt verwendet wird, in ein anderes C# -Projekt, das ist:

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

    } 
} 

Dies führt jedoch immer zu InvalidCastException (E_NOINTERFACE) innerhalb des Codes von t1 ausgelöst. Ich habe auch versucht, ApartmentState zu MTA ohne Erfolg zu ändern.

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

Könnte jemand bitte erklären, was ich hier falsch mache?

+0

Vielleicht denkt das JIT, dass Sie nicht "Instanz" verwenden und es früh freigeben. versuchen Sie, Marshal.ReleaseComObject (Instanz) nach den Joins zu setzen. – adrianm

+0

@adrianm Immer noch nicht funktioniert, aber danke dafür – Gant

+0

Versuchen Sie, die erste Zeile in MyCOMLib.IMyCalcServer zu ändern instance = new MyCOMLib.MyCalcServer(); Ich denke, nur Schnittstellen (keine Klassen) können zwischen Threads gemarshallt werden. – adrianm

Antwort

3

Sie explizit COM bitten, Instanz für Hauptthread zu erstellen, dann übergeben Sie dies an einen anderen Thread. Unter bestimmten Umständen ist es natürlich erlaubt (zB MyCalcServer als Multithread deklarieren).

Aber in Ihrem Fall sieht es aus, Sie müssen Proxy für einen anderen Thread erstellen. In regulären COM-Clients wird dies von CoMarshalInterThreadInterfaceInStream erledigt. Es gibt einen großen Artikel, um es zu klären http://www.codeproject.com/KB/COM/cominterop.aspx

+2

Der .Net-Wrapper führt das Marshalling zwischen Threads automatisch aus (andernfalls würde der Finalizer nicht funktionieren). Wenn der automatische Marshal nicht funktionierte, würde der Fehler E_WRONG_THREAD (8001010E) sein – adrianm

1

Ich schaffte es, diese Entschlossenheit zu bekommen.

Da ich neu bei COM bin, weiß ich nicht viel über Proxy/Stub und dass sie für Marshalling-Stoffe zwischen STA und STA benötigt werden. Nach dem Erstellen eines neuen ATL-Projekts und stellen Sie sicher, dass "Merge Proxy/Stub" aktiviert ist. Das Problem ist verschwunden.

finde ich die Informationen auf dieser Seite hilfreich: 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.

I @ Dewfy Antwort markieren wird so akzeptieren, wie er etwas Licht auf das Proxy Thema vergossen hat.

Verwandte Themen