diff options
Diffstat (limited to 'src/activeqt/control/qaxfactory.cpp')
-rw-r--r-- | src/activeqt/control/qaxfactory.cpp | 591 |
1 files changed, 591 insertions, 0 deletions
diff --git a/src/activeqt/control/qaxfactory.cpp b/src/activeqt/control/qaxfactory.cpp new file mode 100644 index 0000000..ec72c830 --- /dev/null +++ b/src/activeqt/control/qaxfactory.cpp @@ -0,0 +1,591 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the ActiveQt framework of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaxfactory.h" + +#ifndef QT_NO_WIN_ACTIVEQT + +#include <qfile.h> +#include <qfileinfo.h> +#include <qmetaobject.h> +#include <qsettings.h> +#include <qwidget.h> +#include <qt_windows.h> + +QT_BEGIN_NAMESPACE + +extern char qAxModuleFilename[MAX_PATH]; + +/*! + \class QAxFactory + \brief The QAxFactory class defines a factory for the creation of COM components. + + \inmodule QAxServer + + Implement this factory once in your COM server to provide information + about the components the server can create. Subclass QAxFactory and implement + the pure virtual functions in any implementation file (e.g. main.cpp), and export + the factory using the \c QAXFACTORY_EXPORT() macro. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 0 + + If you use the \c Q_CLASSINFO() macro to provide the unique + identifiers or other attributes for your class you can use the \c + QAXFACTORY_BEGIN(), \c QAXCLASS() and \c QAXFACTORY_END() macros to + expose one or more classes as COM objects. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 1 + + + If your server supports just a single COM object, you can use + a default factory implementation through the \c QAXFACTORY_DEFAULT() macro. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 2 + + Only one QAxFactory implementation may be instantiated and + exported by an ActiveX server application. This instance is accessible + through the global qAxFactory() function. + + A factory can also reimplement the registerClass() and + unregisterClass() functions to set additional flags for an ActiveX + control in the registry. To limit the number of methods or + properties a widget class exposes from its parent classes + reimplement exposeToSuperClass(). + + \sa QAxAggregated, QAxBindable, {ActiveQt Framework} +*/ + +/*! + Constructs a QAxFactory object that returns \a libid and \a appid + in the implementation of the respective interface functions. +*/ + +QAxFactory::QAxFactory(const QUuid &libid, const QUuid &appid) +: typelib(libid), app(appid) +{ +} + +/*! + Destroys the QAxFactory object. +*/ +QAxFactory::~QAxFactory() +{ +} + +/*! + \fn QUuid QAxFactory::typeLibID() const + + Reimplement this function to return the ActiveX server's type + library identifier. +*/ +QUuid QAxFactory::typeLibID() const +{ + return typelib; +} + +/*! + \fn QUuid QAxFactory::appID() const + + Reimplement this function to return the ActiveX server's + application identifier. +*/ +QUuid QAxFactory::appID() const +{ + return app; +} + +/*! + \fn QStringList QAxFactory::featureList() const + + Reimplement this function to return a list of the widgets (class + names) supported by this factory. +*/ + +/*! + \fn QObject *QAxFactory::createObject(const QString &key) + + Reimplement this function to return a new object for \a key, or 0 if + this factory doesn't support the value of \a key. + + If the object returned is a QWidget it will be exposed as an ActiveX + control, otherwise the returned object will be exposed as a simple COM + object. +*/ + +/*! + \fn const QMetaObject *QAxFactory::metaObject(const QString &key) const + + Reimplement this function to return the QMetaObject corresponding to + \a key, or 0 if this factory doesn't support the value of \a key. +*/ + +/*! + \fn bool QAxFactory::createObjectWrapper(QObject *object, IDispatch **wrapper) + + Reimplement this function to provide the COM object for \a object + in \a wrapper. Return true if the function was successful; otherwise + return false. + + The default implementation creates a generic automation wrapper based + on the meta object information of \a object. +*/ +// implementation in qaxserverbase.cpp + +/*! + Reimplement this function to return the class identifier for each + \a key returned by the featureList() implementation, or an empty + QUuid if this factory doesn't support the value of \a key. + + The default implementation interprets \a key as the class name, + and returns the value of the Q_CLASSINFO() entry "ClassID". +*/ +QUuid QAxFactory::classID(const QString &key) const +{ + const QMetaObject *mo = metaObject(key); + if (!mo) + return QUuid(); + QString id = QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("ClassID")).value()); + + return QUuid(id); +} + +/*! + Reimplement this function to return the interface identifier for + each \a key returned by the featureList() implementation, or an + empty QUuid if this factory doesn't support the value of \a key. + + The default implementation interprets \a key as the class name, + and returns the value of the Q_CLASSINFO() entry "InterfaceID". +*/ +QUuid QAxFactory::interfaceID(const QString &key) const +{ + const QMetaObject *mo = metaObject(key); + if (!mo) + return QUuid(); + QString id = QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("InterfaceID")).value()); + + return QUuid(id); +} + +/*! + Reimplement this function to return the identifier of the event + interface for each \a key returned by the featureList() + implementation, or an empty QUuid if this factory doesn't support + the value of \a key. + + The default implementation interprets \a key as the class name, + and returns the value of the Q_CLASSINFO() entry "EventsID". +*/ +QUuid QAxFactory::eventsID(const QString &key) const +{ + const QMetaObject *mo = metaObject(key); + if (!mo) + return QUuid(); + QString id = QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("EventsID")).value()); + + return QUuid(id); +} + +/*! + Registers additional values for the class \a key in the system + registry using the \a settings object. The standard values have + already been registered by the framework, but additional values, + e.g. implemented categories, can be added in an implementation of + this function. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 3 + + If you reimplement this function you must also reimplement + unregisterClass() to remove the additional registry values. + + \sa QSettings +*/ +void QAxFactory::registerClass(const QString &key, QSettings *settings) const +{ + Q_UNUSED(key); + Q_UNUSED(settings) +} + +/*! + Unregisters any additional values for the class \a key from the + system registry using the \a settings object. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 4 + + \sa registerClass(), QSettings +*/ +void QAxFactory::unregisterClass(const QString &key, QSettings *settings) const +{ + Q_UNUSED(key); + Q_UNUSED(settings) +} + +/*! + Reimplement this function to return true if \a licenseKey is a valid + license for the class \a key, or if the current machine is licensed. + + The default implementation returns true if the class \a key is + not licensed (ie. no \c Q_CLASSINFO() attribute "LicenseKey"), or + if \a licenseKey matches the value of the "LicenseKey" + attribute, or if the machine is licensed through a .LIC file with + the same filename as this COM server. +*/ +bool QAxFactory::validateLicenseKey(const QString &key, const QString &licenseKey) const +{ + const QMetaObject *mo = metaObject(key); + if (!mo) + return true; + + QString classKey = QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("LicenseKey")).value()); + if (classKey.isEmpty()) + return true; + + if (licenseKey.isEmpty()) { + QString licFile(QFile::decodeName(qAxModuleFilename)); + int lastDot = licFile.lastIndexOf(QLatin1Char('.')); + licFile = licFile.left(lastDot) + QLatin1String(".lic"); + if (QFile::exists(licFile)) + return true; + return false; + } + return licenseKey == classKey; +} + +/*! + Reimplement this function to return the name of the super class of + \a key up to which methods and properties should be exposed by the + ActiveX control. + + The default implementation interprets \a key as the class name, + and returns the value of the \c Q_CLASSINFO() entry + "ToSuperClass". If no such value is set the null-string is + returned, and the functions and properties of all the super + classes including QWidget will be exposed. + + To only expose the functions and properties of the class itself, + reimplement this function to return \a key. +*/ +QString QAxFactory::exposeToSuperClass(const QString &key) const +{ + const QMetaObject *mo = metaObject(key); + if (!mo) + return QString(); + return QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("ToSuperClass")).value()); +} + +/*! + Reimplement this function to return true if the ActiveX control \a key + should be a top level window, e.g. a dialog. The default implementation + returns false. +*/ +bool QAxFactory::stayTopLevel(const QString &key) const +{ + return false; +} + +/*! + Reimplement this function to return true if the ActiveX control + \a key should support the standard ActiveX events + \list + \i Click + \i DblClick + \i KeyDown + \i KeyPress + \i KeyUp + \i MouseDown + \i MouseUp + \i MouseMove + \endlist + + The default implementation interprets \a key as the class name, + and returns true if the value of the \c Q_CLASSINFO() entry + "StockEvents" is "yes". Otherwise this function returns false. +*/ +bool QAxFactory::hasStockEvents(const QString &key) const +{ + const QMetaObject *mo = metaObject(key); + if (!mo) + return false; + return QString::fromLatin1(mo->classInfo(mo->indexOfClassInfo("StockEvents")).value()) == QLatin1String("yes"); +} + + +extern bool qAxIsServer; + +/*! + Returns true if the application has been started (by COM) as an ActiveX + server, otherwise returns false. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 5 +*/ + +bool QAxFactory::isServer() +{ + return qAxIsServer; +} + +extern char qAxModuleFilename[MAX_PATH]; + +/*! + Returns the directory that contains the server binary. + + For out-of-process servers this is the same as + QApplication::applicationDirPath(). For in-process servers + that function returns the directory that contains the hosting + application. +*/ +QString QAxFactory::serverDirPath() +{ + return QFileInfo(QString::fromLocal8Bit(qAxModuleFilename)).absolutePath(); +} + +/*! + Returns the file path of the server binary. + + For out-of-process servers this is the same as + QApplication::applicationFilePath(). For in-process servers + that function returns the file path of the hosting application. +*/ +QString QAxFactory::serverFilePath() +{ + return QString::fromLocal8Bit(qAxModuleFilename); +} + +/*! + Reimplement this function to return true if the server is + running as a persistent service (e.g. an NT service) and should + not terminate even when all objects provided have been released. + + The default implementation returns false. +*/ +bool QAxFactory::isService() const +{ + return false; +} + +/*! + \enum QAxFactory::ServerType + + This enum specifies the different types of servers that can be + started with startServer. + + \value SingleInstance The server process can create only one instance of each + exported class. COM starts a new process for each request. This is typically + used in servers that export only one creatable class. + \value MultipleInstances The server can create multiple instances of + each exported class. This is the default. All instances will live in the same + thread, and will share static resources. +*/ + +/*! + \fn bool QAxFactory::startServer(ServerType type); + + Starts the COM server with \a type and returns true if successful, + otherwise returns false. + + Calling this function if the server is already running (or for an + in-process server) does nothing and returns true. + + The server is started automatically with \a type set to \c MultipleInstances + if the server executable has been started with the \c -activex + command line parameter. To switch to SingleInstance, call + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 6 + + in your own main() entry point function. +*/ + +/*! + \fn bool QAxFactory::stopServer(); + + Stops the COM server and returns true if successful, otherwise + returns false. + + Calling this function if the server is not running (or for an + in-process server) does nothing and returns true. + + Stopping the server will not invalidate existing objects, but no + new objects can be created from the existing server process. Usually + COM will start a new server process if additional objects are requested. + + The server is stopped automatically when the main() function returns. +*/ + +class ActiveObject : public QObject +{ +public: + ActiveObject(QObject *parent, QAxFactory *factory); + ~ActiveObject(); + + IDispatch *wrapper; + DWORD cookie; +}; + +ActiveObject::ActiveObject(QObject *parent, QAxFactory *factory) +: QObject(parent), wrapper(0), cookie(0) +{ + QLatin1String key(parent->metaObject()->className()); + + factory->createObjectWrapper(parent, &wrapper); + if (wrapper) + RegisterActiveObject(wrapper, QUuid(factory->classID(key)), ACTIVEOBJECT_STRONG, &cookie); +} + +ActiveObject::~ActiveObject() +{ + if (cookie) + RevokeActiveObject(cookie, 0); + if (wrapper) + wrapper->Release(); +} + +/*! + Registers the QObject \a object with COM as a running object, and returns true if + the registration succeeded, otherwise returns false. The object is unregistered + automatically when it is destroyed. + + This function should only be called if the application has been started by the user + (i.e. not by COM to respond to a request), and only for one object, usually the + toplevel object of the application's object hierarchy. + + This function does nothing and returns false if the object's class info for + "RegisterObject" is not set to "yes", or if the server is an in-process server. +*/ +bool QAxFactory::registerActiveObject(QObject *object) +{ + if (qstricmp(object->metaObject()->classInfo(object->metaObject()->indexOfClassInfo("RegisterObject")).value(), "yes")) + return false; + + if (!QString::fromLocal8Bit(qAxModuleFilename).toLower().endsWith(QLatin1String(".exe"))) + return false; + + ActiveObject *active = new ActiveObject(object, qAxFactory()); + if (!active->wrapper || !active->cookie) { + delete active; + return false; + } + return true; +} + +/*! + \macro QAXFACTORY_DEFAULT(Class, ClassID, InterfaceID, EventID, LibID, AppID) + \relates QAxFactory + + This macro can be used to export a single QObject subclass \a Class a this + COM server through an implicitly declared QAxFactory implementation. + + This macro exports the class \a Class as a COM coclass with the CLSID \a ClassID. + The properties and slots will be declared through a COM interface with the IID + \a InterfaceID, and signals will be declared through a COM event interface with + the IID \a EventID. All declarations will be in a type library with the id \a LibID, + and if the server is an executable server then it will have the application id + \a AppID. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 7 + + \sa QAXFACTORY_EXPORT(), QAXFACTORY_BEGIN() +*/ + +/*! + \macro QAXFACTORY_EXPORT(Class, LibID, AppID) + \relates QAxFactory + + This macro can be used to export a QAxFactory implementation \a Class from + a COM server. All declarations will be in a type library with the id \a LibID, + and if the server is an executable server then it will have the application id + \a AppID. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 8 + + \sa QAXFACTORY_BEGIN() +*/ + +/*! + \macro QAXFACTORY_BEGIN(IDTypeLib, IDApp) + \relates QAxFactory + + This macro can be used to export multiple QObject classes through an + implicitly declared QAxFactory implementation. All QObject classes have to + declare the ClassID, InterfaceID and EventsID (if applicable) through the + Q_CLASSINFO() macro. All declarations will be in a type library with the id + \a IDTypeLib, and if the server is an executable server then it will have the + application id \a IDApp. + + This macro needs to be used together with the QAXCLASS(), QAXTYPE() + and QAXFACTORY_END() macros. + + \snippet doc/src/snippets/code/src_activeqt_control_qaxfactory.cpp 9 +*/ + +/*! + \macro QAXCLASS(Class) + \relates QAxFactory + + This macro adds a creatable COM class \a Class to the QAxFactory declared + with the QAXFACTORY_BEGIN() macro. + + \sa QAXFACTORY_BEGIN(), QAXTYPE(), QAXFACTORY_END(), Q_CLASSINFO() +*/ + +/*! + \macro QAXTYPE(Class) + \relates QAxFactory + + This macro adds a non-creatable COM class \a Class to the QAxFactory + declared with the QAXFACTORY_BEGIN(). The class \a Class can be used + in APIs of other COM classes exported through QAXTYPE() or QAXCLASS(). + + Instances of type \a Class can only be retrieved using APIs of already + instantiated objects. + + \sa QAXFACTORY_BEGIN(), QAXCLASS(), QAXFACTORY_END(), Q_CLASSINFO() +*/ + +/*! + \macro QAXFACTORY_END() + \relates QAxFactory + + Completes the QAxFactory declaration started with the QAXFACTORY_BEGIN() + macro. + + \sa QAXFACTORY_BEGIN(), QAXCLASS(), QAXTYPE() +*/ + +QT_END_NAMESPACE +#endif // QT_NO_WIN_ACTIVEQT |