Регистрация COM объектов. Часть I
Apr 13, 2007 · CommentsCOMПрограммированиеWindowsWow64
Изначально, данный пост должен был называться «Регистрация COM объектов на 64-х разрядных версиях Windows» и речь должна было пойти про особенности 64-х разрядных версий Windows с точки зрения регистрации COM компонент. Однако пост получился слишком большим и его пришлось разбить на две части. Про особенности 64-х разрядных систем я расскажу во второй части.
Для начала немного теории. Взаимодействие клиента (приложения вызвавшего CoCreateInstance) и сервера (COM объекта) в общем случае можно изобразить с помощью вот такой схемы:
В общем случае, когда клиент и сервер находятся в разных квартирах (apartments), процессах или на разных машинах, они не могут общаться напрямую. Вместо этого они используют посредника - так называемую Proxy/Stub DLL. Эта DLL перехватывает вызовы методов сервера, упаковывает полученные параметры в RPC сообщение и взаимодействует с COM и RPC подсистемой, которая в свою очередь берёт на себя передачу RPC сообщений в обе стороны.
Очень подробная статья на RSDN на эту тему: Секреты маршалинга.
Proxy/Stub DLL, хотя и может быть написана вручную, обычно генерируется автоматически из .idl описания интерфейсов с помощью утилиты midl.exe. Если вы создаёте заготовку COM сервера в Visual Studio, то Proxy/Stub DLL обычно выглядит как дополнительный проект с именем вида «<имя основного проекта>PS».
Proxy/Stub DLL не создаётся для интерфейсов, помеченных атрибутами [dual] или [automation]. Вместо этого используется общий для всех подобных интерфейсов универсальный маршалер. Универсальный маршалер использует информацию из библиотеки типов (typelib, файл с расширением .tlb) для упаковки параметров в RPC сообщения. Реализация универсального маршалера находится в oleaut32.dll.
Теперь вернёмся к теме этого поста. Регистрация COM сервера заключается в:
-
Регистрации самого COM объекта на сервере;
-
Регистрации Proxy/Stub DLL для каждого интерфейса как на клиенте так и на сервере;
-
Регистрация библиотеки типов (typelib) для каждого интерфейса, помеченного атрибутом [dual] или [automation], как на клиенте так и на сервере.
При регистрации COM сервера в реестре создается ключ вида “HKEY_CLASSES_ROOT\CLSID{…}” с необходимыми под-ключами. По большому счету это единственный ключ необходимый для создания экземпляра COM объекта.
Регистрация Proxy/Stub DLL создаёт два ключа на каждый интерфейс: ключ маршалера под “HKEY_CLASSES_ROOT\CLSID” и ключ самого интерфейса под «HKEY_CLASSES_ROOT\Interface». При этом «ProxyStubClsid32» указывает на регистрацию маршалера, позволяя тем самым найти нужный объект во время вызова IUknown::QueryInterface.
Регистрация библиотеки типов также добавляет два ключа на каждый интерфейс: ключ интерфейса под «HKEY_CLASSES_ROOT\Interface» и ключ библиотеки типов под «HKEY_CLASSES_ROOT\Typelib». Ключ маршалера при этом не создаётся, так как универсальный маршалер регистрируется при установке системы.
Итого, чтобы все работало нужно зарегистрировать сам COM объект и все необходимые Proxy/Stub DLL и библиотеки типов на сервере, а также все необходимые Proxy/Stub DLL и библиотеки типов на клиенте.
Продолжение следует…