Spec-Zone.ru › Qt 5.15

Создание серверов 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, не существует. Конструктор вашего виджета не должен полагаться на создание других объектов, например, он должен проверять указатели на 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 для генерации файла makefile и используйте инструмент 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.

"No overloaded function takes 2 parameters"

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

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

MyFactory(const QUuid &, const QUuid &);

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

"Syntax error: bad suffix on number"

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

"Unresolved external symbol _ucm_instantiate"

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

"_ucm_initialize already defined in ..."

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

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

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

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

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

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

Для отладки сервера в процессе в 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 Указанная сигнала представляет собой сигнал по умолчанию для этого класса. Например, сигнал по умолчанию для кнопки — "нажатие".
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, реализующему управление.

В вашем подклассе 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.15/activeqt-server.html

Spec-Zone.ru

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