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


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

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

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

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

Методы

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

 
IMarshal::D isconnectObject

Метод IMarshal::D isconnectObject (objidlbase.h) освобождает все подключения к объекту, сервер которого вызывает реализацию этого метода объектом.
IMarshal::MarshalInterface

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

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

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

Комментарии

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

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

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

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

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

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

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

Прокси-сервер интерфейса находится в клиентском процессе; заглушка интерфейса находится на сервере. Вместе каждая пара обрабатывает все маршалинга для интерфейса. Задача каждого прокси-сервера интерфейса заключается в маршале аргументов и отмене маршалирования возвращаемых значений и параметров out, которые передаются в последующих вызовах интерфейса. Задача каждой заглушки интерфейса заключается в том, чтобы отменить маршалирование аргументов функции и передать их исходному объекту, а затем маршалировать возвращаемые значения и параметры 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 objidlbase.h (включая ObjIdl.h)

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

IStdMarshalInfo