[Предыдущая: Модуль QAxContainer] [Модули Qt] [Следующая: Модуль QtDBus] Модуль QAxServer
|
Тип данных 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] struct QRect (user defined) |
QSize& | [in, out] struct QSize (определяется пользователем) |
QPoint& | [in, out] struct QPoint (определяется пользователем) |
Также поддерживаются экспортируемые перечисления и флаги (смотрите Q_ENUMS() и Q_FLAGS()). Внутрипараметрические (in-parameter) типы также поддерживаются как возвращаемые значения.
Свойства и сигналы/слоты, которые имеют параметры, использующие любые другие типы данных, игнорируются каркасом ActiveQt.
COM-объекты может иметь множество подобъектов, которые могут представлять субэлемент COM-объекта. COM-объект, отображающий приложение многодокументной электронной таблицы, может предоставить например один подобъект для каждого листа таблицы.
Any QObject subclass can be used as the type for a sub object in ActiveX, as long as it is known to the QAxFactory. Затем тип можно использовать в свойствах, или в качестве возвращаемого типа или параметра слота.
To make the properties bindable for the ActiveX client, use multiple inheritance from the QAxBindable class:
#include <QAxBindable> #include <QWidget> class MyActiveX : public QWidget, public QAxBindable { Q_OBJECT
When implementing the property write functions, use the QAxBindable class's requestPropertyChange() and propertyChanged() functions to allow ActiveX clients to bind to the control properties.
Чтобы сделать COM-сервер доступны для системы COM нужно его зарегистрировать в системном реестре используя пять уникальных идентификаторов. Эти идентификаторы предоставляются инструментами тип guidgen или uuidgen. Информация о регистрации позволяет COM для локализации бинарного файла, предоставляемого запрашиваемым элементом управления ActiveX, передавать (marshall) вызовы удаленных процедур для элемента управления и прочитать информацию типов о методах и свойствах отрытых элементом управления.
To create the COM object when the client asks for it the server must export an implementation of a 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.
The QAxFactory class documentation explains how to use this macro, and how to implement and use custom factories.
Для внепроцессных исполняемых файлов серверов вы можете реализовать функцию main() чтобы создать экземпляр объекта QApplication и войти в цикл обработки событий так же как любое обычное приложение Qt. По умолчанию приложение будет запущено как стандартное приложение Qt, но если вы передадите -activex в командной строке то оно будет запущено как сервер ActiveX. Use QAxFactory::isServer() to create and run a standard application interface, or to prevent a stand-alone execution:
#include <QApplication> #include <QAxFactory> int main(int argc, char *argv[]) { QApplication app(argc, argv); if (!QAxFactory::isServer()) { // создаём и показываем главное окно } return app.exec(); }
Этого однако не требуется так как ActiveQt предоставляет реализацию по умолчанию функции main. The default implemenation calls QAxFactory::startServer(), creates a QApplication instance and calls exec().
Чтобы собрать исполняемый файл сервера ActiveX запустите qmake для генерации make-файла, и используйте make-инструмент вашего компилятора как любого другого приложения Qt. Процесс создания будет также регистрировать элементы управления в системном реестре вызывая получившийся исполняемый файл с опцией -regserver командной строки.
Если сервер ActiveX является исполняемым файлом, то поддерживаются следующие опции командной строки:
Опция | Результат |
---|---|
-regserver | Регистрируем сервер в системном реестре |
-unregserver | Отменяем регистрацию сервера в системном реестре |
-activex | Запускаем приложение как ActiveX-сервер |
-dumpidl <file> -version x.y | Записываем IDL сервера в указанный файл. Библиотека типов будет иметь версию x.y |
Внутрипроцессные сервера могут быть зарегистрированы используя инструмент regsvr32, доступный на всех системах Windows.
Перечисленные ошибки компилятора/линкера основаны на таких проблемах компилятора Microsoft Visual C++ 6.0.
When the error occurs in code that uses the QAXFACTORY_DEFAULT() macro, the widget class had no constructor that can be used by the default factory. Либо добавьте стандартный конструктор виджета, либо реализуйте пользовательскую фабрику, которой он не требуется.
When the error occurs in code that uses the QAXFACTORY_EXPORT() macro, the QAxFactory subclass had no appropriate constructor. Предоставьте общий конструктор класса, похожий на
MyFactory(const QUuid &, const QUuid &);
для вашего класса фабрики.
The unique identifiers have not been passed as strings into the QAXFACTORY_EXPORT() or QAXFACTORY_DEFAULT() macro.
The server does not export an implementation of a QAxFactory. Use the QAXFACTORY_EXPORT() macro in one of the project's implementation files to instantiate and export a factory, or use the QAXFACTORY_DEFAULT() macro to use the default factory.
The server exports more than one implementation of a QAxFactory, or exports the same implementation twice. If you use the default factory, the QAXFACTORY_DEFAULT() macro must only be used once in the project. Use a custom QAxFactory implementation and the QAXFACTORY_EXPORT() macro if the server provides multiple ActiveX controls.
Сервера ActiveX написанные с помощью Qt могут использовать Qt либо как разделяемую библиотеку, либо имеют Qt, слинкованную статически в бинарный файл. В результате обоих способов получаются весьма большие пакеты (либо сам бинарный файл сервера становится больше, либо вы поставляет Qt DLL).
Если ваш сервер 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) // обработка ошибки
Если вы хотите использовать элементы управления вашего сервера в веб-страницах, вам нужно сделать доступным сервер для браузера, используемого для просмотра вашей страницы, и вам нужно указать расположение пакета сервера в вашей странице.
Чтобы указать расположение сервера используйте атрибут CODEBASE тега OBJECT вашего веб-сайта. Значение может указывать на сам файл сервера, на INF-файл, перечисляющий другие файлы требуемые серверу (например, DLL Qt), или сжатый архив CAB.
Файлы INF и CAB документированы почти в каждой доступной книге о программировании ActiveX и COM также, как и в библиотеке MSDN и различных онлайн ресурсах. Примеры включают INF-файлы, которые могут быть использованы для сборки архивов CAB:
Инструмент CABARC от Microsoft легко может генерировать архивы CAB:
cabarc N simpleax.cab simpleax.exe simple.inf
INF-файлы допускают статическую сборку Qt, поэтому зависимости от других DLL не перечисляются в INF-файлах. Чтобы распространить DLLки, от которых зависит сервер ActiveX, вы должны добавить зависимости и предоставить библиотечные файлы с архивом.
Чтобы использовать элементы управления ActiveX, например, для встраивания их в веб-страницу, используйте HTML-тег <object>.
<object ID="MyActiveX1" CLASSID="CLSID:ad90301a-849e-4e8b-9a91-0a6dc5f6461f"> ... <\object>
To initialize the control's properties, use
<object ID=...> <param name="name" value="value"> <\object>
Если веб-браузер поддерживает выполнение скриптов используйте JavaScript, VBScript и формы для сценария элемента управления. The ActiveQt examples include demonstration HTML pages for the example controls.
Нижеследующее в значительной мере базируется на наших экспериментах с элементами управления ActiveX и клиентскими приложениями, и никоим образом не являются исчерпывающими.
Эти стандартные приложения работают с элементами управления ActiveX, разработанными с помощью ActiveQt. Обратите внимание на то, что некоторые клиенты поддерживают только внутрипроцессные элементы управления.
Приложения Microsoft Office поддерживаются, но вам нужно зарегистрировать элементы управления как "Insertable" объекты. Переопределите QAxFactory::registerClass чтобы добавить этот атрибут к классу COM, или установите "Insertable" информацию класса для вашего класса равной "yes" используя макрос Q_CLASSINFO.
Мы не сумели заставить работать COM-объекты, основанные на ActiveQt, со следующими клиентскими приложениями.
Если система не может запустить сервер (проверьте с помощью менеджера задач запущен ли процесс сервера), убедитесь что DLL, от которых зависит сервер, присутствуют в системных путях (например, Qt DLL!). Используйте dependency walker чтобы увидеть все зависимости бинарного файла сервера.
Если сервер запущен (например, есть в списке менеджера задач), информацию по отладке вашего сервера смотрите в следующем разделе.
Если сервер может быть собран и правильно зарегистрирован во время процесса сборки, но объект не может быть инициализирован, например, приложение OLE/COM Object Viewer, убедитесь, что DLL, от которых зависит сервер, присутствуют в системных путях (например, Qt DLL). Используйте dependency walker чтобы увидеть все зависимости бинарного файла сервера.
Если сервер запущен, информацию по отладке вашего сервера смотрите в следующем разделе.
Чтобы отладить внутрипроцессный сервер в Visual Studio установите проект сервера в качестве активного проекта и укажите клиент "executable for debug session" в настройках проекта (например, используйте Тестовый контейнер 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 | Объекты делают видимыми события запаса если значение равно "yes". See QAxFactory::hasStockEvents() |
ToSuperClass | Объекты делают видимыми функциональность всех суперклассов выше по иерархии и включая класс с именем в значении. See QAxFactory::exposeToSuperClass() |
Insertable | Если значение равно "yes", класс регистрируется как "Insertable" и будет приведён в списке контейнеров OLE 2 (т.е. Microsoft Office). Этот атрибут по умолчанию не установлен. |
Aggregatable | Если значение равно "no", класс не поддерживают агрегацию. По умолчанию агрегация поддерживается. |
Creatable | Если значение равно "no", класс не может быть создан клиентом и доступен только через API другого класса (т.е. класс является подтипом). |
RegisterObject | Если значение равно "yes", объекты этого класса регистрируются с помощью OLE и доступны из таблицы запущенных объектов (т.е. клиенты могут присоединиться к уже запущенному экземпляру объекта этого класса). Этот атрибут поддерживается только во внепроцессных серверах. |
MIME | Объект может обработать данные и файлы формата, указанного в значении. Значение имеет формат mime:extension:description. Множественные форматы разделяются точкой с запятой. |
CoClassAlias | Имя класса, используемого в сгенерированном IDL и в реестре. Это особенно useful for C++ classes that live in a namespace - by default, ActiveQt just removes the "::" to make the IDL compile. |
Обратите внимание на то, что и ключи, и значения являются чувствительными к регистру.
Нижеследующее объявляет версию 2.0 класса, который делает видимым только свой собственный API, и доступен в диалоге "Insert Objects" приложений 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" до тех пор, пока пользователи приложения не смогут создать элемент управления мез лицензионного ключа.
Если единственного лицензионного ключа для элемента управления недостаточно (т.е. you want differnet developers to receive different license keys) you can specify an empty key to indicate that the control requires a license, and reimplement QAxFactory::validateLicenseKey() to verify that a license exists on the system (ie. через файл лицензии).
Элементы управления ActiveX, предоставленные серверами ActiveQt, поддерживают минимальный набор интерфейсов COM для реализации спецификаций OLE. When the ActiveX class inherits from the QAxBindable class it can also implement additional COM interfaces.
Create a new subclass of QAxAggregated and use multiple inheritance to subclass additional COM interface classes.
class AxImpl : public QAxAggregated, public ISomeCOMInterface { public: AxImpl() {} long queryInterface(const QUuid &iid, void **iface); // IUnknown QAXAGG_IUNKNOWN // ISomeCOMInterface ... }
Reimplement the QAxAggregated::queryInterface() function to support the additional COM interfaces.
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 в определении вашего класса. If you implement the IUnknown functions manually, delegate the calls to the interface pointer returned by the QAxAggregated::controllingUnknown() function, e.g.
HRESULT AxImpl::QueryInterface(REFIID iid, void **iface) { return controllingUnknown()->QueryInterface(iid, iface); }
Do not support the IUnknown interface itself in your queryInterface() implementation.
Implement the methods of the COM interfaces, and use QAxAggregated::object() if you need to make calls to the QObject subclass implementing the control.
In your QAxBindable subclass, implement QAxBindable::createAggregate() to return a new object of the QAxAggregated subclass.
class MyActiveX : public QWidget, public QAxBindable { Q_OBJECT public: MyActiveX(QWidget *parent); QAxAggregated *createAggregate() { return new AxImpl(); } };
Смотрите также Каркас ActiveQt.
[Предыдущая: Модуль QAxContainer] [Модули Qt] [Следующая: Модуль QtDBus]
Copyright © 2008 Nokia | Торговые марки | Qt 4.4.3 |
Попытка перевода Qt документации. Если есть желание присоединиться, или если есть замечания или пожелания, то заходите на форум: Перевод Qt документации на русский язык... Люди внесшие вклад в перевод: Команда переводчиков |