Как реализовать IMarshal для пользовательского интерфейса маршаллинга с сервера вне процесса - PullRequest
3 голосов
/ 20 сентября 2011

Я пытаюсь выяснить, как реализовать пользовательское распределение для COM-сервера вне процесса, когда он запускает событие. Сервер реализует интерфейс IConnectionPoint. Один из методов интерфейса, который он вызывает для оповещения о событии, получает указатель на интерфейс (назовите его IMyEventData.). Класс, который реализует IMyEventData на сервере, также реализует IMarshal. Когда мой сервер запускает событие, я получаю ожидаемые вызовы IMarshal, включая GetMarshalSizeMax, GetUnmarshalClass и MarshalInterface. Пока все хорошо.

Я реализовал unmarshaller в отдельной DLL, которая зарегистрирована в системе. Сразу после того, как сервер обработает вызов MarshalInterface, моя unmarshaller DLL загружается в клиент, но вызовы, которые я получаю через его интерфейс IMarshal, не являются тем, что я ожидаю. Вызовы GetUnmarshalClass, GetMarshalSizeMax и MarshalInterface. Во всех этих вызовах контекст внутрипроцессный, по-видимому, пытается маршалировать через квартиры, а не обрабатывать границы. Я никогда не получаю ожидаемый вызов UnmarshalInterface. Когда я запускаю как клиент, так и сервер в отладчике, каждый из них отображает исключение в окне вывода сразу после вызова интерфейса IMarshal моего демаршаллера, указывая на то, что произошла неправильная ошибка параметра (0x80070057).

Может кто-нибудь сказать мне, что я делаю не так? Я ожидал, что мой unmarshaller получит вызов IMarshal :: UnmarshalInterface, чтобы получить доступ к данным, которые сервер предоставил при вызове IMarshal :: MarshalInterface. Я, должно быть, здесь упускаю что-то простое.

Спасибо.

Wayne

1 Ответ

2 голосов
/ 28 сентября 2013

Вопрос немного не конкретен, поэтому в ответе будут изложены основные шаги, которые происходят.

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

Серверная сторона

  • COM запрашивает рассматриваемый COM-объект для IMarshal интерфейса - это успешно, наш объект действительно реализует его
  • COM вызывает IMarshal::GetUnmarshalClass, чтобы получить CLSID класса, отвечающего за демаршалинг на стороне клиента; это может быть тот же CLSID объекта сервера, это может быть прокси-класс CLSID или прокси-класс фабрики CLSID - идея заключается в том, что COM запрашивает это через вызов метода, поэтому объект может возвращать все, что кажется подходящим
  • COM может вызвать IMarshal::GetMarshalSizeMax для подготовки буфера для маршалинга данных
  • COM звонки IMarshal::MarshalInterface для маршала данных

Клиентская сторона

  • COM начинается здесь с получения внешнего запроса, предполагающего, что для порождения прокси-объекта и получения указателя COM-интерфейса, который должен быть передан управляющему / вызывающему приложению, требуется какое-то волшебство
  • COM имеет на руках CLSID класса unmarshaler и данные от маршалера
  • COM создает экземпляр класса, используя CLSID
  • COM вызывает IMarhsal::UnmarshalInterface для созданного класса и предоставляет IID, который он в конечном итоге хочет получить

Обратите внимание, что на последнем шаге выше COM имеет следующее:

  • CLSID класса для создания экземпляра для запроса указателя интерфейса у
  • IID запрошенного указателя интерфейса
  • Данные, полученные на сервере в результате процесса маршалинга

Со всеми этими входами ожидается, что класс unmarshaler вернет действительный указатель, который может быть или не быть интерфейсом самого unmarshaler. Таким образом, вы можете сами выбирать, хотите ли вы, чтобы специализированный класс unmarshaler «фабрики» создавал объект на стороне клиента, или вы просто хотите создать новый экземпляр и инициализировать его из данных маршалинга.

...