<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- /home/espenr/tmp/qt - 3.3.8 - espenr - 2499/qt - x11 - free - 3.3.8/extensions/activeqt/doc/control.doc:1 -->
< html >
< head >
< meta http-equiv = "Content-Type" content = "text/html; charset=ISO-8859-1" >
< title > The TQAxServer Module< / title >
< style type = "text/css" > < ! - -
fn { margin-left: 1cm; text-indent: -1cm; }
a:link { color: #004faf; text-decoration: none }
a:visited { color: #672967; text-decoration: none }
body { background: #ffffff; color: black; }
-->< / style >
< / head >
< body >
< table border = "0" cellpadding = "0" cellspacing = "0" width = "100%" >
< tr bgcolor = "#E5E5E5" >
< td valign = center >
< a href = "index.html" >
< font color = "#004faf" > Home< / font > < / a >
| < a href = "classes.html" >
< font color = "#004faf" > All Classes< / font > < / a >
| < a href = "mainclasses.html" >
< font color = "#004faf" > Main Classes< / font > < / a >
| < a href = "annotated.html" >
< font color = "#004faf" > Annotated< / font > < / a >
| < a href = "groups.html" >
< font color = "#004faf" > Grouped Classes< / font > < / a >
| < a href = "functions.html" >
< font color = "#004faf" > Functions< / font > < / a >
< / td >
< td align = "right" valign = "center" > < img src = "logo32.png" align = "right" width = "64" height = "32" border = "0" > < / td > < / tr > < / table > < h1 align = center > The TQAxServer Module< / h1 >
< p >
< p > <!-- toc -->
< ul >
< li > < a href = "#1" > Introduction
< / a >
< li > < a href = "#2" > Building the library
< / a >
< li > < a href = "#3" > Using the library
< / a >
< ul >
< li > < a href = "#3-1" > Out-of-process vs. In-process
< / a >
< / ul >
< li > < a href = "#4" > The TQAxServer build system
< / a >
< ul >
< li > < a href = "#4-1" > Typical build problems
< / a >
< ul >
< li > < a href = "#4-1-1" > Compiler errors
< / a >
< ul >
< li > < a href = "#4-1-1-1" > "No overloaded function takes 2 parameters"
< / a >
< li > < a href = "#4-1-1-2" > "syntax error: bad suffix on number"
< / a >
< / ul >
< li > < a href = "#4-1-2" > Linker errors
< / a >
< ul >
< li > < a href = "#4-1-2-1" > "unresolved external symbol _ucm_instantiate"
< / a >
< li > < a href = "#4-1-2-2" > "_ucm_initialize already defined in ..."
< / a >
< li > < a href = "#4-1-2-3" > "cannot open file ... "
< / a >
< / ul >
< li > < a href = "#4-1-3" > Postprocessing and runtime errors
< / a >
< ul >
< li > < a href = "#4-1-3-1" > The server executable crashes
< / a >
< li > < a href = "#4-1-3-2" > The server executable is not a valid Win32 application
< / a >
< li > < a href = "#4-1-3-3" > "Unable to Locate DLL"
< / a >
< li > < a href = "#4-1-3-4" > The Server does not respond
< / a >
< li > < a href = "#4-1-3-5" > The Object cannot be created
< / a >
< / ul >
< / ul >
< li > < a href = "#4-2" > Debugging runtime errors
< / a >
< / ul >
< li > < a href = "#5" > Implementing Controls
< / a >
< ul >
< li > < a href = "#5-1" > Data Types
< / a >
< li > < a href = "#5-2" > Sub-Objects
< / a >
< li > < a href = "#5-3" > Property Notification
< / a >
< / ul >
< li > < a href = "#6" > Serving Controls
< / a >
< ul >
< li > < a href = "#6-1" > Distributing TQAxServer binaries
< / a >
< ul >
< li > < a href = "#6-1-1" > Installing stand-alone Servers
< / a >
< li > < a href = "#6-1-2" > Installing In-process Servers
< / a >
< li > < a href = "#6-1-3" > Distributing Servers over the Internet
< / a >
< / ul >
< / ul >
< li > < a href = "#7" > Using the Controls
< / a >
< ul >
< li > < a href = "#7-1" > Supported and Unsupported ActiveX clients
< / a >
< ul >
< li > < a href = "#7-1-1" > Supported Clients
< / a >
< li > < a href = "#7-1-2" > Unsupported Clients
< / a >
< / ul >
< / ul >
< li > < a href = "#8" > Enhanced features
< / a >
< ul >
< li > < a href = "#8-1" > Fewer methods and properties
< / a >
< li > < a href = "#8-2" > Class Information and Tuning
< / a >
< li > < a href = "#8-3" > Developing licensed components
< / a >
< li > < a href = "#8-4" > More Interfaces
< / a >
< / ul >
< / ul >
<!-- endtoc -->
< p > < h2 > Introduction
< / h2 >
< a name = "1" > < / a > < p > The TQAxServer module provides a static library implementing the
functions required to turn a standard TQt binary into an ActiveX
control server.
< p > This module is part of the < a href = "activentqt.html" > ActiveTQt
framework< / a > . (To incorporate ActiveX controls in a TQt
application see the < a href = "qaxcontainer.html" > TQAxContainer
module< / a > .)
< p > The module consists of three classes
< ul >
< li > < a href = "qaxfactory.html" > TQAxFactory< / a > defines a factory for the creation of ActiveX components.
< li > < a href = "qaxbindable.html" > TQAxBindable< / a > provides an interface between the TQt widget and the
ActiveX control.
< li > < a href = "qaxaggregated.html" > TQAxAggregated< / a > can be subclassed to implement additional COM interfaces.
< / ul >
< p > Some < a href = "qaxserver-examples.html" > example implementations< / a >
of ActiveX controls are provided.
< p > < h2 > Building the library
< / h2 >
< a name = "2" > < / a > < p > In the < tt > activeqt< / tt > directory (usually < tt > TQTDIR/extensions/activeqt< / tt > )
enter the < tt > control< / tt > subdirectory and run < tt > qmake< / tt > to generate the
makefile, and use the make tool (< tt > nmake< / tt > for VC++, < tt > make< / tt > for Borland)
to build the library. The library < tt > qaxserver.lib< / tt > will be linked into
< tt > TQTDIR/lib< / tt > .
< p > < h2 > Using the library
< / h2 >
< a name = "3" > < / a > < p > To turn a standard TQt application into an ActiveX server using the
TQAxServer library you must add < tt > activeqt< / tt > as a CONFIG setting
in your < tt > .pro< / tt > file.
< p > An out-of-process executable server is generated from a < tt > .pro< / tt >
file like this:
< pre >
TEMPLATE = app
CONFIG += qt activeqt
RC_FILE = qaxserver.rc
...
< / pre >
< p > To build an in-process server, use a < tt > .pro< / tt > file like this:
< pre >
TEMPLATE = lib
CONFIG += qt activeqt dll
DEF_FILE = qaxserver.def
RC_FILE = qaxserver.rc
...
< / pre >
< p > The files < tt > qaxserver.rc< / tt > and < tt > qaxserver.def< / tt > are part of the
framework and can be used from their usual location (specify a
path in the < tt > .pro< / tt > 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.
< p > The < tt > activeqt< / tt > configuration will cause the < tt > qmake< / tt > tool to add the
required build steps to the build system:
< ul >
< li > link the binary against < tt > qaxserver.lib< / tt >
< li > generate an interface definition and link the type library into
the binary
< li > register the server
< / ul >
< p > Additionally you can specify a version number using the < tt > VERSION< / tt >
variable, e.g.
< pre >
TEMPLATE = lib
VERSION = 2.5
...
< / pre >
The version number specified will be used as the version of the type
library and of the server when registering.
< p > < h3 > Out-of-process vs. In-process
< / h3 >
< a name = "3-1" > < / a > < p > Whether 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.
< p > 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.
< p > 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.
< p > Both server types can use TQt either as a shared library, or
statically linked into the server binary.
< p > < h2 > The TQAxServer build system
< / h2 >
< a name = "4" > < / a > < p > To be able to build ActiveX controls with TQt, the build system
must be extended to include some additional build steps that are
used when the < tt > .pro< / tt > file includes < tt > activeqt< / tt > in the < tt > CONFIG< / tt >
settings. The resulting makefile will:
< p > < ul >
< li > Link the executable against < tt > qaxserver.lib< / tt > instead of < tt > qtmain.lib< / tt >
< li > Call the resulting executable with the < tt > -dumpidl< / tt > parameter to
generate an IDL description of the ActiveX controls provided by
the server.
< li > Compile the IDL into a type library using the MIDL tool
< li > Attach the resulting type library as a binary resource to the server
executable
< / ul >
< p > 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.
< p > < h3 > Typical build problems
< / h3 >
< a name = "4-1" > < / a > < p > The compiler/linker errors listed are based on those issued by the
Microsoft Visual C++ 6.0 compiler.
< p > < h4 > Compiler errors
< / h4 >
< a name = "4-1-1" > < / a > < p > < h5 > "No overloaded function takes 2 parameters"
< / h5 >
< a name = "4-1-1-1" > < / a > < p > When the error occurs in code that uses the < a href = "qaxfactory.html#TQAXFACTORY_DEFAULT" > TQAXFACTORY_DEFAULT< / a >
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.
< p > When the error occurs in code that uses the < a href = "qaxfactory.html#TQAXFACTORY_EXPORT" > TQAXFACTORY_EXPORT< / a >
macro, the < a href = "qaxfactory.html" > TQAxFactory< / a > subclass had no appropriate constructor.
Provide a public class constructor like
< pre >
MyFactory( const < a href = "ntquuid.html" > TQUuid< / a > & , const < a href = "ntquuid.html" > TQUuid< / a > & );
< / pre >
for your factory class.
< p > < h5 > "syntax error: bad suffix on number"
< / h5 >
< a name = "4-1-1-2" > < / a > < p > The unique identifiers have not been passed as strings into the
< a href = "qaxfactory.html#TQAXFACTORY_EXPORT" > TQAXFACTORY_EXPORT< / a > or < a href = "qaxfactory.html#TQAXFACTORY_DEFAULT" > TQAXFACTORY_DEFAULT< / a > macro.
< p > < h4 > Linker errors
< / h4 >
< a name = "4-1-2" > < / a > < p > < h5 > "unresolved external symbol _ucm_instantiate"
< / h5 >
< a name = "4-1-2-1" > < / a > < p > The server does not export an implementation of a TQAxFactory. Use
the < a href = "qaxfactory.html#TQAXFACTORY_EXPORT" > TQAXFACTORY_EXPORT< / a > macro in one of the project's
implementation files to instantiate and export a factory, or use
the < a href = "qaxfactory.html#TQAXFACTORY_DEFAULT" > TQAXFACTORY_DEFAULT< / a > macro to use the default factory.
< p > < h5 > "_ucm_initialize already defined in ..."
< / h5 >
< a name = "4-1-2-2" > < / a > < p > The server exports more than one implementation of a < a href = "qaxfactory.html" > TQAxFactory< / a > ,
or exports the same implementation twice. If you use the default
factory, the < a href = "qaxfactory.html#TQAXFACTORY_DEFAULT" > TQAXFACTORY_DEFAULT< / a > macro must only be used once in
the project. Use a custom TQAxFactory implementation and the < a href = "qaxfactory.html#TQAXFACTORY_EXPORT" > TQAXFACTORY_EXPORT< / a > macro if the server provides multiple ActiveX
controls.
< p > < h5 > "cannot open file ... "
< / h5 >
< a name = "4-1-2-3" > < / a > < p > 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).
< p > < h4 > Postprocessing and runtime errors
< / h4 >
< a name = "4-1-3" > < / a > < p > The < a href = "activentqt.html#ActiveTQt" > ActiveTQt< / a > build system performs four commands after the linking
of the binary to make it into an ActiveX server.
< p > < ul >
< li > Call the server to dump the IDL for the controls
< li > Compile the IDL into a type library
< li > Attach the type library as a binary resource to the server
< li > Register the server
< / ul >
< p > For this to work the server has to meet some requirements:
< p > < ul >
< li > All controls exposed can be created with nothing but a < a href = "ntqapplication.html" > TQApplication< / a >
instance being present
< li > The initial linking of the server includes a temporary type
library resource
< li > All dependencies required to run the server are in the system path
(or in the path used by the calling environment; note that Visual
Studio has it's own set of environment variables listed in the
Tools|Options|Directories dialog).
< / ul >
< p > If those requirements are not met one ore more of the following
errors are likely to occure:
< p > < h5 > The server executable crashes
< / h5 >
< a name = "4-1-3-1" > < / a > < p > To generate the IDL the widgets exposed as ActiveX controls need to
be instantiated (the constructor is called). At this point, nothing
else but a TQApplication object exists. Your widget constructor must
not rely on any other objects to be created, e.g. it should check for
null-pointers.
< p > To debug your server run it with -dumpidl outputfile and check where
it crashes.
< p > Note that no functions of the control are called.
< p > < h5 > The server executable is not a valid Win32 application
< / h5 >
< a name = "4-1-3-2" > < / a > < p > Attaching the type library corrupted the server binary. This is a
bug in Windows and happens only with release builds.
< p > 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.
< p > < h5 > "Unable to Locate DLL"
< / h5 >
< a name = "4-1-3-3" > < / a > < p > 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.
< p > < h5 > The Server does not respond
< / h5 >
< a name = "4-1-3-4" > < / a > < p > If 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 TQt
DLL!). Use a dependency walker to view all dependencies of the server
binary.
< p > If the server runs (e.g. the task manager lists a process), see
the following section for information on debugging your server.
< p > < h5 > The Object cannot be created
< / h5 >
< a name = "4-1-3-5" > < / a > < p > If 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 TQt DLL). Use a dependency walker
to view all dependencies of the server binary.
< p > If the server runs, see the following section for information on
debugging your server.
< p > < h3 > Debugging runtime errors
< / h3 >
< a name = "4-2" > < / a > < p > To 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 ActiveTQt and
TQt code if you installed the debug version.
< p > 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.
< p > < h2 > Implementing Controls
< / h2 >
< a name = "5" > < / a > < p > To implement an ActiveX control with TQt, create a subclass of < a href = "tqwidget.html" > TQWidget< / a >
or any existing TQWidget subclass:
< p > < pre >
#include < < a href = "tqwidget-h.html" > tqwidget.h< / a > >
class MyActiveX : public < a href = "tqwidget.html" > TQWidget< / a >
{
< a href = "metaobjects.html#TQ_OBJECT" > TQ_OBJECT< / a >
< / pre >
< p > The < a href = "metaobjects.html#TQ_OBJECT" > TQ_OBJECT< / a > macro is required to provide the < a href = "metaobjects.html#meta-object" > meta object< / a > information
about the widget to the ActiveTQt framework.
Use the < tt > TQ_PROPERTY< / tt > macro to declare properties for the ActiveX control:
< p > < pre >
TQ_PROPERTY( int value READ value WRITE setValue )
< / pre >
< p > Declare a standard TQWidget constructor taking a parent widget and a name,
and functions, signals and slots like any normal TQWidget.
< a href = "#footnote1" > < sup > (1)< / sup > < / a > < a name = "footnote-call1" > < / a >
< p > < pre >
public:
MyActiveX( < a href = "tqwidget.html" > TQWidget< / a > *parent = 0, const char *name = 0 )
...
int value() const;
public slots:
void setValue( int );
...
signals:
void valueChange( int );
...
};
< / pre >
< p > The ActiveTQt framework will expose properties and public slots as ActiveX
properties and methods, and signals as ActiveX events, and convert between
the TQt data types and the equivalent COM data types.
< p > < h3 > Data Types
< / h3 >
< a name = "5-1" > < / a > < p > The TQt data types that are supported for properties are:
< p > < center > < table cellpadding = "4" cellspacing = "2" border = "0" >
< tr bgcolor = "#a2c511" >
< th valign = "top" > TQt data type
< th valign = "top" > COM property
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > bool
< td valign = "top" > VARIANT_BOOL
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQString
< td valign = "top" > BSTR
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQCString
< td valign = "top" > BSTR
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > int
< td valign = "top" > int
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > uint
< td valign = "top" > unsigned int
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > double
< td valign = "top" > double
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQ_LLONG
< td valign = "top" > CY
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQ_ULLONG
< td valign = "top" > CY
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQColor
< td valign = "top" > OLE_COLOR
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQDate
< td valign = "top" > DATE
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQDateTime
< td valign = "top" > DATE
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQTime
< td valign = "top" > DATE
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQFont
< td valign = "top" > IFontDisp*
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQPixmap
< td valign = "top" > IPictureDisp*
< a href = "#footnote2" > < sup > (2)< / sup > < / a > < a name = "footnote-call2" > < / a >
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQVariant
< td valign = "top" > VARIANT
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQValueList< TQVariant>
< td valign = "top" > SAFEARRAY(VARIANT)
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQStringList
< td valign = "top" > SAFEARRAY(BSTR)
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQByteArray
< td valign = "top" > SAFEARRAY(BYTE)
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQRect
< td valign = "top" > User defined type
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQSize
< td valign = "top" > User defined type
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQPoint
< td valign = "top" > User defined type
< / table > < / center >
< p > The TQt data types that are supported for parameters in signals and
slots are:
< center > < table cellpadding = "4" cellspacing = "2" border = "0" >
< tr bgcolor = "#a2c511" >
< th valign = "top" > TQt data type
< th valign = "top" > COM parameter
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > bool
< td valign = "top" > [in] VARIANT_BOOL
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > bool&
< td valign = "top" > [in, out] VARIANT_BOOL*
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQString, const < a href = "ntqstring.html" > TQString< / a > &
< td valign = "top" > [in] BSTR
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQString&
< td valign = "top" > [in, out] BSTR*
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQCString, const < a href = "ntqcstring.html" > TQCString< / a > &
< td valign = "top" > [in] BSTR
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQString&
< td valign = "top" > [in, out] BSTR*
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > int
< td valign = "top" > [in] int
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > int&
< td valign = "top" > [in,out] int
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > uint
< td valign = "top" > [in] unsigned int
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > uint&
< td valign = "top" > [in, out] unsigned int*
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > double
< td valign = "top" > [in] double
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > double&
< td valign = "top" > [in, out] double*
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQColor, const < a href = "ntqcolor.html" > TQColor< / a > &
< td valign = "top" > [in] OLE_COLOR
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQColor&
< td valign = "top" > [in, out] OLE_COLOR*
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQDate, const < a href = "qdate.html" > TQDate< / a > &
< td valign = "top" > [in] DATE
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQDate&
< td valign = "top" > [in, out] DATE*
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQDateTime, const < a href = "ntqdatetime.html" > TQDateTime< / a > &
< td valign = "top" > [in] DATE
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQDateTime&
< td valign = "top" > [in, out] DATE*
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQFont, const < a href = "ntqfont.html" > TQFont< / a > &
< td valign = "top" > [in] IFontDisp*
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQFont&
< td valign = "top" > [in, out] IFontDisp**
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQPixmap, const < a href = "ntqpixmap.html" > TQPixmap< / a > &
< td valign = "top" > [in] IPictureDisp*
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQPixmap&
< td valign = "top" > [in, out] IPictureDisp**
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQValueList< TQVariant> , const < a href = "ntqvaluelist.html" > TQValueList< / a > < TQVariant> &
< td valign = "top" > [in] SAFEARRAY(VARIANT)
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQValueList< TQVariant> &
< td valign = "top" > [in, out] SAFEARRAY(VARIANT)*
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQStringList, const < a href = "ntqstringlist.html" > TQStringList< / a > &
< td valign = "top" > [in] SAFEARRAY(BSTR)
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQStringList&
< td valign = "top" > [in, out] SAFEARRAY(BSTR)*
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQByteArray, const < a href = "qbytearray.html" > TQByteArray< / a > &
< td valign = "top" > [in] SAFEARRAY(BYTE)
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQByteArray&
< td valign = "top" > [in, out] SAFEARRAY(BYTE)*
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQObject*
< td valign = "top" > [in] IDispatch*
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQRect&
< a href = "#footnote3" > < sup > (3)< / sup > < / a > < a name = "footnote-call3" > < / a >
< td valign = "top" > [in, out] struct < a href = "ntqrect.html" > TQRect< / a > (user defined)
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > TQSize&
< td valign = "top" > [in, out] struct < a href = "ntqsize.html" > TQSize< / a > (user defined)
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > TQPoint&
< td valign = "top" > [in, out] struct < a href = "ntqpoint.html" > TQPoint< / a > (user defined)
< / table > < / center >
< p > Also supported are exported enums and sets (see TQ_ENUMS and TQ_SETS).
The in-parameter types are also supported as return values.
< p > Properties and signals/slots that have parameters using any other
data types are ignored by the TQActiveX framework.
< p > < h3 > Sub-Objects
< / h3 >
< a name = "5-2" > < / a > < p > 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.
< p > Any < a href = "tqobject.html" > TQObject< / a > subclass can be used as the type for a sub object in ActiveX. The
< a href = "qaxfactory.html" > TQAxFactory< / a > 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.
< p > < h3 > Property Notification
< / h3 >
< a name = "5-3" > < / a > < p > To make the properties bindable for the ActiveX client, use multiple
inheritance from the < a href = "qaxbindable.html" > TQAxBindable< / a > class:
< p >
< pre >
#include < tqwidget.h>
< b > #include < qaxbindable.h> < / b >
class MyActiveX : public < a href = "tqwidget.html" > TQWidget< / a > < b > , public TQAxBindable< / b >
{
TQ_OBJECT
< / pre >
When implementing the property write functions, use the
TQAxBindable class's requestPropertyChange() and propertyChanged()
functions to allow ActiveX clients to bind to the control
properties.
< a href = "#footnote4" > < sup > (4)< / sup > < / a > < a name = "footnote-call4" > < / a >
< p > < h2 > Serving Controls
< / h2 >
< a name = "6" > < / a > < p > 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 < tt > guidgen< / tt > or < tt > uuidgen< / tt > . 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.
< p > To create the ActiveX control when the client asks for it the
server must export an implementation of a < a href = "qaxfactory.html" > TQAxFactory< / a > . Use the
default factory when the server provides only a single ActiveX
control, and implement a subclass of TQAxFactory 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:
< p > < pre >
TQAXFACTORY_DEFAULT ( MyActiveX,
"{ad90301a-849e-4e8b-9a91-0a6dc5f6461f}",
"{87a5b65e-7fa9-4dc6-a176-47295988dcbd}",
"{a6130ae9-8327-47ec-815b-d0b45a0d6e5e}",
"{26c4e136-4e23-4347-af37-faf933b027e9}",
"{a8f21901-7ff7-4f6a-b939-789620c03d83}" )
< / pre >
< p > The < a href = "qaxfactory.html" > TQAxFactory class documentation< / a > explains
how to use this macro, and how to implement and use custom factories.
< p > For out-of-process executable servers you can implement a main()
function to instantiate a < a href = "ntqapplication.html" > TQApplication< / a > object and enter the event
loop just like any normal TQt application. By default the
application will start as a standard TQt application, but if you
pass < tt > -activex< / tt > on the command line it will start as an ActiveX
server. Use < a href = "qaxfactory.html#isServer" > TQAxFactory::isServer< / a > () to create and run a standard
application interface, or to prevent a stand-alone execution:
< p >
< pre >
#include < ntqapplication.h>
< b > #include < qaxfactory.h> < / b >
int main( int argc, char **argv )
{
TQApplication app( argc, argv );
< b > if ( !TQAxFactory::isServer() ) {
// create and show main window...
}< / b >
return app.exec();
}
< / pre >
This is however not necessary as ActiveTQt provides a default implementation
of a main function. The default implemenation calls < a href = "qaxfactory.html#startServer" > TQAxFactory::startServer< / a > (),
creates a TQApplication instance and calls exec().
< p > To build the ActiveX server executable run < a href = "qmake-manual.html" > qmake< / a > to generate the makefile, and use your compiler's
make tool as for any other TQt application. The make process will
also register the controls in the system registry by calling the
resulting executable with the < tt > -regserver< / tt > command line option.
< p > If the ActiveX server is an executable, the following command line
options are supported:
< center > < table cellpadding = "4" cellspacing = "2" border = "0" >
< tr bgcolor = "#a2c511" > < th valign = "top" > Option < th valign = "top" > Result
< tr bgcolor = "#d0d0d0" > < td valign = "top" > < tt > -regserver< / tt > < td valign = "top" > Registers the server in the system registry
< tr bgcolor = "#f0f0f0" > < td valign = "top" > < tt > -unregserver< / tt > < td valign = "top" > Unregisters the server from the system registry
< tr bgcolor = "#d0d0d0" > < td valign = "top" > < tt > -activex< / tt > < td valign = "top" > Starts the application as an ActiveX server
< tr bgcolor = "#f0f0f0" > < td valign = "top" > < tt > -dumpidl < file> -version x.y< / tt > < td valign = "top" > Writes the server's IDL to the
specified file. The type library will have version x.y
< / table > < / center >
< p > In-process servers can be registered using the < tt > regsvr32< / tt > tool available
on all Windows systems.
< p > < h3 > Distributing TQAxServer binaries
< / h3 >
< a name = "6-1" > < / a > < p > ActiveX servers written with TQt can use TQt either as a shared
library, or have TQt 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 TQt DLL).
< p > < h4 > Installing stand-alone Servers
< / h4 >
< a name = "6-1-1" > < / a > < p > When your ActiveX server can also run as a stand-alone application,
run the server executable with the < tt > -regserver< / tt > 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.
< p > < h4 > Installing In-process Servers
< / h4 >
< a name = "6-1-2" > < / a > < p > When your ActiveX server is part of an installation package, use the
< tt > regsvr32< / tt > 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 < tt > DllRegisterServer< / tt > symbol and
call the function:
< p > < pre >
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
< / pre >
< p > < h4 > Distributing Servers over the Internet
< / h4 >
< a name = "6-1-3" > < / a > < p > 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.
< p > 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 < tt > INF< / tt > file listing other files the server requires
(e.g. the TQt DLL), or a compressed < tt > CAB< / tt > archive.
< p > 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:
< p >
< pre > [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
< / pre >
< p > The CABARC tool from Microsoft can easily generate CAB archives:
< pre > cabarc N simpleax.cab simpleax.exe simple.inf < / pre >
< p > The INF files assume a static build of TQt, 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.
< p > < h2 > Using the Controls
< / h2 >
< a name = "7" > < / a > < p > To use the ActiveX controls, e.g. to embed them in a web page, use
the < tt > < object> < / tt > HTML tag.
< p > < pre >
< object ID="MyActiveX1" CLASSID="CLSID:ad90301a-849e-4e8b-9a91-0a6dc5f6461f">
...
< \object>
< / pre >
< p > To initialize the control's properties, use
< pre >
< object ID=...>
< param name="name" value="value">
< \object>
< / pre >
< p > If the web browser supports scripting use JavaScript, VBScript and
forms to script the control. The < a href = "qaxserver-examples.html" > examples< / a > include demonstration HTML pages for the
example controls.
< p > < h3 > Supported and Unsupported ActiveX clients
< / h3 >
< a name = "7-1" > < / a > < p > The following is largly based on our own experiements with ActiveX
controls and client applications, and is by no means complete.
< p > < h4 > Supported Clients
< / h4 >
< a name = "7-1-1" > < / a > < p > These standard applications work with ActiveX controls developed with
ActiveTQt. Note that some clients support only in-process controls.
< p > < ul >
< li > Internet Explorer
< li > Microsoft ActiveX Control Test Container
< li > Microsoft Visual Studio 6.0
< li > Microsoft Visual Studio.NET/2003
< li > Microsoft Visual Basic 6.0
< li > MFC- and ATL-based containers
< li > Sybase PowerBuilder
< li > ActiveTQt based containers
< / ul >
< p > Microsoft Office applications are supported, but you need to register
the controls as "Insertable" objects. Reimplement < tt > TQAxFactory::registerClass< / tt >
to add this attribute to the COM class, or set the "Insertable" class info
for your class to "yes" using the TQ_CLASSINFO macro.
< p > < h4 > Unsupported Clients
< / h4 >
< a name = "7-1-2" > < / a > < p > We have not managed to make ActiveTQt based COM objects work with the
following client applications.
< p > < ul >
< li > Borland C++ Builder (Versions 5 and 6)
< li > Borland Delphi
< / ul >
< p > < h2 > Enhanced features
< / h2 >
< a name = "8" > < / a > < p > < h3 > Fewer methods and properties
< / h3 >
< a name = "8-1" > < / a > < p > By default all ActiveX controls expose not only their own methods
and properties to ActiveX clients, but also those of all super
classes, including < a href = "tqwidget.html" > TQWidget< / a > .
< p > This can be controlled by reimplementing < a href = "qaxfactory.html" > TQAxFactory< / a > 's
exposeToSuperClass() function. Reimplement the function to return
the last (furthest up the inheritance hierarchy) super class that
should be exposed:
< p > < pre >
TQString MyFactory::exposeToSuperClass( const < a href = "ntqstring.html" > TQString< / a > & key ) const
{
if ( key == "SmallActiveX" )
return key;
return TQAxFactory::exposeToSuperClass( key );
}
< / pre >
< p > 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 TQWidget. The
SmallActiveX class can of course propagate some of the TQWidget
functions and properties into its own interface.
< p > < h3 > Class Information and Tuning
< / h3 >
< a name = "8-2" > < / a > < p > An alternative way to reimplementing TQAxFactory to have more control
about how objects are registered or exposed is to provide class
specific information using the TQ_CLASSINFO macro, which is part of
TQt's meta object system.
< p > < center > < table cellpadding = "4" cellspacing = "2" border = "0" >
< tr bgcolor = "#a2c511" >
< th valign = "top" > Key
< th valign = "top" > Meaning of value
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > Version
< td valign = "top" > The version of the class (1.0 is default)
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > Description
< td valign = "top" > A string describing the class.
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > ClassID
< td valign = "top" > The class ID.
You must reimplement TQAxFactory::classID if not specified.
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > InterfaceID
< td valign = "top" > The interface ID.
You must reimplement TQAxFactory::interfaceID if not specified.
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > EventsID
< td valign = "top" > The event interface ID.
No signals are exposed as COM events if not specified.
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > DefaultProperty
< td valign = "top" > The property specified represents the default property of this class.
Ie. the default property of a push button would be "text".
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > DefaultSignal
< td valign = "top" > The signal specified respresents the default signal of this class.
Ie. the default signal of a push button would be "clicked".
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > LicenseKey
< td valign = "top" > Object creation requires the specified license key. The key can be
empty to require a licensed machine. By default classes are not
licensed. Also see the following section.
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > StockEvents
< td valign = "top" > Objects expose stock events if value is "yes".
See < a href = "qaxfactory.html#hasStockEvents" > TQAxFactory::hasStockEvents< / a > ()
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > ToSuperClass
< td valign = "top" > Objects expose functionality of all super classes up to and
including the class name in value.
See < a href = "qaxfactory.html#exposeToSuperClass" > TQAxFactory::exposeToSuperClass< / a > ()
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > Insertable
< td valign = "top" > If the value is "yes" the class is registered to be "Insertable"
and will be listed in OLE 2 containers (ie. Microsoft Office). This
attribute is not be set by default.
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > Aggregatable
< td valign = "top" > If the value is "no" the class does not support aggregation. By
default aggregation is supported.
< tr bgcolor = "#d0d0d0" >
< td valign = "top" > Creatable
< td valign = "top" > If the value is "no" the class cannot be created by the client,
and is only available through the API of another class (ie. the
class is a sub-type).
< tr bgcolor = "#f0f0f0" >
< td valign = "top" > RegisterObject
< td valign = "top" > If the value is "yes" objects of this class are registered with
OLE and accessible from the running object table (ie. clients
can connect to an already running instance of this class). This
attribute is only supported in out-of-process servers.
< / table > < / center >
< p > Note that both keys and values are case sensitive.
< p > 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.
< p >
< pre >
class MyActiveX : public < a href = "tqwidget.html" > TQWidget< / a >
{
TQ_OBJECT
< b > TQ_CLASSINFO("Version", "2.0")
TQ_CLASSINFO("ClassID", "{7a4cffd8-cbcd-4ae9-ae7e-343e1e5710df}")
TQ_CLASSINFO("InterfaceID", "{6fb035bf-8019-48d8-be51-ef05427d8994}")
TQ_CLASSINFO("EventsID", "{c42fffdf-6557-47c9-817a-2da2228bc29c}")
TQ_CLASSINFO("Insertable", "yes")
TQ_CLASSINFO("ToSuperClass", "MyActiveX")< / b >
TQ_PROPERTY( ...
public:
MyActiveX(TQWidget *parent = 0, const char *name = 0);
...
};
< / pre >
< h3 > Developing licensed components
< / h3 >
< a name = "8-3" > < / a > < p > 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.
< p > 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.
< p > To mark a TQt class as licensed specify a "LicenseKey" using the < tt > TQ_CLASSINFO< / tt >
macro.
< pre >
class MyLicensedControl : public < a href = "tqwidget.html" > TQWidget< / a >
{
TQ_OBJECT
< b > TQ_CLASSINFO("LicenseKey", "< key string> ")< / b >
...
};
< / pre >
The key is required to be able to create an instance of < tt > MyLicensedControl< / tt >
on a machine that is not licensed itself. The licensed developer can now
redistributes the server binary with his application, which creates the control
using the value of "LicenseKey", while users of the application cannot create
the control without the license key.
< p > 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
< a href = "qaxfactory.html#validateLicenseKey" > TQAxFactory::validateLicenseKey< / a > () to verify that a license exists on the
system (ie. through a license file).
< p > < h3 > More Interfaces
< / h3 >
< a name = "8-4" > < / a > < p > ActiveX controls provided by ActiveTQt servers support a minimal set of COM
interfaces to implement the OLE specifications. When the ActiveX class inherits
from the < a href = "qaxbindable.html" > TQAxBindable< / a > class it can also implement additional COM interfaces.
< p > Create a new subclass of < a href = "qaxaggregated.html" > TQAxAggregated< / a > and use multiple inheritance
to subclass additional COM interface classes.
< p > < pre >
class AxImpl : public < a href = "qaxaggregated.html" > TQAxAggregated< / a > , public ISomeCOMInterface
{
public:
AxImpl() {}
long queryInterface( const < a href = "ntquuid.html" > TQUuid< / a > & iid, void **iface );
// IUnknown
TQAXAGG_IUNKNOWN
// ISomeCOMInterface
...
}
< / pre >
< p > Reimplement the < tt > queryInterface()< / tt > function to support the additional
COM interfaces.
< p > < pre >
long AxImpl::queryInterface( const < a href = "ntquuid.html" > TQUuid< / a > & iid, void **iface )
{
*iface = 0;
if ( iid == IID_ISomeCOMInterface )
*iface = (ISomeCOMInterface*)this;
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
< / pre >
< p > Since < tt > ISomeCOMInterface< / tt > is a subclass of < tt > IUnknown< / tt > you will have
to implement the < tt > QueryInterface< / tt > , < tt > AddRef< / tt > and < tt > Release< / tt > functions.
Use the < tt > TQAXAGG_IUNKNOWN< / tt > 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.
< pre >
HRESULT AxImpl::QueryInterface( REFIID iid, void **iface )
{
return controllingUnknown()-> QueryInterface( iid, iface );
}
< / pre >
Do not support the < tt > IUnknown< / tt > interface itself in your < tt > queryInterface()< / tt >
implementation.
< p > Implement the methods of the COM interfaces, and use TQAxAggregated::Object()
if you need to make calls to the < a href = "tqobject.html" > TQObject< / a > subclass implementing the control.
< p > In your < a href = "qaxbindable.html" > TQAxBindable< / a > subclass, implement < tt > createAggregate()< / tt > to return
a new object of the < a href = "qaxaggregated.html" > TQAxAggregated< / a > subclass.
< p >
< pre >
class MyActiveX : public < a href = "tqwidget.html" > TQWidget< / a > ,
< b > public TQAxBindable< / b >
{
TQ_OBJECT
public:
MyActiveX( TQWidget *parent, const char *name = 0 );
< b > TQAxAggregated *createAggregate()
{
return new AxImpl();
}
< / b >
};
< / pre >
< hr >
< ol > < li > < a name = "footnote1" > < / a >
If a standard constructor is not present the compiler will issue
an error "no overloaded function takes 2 parameters" when using
the default factory through the < a href = "qaxfactory.html#TQAXFACTORY_DEFAULT" > TQAXFACTORY_DEFAULT< / a > macro. If you
cannot provide a standard constructor you must implement a < a href = "qaxfactory.html" > TQAxFactory< / a > custom factory and call the constructor you have in
your implementation of TQAxFactory::create.
< a href = "#footnote-call1" > Back...< / a > < li > < a name = "footnote2" > < / a >
COM cannot marshal IPictureDisp accross process boundaries,
so < a href = "ntqpixmap.html" > TQPixmap< / a > properties cannot be called for out-of-process servers. You
can however marshal the image data via e.g. temporary files. See the
Microsoft
< a href = "http://support.microsoft.com/default.aspx?scid=kb;[LN];Q150034" > KB article
Q150034< / a > for more information.
< a href = "#footnote-call2" > Back...< / a > < li > < a name = "footnote3" > < / a >
OLE needs to marshal user defined types by reference (ByRef), and cannot
marshal them by value (ByVal). This is why const-references and object
parameters are not supported for < a href = "ntqrect.html" > TQRect< / a > , < a href = "ntqsize.html" > TQSize< / a > and < a href = "ntqpoint.html" > TQPoint< / a > . Also note that
servers with this datatype require Windows 98 or DCOM 1.2 to be installed.
< a href = "#footnote-call3" > Back...< / a > < li > < a name = "footnote4" > < / a >
This is not required, but gives the client more control over
the ActiveX control.
< a href = "#footnote-call4" > Back...< / a > < / ol >
< / hr >
<!-- eof -->
< p > < address > < hr > < div align = center >
< table width = 100% cellspacing = 0 border = 0 > < tr >
< td > Copyright © 2007
< a href = "troll.html" > Trolltech< / a > < td align = center > < a href = "trademarks.html" > Trademarks< / a >
< td align = right > < div align = right > TQt 3.3.8< / div >
< / table > < / div > < / address > < / body >
< / html >