Пользовательская реализация COM? - PullRequest
9 голосов
/ 28 января 2010

Я хочу реализовать пользовательскую реализацию COM в C ++ на платформе типа UNIX, чтобы позволить мне динамически загружать и связывать объектно-ориентированный код.Я думаю, что это будет основано на аналогичном наборе функциональных возможностей, которые POSIX предоставляет для загрузки и вызова dll, т.е. dlopen, dlsym и dlclose.

Я понимаю, что общая идея COM заключается в том, что вы ссылаетесь на несколько функций, например QueryInterface, AddRef и Release, в общей dll (Kernel32.dll), которая затем позволяет вам получить доступ к интерфейсам, которые являются просто таблицейуказатели на функции, инкапсулированные указателем на объект, для которого должны быть вызваны указатели на функции.Эти функции доступны через IUnknown, от которого вы должны наследовать.

Так как же все это работает?Есть ли лучший способ динамически связать и загрузить объектно-ориентированный код?Как работает наследование от dll - каждый ли вызов базового класса должен относиться к открытой функции-члену, т.е. private / protected / public просто игнорируется?

Я довольно хорошо разбираюсь в C ++ и мета-шаблонах.-программирование и уже имеет полностью отражающую систему C ++, т.е. свойства-члены, функции-члены и глобальные / статические функции, которые используют boost.

Ответы [ 6 ]

6 голосов
/ 28 января 2010

Несколько вещей, которые нужно иметь в виду:

  • Сила COM в значительной степени зависит от IDL и midl-компилятора. Он позволяет очень точное определение объектов и интерфейсов со всеми сгенерированными для вас шаблонами C / C ++.

  • COM регистрация. В Windows идентификаторы классов (CLSID) записываются в реестр, где они связаны с исполняемым файлом. Вы должны предоставить аналогичные функции в среде UNIX.

  • Вся реализация IUnknown довольно тривиальна, за исключением QueryInterface, который работает при реализации в C (то есть без RTTI).

  • Целым другим аспектом COM является IDispatch - то есть вызов и обнаружение метода с поздней привязкой (отражение только для чтения).

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

4 голосов
/ 28 января 2010

Я хочу реализовать пользовательскую реализацию COM в C ++ на платформе типа UNIX, чтобы позволить мне динамически загружать и связывать объектно-ориентированный код. Я думаю, что это будет основано на аналогичном наборе функциональных возможностей, которые POSIX предоставляет для загрузки и вызова dll, т.е. dlopen, dlsym и dlclose.

На самом простом уровне COM реализован с помощью интерфейсов. В c ++, если вас устраивает идея чисто виртуальных или абстрактных базовых классов, то вы уже знаете, как определить интерфейс в c ++

struct IMyInterface {
  void Method1() =0;
  void Method2() =0;
};

Среда выполнения COM предоставляет множество дополнительных сервисов, которые применяются к среде Windows, но на самом деле не нужны при реализации «мини» COM в одном приложении в качестве средства для динамической связи с большим количеством ОО-интерфейсов, чем это традиционно допускает dlopen. , дслым и т. д.

COM-объекты реализованы в файлах .dll, .so или .dylib в зависимости от вашей платформы. Эти файлы должны экспортировать хотя бы одну стандартизированную функцию: DllGetClassObject

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

Основная идея заключается в том, что передается указатель на GUID - 16 байтов, которые уникальным образом назначаются конкретному объекту, и он создает (на основе GUID) и возвращает IClassFactory * фабричного объекта.

Затем фабричный объект используется средой выполнения COM для создания экземпляров объекта при вызове метода IClassFactory :: CreateInstance.

Итак, пока у вас есть

  • динамическая библиотека, экспортирующая хотя бы один символ с именем «DllGetClassObject» (или некоторый его вариант)
  • Метод DllGetClassObject, который проверяет переданный GUID, чтобы узнать, запрашивается ли и какой объект, и затем выполняет «новый CSomeObjectClassFactory»
  • Реализация CSomeObjectClassFactory, которая реализует (наследует) IClassFactory и реализует метод CreateInstance для «новых» экземпляров CSupportedObject.
  • CSomeSupportedObject, который реализует пользовательский или определенный COM интерфейс, производный от IUnknown. Это важно, потому что IClassFactory :: CreateInstance передается IID (опять же, 16-байтовый уникальный идентификатор, определяющий интерфейс на этот раз), для которого ему потребуется QueryInterface для объекта.

Я понимаю, что общая идея COM заключается в том, что вы ссылаетесь на несколько функций, например QueryInterface, AddRef и Release, в общей dll (Kernel32.dll), которая затем позволяет вам получить доступ к интерфейсам, которые являются просто таблицей указатели на функции, инкапсулированные указателем на объект, для которого должны быть вызваны указатели на функции. Эти функции доступны через IUnknown, от которого вы должны наследовать.

