2011-01-14 11 views
5

Ho un server COM fuori processo che deve tenere d'occhio le cose. Questo server viene eseguito come servizio ed è, internamente, un singleton. Per motivi di semplicità, lo chiamerò BossCom.Come posso effettuare il marshalling di un riferimento COM fuori processo tra i limiti del processo?

Ho un altro server COM out-of-process che è un lavoratore. È, per la stabilità del sistema, un server monouso (nel senso che se crei 2 WorkerCom, ci sono 2 WorkerCom.exe in esecuzione). Per motivi di semplicità, lo chiamerò WorkerCom.

WorkerCom può essere avviato da qualsiasi cosa, anche da solo se qualcuno lo esegue tramite la riga di comando con gli argomenti della riga di comando destra.

L'obiettivo generale è che BossCom sappia cosa sono WorkerComs in giro, sanno cosa stanno facendo e sono in grado di impartire ordini (pausa, arresto, accelerazione, ecc.).

Il mio pensiero iniziale è che ogni volta che WorkerCom inizia, CoCreateInstance è un BossCom e chiama BossCom-> RegisterWorker (IUnknown me). Poi, quando WorkerCom sta per chiudere, chiamerà BossCom-> UnregisterWorker (IUnknown me). BossCom potrebbe QueryInterface IUnknown per IWorkerCom ed essere in grado di emettere comandi.

Ciò funzionerebbe benissimo se tutti questi oggetti COM fossero nello stesso processo, ma non lo sono. Ho pensato di utilizzare GlobalInterfaceTable, ma è globale solo nel senso di un singolo processo.

Ho trascorso alcuni giorni a cercare questo e sono in perdita. Forse sono a visione di tunnel.

Come è possibile effettuare il marshalling di un riferimento a un oggetto com dal Worker al Boss?

Oh, e, per quello che vale, BossCom è scritto in C# e WorkerCom è scritto in ATL C++ ma prenderò soluzioni scritte in VB, Scala, Lisp o altro. Immagino di poter tradurre l'idea principale. :-)

+3

Questo non solo di lavoro? Devo ammettere che non ho fatto molto con la COM, ma il fatto che sia fuori processo è che la COM sta già facendo il marshalling attraverso i confini del processo, vero? –

+0

Giusto, per la maggior parte delle cose, ma IUnknown è solo un puntatore, giusto? Il puntatore "this" in WorkerCom non avrà alcun significato in BossCom, giusto? O il processo di marshalling manterrà il significato. Credo che dovrei almeno provarlo. –

+2

Dovrebbe funzionare off-the-shelf dato che ci sono proxy/stub o typelib per facilitare il marshalling. In realtà, il marshalling è esattamente per questo: dare a un client un oggetto falso ("proxy") che viene specchiato sul server. Funziona in modo trasparente dalla prospettiva del codice. – sharptooth

risposta

2

Come per i commenti, questo funziona davvero fuori dagli schemi. C'è un ulteriore dettaglio però che lo fa funzionare.

In origine, quando stavo guardando le interfacce C# che si occupavano di copiare le interfacce, il tipo di argomento era IntPtr. Bene, un IntPtr è solo un lungo quindi trasferisce il valore così com'è e, come tale, non funziona.

La chiave è impostare l'attributo MarshalAs sull'argomento. Quindi il mio metodo RegisterWorker assomiglia a questo:

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

Assolutamente fantastico.

1

Ho dovuto fare qualcosa di simile di recente e ho scoperto che l'uso della memoria condivisa funzionava molto bene per me. BossCom potrebbe creare e possedere la memoria condivisa e gli operatori potrebbero registrarsi inserendo una voce nella memoria condivisa. Ecco uno MSDN link di cui sto parlando. Ricorda di utilizzare un mutex per sincronizzare l'accesso alla memoria ...

+0

Che gestisce la registrazione ok, ma non sono chiaro su come questo aiuti con il comando e il controllo dei lavoratori. –

+0

La memoria condivisa è semplicemente un modo di comunicare attraverso uno scratchpad. BossCom potrebbe scrivere i comandi nella memoria e segnalare un evento che i lavoratori attendono. Ci sono molti altri modi per farlo e tutto dipende dai tuoi requisiti di sicurezza. Ho appena trovato questo approccio molto veloce da implementare e molto flessibile. – T33C

+0

Apprezzo l'idea, ma l'UAC rende questo più difficile. La mia applicazione deve essere eseguita in Windows XP e versioni successive. Le API che rendono utilizzabile la memoria condivisa attraverso i confini utente UAC non esistono in XP. Ho lavorato su questo in passato, ma non ho voglia di farlo di nuovo. –

1

Sei un po 'limitato nel riuscire a creare interfacce marshalable in C#. Non è un modo semplice per configurare il proxy. Nessun problema di questo tipo in ATL, dichiara un'interfaccia di callback nell'IDL. E passare un puntatore di istanza con la chiamata RegisterWorker(). Il server dovrebbe memorizzarlo finché non riceve la chiamata di annullamento della registrazione. Usa quell'interfaccia di callback per generare notifiche.

2

Si dovrebbe dare un'occhiata a Monikers, che vengono utilizzati per identificare un'istanza dell'oggetto COM anche su macchine diverse.

+0

Questo è interessante. E potenzialmente renderà più facili altre parti del mio progetto. Ricordo di aver lavorato con DirectShow, i moniker erano solo stringhe di testo. Quelli dovrebbero maresciallo estremamente facile. Diamine, potrei persino metterli in una tabella ESE in modo che chiunque (come gli altri lavoratori) possa trovarli. Una rapida ricerca non mostra come posso creare un moniker per il mio oggetto. Qualche indicazione? –

+0

Forse CreateObjrefMoniker? –

Problemi correlati