Доступ к объекту c # на COM-сервере outproc из другого процесса на том же компьютере

Я пытаюсь получить доступ к объектам C # из другого процесса, чем тот, в котором они находятся, через COM. Объекты C # доступны для COM.

Проблема в том, что когда я вызываю метод для этих объектов, вызовы выполняются локально, а не на COM-сервере outproc, где я хочу, чтобы возникали побочные эффекты этих вызовов.

Точнее, вот что я делаю, пытаясь получить доступ к объектам, находящимся на COM-сервере outproc:

Type oType = Type.GetTypeFromProgID("myProgId");

var obj = Activator.CreateInstance(oType);

var result = oType.InvokeMember("GetObjForMyClassMethod",
                                BindingFlags.InvokeMethod, null, obj, null);

Затем я передаю результат в соответствующий интерфейс (IMyInterface) класса C #, и когда я вызываю методы этого интерфейса, они выполняются удаленно на COM-сервере outproc, как я и ожидал.

Проблема начинается, когда я использую этот интерфейс для получения других объектов C # (я использую метод IMyInterface.GetOtherObject(), который возвращает IOtherObjectInterface).

Когда я вызываю IOtherObjectInterface, они выполняются локально, а не на COM-сервере outproc, поэтому их побочные эффекты теряются (например, если я вызываю метод SetValue, значение не поступает на сервер outproc и теряется).

Более того, когда я смотрю в отладчик во время выполнения, я вижу, что тип интерфейса, для которого работают удаленные вызовы, равен System._ComObject, тогда как тип интерфейса, в котором удаленные вызовы не работают, является фактическим типом (IOtherObjectInterface).

Я попытался реплицировать все (все атрибуты и другие реализованные интерфейсы) о том, как IMyInterface (тот, для которого работают удаленные вызовы) отображается в COM на IOtherObjectInterface (тот, для которого удаленные вызовы не работают), но не повезло .

Что нужно сделать, чтобы вызовы, которые я делаю на IOtherObjectInterface, выполнялись на сервере outproc через RPC, а не в локальном процессе (тот, где отправляются вызовы), где они никому не нужны?

ИЗМЕНИТЬ:

С тех пор я обнаружил, что если я извлекаю объект, для которого он не работает (IOtherObjectInterface), используя тот же метод, который я использую для объекта, для которого он работает (oType.InvokeMember ("GetOtherObjForMyClassMethod", ....), он по-прежнему не работает (вызовы, которые я делаю для объекта, все еще не перенаправляются на COM-сервер outproc).

Таким образом, проблема связана с самим классом, а не с методом, используемым для получения объектов.

Я сильно подозреваю, что эта проблема как-то связана с сериализацией, хотя оба класса (работающие и не работающие), похоже, реализуют сериализацию одинаково ...

РЕДАКТИРОВАТЬ2:

Я не понимаю, что класс, для которого работает это «удаленное взаимодействие с COM» (тот, для которого я получаю System._ComObject, когда я получаю объект вне COM-сервера) имеет атрибут «сериализуемый». Я думал, что по умолчанию для типов с этим атрибутом используется сортировка по значению.


person mnrtyrpt123    schedule 11.09.2012    source источник
comment
Примечание. Я обнаружил, что это не вопрос DCOM, процессы выполняются на одном компьютере.   -  person Hans Passant    schedule 11.09.2012
comment
I thought the default for types with this attribute was marshal-by-value. - Да, но вы не маршалируете этот экземпляр (он находится в процессе сервера OOP COM), вы разговариваете с его __ComObject прокси, созданным CLR.   -  person Chris Dickson    schedule 14.09.2012


Ответы (3)


Вам нужно использовать ServicedComponent в соответствии с ответом Марка здесь:

Создать внепроцессный COM в C # /. Net?

person Slugart    schedule 11.09.2012
comment
Он говорит, что это один из вариантов. Как я объяснил выше, он работает для одного класса (без использования ServicedComponent), но не для другого, но я не могу понять разницу между двумя, которые заставляют его работать в одном случае, а не в другом ... - person mnrtyrpt123; 11.09.2012

Что вы можете сделать, так это создать новое приложение в консоли Component Services и объявить его внепроцессным приложением. Для этого вам понадобится

  1. Создать новое приложение
  2. Щелкните это приложение правой кнопкой мыши
  3. Перейдите на вкладку «Активация» и выберите «Серверное приложение».
  4. Добавьте свою DLL в это приложение

Возможно, вам придется настроить безопасность.

person Simon Mourier    schedule 11.09.2012
comment
Как я уже сказал, это работает для одного класса, а не для другого. Таким образом, проблема не в конфигурации приложения, в котором размещены эти 2 класса (иначе это вообще не сработало бы). - person mnrtyrpt123; 11.09.2012

Я думаю, вы подтвердили, что IMyInterface.GetOtherObject() выполняется удаленно, и ваш вопрос заключается в том, почему объект, возвращаемый вашему вызывающему коду, является конкретным экземпляром типа .NET, реализующим IOtherObjectInterface, а не System._ComObject или чем-то еще, что может вызвать вызовы методов на этот объект будет удален.

Ответ должен заключаться в том, что IMyInterface.GetOtherObject() создает экземпляр «OtherObject», а затем, когда он возвращается, этот экземпляр маршалируется для вашего вызывающего процесса. Это произойдет по умолчанию, если объект имеет сериализуемый тип .NET.

Я думаю, что если бы объект был MarshalByRefObject, он не был бы упорядочен обратно в вызывающий процесс: вызывающий код получил бы вместо этого TransparentProxy, а затем вызовы к нему были бы удаленными, как вы ожидаете.

Исходный объект (IMyInterface) является особым случаем, потому что вызывающий код сам создает его экземпляр, используя активатор и тип, производный от ProgID, с помощью (под капотом) среды выполнения COM, в результате чего создается специальный прокси-тип _ComObject.

person Chris Dickson    schedule 12.09.2012
comment
Прежде всего, спасибо за понимание моего вопроса ;-) Я подумал о MarshalByRefObject, но я думаю, что это подразумевает использование удаленного взаимодействия, и я понимаю, что эта технология более или менее устарела ... Возможно, мне придется использовать это решение в крайнем случае. - person mnrtyrpt123; 12.09.2012
comment
Ну, System.__ComObject является производным от MarshalByRefObject, так что вы его уже используете. Я думаю, что ваше беспокойство по поводу использования устаревшей технологии удаленного взаимодействия необоснованно. Само по себе удаленное взаимодействие устарело в пользу WCF для реализации IPC, но базовая инфраструктура присутствует в CLR и является фундаментальной для COM-взаимодействия и WCF. - person Chris Dickson; 12.09.2012
comment
Дело в том, что я хотел бы продолжать использовать MarshalByRefObject через System._ComObject. - person mnrtyrpt123; 14.09.2012