Создание серверов ActiveX в Qt
Модуль QAxServer является частью фреймворка ActiveQt. Он состоит из трёх классов:
- QAxFactory определяет фабрику для создания объектов COM.
- QAxBindable предоставляет интерфейс между виджетом Qt и объектом COM.
- QAxAggregated может быть подклассом для реализации дополнительных интерфейсов COM.
Предоставляются некоторые примеры реализации ActiveX-компонентов и объектов COM.
Темы:
Использование библиотеки
Для превращения стандартного приложения Qt в COM-сервер, используя библиотеку QAxServer, необходимо добавить axserver к переменной QT в вашем файле .pro.
Сервер исполняемого файла вне процесса генерируется из файла .pro следующим образом:
TEMPLATE = app QT += axserver RC_FILE = qaxserver.rc ...
Для построения сервера в процессе используйте файл .pro следующим образом:
TEMPLATE = lib QT += axserver CONFIG += dll DEF_FILE = qaxserver.def RC_FILE = qaxserver.rc ...
Файлы qaxserver.rc и qaxserver.def являются частью фреймворка и могут быть использованы из своего обычного расположения (укажите путь в файле .pro), или скопированы в директорию проекта. Вы можете изменять эти файлы, пока это включает любой файл в качестве записи библиотеки типов, например, вы можете добавить информацию о версии или указать другой значок инструментария.
Использование модуля axserver заставит инструмент qmake добавить необходимые этапы сборки в систему сборки:
- Связать двоичный файл с
qaxserver.libвместоqtmain.lib - Вызвать инструмент idc для генерации файла IDL для COM-сервера
- Компилировать IDL в библиотеку типов с помощью инструмента MIDL (входит в установку компилятора)
- Присоединить получившуюся библиотеку типов как двоичный ресурс к двоичному файлу сервера (опять же, используя инструмент idc)
- Зарегистрировать сервер. Этот шаг может потребовать административных привилегий и может быть пропущен, установив конфигурацию
qaxserver_no_register.
Чтобы пропустить этап пост-обработки, также установите конфигурацию qaxserver_no_postlink.
Кроме того, вы можете указать номер версии, используя переменную VERSION, например:
TEMPLATE = lib VERSION = 2.5 ...
Указанный номер версии будет использоваться в качестве версии библиотеки типов и сервера при регистрации.
Серверы вне процесса против серверов в процессе
То, будет ли ваш COM-сервер работать как самостоятельная программа или как общая библиотека в процессе клиента, в основном зависит от типа COM-объектов, которые вы хотите предоставить на сервере.
Сервер исполняемого файла имеет преимущество в том, что может работать как отдельное приложение, но добавляет значительную нагрузку на взаимодействие между COM-клиентом и COM-объектом. Если у компонента есть ошибка программирования, то только процесс сервера, выполняющего компонент, зависнет, и приложение-клиент, вероятно, продолжит работать. Не все COM-клиенты поддерживают серверы исполняемых файлов.
Сервер в процессе обычно меньше и имеет более быстрое время запуска. Взаимодействие между клиентом и сервером происходит напрямую через виртуальные вызовы функций и не вводит нагрузку, необходимую для удалённых вызовов процедур. Однако, если сервер зависнет, приложение-клиент, скорее всего, также зависнет, и не все функции доступны для серверов в процессе (например, регистрация в таблице выполняемых объектов COM).
Оба типа серверов могут использовать Qt как общую библиотеку или статически скомпоновать её в двоичный файл сервера.
Типичные ошибки при этапах пост-сборки
Для работы ActiveQt-специфических этапов пост-обработки сервер должен удовлетворять некоторым требованиям:
- Все экспонируемые компоненты могут быть созданы, имея только экземпляр QApplication
- Начальная компоновка сервера включает временный ресурс библиотеки типов
- Все зависимости, необходимые для работы сервера, находятся в системном пути (или в пути, используемом вызывающей средой; обратите внимание, что Visual Studio имеет свой собственный набор переменных среды, перечисленных в диалоговом окне «Инструменты | Параметры | Каталоги»).
Если эти требования не выполнены, может возникнуть одна или несколько из следующих ошибок:
Сервер зависает
Для генерации IDL виджеты, экспонируемые как ActiveX-компоненты, должны быть созданы (вызывается конструктор). В этот момент ничего, кроме объекта QApplication, не существует. Конструктор вашего виджета не должен полагаться на создание других объектов, например, он должен проверять указатели на null.
Для отладки сервера запустите его с выводом -dumpidl outputfile и проверьте, где он зависает.
Обратите внимание, что никакие функции компонента не вызываются.
Сервер не является корректным приложением Win32
Присоединение библиотеки типов повредило двоичный файл сервера. Это ошибка Windows и происходит только со сборками релиз.
Первый шаг компоновки должен скомпоновать в исполняемый файл заглушку библиотеки типов, которую позже можно заменить idc. Добавьте файл ресурсов с библиотекой типов в свой проект, как показано в примерах.
"Не удаётся найти DLL"
Система сборки должна запустить исполняемый файл сервера для генерации определения интерфейса и регистрации сервера. Если динамическая библиотека, с которой связан сервер, не находится в пути, это может потерпеть неудачу (например, Visual Studio вызывает сервер, используя настройки среды, указанные в опции «Каталоги»). Убедитесь, что все DLL и плагины, необходимые серверу, находятся в каталоге, который указан в пути, как напечатано в окне сообщения об ошибке (см. также Инструмент развертывания Windows).
"Не удаётся открыть файл ..."
Сервер ActiveX не смог корректно завершить работу, когда последний клиент перестал его использовать. Обычно приложение завершает работу примерно через две секунды, но вам может потребоваться использовать диспетчер задач для завершения процесса (например, когда клиент не освобождает компоненты должным образом).
Компонент не может быть создан
В этом случае может помочь регистрация сервера от имени администратора.
Реализация компонентов
Для реализации объекта COM с помощью Qt создайте подкласс QObject или любого существующего подкласса QObject. Если класс является подклассом QWidget, объект COM будет ActiveX-компонентом.
#include <QWidget>
class MyActiveX : public QWidget
{
Q_OBJECT Макрос Q_OBJECT необходим для предоставления метаобъектной информации о виджете фреймворку ActiveQt.
Q_CLASSINFO("ClassID", "{1D9928BD-4453-4bdd-903D-E525ED17FDE5}")
Q_CLASSINFO("InterfaceID", "{99F6860E-2C5A-42ec-87F2-43396F4BE389}")
Q_CLASSINFO("EventsID", "{0A3E9F27-E4F1-45bb-9E47-63099BCCD0E3}") Используйте макрос Q_CLASSINFO() для указания идентификаторов COM для объекта COM. ClassID и InterfaceID являются обязательными, тогда как EventsID необходим только в случае, если ваш объект имеет сигналы. Для генерации этих идентификаторов используйте системные инструменты, такие как uuidgen или guidgen.
Вы можете указать дополнительные атрибуты для каждого из ваших классов; см. Сведения о классе и настройка для получения подробной информации.
Q_PROPERTY(int value READ value WRITE setValue)
Используйте макрос Q_PROPERTY() для объявления свойств ActiveX-компонента.
Объявите стандартный конструктор, принимающий родительский объект, а также функции, сигналы и слоты, как и для любого подкласса QObject.
public:
MyActiveX(QWidget *parent = 0)
...
int value() const;
public slots:
void setValue(int v);
...
signals:
void valueChange(int v);
...
}; Фреймворк ActiveQt экспонирует свойства и публичные слоты как свойства и методы ActiveX, а сигналы — как события ActiveX, и конвертирует между типами данных Qt и эквивалентными типами данных COM.
Типы данных
Типы данных Qt, которые поддерживаются для свойств:
| Тип данных Qt | Свойство COM |
|---|---|
| bool | VARIANT_BOOL |
| QString | BSTR |
| int | int |
| uint | unsigned int |
| double | double |
| qlonglong | CY |
| qulonglong | CY |
| QColor | OLE_COLOR |
| QDate | DATE |
| QDateTime | DATE |
| QTime | DATE |
| QFont | IFontDisp* |
| QPixmap | IPictureDisp* |
| QVariant | VARIANT |
| QVariantList (то же, что QList<QVariant>) | SAFEARRAY(VARIANT) |
| QStringList | SAFEARRAY(BSTR) |
| QByteArray | SAFEARRAY(BYTE) |
| QRect | Пользовательский тип данных |
| QSize | Пользовательский тип данных |
| QPoint | Пользовательский тип данных |
Типы данных Qt, которые поддерживаются в качестве параметров в сигналах и слотах:
| Тип данных Qt | Параметр COM |
|---|---|
| bool | [in] VARIANT_BOOL |
| bool& | [in, out] VARIANT_BOOL* |
| QString, const QString& | [in] BSTR |
| QString& | [in, out] BSTR* |
| QString& | [in, out] BSTR* |
| int | [in] int |
| int& | [in,out] int |
| uint | [in] unsigned int |
| uint& | [in, out] unsigned int* |
| double | [in] double |
| double& | [in, out] double* |
| QColor, const QColor& | [in] OLE_COLOR |
| QColor& | [in, out] OLE_COLOR* |
| QDate, const QDate& | [in] DATE |
| QDate& | [in, out] DATE* |
| QDateTime, const QDateTime& | [in] DATE |
| QDateTime& | [in, out] DATE* |
| QFont, const QFont& | [in] IFontDisp* |
| QFont& | [in, out] IFontDisp** |
| QPixmap, const QPixmap& | [in] IPictureDisp* |
| QPixmap& | [in, out] IPictureDisp** |
| QList<QVariant>, const QList<QVariant>& | [in] SAFEARRAY(VARIANT) |
| QList<QVariant>& | [in, out] SAFEARRAY(VARIANT)* |
| QStringList, const QStringList& | [in] SAFEARRAY(BSTR) |
| QStringList& | [in, out] SAFEARRAY(BSTR)* |
| QByteArray, const QByteArray& | [in] SAFEARRAY(BYTE) |
| QByteArray& | [in, out] SAFEARRAY(BYTE)* |
| QObject* | [in] IDispatch* |
| QRect& | [in, out] структура QRect (определяется пользователем) |
| QSize& | [in, out] структура QSize (определяется пользователем) |
| QPoint& | [in, out] структура QPoint (определяется пользователем) |
Также поддерживаются экспортируемые перечисления и флаги (см. Q_ENUMS() и Q_FLAGS()). Типы параметров in также поддерживаются в качестве возвращаемых значений.
Свойства и сигналы/слоты, имеющие параметры других типов данных, игнорируются фреймворком ActiveQt.
Подобъекты
Объекты COM могут иметь несколько подобъектов, которые могут представлять подэлемент объекта COM. Например, объект COM, представляющий приложение с несколькими документами и электронной таблицей, может предоставлять один подобъект для каждой электронной таблицы.
Любой подкласс QObject может использоваться в качестве типа подобъекта в ActiveX, если он известен QAxFactory. Затем тип может быть использован в свойствах или в качестве возвращаемого типа или параметра слота.
Уведомление о свойстве
Чтобы сделать свойства привязываемыми для клиента ActiveX, используйте множественное наследование от класса QAxBindable:
#include <QAxBindable>
#include <QWidget>
class MyActiveX : public QWidget, public QAxBindable
{
Q_OBJECT При реализации функций записи свойств используйте функции класса QAxBindable requestPropertyChange() и propertyChanged(), чтобы разрешить клиентам ActiveX привязку к свойствам управления.
Обслуживание элементов управления
Чтобы сделать сервер COM доступным для системы COM, он должен быть зарегистрирован в системном реестре с использованием пяти уникальных идентификаторов. Эти идентификаторы предоставляются инструментами, такими как guidgen или uuidgen. Информация о регистрации позволяет COM локализовать двоичный файл, предоставляющий запрашиваемый ActiveX-элемент управления, передавать удаленные вызовы процедур элементу управления и читать информацию о типах методов и свойств, предоставляемых элементом управления.
Для создания объекта COM при запросе клиентом сервер должен экспортировать реализацию QAxFactory. Самый простой способ сделать это — использовать набор макросов:
QAXFACTORY_BEGIN("{ad90301a-849e-4e8b-9a91-0a6dc5f6461f}",
"{a8f21901-7ff7-4f6a-b939-789620c03d83}")
QAXCLASS(MyWidget)
QAXCLASS(MyWidget2)
QAXTYPE(MySubType)
QAXFACTORY_END() Это экспортирует MyWidget и MyWidget2 как объекты COM, которые могут быть созданы клиентами COM, и зарегистрирует MySubType как тип, который может быть использован в свойствах и параметрах MyWidget и MyWidget2.
Документация класса QAxFactory объясняет, как использовать этот макрос, а также как реализовать и использовать пользовательские фабрики.
Для серверов исполняемых файлов вне процесса вы можете реализовать функцию main() для создания объекта QApplication и ввода в цикл событий, как и в любом обычном приложении Qt. По умолчанию приложение будет запускаться как стандартное приложение Qt, но если вы передадите -activex в командной строке, оно будет запущено как сервер ActiveX. Используйте QAxFactory::isServer(), чтобы создать и запустить стандартный интерфейс приложения или предотвратить автономное выполнение:
#include <QApplication>
#include <QAxFactory>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
if (!QAxFactory::isServer()) {
// create and show main window
}
return app.exec();
} Однако это не обязательно, так как ActiveQt предоставляет по умолчанию реализацию функции main. По умолчанию реализация вызывает QAxFactory::startServer(), создает экземпляр QApplication и вызывает exec().
Для создания исполняемого файла сервера ActiveX запустите qmake для генерации файла проекта, и используйте инструмент make вашего компилятора, как и для любого другого приложения Qt. Процесс make также зарегистрирует элементы управления в системном реестре, вызвав результирующий исполняемый файл с опцией командной строки -regserver.
Если сервер ActiveX является исполняемым файлом, поддерживаются следующие параметры командной строки:
| Параметр | Результат |
|---|---|
-regserver |
Регистрация сервера в системном реестре |
-regserverperuser |
Регистрация сервера в системном реестре для текущего пользователя (с версии 5.14) |
-unregserver |
Дерегистрация сервера из системного реестра |
-unregserverperuser |
Дерегистрация сервера из системного реестра для текущего пользователя (с версии 5.14) |
-activex |
Запуск приложения как сервера ActiveX |
-dumpidl <file> -version x.y |
Запись IDL сервера в указанный файл. Библиотека типов будет иметь версию x.y |
Серверы в процессе могут быть зарегистрированы с помощью инструмента regsvr32, доступного на всех системах Windows.
Типичные проблемы при компиляции
Ошибки компилятора/линкера перечислены на основе ошибок, выдаваемых компилятором Microsoft Visual C++ 6.0.
"Нет перегруженной функции, принимающей 2 параметра"
При возникновении ошибки в коде, использующем макрос QAXCLASS() или QAXFACTORY_DEFAULT(), класс виджета не имел конструктора, который может быть использован стандартной фабрикой. Либо добавьте стандартный конструктор виджета, либо реализуйте пользовательскую фабрику, которая не требует его.
При возникновении ошибки в коде, использующем макрос QAXFACTORY_EXPORT(), у подкласса QAxFactory не было соответствующего конструктора. Предоставьте публичный конструктор класса, например
MyFactory(const QUuid &, const QUuid &);
для вашего класса фабрики.
"Синтаксическая ошибка: неверный суффикс в числе"
Уникальные идентификаторы не были переданы в виде строк в макрос QAXFACTORY_EXPORT(), QAXFACTORY_BEGIN() или QAXFACTORY_DEFAULT().
"Неразрешенный внешний символ _ucm_instantiate"
Сервер не экспортирует реализацию QAxFactory. Используйте макрос QAXFACTORY_EXPORT() в одном из файлов реализации проекта для создания и экспорта фабрики или используйте макрос QAXCLASS() или QAXFACTORY_DEFAULT() для использования стандартной фабрики.
"_ucm_initialize уже определён в ..."
Сервер экспортирует более одной реализации QAxFactory или экспортирует одну реализацию дважды. Если вы используете стандартную фабрику, макросы QAXFACTORY_BEGIN() или QAXFACTORY_DEFAULT() должны использоваться только один раз в проекте. Используйте пользовательскую реализацию QAxFactory и макрос QAXFACTORY_EXPORT(), если сервер предоставляет несколько ActiveX-элементов управления.
Распространение библиотек QAxServer
Серверы ActiveX, написанные с Qt, могут использовать Qt как общую библиотеку или иметь Qt, связанный статически с двоичным файлом. Оба способа приведут к довольно большим пакетам (либо сам двоичный файл сервера станет большим, либо вам придётся распространять DLL Qt).
Установка автономных серверов
Если ваш сервер ActiveX также может запускаться как автономное приложение, запустите исполняемый файл сервера с параметром командной строки -regserver после установки исполняемого файла на целевую систему. После этого элементы управления, предоставляемые сервером, станут доступны клиентам ActiveX.
Установка серверов в процессе
Если ваш сервер ActiveX является частью пакета установки, используйте инструмент regsvr32 от Microsoft для регистрации элементов управления на целевой системе. Если этот инструмент отсутствует, загрузите DLL в процесс установщика, найдите символ DllRegisterServer и вызовите функцию:
HMODULE dll = LoadLibrary("myserver.dll");
typedef HRESULT(__stdcall *DllRegisterServerProc)();
DllRegisterServerProc DllRegisterServer =
(DllRegisterServerProc)GetProcAddress(dll, "DllRegisterServer");
HRESULT res = E_FAIL;
if (DllRegisterServer)
res = DllRegisterServer();
if (res != S_OK)
// error handling Распределение серверов по сети Интернет
Если вы хотите использовать элементы управления на своём сервере в веб-страницах, вам необходимо сделать сервер доступным для браузера, используемого для просмотра вашей страницы, и указать расположение пакета сервера на вашей странице.
Для указания расположения сервера используйте атрибут CODEBASE в теге OBJECT вашего веб-сайта. Значение может указывать на сам файл сервера, на файл INF, перечисляющий другие файлы, необходимые серверу (например, Qt DLL), или на сжатый архив CAB.
Файлы INF и CAB документированы практически в каждой книге, посвященной программированию ActiveX и COM, а также в библиотеке MSDN и различных других онлайн-ресурсах. Примеры включают файлы INF, которые могут быть использованы для создания архивов CAB:
[version]
signature="$CHICAGO$"
AdvancedINF=2.0
[Add.Code]
simpleax.exe=simpleax.exe
[simpleax.exe]
file-win32-x86=thiscab
clsid={DF16845C-92CD-4AAB-A982-EB9840E74669}
RegisterServer=yes Инструмент CABARC от Microsoft может легко генерировать архивы CAB:
cabarc N simpleax.cab simpleax.exe simple.inf
Файлы INF предполагают статическую сборку Qt, поэтому зависимости от других DLL не перечислены в файлах INF. Для распространения сервера ActiveX, зависящего от DLL, необходимо добавить зависимости и предоставить файлы библиотек в архив.
Использование элементов управления
Для использования элементов управления ActiveX, например, для их встраивания в веб-страницу, используйте тег <object> HTML.
<object ID="MyActiveX1" CLASSID="CLSID:ad90301a-849e-4e8b-9a91-0a6dc5f6461f"> ... <\object>
Для инициализации свойств элемента управления используйте
<object ID=...>
<param name="name" value="value">
<\object> Если веб-браузер поддерживает скрипты, используйте JavaScript, VBScript и формы для управления элементом управления. Примеры ActiveQt включают демонстрационные HTML-страницы для примеров элементов управления.
Поддерживаемые и неподдерживаемые клиенты ActiveX
Следующая информация в значительной степени основана на наших собственных экспериментах с элементами управления ActiveX и клиентскими приложениями и никоим образом не является исчерпывающей.
Поддерживаемые клиенты
Эти стандартные приложения работают с элементами управления ActiveX, разработанными с помощью ActiveQt. Обратите внимание, что некоторые клиенты поддерживают только элементы управления в процессе.
- Internet Explorer
- Microsoft ActiveX Control Test Container
- Microsoft Visual Studio 6.0
- Microsoft Visual Studio.NET/2003
- Microsoft Visual Basic 6.0
- Контейнеры на основе MFC и ATL
- Sybase PowerBuilder
- Контейнеры на основе ActiveQt
Приложения Microsoft Office поддерживаются, но вам необходимо зарегистрировать элементы управления как "вставляемые" объекты. Переопределите QAxFactory::registerClass, чтобы добавить этот атрибут к классу COM, или установите информацию о классе "вставляемый" для вашего класса в "да" с помощью макроса Q_CLASSINFO.
Неподдерживаемые клиенты
Нам не удалось заставить объекты COM на основе ActiveQt работать со следующими клиентскими приложениями.
- Borland C++ Builder (версии 5 и 6)
- Borland Delphi
Типичные ошибки во время выполнения
Сервер не отвечает
Если система не может запустить сервер (проверьте в диспетчере задач, работает ли сервер), убедитесь, что ни одна DLL, от которой зависит сервер, не отсутствует в системном пути (например, DLL Qt!). Используйте утилиту Dependency Walker для просмотра всех зависимостей двоичного файла сервера.
Если сервер работает (например, диспетчер задач отображает процесс), см. следующий раздел для получения информации о отладке вашего сервера.
Объект не может быть создан
Если сервер был успешно построен и зарегистрирован в процессе сборки, но объект не может быть инициализирован, например, приложением OLE/COM Object Viewer, убедитесь, что ни одна DLL, от которой зависит сервер, не отсутствует в системном пути (например, DLL Qt). Используйте утилиту Dependency Walker для просмотра всех зависимостей двоичного файла сервера.
Если сервер работает, см. следующий раздел для получения информации о отладке вашего сервера.
Отладка ошибок во время выполнения
Для отладки сервера в процессе в Visual Studio установите проект сервера в качестве активного проекта и укажите исполняемый файл клиента "для сеанса отладки" в настройках проекта (например, используйте ActiveX Test Container). Вы можете устанавливать точки останова в вашем коде, а также входить в код ActiveQt и Qt, если вы установили отладочную версию.
Для отладки исполняемого сервера запустите приложение в отладчике и начните с параметра командной строки -activex. Затем запустите свой клиент и создайте экземпляр вашего элемента управления ActiveX. COM будет использовать существующий процесс для следующего клиента, пытающегося создать элемент управления ActiveX.
Информация о классе и настройка
Для предоставления атрибутов для каждого класса COM используйте макрос Q_CLASSINFO, который является частью системы метаобъектов Qt.
| Ключ | Значение |
|---|---|
| Версия | Версия класса (по умолчанию 1.0) |
| Описание | Строка, описывающая класс. |
| ClassID | Идентификатор класса. Вы должны переопределить QAxFactory::classID, если он не указан. |
| InterfaceID | Идентификатор интерфейса. Вы должны переопределить QAxFactory::interfaceID, если он не указан. |
| EventsID | Идентификатор интерфейса событий. Сигналы не будут экспонированы как события COM, если не указаны. |
| DefaultProperty | Указанное свойство представляет собой свойство по умолчанию для этого класса. Например, свойство по умолчанию для кнопки будет "text". |
| DefaultSignal | Указанный сигнал представляет собой сигнал по умолчанию для этого класса. Например, сигналом по умолчанию для кнопки будет "clicked". |
| LicenseKey | Для создания объекта требуется указанный ключ лицензии. Ключ может быть пустым, чтобы требовать лицензированный компьютер. По умолчанию классы не лицензируются. Также см. следующий раздел. |
| StockEvents | Объекты экспонируют стандартные события, если значение равно "да". См. QAxFactory::hasStockEvents() |
| ToSuperClass | Объекты экспонируют функциональность всех суперклассов до и включая имя класса в значении. См. QAxFactory::exposeToSuperClass() |
| Insertable | Если значение равно "да", класс регистрируется как "вставляемый" и будет отображаться в контейнерах OLE 2 (например, приложениях Microsoft Office). Этот атрибут не установлен по умолчанию. |
| Aggregatable | Если значение равно "нет", класс не поддерживает агрегацию. По умолчанию агрегация поддерживается. |
| Creatable | Если значение равно "нет", класс не может быть создан клиентом и доступен только через API другого класса (то есть класс является подтипом). |
| RegisterObject | Если значение равно "да", объекты этого класса регистрируются в OLE и доступны из таблицы выполняемых объектов (т.е. клиенты могут подключиться к уже запущенному экземпляру этого класса). Этот атрибут поддерживается только в серверах вне процесса. |
| MIME | Объект может обрабатывать данные и файлы указанного в значении формата. Значение имеет формат mime:расширение:описание. Несколько форматов разделены точкой с запятой. |
| CoClassAlias | Имя класса, используемое в сгенерированном IDL и в реестре. Это особенно полезно для классов C++, которые находятся в пространстве имен — по умолчанию ActiveQt просто удаляет "::", чтобы IDL можно было скомпилировать. |
| Реализованные категории | Список UUID идентификаторов категорий (CATID), разделенных запятыми. Общий механизм для указания дополнительных возможностей контейнера, помимо "элемента управления", "вставляемого" и т. д. Типичные CATID включают CATID_InternetAware ("{0DE86A58-2BAA-11CF-A229-00AA003D7352}"), CATID_SafeForScripting ("{7DD95801-9882-11CF-9FA9-00AA006C42C4}") а также пользовательские значения CATID. |
Обратите внимание, что и ключи, и значения чувствительны к регистру.
Следующее объявление версии 2.0 класса, который экспонирует только свой собственный API и доступен в диалоговом окне "Вставить объекты" приложений Microsoft Office.
class MyActiveX : public QWidget
{
Q_OBJECT
Q_CLASSINFO("Version", "2.0")
Q_CLASSINFO("ClassID", "{7a4cffd8-cbcd-4ae9-ae7e-343e1e5710df}")
Q_CLASSINFO("InterfaceID", "{6fb035bf-8019-48d8-be51-ef05427d8994}")
Q_CLASSINFO("EventsID", "{c42fffdf-6557-47c9-817a-2da2228bc29c}")
Q_CLASSINFO("Insertable", "yes")
Q_CLASSINFO("ToSuperClass", "MyActiveX")
Q_PROPERTY(...)
public:
MyActiveX(QWidget *parent = 0);
...
}; Разработка лицензированных компонентов
Если вы разрабатываете компоненты, вы можете захотеть контролировать, кто может их создавать. Поскольку двоичный файл сервера может быть передан и зарегистрирован на любом клиентском компьютере, любой может использовать эти компоненты в своем собственном программном обеспечении.
Лицензирование компонентов может быть выполнено с помощью различных методов, например, код, создающий элемент управления, может предоставить ключ лицензии, или компьютер, на котором предполагается запустить элемент управления, должен быть лицензированным.
Для обозначения класса Qt как лицензированного укажите "LicenseKey" с помощью макроса Q_CLASSINFO().
class MyLicensedControl : public QWidget
{
Q_OBJECT
Q_CLASSINFO("LicenseKey", "<key string>")
...
}; Ключ необходим для создания экземпляра MyLicensedControl на компьютере, который сам не лицензирован. Теперь лицензированный разработчик может перераспределить двоичный файл сервера со своим приложением, которое создаёт элемент управления, используя значение "LicenseKey", тогда как пользователи приложения не могут создать элемент управления без ключа лицензии.
Если одного ключа лицензии для элемента управления недостаточно (например, вы хотите, чтобы разные разработчики получали разные ключи лицензии), вы можете указать пустой ключ, чтобы указать, что для элемента управления требуется лицензия, и переопределить QAxFactory::validateLicenseKey(), чтобы проверить, существует ли лицензия на системе (например, через файл лицензии).
Дополнительные интерфейсы
Элементы управления ActiveX, предоставляемые серверами ActiveQt, поддерживают минимальный набор интерфейсов COM для реализации спецификаций OLE. Когда класс ActiveX наследуется от класса QAxBindable, он также может реализовывать дополнительные интерфейсы COM.
Создайте новый подкласс QAxAggregated и используйте множественное наследование, чтобы подклассировать дополнительные классы интерфейсов COM.
class AxImpl : public QAxAggregated, public ISomeCOMInterface
{
public:
AxImpl() {}
long queryInterface(const QUuid &iid, void **iface);
// IUnknown
QAXAGG_IUNKNOWN
// ISomeCOMInterface
...
} Переопределите функцию QAxAggregated::queryInterface() для поддержки дополнительных интерфейсов COM.
long AxImpl::queryInterface(const QUuid &iid, void **iface)
{
*iface = 0;
if (iid == IID_ISomeCOMInterface)
*iface = (ISomeCOMInterface *)this;
else
return E_NOINTERFACE;
AddRef();
return S_OK;
} Поскольку ISomeCOMInterface является подклассом IUnknown, вам необходимо реализовать функции QueryInterface(), AddRef() и Release(). Используйте макрос QAXAGG_IUNKNOWN в определении вашего класса, чтобы сделать это. Если вы реализуете функции IUnknown вручную, передайте вызовы указателю на интерфейс, возвращённый функцией QAxAggregated::controllingUnknown(), например:
HRESULT AxImpl::QueryInterface(REFIID iid, void **iface)
{
return controllingUnknown()->QueryInterface(iid, iface);
} Не поддерживайте сам интерфейс IUnknown в вашей реализации queryInterface().
Реализуйте методы интерфейсов COM и используйте QAxAggregated::object(), если вам нужно выполнить вызовы подкласса QObject, реализующего элемент управления.
END_OF_DOCUMENT_MARKERВ подклассе QAxBindable, реализуйте QAxBindable::createAggregate(), чтобы вернуть новый объект подкласса QAxAggregated.
class MyActiveX : public QWidget, public QAxBindable
{
Q_OBJECT
public:
MyActiveX(QWidget *parent);
QAxAggregated *createAggregate()
{
return new AxImpl();
}
}; См. также ActiveQt Framework.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.1/activeqt-server.html