На самом деле COM реализован с помощью OLE32.dll, который предоставляет API-интерфейс c, называемый CoCreateInstance. Приложение передало CoCreateInstance GUID, который он ищет в реестре Windows, в котором есть БД GUID -> сопоставления «путь к dll». Затем OLE / COM загружает (dlopen) dll, вызывает его метод DllGetClassObject (dlsym), снова передает GUID, при условии, что это успешно, OLE / COM затем вызывает CreateInstance и возвращает полученный интерфейс приложению.

Так как все это работает? Есть ли лучший способ динамически связать и загрузить объектно-ориентированный код? Как работает наследование от dll - каждый ли вызов базового класса должен относиться к открытой функции-члену, т.е. private / protected / public просто игнорируется?

неявное наследование кода c ++ от dll / so / dylib работает путем экспорта каждого метода в классе как «украшенный» символ. Имя метода украшено классом и типом каждого параметра. Это так же, как символы экспортируются из статических библиотек (.a или .lib файлы iirc). Статические или динамические библиотеки, "частные, защищенные и т. Д." всегда выполняются компилятором, анализируя заголовочные файлы, а не компоновщиком.

Я достаточно хорошо разбираюсь в C ++ и шаблонном метапрограммировании, и у меня уже есть полностью рефлексивная система C ++, т.е. свойства-члены, функции-члены и глобальные / статические функции, использующие boost.

классы c ++ обычно могут быть экспортированы только из dll со статической связью - dll, которые загружаются при загрузке, а не через dlopen во время выполнения. COM позволяет динамически загружать интерфейсы c ++, гарантируя, что все типы данных, используемые в COM, являются либо типами pod, либо являются чисто виртуальными интерфейсами. Если вы нарушите это правило, определив интерфейс, который пытается передать повышение или любой другой тип объекта, вы быстро попадете в ситуацию, когда компилятору / компоновщику понадобится больше, чем просто файл заголовка, чтобы выяснить, что происходит, и ваш Тщательно подготовленный «com» ​​dll должен быть статически или неявно связан, чтобы функционировать.

Другое правило COM - никогда не передавать права собственности на объект через границы динамической библиотеки. то есть никогда не возвращать интерфейс или данные из библиотеки DLL и требовать, чтобы приложение удалило их. Все интерфейсы должны реализовывать IUnknown или, по крайней мере, метод Release (), который позволяет объекту выполнить this. Любые возвращаемые типы данных также должны иметь хорошо известный деселектор - если у вас есть интерфейс с методом с именем «CreateBlob», вероятно, должен быть метод приятеля с именем «DeleteBlob».

3 голосов
/ 28 января 2010

Базовый дизайн COM довольно прост.

  1. Все COM-объекты предоставляют свои функциональные возможности через один или несколько интерфейсов.
  2. Все интерфейсы являются производными от интерфейса IUnknown, поэтому все интерфейсы имеют QueryInterface, AddRef & Release методы как первые 3 метода их виртуального таблица функций в известном порядке
  3. Все объекты реализуют IUnknown
  4. Любой интерфейс, который поддерживает объект, может быть запрошен из любого другого интерфейса.
  5. Интерфейсы идентифицируются глобально уникальными идентификаторами, это идентификаторы GUID или CLSID идентификатора IID, но на самом деле это одно и то же. http://en.wikipedia.org/wiki/Globally_Unique_Identifier

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

Реализация COM в Windows позволяет регистрировать объекты (первоначальное использование реестра Windows было для COM). Как минимум, реестр COM содержит соответствие между уникальным GUID для COM-объекта и библиотекой (dll), содержащей его код.

Чтобы это работало. Библиотеки DLL, которые реализуют COM-объекты, должны иметь ClassFactory - точку входа в DLL со стандартным именем, которую можно вызывать для создания одного из COM-объектов, которые реализует DLL. (На практике Windows COM получает объект IClassFactory из этой точки входа и использует его для создания других объектов COM).

так что это тур за 10 центов, но чтобы действительно понять это, вам нужно прочитать Essential COM от Don Box.

3 голосов
/ 28 января 2010

Посмотрите документацию CORBA, System.ComponentModel в sscli, части XPCOM базы кода Mozilla. Мигель де Иказа реализовал что-то вроде OLE в GNOME под названием Bonobo , что также может быть полезно.

В зависимости от того, что вы делаете с C ++, вы можете посмотреть на каркасы плагинов для C ++, такие как Yehia. Я считаю, что Boost также имеет нечто подобное.

Редактировать: мопс кажется лучше поддерживается, чем Yehia в данный момент. Я не пробовал это все же.

3 голосов
/ 28 января 2010

Чтобы по-настоящему понять, как работает COM, я предлагаю прочитать «Essential COM» от Don Box.

2 голосов
/ 28 января 2010

Возможно, вас заинтересует (еще не) библиотека Boost.Extension .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...