Создание серверов 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 для генерации файла make и используйте инструмент 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!). Используйте утилиту Dependency Walker для просмотра всех зависимостей двоичного файла сервера.
Если сервер работает (например, диспетчер задач отображает процесс), см. следующий раздел для получения информации об отладке сервера.
Объект не может быть создан
Если сервер был правильно построен и зарегистрирован во время процесса сборки, но объект не может быть инициализирован, например, приложением OLE/COM Object Viewer, убедитесь, что отсутствующая DLL, от которой зависит сервер, не отсутствует в системном пути (например, Qt DLL). Используйте утилиту 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 | Указанное свойство представляет собой свойство по умолчанию для этого класса. Например, свойством по умолчанию для кнопки будет "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 компилировался. |
| Реализованные категории | Список идентификаторов категорий, разделенных запятыми (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.14/activeqt-server.html