Вопросы новичка о COM - PullRequest
       11

Вопросы новичка о COM

6 голосов
/ 27 марта 2010

Я новичок в COM, поэтому вопрос может показаться наивным.

Q1. О Windows DLL

Насколько я понимаю, Windows DLL может экспортировать функции, типы (классы) и глобальные переменные. С этим пониманием все в порядке?

Q2. О COM

Мое наивное понимание таково: COM DLL, похоже, является просто новым логическим способом организации функций и типов, экспортируемых стандартной Windows DLL. COM DLL экспортирует обе функции, такие как DllRegisterServer () и DllGetClassObject () , а также Classes , который реализует интерфейс IUnknown . С этим пониманием все в порядке?

Q3. * .def & * .idl

*. Def используется для определения функций, экспортируемых DLL-библиотекой Windows традиционным способом, например, DllGetClassObject () . * .idl используется для определения интерфейса, реализуемого COM-классом COM.

Заранее спасибо.

Ответы [ 3 ]

14 голосов
/ 27 марта 2010

Думайте о COM как о двоичном совместимом способе обмена интерфейсами через границы DLL. Классы C ++ не могут быть легко экспортированы из DLL из-за нестандартного искажения имени между различными версиями компилятора. COM позволяет коду в одной DLL или исполняемом файле создавать реализацию интерфейса из другой DLL или EXE, если эта реализация следует определенному интерфейсу и соглашению о вызовах. Это то, что позволяет классу COM быть написанным на C # и вызываться из C ++, Python и многих других языков, поддерживающих COM.

COM-интерфейсы - это просто стандартные классы C ++, содержащие все чисто виртуальные функции и производные от IUnknown. IUnknown - это предопределенный интерфейс, из которого должны быть получены все совместимые COM-интерфейсы, который предоставляет общие средства, такие как подсчет ссылок и возможность запрашивать, реализует ли объект конкретный интерфейс.

Библиотеки DLL, которые хотят сообщить о том, что могут создавать реализации интерфейсов COM, делают это путем экспорта 4 функций:

  • DllGetClassObject => Возвращает фабрику классов запрошенного интерфейса
  • DllCanUnloadNow => Все ли розданные экземпляры были освобождены
  • DllRegisterServer => Зарегистрировать типы, которые эта DLL поставляет в реестре
  • DllUnregisterServer => Отменить регистрацию этой DLL и ее типов в реестре

Итак, чтобы ответить на ваши вопросы:

Q1. О Windows DLL Насколько я понимаю, Windows DLL может экспортировать функции, типы (классы) и глобальные переменные. С этим пониманием все в порядке?

DLL могут экспортировать функции и классы (не уверен насчет глобальных переменных, но вы не хотите экспортировать их DLL, даже если можете!) DLL или EXE-файлы с одинаковыми именами (плохой способ ведения бизнеса). Функции с соглашением о вызовах в стиле C не искажены, поэтому их можно без проблем экспортировать и вызывать из других мест.

Q2. COM DLL экспортирует обе функции, такие как DllRegisterServer () и DllGetClassObject (), а также классы, которые реализуют интерфейс IUnknown. Это понимание всех право?

На полпути, есть 4 функции для экспорта в полноценную COM-совместимую DLL (показано выше). Вы можете найти в MSDN любое из этих имен, чтобы увидеть их полные подписи. Ваша реализация для DllGetClassObject будет основной, которую будут использовать внешние стороны. Они могут использовать это, чтобы получить IClassFactory к интерфейсу, который предоставляет ваша DLL, а затем использовать его для создания экземпляра.

COM - большой и сложный зверь, но его основы довольно просты. Вы также можете проверить эту ссылку COM Intro для получения дополнительной информации. Удачи!

5 голосов
/ 27 марта 2010

Чтобы добавить хороший ответ cpalmer, нет особой причины, по которой вам нужно использовать реестр и четыре рекомендуемые функции для экспорта COM из вашей DLL.

Вы можете использовать COM-режим без регистрации или COM-lite подход, где вы просто экспортируете фабричные методы, такие как

__ declspec (dllexport) void MyDllCreateFoo (IFoo ** ppFoo);

