2011-01-14 14 views
5

Ich habe einen Out-of-Process-COM-Server, der die Dinge im Auge behalten muss. Dieser Server wird als Dienst ausgeführt und ist intern ein Singleton. Der Einfachheit halber werde ich ihn BossCom nennen.Wie kann ich eine prozessexterne COM-Referenz über Prozessgrenzen hinweg bereitstellen?

Ich habe einen anderen Out-of-Process-COM-Server, der ein Arbeiter ist. Aus Gründen der Systemstabilität handelt es sich um einen Single-Use-Server (das heißt, wenn Sie 2 WorkerCom erstellen, werden 2 WorkerCom.exe ausgeführt). Der Einfachheit halber werde ich ihn WorkerCom nennen.

WorkerCom kann von jedem gestartet werden, auch von selbst, wenn jemand ihn über die Befehlszeile mit den richtigen Befehlszeilenargumenten ausführt.

Das übergeordnete Ziel ist, dass BossCom weiß, welche WorkerComs in der Nähe sind, was sie tun und in der Lage sind, ihnen Befehle zu erteilen (Pause, Stopp, Hochfahren, usw.).

Mein erster Gedanke daran wäre, dass wann immer WorkerCom startet, er CoCreateInstance ein BossCom und BossCom-> RegisterWorker (IUnknown me) aufrufen würde. Wenn dann die WorkerCom kurz vor dem Herunterfahren steht, ruft sie BossCom-> UnregisterWorker (IUnknown me) an. BossCom konnte das IUnknown für IWorkerCom mit QueryInterface abfragen und Befehle ausgeben.

Das würde gut funktionieren, wenn alle diese com-Objekte in demselben Prozess sind, aber sie sind nicht. Ich habe über die Verwendung von GlobalInterfaceTable nachgedacht, aber es ist nur global im Sinne eines einzelnen Prozesses.

Ich habe ein paar Tage damit verbracht, dies zu erforschen und bin ratlos. Vielleicht bin ich Tunnel-Visoned.

Wie kann ich einen Verweis auf ein com-Objekt vom Arbeiter zum Chef marshalieren?

Oh, und was es wert ist, ist BossCom in C# geschrieben und WorkerCom ist in ATL C++ geschrieben, aber ich nehme Lösungen in VB, Scala, Lisp oder irgendetwas geschrieben. Ich denke, ich kann die Kernidee übersetzen. :-)

+3

Ist das nicht funktionieren? Ich gebe zu, ich habe mit COM nicht viel getan, aber der Hauptgrund dafür ist, dass Sie bereits COM bekommen, um Anrufe über Prozessgrenzen zu verteilen, nicht wahr? –

+0

Richtig, für die meisten Dinge, aber IUnknown ist nur ein Zeiger, oder? Der "This" -Zeiger in WorkerCom wird in BossCom keine Bedeutung haben, richtig? Oder wird der Marshalling-Prozess die Bedeutung behalten? Ich denke, ich sollte es zumindest versuchen. –

+2

Es sollte von der Stange funktionieren, vorausgesetzt, es gibt Proxy/Stubs oder Typelib, um das Marshalling zu erleichtern. Tatsächlich ist das Marshalling genau das - um einem Client ein gefälschtes Objekt ("Proxy") zu geben, das auf den Server gespiegelt wird. Es funktioniert transparent aus der Code-Perspektive. – sharptooth

Antwort

2

Laut den Kommentaren funktioniert das tatsächlich out of the box. Es gibt jedoch ein zusätzliches Detail, das es funktioniert.

Ursprünglich, als ich C# -Schnittstellen betrachtete, die sich mit dem Kopieren von Schnittstellen befassten, war der Argumenttyp IntPtr. Nun, ein IntPtr ist nur so lang, dass er den Wert unverändert überträgt und als solcher nicht funktioniert.

Der Schlüssel besteht darin, das MarshalAs-Attribut für das Argument festzulegen. Also meine RegisterWorker-Methode sieht so aus:

public void RegisterWorker(
     [In, MarshalAs(UnmanagedType.IUnknown)] object ptr 
     ) 
    { 
     IWorkerCom worker = (IWorkerCom) ptr; 
     Workers.Add(worker); 
    } 

Absolut erstaunlich.

1

Ich musste kürzlich etwas Ähnliches machen und fand heraus, dass die Verwendung von Shared Memory sehr gut für mich funktionierte. Der BossCom könnte den gemeinsamen Speicher erstellen und besitzen, und die Arbeiter könnten sich registrieren, indem sie einen Eintrag im gemeinsamen Speicher machen. Hier ist ein MSDN link zu dem, worüber ich spreche. Denken Sie daran, einen Mutex zu verwenden, um den Zugriff auf den Speicher zu synchronisieren ...

+0

Das macht die Registrierung in Ordnung, aber ich weiß nicht, wie das bei der Steuerung und Kontrolle der Arbeiter hilft. –

+0

Der Shared Memory ist einfach eine Art der Kommunikation über einen Notizblock. Der BossCom könnte die Befehle in den Speicher schreiben und ein Ereignis signalisieren, auf das die Arbeiter warten. Es gibt viele andere Möglichkeiten, dies zu tun, und alles hängt von Ihren Sicherheitsanforderungen ab. Ich fand diesen Ansatz sehr schnell und sehr flexibel. – T33C

+0

Ich schätze die Idee, aber UAC macht es schwieriger. Meine Anwendung muss in Windows XP und höher ausgeführt werden. Die APIs, die freigegebenen Speicher über UAC-Benutzergrenzen hinweg nutzbar machen, sind in XP nicht vorhanden. Ich habe in der Vergangenheit daran gearbeitet, aber ich bin nicht bereit, es noch einmal zu tun. –

1

Sie sind nur eingeschränkt in der Lage, marshalable Schnittstellen in C# zu erstellen. Keine einfache Möglichkeit, den Proxy einzurichten. Kein solches Problem in ATL, eine Callback-Schnittstelle in der IDL deklarieren. Und übergeben Sie einen Instanzzeiger mit dem Aufruf von RegisterWorker(). Der Server sollte es speichern, bis es den Unregister-Aufruf erhält. Verwenden Sie diese Callback-Schnittstelle, um Benachrichtigungen zu generieren.

2

Sie sollten einen Blick auf Monikers werfen, die verwendet werden, um eine COM-Objektinstanz auch über verschiedene Maschinen hinweg zu identifizieren.

+0

Das ist interessant. Und es wird möglicherweise andere Teile meines Projekts erleichtern. Ich erinnere mich an die Arbeit mit DirectShow, Moniker waren nur Textstrings. Diese sollten extrem einfach marshalen. Verdammt, ich könnte sie sogar in einen ESE-Tisch legen, damit jeder (wie andere Arbeiter) sie finden kann. Eine Schnellsuche zeigte nicht, wie ich einen Moniker für mein Objekt erstellen kann. Irgendwelche Zeiger? –

+0

Vielleicht CreateObjrefMoniker? –