Поделиться через


Интерфейс IMarshal (objidl.h)

Позволяет COM-объекту определять свои указатели интерфейса и управлять их маршалингом.

Наследование

Интерфейс IMarshal наследуется от интерфейса IUnknown . IMarshal также имеет следующие типы членов:

Методы

Интерфейс IMarshal имеет следующие методы.

 
IMarshal::D isconnectObject

Метод IMarshal::D isconnectObject (objidl.h) освобождает все подключения к объекту до завершения работы.
IMarshal::GetMarshalSizeMax

Извлекает максимальный размер буфера, который потребуется во время маршалинга.
IMarshal::GetUnmarshalClass

Извлекает ИДЕНТИФИКАТОР CLSID кода распаковки.
IMarshal::MarshalInterface

Метод IMarshal::MarshalInterface (objidl.h) маршалирует указатель интерфейса.
IMarshal::ReleaseMarshalData

Метод IMarshal::ReleaseMarshalData (objidl.h) уничтожает маршалированные пакеты данных.
IMarshal::UnmarshalInterface

Метод IMarshal::UnmarshalInterface (objidl.h) отменяет удаление указателя интерфейса.

Комментарии

Маршалинг — это процесс упаковки данных в пакеты для передачи другому процессу или компьютеру. Отмена марширования — это процесс восстановления этих данных на принимающем конце. В любом вызове аргументы метода маршалируются и отменяются в одном направлении, а возвращаемые значения маршалируются и отменяются в другом.

Хотя маршалинг применяется ко всем типам данных, указатели интерфейса требуют специальной обработки. Основная проблема заключается в том, как клиентский код, выполняющийся в одном адресном пространстве, может правильно разыменовать указатель на интерфейс объекта, размещенного в другом адресном пространстве. Решение COM предназначено для взаимодействия клиентского приложения с исходным объектом через суррогатный объект или прокси-сервер, который находится в процессе клиента. Прокси-сервер содержит ссылку на интерфейс в исходном объекте и передает клиенту указатель на интерфейс на себя. Когда клиент вызывает метод интерфейса для исходного объекта, его вызов на самом деле выполняется на прокси-сервер. Таким образом, с точки зрения клиента, все вызовы являются внутрипроцессными.

При получении вызова прокси-сервер маршалирует аргументы метода и с помощью некоторых средств межпроцессного взаимодействия, таких как RPC, передает их в код в серверном процессе, который отменяет удаление аргументов и передает их исходному объекту. Этот же код маршалирует возвращаемые значения для передачи обратно на прокси-сервер, который отменяет их и передает их клиентскому приложению.

IMarshal предоставляет методы для создания, инициализации и управления прокси-сервером в клиентском процессе; он не определяет, как прокси-сервер должен взаимодействовать с исходным объектом. В реализации IMarshal по умолчанию COM используется RPC. При самостоятельной реализации этого интерфейса вы можете выбрать любой метод межпроцессного взаимодействия, который вы считаете подходящим для вашего приложения: общую память, именованный канал, дескриптор окна, RPC, то есть все, что работает.

Реализация по умолчанию IMarshal

COM использует собственную внутреннюю реализацию интерфейса IMarshal для маршалирования любого объекта, который не предоставляет собственную реализацию. COM делает это определение, запрашивая объект для IMarshal. Если интерфейс отсутствует, COM по умолчанию использует свою внутреннюю реализацию.

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

Прокси-сервер интерфейса находится в клиентском процессе; Заглушка интерфейса находится на сервере. Вместе каждая пара обрабатывает все маршалинга для интерфейса. Задача каждого прокси-сервера интерфейса заключается в маршале аргументов и отмене маршалирования возвращаемых значений и параметров, которые передаются в последующих вызовах интерфейса. Задача каждой заглушки интерфейса состоит в том, чтобы отменить маршал аргументы функции и передать их исходному объекту, а затем маршалировать возвращаемые значения и параметры out, возвращаемые объектом.

