Как я могу вывести ссылку COM вне процесса через границы процесса? - PullRequest
5 голосов
/ 14 января 2011

У меня есть COM-сервер вне процесса, который должен следить за вещами. Этот сервер работает как служба и является внутренним компонентом. Ради простоты я назову его BossCom.

У меня есть еще один внепроцессный COM-сервер, который работает. Для стабильности системы это одноразовый сервер (это означает, что если вы создаете 2 WorkerCom, то работает 2 WorkerCom.exe). Ради простоты я назову его WorkerCom.

WorkerCom может быть запущен чем угодно, даже сам, если кто-то запускает его через командную строку с правильными аргументами командной строки.

Общая цель для BossCom - узнать, что вокруг WorkerComs, знать, что они делают, и иметь возможность отдавать им приказы (пауза, остановка, увеличение и т. Д.).

Сначала я подумал, что всякий раз, когда WorkerCom запускается, он CoCreateInstance создает BossCom и вызывает BossCom-> RegisterWorker (я не знаю). Затем, когда WorkerCom собирается завершить работу, он вызывает BossCom-> UnregisterWorker (я не знаю). BossCom может QueryInterface IUnknown для IWorkerCom и может выдавать команды.

Это бы отлично работало, если бы все эти com-объекты были в одном процессе, но это не так. Я думал об использовании GlobalInterfaceTable, но он является глобальным в смысле одного процесса.

Я провел несколько дней, исследуя это, и растерялся. Может быть, у меня туннельное зрение.

Как я могу вывести ссылку на ком-объект от Рабочего к Боссу?

Да, и, как ни крути, BossCom написан на C #, а WorkerCom написан на ATL C ++, но я возьму решения, написанные на VB, Scala, Lisp или чем-то еще. Я полагаю, я могу перевести основную идею. : -)

Ответы [ 5 ]

2 голосов
/ 14 января 2011

Согласно комментариям, это действительно работает из коробки. Однако есть одна дополнительная деталь, которая заставляет его работать.

Первоначально, когда я смотрел на интерфейсы C #, которые имели дело с копированием интерфейсов, тип аргумента был IntPtr. Ну, IntPtr - это просто long, поэтому он передает значение как есть и, как таковое, не работает.

Ключ должен установить атрибут MarshalAs для аргумента. Так что мой метод RegisterWorker выглядит так:

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

Совершенно удивительно.

2 голосов
/ 14 января 2011

Вы должны взглянуть на Monikers , которые используются для идентификации экземпляра COM-объекта даже на разных машинах.

1 голос
/ 14 января 2011

Вы немного ограничены в возможности создавать маршалируемые интерфейсы в C #.Нет простого способа настроить прокси.Нет такой проблемы в ATL, объявите интерфейс обратного вызова в IDL.И передайте указатель экземпляра с помощью вызова RegisterWorker ().Сервер должен хранить его, пока не получит незарегистрированный вызов.Используйте этот интерфейс обратного вызова для генерации уведомлений.

1 голос
/ 14 января 2011

Недавно мне пришлось сделать нечто подобное, и я обнаружил, что использование общей памяти работает очень хорошо для меня. BossCom может создавать и владеть общей памятью, а рабочие могут зарегистрироваться, сделав запись в общей памяти. Вот ссылка MSDN на то, о чем я говорю. Не забудьте использовать мьютекс для синхронизации доступа к памяти ...

0 голосов
/ 28 октября 2011

Вам также следует заглянуть в ROT (Таблица бегущих объектов), это может быть другой способ решения этой проблемы.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms695276(v=vs.85).aspx

http://www.codeproject.com/KB/COM/ROTStuff.aspx

...