Spec-Zone.ru › Qt 5.12

Создание серверов 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 имеет свой собственный набор переменных среды, перечисленных в диалоговом окне Tools|Options|Directories).

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

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

Для генерации 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

При реализации функций записи свойств используйте функции requestPropertyChange() и propertyChanged() класса QAxBindable, чтобы позволить клиентам 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-приложения. Процесс сборки также зарегистрирует элементы управления в системном реестре, вызвав результируемый исполняемый файл с параметром командной строки -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.

END_OF_DOCUMENT_MARKER

Файлы 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!). Используйте утилиту просмотра зависимостей для просмотра всех зависимостей двоичного файла сервера.

Если сервер работает (например, диспетчер задач отображает процесс), см. следующий раздел для получения информации о отладке сервера.

Объект не может быть создан

Если сервер был успешно собран и зарегистрирован во время процесса сборки, но объект не может быть инициализирован, например, приложением «Просмотрщик объектов OLE/COM», убедитесь, что из системного пути отсутствуют DLL, от которых зависит сервер (например, DLL Qt). Используйте утилиту просмотра зависимостей для просмотра всех зависимостей двоичного файла сервера.

Если сервер работает, см. следующий раздел для получения информации о отладке сервера.

Отладка ошибок во время выполнения

Для отладки сервера в процессе в 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.12/activeqt-server.html

Spec-Zone.ru

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