Пользователи DLL будут вызывать вашу фабрику для создания вашего класса CMyFoo, который реализует IFoo. Что такое DllRegisterServer et. и др. сделать, кроме всего прочего, разрешить поиск CMyFoo и других классов в реестре.

Q3: Вы правы на самом деле, если не в духе. Файлы .def и .idl довольно разные звери. Файлы .def используются только компоновщиком и даже не нужны - вы можете экспортировать все функции, которые хотите использовать __declspec (dllexport) void foo () { }

внутри вашего кода C ++.

.idl файлы используются для генерации заголовков C ++ (.h файлов), которые включены как DLL, так и ее клиентами. Он генерирует интерфейсы плюс некоторый клейкий код, который выполняет такие вещи, как смешивание параметров.

Опять же, вам не обязательно использовать IDL для использования COM, но это может сделать вещи более удобными.

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

4 голосов
/ 27 марта 2010

Пока у вас все в порядке. Единственное, что я хотел бы уточнить, это «Классы, которые реализуют интерфейс IUnknown». Класс представлен объектом, который реализует интерфейс IClassFactory. Вы можете получить такую ​​фабрику классов, вызвав DllGetClassObject в DLL, а затем попросите фабрику классов создать объект этого класса. Это похоже на многие другие объектно-ориентированные системы: существует множество объектов, которые представляют классы и которые могут использоваться для создания экземпляров.

Другие полезные факты о COM:

  • Существует небольшая, но сложная библиотека вспомогательных функций, в основном с префиксом Co. Именно они на самом деле загружают библиотеки DLL, находят экспортированные функции и вызывают их. Клиентский код обычно не вызывает экспорт DLL напрямую (хотя довольно просто написать собственную хостинговую систему для простых внутрипроцессных COM-объектов).
  • Существует важный интерфейс IDispatch, который добавляет еще один уровень абстракции, так что можно динамически идентифицировать методы для вызова объекта, используя строку для поиска метода и передавая массив значений аргументов. Это позволяет языкам сценариев безопасно вызывать COM-объекты (т. Е. Таким образом, что допускает ошибки программиста вместо сбоев).
  • Существует более сложная система сортировки, позволяющая вызывать объекты из других потоков, других процессов или даже других компьютеров; в своей удаленной (и защищенной) форме он назывался DCOM. Он не преуспел ни в каком масштабе, как другие COM.
  • Межпроцессная поддержка была основой OLE2, уловки, которую каждое приложение спешило поддерживать в начале 1990-х годов, большинство из них неправильно реализовали (очень сложные) интерфейсы и поэтому терпели крах везде.
  • Гораздо успешнее были OLE-элементы управления, которые были технически намного проще (без маршалинга) и которые предлагали способ расширения Visual Basic.
  • Существует, по крайней мере, одна широко распространенная система, основанная на COM, которая не совместима с COM, но разделяет те же понятия (по крайней мере, простые вещи), которая называется XPCOM и является основой веб-браузера Mozilla Firefox.
  • Если вы будете использовать COM повсеместно, у вас будет отличный способ интеграции с платформой .NET, поскольку он обеспечивает превосходную совместимость с COM. Но вы должны точно следовать правилам COM: AddRef / Release должно работать точно так, как определено, поэтому объект никогда не должен быть уничтожен, пока его счетчик ссылок больше нуля, должна быть возможность использовать QueryInterface, чтобы найти IUnknown из любого интерфейса, а оттуда, чтобы вернуться к исходному интерфейсу, IUnknown, полученный из любого интерфейса, должен всегда иметь один и тот же адрес памяти в течение всего времени существования объекта (поэтому его можно использовать для сравнения идентификаторов). Так, например: не создавайте COM-объекты в стеке и не возвращайте отдельные объекты из QueryInterface (то есть объекты, которые имеют свои собственные QueryInterface, которые возвращают различные интерфейсы).
  • Основная особенность COM заключается в том, что у него есть как минимум два стандартных способа представления строк. Ни один из них не использует подсчет ссылок. Почему они никогда не определили интерфейс IString, мне не понятно, но они этого не сделали.
  • Вы сойдете с ума, если попытаетесь написать COM-код без умных указателей для хранения ссылок или без базового класса, чтобы помочь вам реализовать интерфейсы, например, class MyClass : COM::Object<IThis, IThat> {...)
...