Spec-Zone.ru › Qt 5.13

Создание серверов 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_postlink.

Кроме того, вы можете указать номер версии с помощью переменной VERSION, например:

TEMPLATE = lib
VERSION = 2.5
...

Указанная версия будет использоваться в качестве версии библиотеки типов и сервера при регистрации.

Серверы вне процесса против серверов в процессе

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

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

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

Оба типа серверов могут использовать Qt либо как разделяемую библиотеку, либо статически связанную с двоичным файлом сервера.

Типичные ошибки во время шагов после сборки

Для работы специфических шагов постобработки для ActiveQt сервер должен удовлетворять некоторым требованиям:

  • Все экспонированные элементы управления могут быть созданы только при наличии экземпляра QApplication
  • Первоначальная линковка сервера включает временный ресурс библиотеки типов.
  • Все зависимости, необходимые для работы сервера, находятся в системном пути (или в пути, используемом вызывающей средой; обратите внимание, что у Visual Studio есть свой набор переменных среды, перечисленных в диалоге Сервис|Параметры|Каталоги).

Если эти требования не выполняются, одна или несколько из следующих ошибок, вероятно, возникнут:

Исполняемый файл сервера завершается сбоем

Для генерации IDL элементы управления, экспонированные как ActiveX-контролы, должны быть инстанцированы (вызывается конструктор). В этот момент ничего, кроме объекта QApplication, не существует. Конструктор вашего виджета не должен полагаться на создание каких-либо других объектов, например, он должен проверять указатели на нулевые значения.

Для отладки вашего сервера запустите его с выводом -dumpidl outputfile и проверьте, где он завершается сбоем.

Обратите внимание, что никакие функции элемента управления не вызываются.

Исполняемый файл сервера не является корректным приложением Win32

Прикрепление библиотеки типов повредило двоичный файл сервера. Это ошибка Windows и происходит только при сборке релиз-версии.

Первый шаг линковки должен связать фиктивную библиотеку типов в исполняемый файл, который позже может быть заменён idc. Добавьте файл ресурсов с библиотекой типов в свой проект, как показано в примерах.

"Невозможно найти DLL"

Система сборки должна запустить исполняемый файл сервера для генерации определения интерфейса и регистрации сервера. Если динамическая библиотека, с которой связан сервер, отсутствует в пути, это может завершиться ошибкой (например, Visual Studio вызывает сервер, используя параметры среды, указанные в параметре "Каталоги"). Убедитесь, что все DLL и плагины, необходимые для вашего сервера, находятся в каталоге, который указан в пути, как напечатано в окне сообщения об ошибке (см. также Инструмент развертывания Windows).

"Невозможно открыть файл..."

COM-сервер 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 [вход] VARIANT_BOOL
bool& [вход, выход] VARIANT_BOOL*
QString, const QString& [вход] BSTR
QString& [вход, выход] BSTR*
QString& [вход, выход] BSTR*
int [вход] int
int& [вход, выход] int
uint [вход] unsigned int
uint& [вход, выход] unsigned int*
double [вход] double
double& [вход, выход] double*
QColor, const QColor& [вход] OLE_COLOR
QColor& [вход, выход] OLE_COLOR*
QDate, const QDate& [вход] DATE
QDate& [вход, выход] DATE*
QDateTime, const QDateTime& [вход] DATE
QDateTime& [вход, выход] DATE*
QFont, const QFont& [вход] IFontDisp*
QFont& [вход, выход] IFontDisp**
QPixmap, const QPixmap& [вход] IPictureDisp*
QPixmap& [вход, выход] IPictureDisp**
QList<QVariant>, const QList<QVariant>& [вход] SAFEARRAY(VARIANT)
QList<QVariant>& [вход, выход] SAFEARRAY(VARIANT)*
QStringList, const QStringList& [вход] SAFEARRAY(BSTR)
QStringList& [вход, выход] SAFEARRAY(BSTR)*
QByteArray, const QByteArray& [вход] SAFEARRAY(BYTE)
QByteArray& [вход, выход] SAFEARRAY(BYTE)*
QObject* [вход] IDispatch*
QRect& [вход, выход] структура QRect (определённая пользователем)
QSize& [вход, выход] структура QSize (определённая пользователем)
QPoint& [вход, выход] структура 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 для генерации файла makefile и используйте инструмент make вашего компилятора, как для любого другого приложения Qt. Процесс make также зарегистрирует элементы управления в системном реестре, вызвав полученный исполняемый файл с параметром командной строки -regserver.

