Создание серверов 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, поэтому в файлах INF не перечислены зависимости от других DLL. Для распространения сервера ActiveX, зависящего от DLL, необходимо добавить зависимости и предоставить файлы библиотек вместе с архивом.
Использование компонентов
Для использования ActiveX-компонентов, например, для их встраивания в веб-страницу, используйте тег <object> HTML.
<object ID="MyActiveX1" CLASSID="CLSID:ad90301a-849e-4e8b-9a91-0a6dc5f6461f"> ... <\object>
Для инициализации свойств компонента используйте
<object ID=...>
<param name="name" value="value">
<\object> Если веб-браузер поддерживает скриптинг, используйте JavaScript, VBScript и формы для управления компонентом. Примеры ActiveQt включают демонстрационные HTML-страницы для примеров компонентов.
Поддерживаемые и неподдерживаемые клиенты ActiveX
Следующее описание в значительной степени основано на наших собственных экспериментах с ActiveX-компонентами и клиентскими приложениями и никоим образом не является полным.
Поддерживаемые клиенты
Эти стандартные приложения работают с ActiveX-компонентами, разработанными с помощью ActiveQt. Обратите внимание, что некоторые клиенты поддерживают только компоненты внутри процесса.
- Internet Explorer
- Microsoft ActiveX Control Test Container
- Microsoft Visual Studio 6.0
- Microsoft Visual Studio.NET/2003
- Microsoft Visual Basic 6.0
- Контейнеры на основе MFC и ATL
- Sybase PowerBuilder
- Контейнеры на основе ActiveQt
Приложения Microsoft Office поддерживаются, но вам необходимо зарегистрировать компоненты как "вставляемые" объекты. Переопределите QAxFactory::registerClass, чтобы добавить этот атрибут к COM-классу, или установите информацию о классе "вставляемый" для вашего класса в "да" с помощью макроса Q_CLASSINFO.
Неподдерживаемые клиенты
Нам не удалось заставить COM-объекты на основе ActiveQt работать с следующими клиентскими приложениями.
- Borland C++ Builder (версии 5 и 6)
- Borland Delphi
Типичные ошибки во время выполнения
Сервер не отвечает
Если система не может запустить сервер (проверьте диспетчер задач, чтобы убедиться, что сервер запускает процесс), убедитесь, что ни одна из DLL, от которых зависит сервер, не отсутствует в системном пути (например, DLL Qt!). Используйте инструмент для анализа зависимостей, чтобы просмотреть все зависимости двоичного файла сервера.
Если сервер работает (например, диспетчер задач показывает процесс), см. следующий раздел для получения информации о отладке вашего сервера.
Объект не может быть создан
Если сервер был успешно построен и зарегистрирован во время процесса сборки, но объект не может быть инициализирован, например, приложением OLE/COM Object Viewer, убедитесь, что ни одна из DLL, от которых зависит сервер, не отсутствует в системном пути (например, DLL Qt). Используйте инструмент для анализа зависимостей, чтобы просмотреть все зависимости двоичного файла сервера.
Если сервер работает, см. следующий раздел для получения информации об отладке вашего сервера.
Отладка ошибок во время выполнения
Чтобы отладить сервер внутри процесса в Visual Studio, установите проект сервера как активный проект и укажите клиентское «исполняемое приложение для сеанса отладки» в настройках проекта (например, используйте контейнер ActiveX Test). Вы можете устанавливать точки останова в вашем коде, а также переходить в код 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 компилировался. |
| Implemented Categories | Список 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/archives/qt-5.11/activeqt-server.html