c# - ¿Cómo puedo ordenar una referencia COM fuera de proceso a través de los límites del proceso?
c++ interprocess (5)
Tengo un servidor COM fuera de proceso que necesita vigilar las cosas. Este servidor se ejecuta como un servicio y, internamente, es un singleton. Por simplicidad, lo llamaré BossCom.
Tengo otro servidor COM fuera de proceso que es un trabajador. Es, para la estabilidad del sistema, un servidor de un solo uso (lo que significa que si crea 2 WorkerCom, hay 2 WorkerCom.exe en ejecución). Por simplicidad, lo llamaré WorkerCom.
WorkerCom puede ser iniciado por cualquier cosa, incluso por sí mismo si alguien lo ejecuta a través de la línea de comando con los argumentos de línea de comando correctos.
El objetivo general es que BossCom sepa lo que hacen los WorkerComs, sepa lo que están haciendo y sea capaz de darles órdenes (pausar, detener, acelerar, etc.).
Mi primer pensamiento en esto sería que cada vez que WorkerCom comience, él CoCreateInstance a BossCom y llamar a BossCom-> RegisterWorker (IUnknown me). Luego, cuando el WorkerCom esté a punto de apagarse, llamaría a BossCom-> UnregisterWorker (No me conocía). BossCom podría QueryInterface the IUnknown para IWorkerCom y poder emitir comandos.
Eso funcionaría muy bien si todos estos objetos com estuvieran en el mismo proceso, pero no es así. Pensé en usar GlobalInterfaceTable, pero solo es global en el sentido de un solo proceso.
He pasado unos días investigando esto y estoy perdido. Tal vez estoy con visión de túnel.
¿Cómo puedo ordenar una referencia a un objeto com del Worker to the Boss?
Ah, y, por lo que vale, BossCom está escrito en C # y WorkerCom está escrito en ATL C ++ pero tomaré las soluciones escritas en VB, Scala, Lisp o cualquier cosa. Me imagino que puedo traducir la idea central. :-)
Estás un poco limitado al poder crear interfaces seleccionables en C #. No es una forma fácil de configurar el proxy. No hay tal problema en ATL, declara una interfaz de devolución de llamada en el IDL. Y pase un puntero de instancia con la llamada RegisterWorker (). El servidor debe almacenarlo hasta que obtenga la llamada para anular el registro. Usa esa interfaz de devolución de llamada para generar notificaciones.
Debería echar un vistazo a los Monikers , que se utilizan para identificar una instancia de objeto COM incluso en diferentes máquinas.
Tuve que hacer algo similar recientemente y descubrí que el uso de la memoria compartida funcionaba muy bien para mí. El BossCom podría crear y poseer la memoria compartida y los trabajadores podrían registrarse haciendo una entrada en la memoria compartida. Aquí hay un enlace de MSDN de lo que estoy hablando. Recuerde usar un mutex para sincronizar el acceso a la memoria ...
Según los comentarios, esto realmente funciona de la caja. Sin embargo, hay un detalle adicional que lo hace funcionar.
Originalmente cuando estaba buscando interfaces C # que trataban con las interfaces de copia, el tipo de argumento era IntPtr. Bueno, un IntPtr es solo un largo, por lo que transfiere el valor como está y, como tal, no funciona.
La clave es establecer el atributo MarshalAs en el argumento. Entonces mi método de RegisterWorker se ve así:
public void RegisterWorker(
[In, MarshalAs(UnmanagedType.IUnknown)] object ptr
)
{
IWorkerCom worker = (IWorkerCom) ptr;
Workers.Add(worker);
}
Absolutamente increíble.
También debe mirar en el ROT (Running Object Table), puede ser una forma diferente de resolver este problema.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms695276(v=vs.85).aspx