Если сервер ActiveX — это исполняемый файл, поддерживаются следующие параметры командной строки:

Параметр Результат
-regserver Регистрирует сервер в системном реестре
-unregserver Дерегистрирует сервер из системного реестра
-activex Запускает приложение как сервер ActiveX
-dumpidl <file> -version x.y Записывает IDL сервера в указанный файл. Библиотека типов будет иметь версию x.y

Серверы внутри процесса можно зарегистрировать с помощью инструмента regsvr32, доступного на всех системах Windows.

Типичные проблемы во время компиляции

Перечисленные ошибки компилятора/линковщика основаны на ошибках, выдаваемых компилятором Microsoft Visual C++ 6.0.

"Нет перегруженной функции, принимающей 2 параметра"

Когда ошибка возникает в коде, использующем макрос QAXFACTORY_DEFAULT(), класс виджета не имел конструктора, который может быть использован фабрикой по умолчанию. Либо добавьте стандартный конструктор виджета, либо реализуйте пользовательскую фабрику, которая не требует его.

Когда ошибка возникает в коде, использующем макрос QAXFACTORY_EXPORT(), подкласс QAxFactory не имел соответствующего конструктора. Предоставьте публичный конструктор класса, как

MyFactory(const QUuid &, const QUuid &);

для вашего класса фабрики.

"Синтаксическая ошибка: неверный суффикс в числе"

Уникальные идентификаторы не были переданы в виде строк в макрос QAXFACTORY_EXPORT() или QAXFACTORY_DEFAULT().

"Неразрешённый внешний символ _ucm_instantiate"

Сервер не экспортирует реализацию QAxFactory. Используйте макрос QAXFACTORY_EXPORT() в одном из файлов реализации проекта для создания и экспорта фабрики или макрос QAXFACTORY_DEFAULT() для использования фабрики по умолчанию.

"_ucm_initialize уже определено в ..."

Сервер экспортирует более одной реализации QAxFactory или экспортирует одну реализацию дважды. Если вы используете фабрику по умолчанию, макрос 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, перечисляющий другие необходимые файлы сервера (например, DLL Qt), или на сжатый архив 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
  • 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). Вы можете устанавливать точки останова в своем коде и также переходить в код ActiveQt и Qt, если вы установили отладочную версию.

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

Информация о классе и настройка

Для предоставления атрибутов для каждого класса COM используйте макрос Q_CLASSINFO, который является частью системы метаобъектов Qt.

Ключ Значение ключа
Версия Версия класса (по умолчанию 1.0)
Описание Строка, описывающая класс.
ClassID Идентификатор класса. Вы должны переопределить QAxFactory::classID, если он не задан.
InterfaceID Идентификатор интерфейса. Вы должны переопределить QAxFactory::interfaceID, если он не задан.
EventsID Идентификатор интерфейса событий. Сигналы не экспонируются как события COM, если не указаны.
DefaultProperty Указанное свойство представляет собой свойство по умолчанию для этого класса. Например, свойство по умолчанию для кнопки будет "текст".
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 мог быть скомпилирован.
Реализованные категории Список идентификаторов категорий (CATID) UUID, разделенных запятыми. Общий механизм для указания дополнительных возможностей контейнера помимо "компонента", "вставляемого" и т. д. Типичные 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, реализующему компонент.

В вашем подклассе QAxBindable, реализуйте QAxBindable::createAggregate(), чтобы вернуть новый объект подкласса QAxAggregated.

class MyActiveX : public QWidget, public QAxBindable
{
    Q_OBJECT

public:
    MyActiveX(QWidget *parent);

    QAxAggregated *createAggregate()
    {
        return new AxImpl();
    }
};

См. также Фреймворк ActiveQt.

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.13/activeqt-server.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API