Прокси-сервер и заглушка обмениваются данными через канал RPC (удаленный вызов процедуры), который использует инфраструктуру RPC системы для межпроцессного взаимодействия. Канал RPC реализует единый интерфейс IRpcChannelBuffer, на который и прокси-серверы интерфейса, и заглушки содержат указатель. Прокси-сервер и заглушка вызывают интерфейс для получения маршалинга пакета, отправки данных их аналогу и уничтожения пакета по завершении. Заглушка интерфейса также содержит указатель на исходный объект.

Для любого заданного интерфейса прокси-сервер и заглушка реализуются как экземпляры одного класса, который указан для каждого интерфейса в системном реестре под меткой ProxyStubClsid32. Эта запись сопоставляет IID интерфейса с CLSID его прокси-сервера и объекта-заглушки. Когда COM требуется маршалировать интерфейс, он выполняет поиск в системном реестре, чтобы получить соответствующий ИДЕНТИФИКАТОР CLSID. Сервер, определяемый этим идентификатором CLSID , реализует прокси-сервер интерфейса и заглушку интерфейса.

Чаще всего класс, на который ссылается этот ИДЕНТИФИКАТОР CLSID , автоматически создается средством, входными данными которого является описание сигнатур функций и семантики данного интерфейса, написанное на каком-то языке описания интерфейса. Хотя использовать такой язык настоятельно рекомендуется и рекомендуется для обеспечения точности, делать это не требуется. Прокси-серверы и заглушки — это просто COM-компоненты, используемые инфраструктурой RPC. Поэтому их можно написать любым нужным способом, при условии, что соблюдаются правильные внешние контракты. Программист, который разрабатывает новый интерфейс, отвечает за обеспечение того, чтобы все существующие прокси-серверы и заглушки интерфейса согласовали представление своих маршалированных данных.

При создании прокси-серверы интерфейса всегда объединяются в более крупный прокси-сервер, который представляет объект в целом. Этот прокси-сервер объекта также агрегирует универсальный прокси-объект COM, который называется диспетчером прокси-серверов. Диспетчер прокси-серверов реализует два интерфейса: IUnknown и IMarshal. Все остальные интерфейсы, которые могут быть реализованы в объекте , предоставляются в его прокси-сервере посредством агрегирования отдельных прокси-серверов интерфейса. Клиент, содержащий указатель на прокси-сервер объекта, считает, что он содержит указатель на фактический объект.

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

Заглушки интерфейса, в отличие от прокси-серверов интерфейса, не агрегируются, так как нет необходимости в том, чтобы они были частью большего целого для какого-то внешнего клиента. При подключении заглушка интерфейса получает указатель на объект сервера, в который она должна пересылать получаемые вызовы метода. Хотя концептуально полезно ссылаться на диспетчер заглушки, то есть любые фрагменты кода и состояние в серверной инфраструктуре RPC, которая обслуживает удаленное взаимодействие данного объекта, нет прямого требования к тому, чтобы код и состояние принимают какую-либо конкретную, хорошо заданную форму.

Когда клиент впервые запрашивает указатель на интерфейс определенного объекта, COM загружает заглушку IClassFactory в серверном процессе и использует ее для маршалинга первого указателя обратно клиенту. В клиентском процессе COM загружает универсальный прокси-сервер для объекта фабрики класса и вызывает свою реализацию IMarshal , чтобы отменить удаление первого указателя. Затем COM создает первый прокси-сервер интерфейса и передает ему указатель на канал RPC. Наконец, COM возвращает указатель IClassFactory на клиент, который использует его для вызова IClassFactory::CreateInstance, передавая ему ссылку на интерфейс.

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

