The QAxServer Module
IntroductionThe QAxServer module provides a static library implementing the functions required to turn a standard Qt binary into an ActiveX control server. This module is part of the ActiveQt framework. (To incorporate ActiveX controls in a Qt application see the QAxContainer module.) The module consists of three classes
Some example implementations of ActiveX controls are provided.
Building the libraryIn the activeqt directory (usually QTDIR/extensions/activeqt) enter the control subdirectory and run qmake to generate the makefile, and use the make tool (nmake for VC++, make for Borland) to build the library. The library qaxserver.lib will be linked into QTDIR/lib.
Using the libraryTo turn a standard Qt application into an ActiveX server using the QAxServer library you must add activeqt as a CONFIG setting in your .pro file. An out-of-process executable server is generated from a .pro file like this: TEMPLATE = app CONFIG += qt activeqt RC_FILE = qaxserver.rc ... To build an in-process server, use a .pro file like this: TEMPLATE = lib CONFIG += qt activeqt dll DEF_FILE = qaxserver.def RC_FILE = qaxserver.rc ... The files qaxserver.rc and qaxserver.def are part of the framework and can be used from their usual location (specify a path in the .pro file), or copied into the project directory. You can modify these files as long as it includes any file as the type library entry, ie. you can add version information or use a different toolbox icon. The activeqt configuration will cause the qmake tool to add the required build steps to the build system:
Additionally you can specify a version number using the VERSION variable, e.g. TEMPLATE = lib VERSION = 2.5 ...The version number specified will be used as the version of the type library and of the server when registering.
Out-of-process vs. In-processWhether your ActiveX server should run as a stand-alone executable or as a shared library in the client process depends mainly on the type of controls you want to provide in the server. An executable server has the advantage of being able to run as a stand-alone application, but adds considerable overhead to the communication between the ActiveX client and the control. If the control has a programming error only the server process running the control will crash, and the client application will probably continue to run. An in-process server is usually smaller and has faster startup time. The communication between client and server is done directly through virtual function calls and does not introduce the overhead required for remote procedure calls. But if the server crashes the client application is likely to crash as well. Both server types can use Qt either as a shared library, or statically linked into the server binary.
The QAxServer build systemTo be able to build ActiveX controls with Qt, the build system must be extended to include some additional build steps that are used when the .pro file includes activeqt in the CONFIG settings. The resulting makefile will:
Attaching resources to an executable is not supported by Windows 95/98/ME, but a server built on Windows NT/2000/XP will work on those versions.
Typical build problemsThe compiler/linker errors listed are based on those issued by the Microsoft Visual C++ 6.0 compiler.
Compiler errors
"No overloaded function takes 2 parameters"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. Either add a standard widget constructor or implement a custom factory that doesn't require one. When the error occurs in code that uses the QAXFACTORY_EXPORT macro, the QAxFactory subclass had no appropriate constructor. Provide a public class constructor like MyFactory( const QUuid &, const QUuid & );for your factory class.
"syntax error: bad suffix on number"The unique identifiers have not been passed as strings into the QAXFACTORY_EXPORT or QAXFACTORY_DEFAULT macro.
Linker errors
"unresolved external symbol _ucm_instantiate"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.
"_ucm_initialize already defined in ..."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.
"cannot open file ... "The ActiveX server could not shut down properly when the last client stopped using it. It usually takes about two seconds for the application to terminate, but you might have to use the task manager to kill the process (e.g. when a client doesn't release the controls properly).
Postprocessing and runtime errorsThe ActiveQt build system performs four commands after the linking of the binary to make it into an ActiveX server.
For this to work the server has to meet some requirements:
If those requirements are not met one ore more of the following errors are likely to occure:
The server executable crashesTo generate the IDL the widgets exposed as ActiveX controls need to be instantiated (the constructor is called). At this point, nothing else but a QApplication object exists. Your widget constructor must not rely on any other objects to be created, e.g. it should check for null-pointers. To debug your server run it with -dumpidl outputfile and check where it crashes. Note that no functions of the control are called.
The server executable is not a valid Win32 applicationAttaching the type library corrupted the server binary. This is a bug in Windows and happens only with release builds. The first linking step has to link a dummy type library into the executable that can later be replaced by idc. Add a resource file with a type library to your project as demonstrated in the examples.
"Unable to Locate DLL"The build system needs to run the server executable to generate the interface definition, and to register the server. If a dynamic link library the server links against is not in the path this might fail (e.g. Visual Studio calls the server using the enivronment settings specified in the "Directories" option). Make sure that all DLLs required by your server are located in a directory that is listed in the path as printed in the error message box.
The Server does not respondIf the system is unable to start the server (check with the task manager whether the server runs a process), make sure that no DLL the server depends on is missing from the system path (e.g. the Qt DLL!). Use a dependency walker to view all dependencies of the server binary. If the server runs (e.g. the task manager lists a process), see the following section for information on debugging your server.
The Object cannot be createdIf the server could be built and registered correctly during the build process, but the object cannot be initiliazed e.g. by the OLE/COM Object Viewer application, make sure that no DLL the server depends on is missing from the system path (e.g. the Qt DLL). Use a dependency walker to view all dependencies of the server binary. If the server runs, see the following section for information on debugging your server.
Debugging runtime errorsTo debug an in-process server in Visual Studio, set the server project as the active project, and specify a client "executable for debug session" in the project settings (e.g. use the ActiveX Test Container). You can set breakpoints in your code, and also step into ActiveQt and Qt code if you installed the debug version. To debug an executable server, run the application in a debugger and start with the command line parameter "-activex". Then start your client and create an instance of your ActiveX control. COM will use the existing process for the next client trying to create an ActiveX control.
Implementing ControlsTo implement an ActiveX control with Qt, create a subclass of QWidget or any existing QWidget subclass:
#include <qwidget.h> class MyActiveX : public QWidget { Q_OBJECT The Q_OBJECT macro is required to provide the meta object information about the widget to the ActiveQt framework. Use the Q_PROPERTY macro to declare properties for the ActiveX control:
Q_PROPERTY( int value READ value WRITE setValue ) Declare a standard QWidget constructor taking a parent widget and a name,
and functions, signals and slots like any normal QWidget.
(1) The ActiveQt framework will expose properties and public slots as ActiveX
properties and methods, and signals as ActiveX events, and convert between
the Qt data types and the equivalent COM data types.
The Qt data types that are supported for properties are:
The Qt data types that are supported for parameters in signals and
slots are:
Also supported are exported enums and sets (see Q_ENUMS and Q_SETS).
The in-parameter types are also supported as return values.
Properties and signals/slots that have parameters using any other
data types are ignored by the QActiveX framework.
COM objects can have multiple sub-objects that can represent a sub element
of the COM object. A COM object representing a multi-document spread sheet
application can for example provide one sub-object for each spread sheet.
Any QObject subclass can be used as the type for a sub object in ActiveX. The
QAxFactory implementation (see below) needs to return the classname of the
sub type as one key in the featureList() implementation, as well as the IDs
for the COM class, the interface and event interface of that type. Then the
type can be used as e.g. the return value or paramter of a slot.
To make the properties bindable for the ActiveX client, use multiple
inheritance from the QAxBindable class:
To make an ActiveX control available to the COM system it must
be registered in the system registry using five unique
identifiers. These identifiers are provided by tools like guidgen or uuidgen. The registration information allows COM to
localize the binary providing a requested ActiveX control,
marshall remote procedure calls to the control and read type
information about the methods and properties exposed by the
control.
To create the ActiveX control when the client asks for it the
server must export an implementation of a QAxFactory. Use the
default factory when the server provides only a single ActiveX
control, and implement a subclass of QAxFactory to provide
multiple ActiveX controls. The default factory is available
through a macro that takes the identifiers COM requires to locate
the ActiveX control on the target system:
The QAxFactory class documentation explains
how to use this macro, and how to implement and use custom factories.
For out-of-process executable servers you can implement a main()
function to instantiate a QApplication object and enter the event
loop just like any normal Qt application. By default the
application will start as a standard Qt application, but if you
pass -activex on the command line it will start as an ActiveX
server. Use QAxFactory::isServer() to create and run a standard
application interface, or to prevent a stand-alone execution:
To build the ActiveX server executable run qmake to generate the makefile, and use your compiler's
make tool as for any other Qt application. The make process will
also register the controls in the system registry by calling the
resulting executable with the -regserver command line option.
If the ActiveX server is an executable, the following command line
options are supported:
In-process servers can be registered using the regsvr32 tool available
on all Windows systems.
ActiveX servers written with Qt can use Qt either as a shared
library, or have Qt linked statically into the binary. Both ways
will produce rather large packages (either the server binary
itself becomes large, or you have to ship the Qt DLL).
When your ActiveX server can also run as a stand-alone application,
run the server executable with the -regserver command line
parameter after installing the executable on the target system.
After that the controls provided by the server will be available to
ActiveX clients.
When your ActiveX server is part of an installation package, use the
regsvr32 tool provided by Microsoft to register the controls on
the target system. If this tool is not present, load the DLL into
your installer process, resolve the DllRegisterServer symbol and
call the function:
If you want to use controls in your server in web-pages you need to
make the server available to the browser used to view your page, and
you need to specify the location of the server package in your page.
To specify the location of a server, use the CODEBASE attribute in
the OBJECT tag of your web-site. The value can point to the server
file itself, to an INF file listing other files the server requires
(e.g. the Qt DLL), or a compressed CAB archive.
INF and CAB files are documented in almost every book available about
ActiveX and COM programming as well as in the MSDN library and various
other Online resources. The examples include INF files that can be used
to build CAB archives:
The CABARC tool from Microsoft can easily generate CAB archives:
The INF files assume a static build of Qt, so no dependencies to other DLLs
are listed in the INF files. To distribute an ActiveX server depending on
DLLs you must add the dependencies, and provide the library files
with the archive.
To use the ActiveX controls, e.g. to embed them in a web page, use
the <object> HTML tag.
To initialize the control's properties, use
If the web browser supports scripting use JavaScript, VBScript and
forms to script the control. The examples include demonstration HTML pages for the
example controls.
The following is largly based on our own experiements with ActiveX
controls and client applications, and is by no means complete.
These standard applications work with ActiveX controls developed with
ActiveQt. Note that some clients support only in-process controls.
Microsoft Office applications are supported, but you need to register
the controls as "Insertable" objects. Reimplement QAxFactory::registerClass
to add this attribute to the COM class, or set the "Insertable" class info
for your class to "yes" using the Q_CLASSINFO macro.
We have not managed to make ActiveQt based COM objects work with the
following client applications.
By default all ActiveX controls expose not only their own methods
and properties to ActiveX clients, but also those of all super
classes, including QWidget.
This can be controlled by reimplementing QAxFactory's
exposeToSuperClass() function. Reimplement the function to return
the last (furthest up the inheritance hierarchy) super class that
should be exposed:
The SmallActiveX control will only expose its own functions and
properties to clients, while all other ActiveX controls provided
by this factory will expose their own functions and properties and
also those of all their super classes including QWidget. The
SmallActiveX class can of course propagate some of the QWidget
functions and properties into its own interface.
An alternative way to reimplementing QAxFactory to have more control
about how objects are registered or exposed is to provide class
specific information using the Q_CLASSINFO macro, which is part of
Qt's meta object system.
Note that both keys and values are case sensitive.
The following declares version 2.0 of a class that exposes only its
own API, and is available in the "Insert Objects" dialog of Microsoft
Office applications.
If you develop components you might want to control who is able to instantiate
those components. Since the server binary can be shipped to and registered on
any client machine it is possible for anybody to use those components in his
own software.
Licensing components can be done using a variety of techniques, e.g. the code
creating the control can provide a license key, or the machine on which the
control is supposed to run needs to be licensed.
To mark a Qt class as licensed specify a "LicenseKey" using the Q_CLASSINFO
macro.
If a single license key for the control is not sufficient (ie. 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. through a license file).
ActiveX controls provided by ActiveQt servers support a minimal set of COM
interfaces to implement the OLE specifications. 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.
Reimplement the queryInterface() function to support the additional
COM interfaces.
Since ISomeCOMInterface is a subclass of IUnknown you will have
to implement the QueryInterface, AddRef and Release functions.
Use the QAXAGG_IUNKNOWN macro in your class definition to do that. If
you implement the IUnknown functions manually, delegate the calls to the
interface pointer returned by the controllingUnknown() function, e.g.
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 createAggregate() to return
a new object of the QAxAggregated subclass.
|
Publicité
Best OfActualités les plus luesSemaine
Mois
Année
Le Qt Quarterly au hasardGénérer du XMLQt Quarterly est la revue trimestrielle proposée par Nokia et à destination des développeurs Qt. Ces articles d'une grande qualité technique sont rédigés par des experts Qt. Lire l'article.
CommunautéRessources
Liens utilesContact
Qt dans le magazine |
Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. | Qt 3.3 | |
Copyright © 2012 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD. | ||
Vous avez déniché une erreur ? Un bug ? Une redirection cassée ? Ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP ! |
Copyright © 2000-2012 - www.developpez.com