Концепция маршалинга
С другой стороны, специальная часть кода на сервере (stub), получает от proxy запрос на вызов метода, распаковывает параметры и вызывает нужный метод реального сервера. Сервер, выполнив клиентский запрос, обычно возвращает какие-то данные. Посредник на стороне сервера (stub) перехватывает эти данные, упаковывает их и направляет соответствующему посреднику на стороне клиента (proxy). Последний получает возвращаемые данные, распаковывает их и передает клиенту. Библиотеки СОМ автоматически обеспечивают код функций proxy/stub для стандартных интерфейсов.
При написании же собственных интерфейсов следует пользоваться интерфейсом, производным от iMarshal. Итак, заместитель расположен в адресном пространстве клиента и представляет интересы СОМ-объекта на стороне клиента, обеспечивая суррогатные точки входа для каждого из методов, обозначенных в исходном IDL-файле. Когда клиент делает вызов удаленной (remote) процедуры сервера, то сначала он вызывает суррогат этой процедуры в заглушке proxy (в пространстве своего процесса). Последняя осуществляет:
- упаковку параметров в буфер сообщения (message buffer), так чтобы они надежно могли быть доставлены удаленному серверу;
- вызов библиотечной процедуры передачи параметров в адресное пространство сервера;
- распаковку выходных (out) или возвращаемых (retval) параметров и передачу их вызывающей процедуре.
Серверная заглушка, или просто stub, распаковывает (unmarshals) параметры и передает их объекту СОМ. Она также запаковывает ответную информацию, возвращаемые параметры, для того чтобы передать их назад клиенту.
Описанные действия называются маршализацией аргументов. Эта процедура сильно зависит от типа параметров. Например, маршализация массива данных значительно сложнее маршализации переменной целого типа или указателя на структуру. Для каждого типа данных существуют свои отдельные функции. Proxy состоит из части, которая размещена в OLE32.DLL (proxy manager), и частей, которые зависят от интерфейсов СОМ-объекта (interface proxies). Для клиента proxy представляет собой реальный СОМ-объект.
Сам канал передачи обслуживается функциями библиотеки СОМ. Канал передает буфер (с маршализованными параметрами) во владение функциям из RPC-библиотеки, которые и занимаются его передачей через границу между процессами. Вы можете выбирать между стандартной маршализацией, обеспечиваемой библиотекой СОМ, и своей собственной (custom marshaling). В последнем случае вы должны разработать интерфейс, производный от IMarshal. Каждый отдельный интерфейс может пользоваться одним из двух способов маршализации своих параметров. Это определяется на этапе проектирования СОМ-класса, реализующего интерфейсы. Здесь уместно привести схему, которую вы также можете увидеть в MSDN (Search › Marshaling Details).
СОМ не накладывает ограничений на структуру компонентов, он определяет лишь порядок их взаимодействия. В основе межпроцессной коммуникации лежит все та же косвенная адресация (таблица виртуальных функций), которая позволяет передать управление либо прямо методу интерфейса (inproc-server), либо его представителю (proxy) на стороне клиента, который, в свою очередь, делает RPC (удаленный вызов) метода настоящего объекта. Прозрачность СОМ-объекта для клиента заключается в том, что proxy-объект знает, где расположен реальный объект (на другом компьютере – remote server, или на том же самом – local server), а клиент об этом не знает.
Когда клиент хочет использовать СОМ-сервер, он обращается к системной библиотеке с просьбой найти и загрузить сервер, чей CLSID равен определенному значению. Заодно клиент передает IID требуемого интерфейса. В ответ на это системная COM DLL вызывает SCM (Service Control Manager) – менеджер сервисов, который запускается во время загрузки системы. SCM является RFC-сервером, который использует системный реестр, чтобы выполнить поиск реализации, то есть отыскать ЕХЕ – или DLL-файл, содержащий требуемый СОМ-сервер. Чтобы найти модуль сервера, SCM ищет в реестре его CLSID. Если он найден, то SCM возвращает связанный с ним файловый путь, а СОМ загружают этот модуль в память.
Теперь возможны два варианта действий: если сервер находится в ЕХЕ-файле, то СОМ запускает его, устанавливает канал связи (RPC) между представителями клиента и сервера (proxy/stub) и возвращает интерфейсный указатель клиенту. Если СОМ-сервер находится в DLL-файле, СОМ просто передаст клиенту указатель на фабрику классов сервера.