При создании нового прокси-сервера интерфейса COM передает ему указатель на реализацию IUnknown диспетчера прокси-серверов, которому он делегирует все вызовы QueryInterface . Каждый прокси-сервер интерфейса реализует два собственных интерфейса: интерфейс, который он представляет, и IRpcProxyBuffer. Прокси-сервер интерфейса предоставляет собственный интерфейс непосредственно клиентам, которые могут получить указатель, вызвав QueryInterface в диспетчере прокси-серверов. Однако только COM может вызывать IRpcProxyBuffer, который используется для подключения и отключения прокси-сервера к каналу RPC. Клиент не может запросить прокси-сервер интерфейса для получения указателя на интерфейс IRpcProxyBuffer .

На стороне сервера каждая заглушка интерфейса реализует IRpcStubBuffer. Код сервера, выполняющий роль диспетчера заглушки, вызывает IRpcStubBuffer::Connect и передает заглушку интерфейса указателю IUnknown своего объекта.

Когда прокси-сервер интерфейса получает вызов метода, он получает маршалинговой пакет из своего канала RPC через вызов IRpcChannelBuffer::GetBuffer. Процесс маршалинга аргументов будет копировать данные в буфер. После завершения маршалинга прокси-сервер интерфейса вызывает IRpcChannelBuffer::SendReceive для отправки маршалированного пакета в соответствующую заглушку интерфейса. При возвращении IRpcChannelBuffer::SendReceive буфер, в который были маршалированы аргументы, будет заменен новым буфером, содержащим возвращаемые значения, маршалированные из заглушки интерфейса. Прокси-сервер интерфейса отменяет удаление возвращаемых значений, вызывает IRpcChannelBuffer::FreeBuffer для освобождения буфера , а затем возвращает возвращаемые значения исходному вызывающей объекту метода .

Именно реализация IRpcChannelBuffer::SendReceive фактически отправляет запрос в серверный процесс и знает, как идентифицировать серверный процесс и в рамках этого процесса объект, которому должен быть отправлен запрос. Реализация канала также знает, как перенаправить запрос в соответствующий диспетчер заглушки в этом процессе. Заглушка интерфейса отменяет удаление аргументов из предоставленного буфера, вызывает указанный метод в объекте сервера и маршалирует возвращаемые значения обратно в новый буфер, выделенный вызовом метода IRpcChannelBuffer::GetBuffer. Затем канал передает возвращаемый пакет данных обратно на прокси-сервер интерфейса, который по-прежнему находится в середине IRpcChannelBuffer::SendReceive, который возвращается прокси-серверу интерфейса.

Конкретный экземпляр прокси-сервера интерфейса можно использовать для обслуживания нескольких интерфейсов при условии, что выполняются следующие условия:

  • Идентификаторы IID затронутых интерфейсов должны быть сопоставлены с соответствующим ProxyStubClsid в системном реестре.
  • Прокси-сервер интерфейса должен поддерживать вызовы QueryInterface из одного поддерживаемого интерфейса в другие интерфейсы, как обычно, а также из IUnknown и IRpcProxyBuffer.
Один экземпляр заглушки интерфейса также может обслуживать несколько интерфейсов, но только в том случае, если этот набор интерфейсов имеет строгую связь с одним наследованием. Это ограничение существует, так как заглушка может направлять вызовы методов в несколько интерфейсов только там, где заранее известно, какие методы реализованы на каких интерфейсах.

В разное время прокси-серверы и заглушки должны выделять или освобождать память. Например, прокси-серверам интерфейса потребуется выделить память для возврата параметров вызывающей объекту. В этом отношении прокси-серверы и заглушки интерфейса являются обычными com-компонентами, в которых они должны использовать стандартный распределител задач. (См. Раздел CoGetMalloc.)

Требования

Требование Значение
Минимальная версия клиента Windows 2000 Профессиональная [классические приложения | Приложения UWP]
Минимальная версия сервера Windows 2000 Server [классические приложения | Приложения UWP]
Целевая платформа Windows
Header objidl.h (включая ObjIdl.h)

См. также раздел

IStdMarshalInfo