| /**************************************************************************** |
| ** |
| ** Copyright (C) 2015 The Qt Company Ltd. |
| ** Contact: http://www.qt.io/licensing/ |
| ** |
| ** This file is part of the ActiveQt framework of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:BSD$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** BSD License Usage |
| ** Alternatively, 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 The Qt Company Ltd 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" |
| |
| #include <qfile.h> |
| #include <qfileinfo.h> |
| #include <qmetaobject.h> |
| #include <qsettings.h> |
| #include <qwidget.h> |
| #include <qt_windows.h> |
| |
| QT_BEGIN_NAMESPACE |
| |
| extern wchar_t 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 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 src_activeqt_control_qaxfactory.cpp 1 |
| |
| |
| 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() = default; |
| |
| /*! |
| \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 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 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(QString::fromWCharArray(qAxModuleFilename)); |
| int lastDot = licFile.lastIndexOf(QLatin1Char('.')); |
| licFile.truncate(lastDot); |
| licFile += QLatin1String(".lic"); |
| return QFile::exists(licFile); |
| } |
| 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 |
| { |
| Q_UNUSED(key) |
| return false; |
| } |
| |
| /*! |
| Reimplement this function to return true if the ActiveX control |
| \a key should support the standard ActiveX events |
| \list |
| \li Click |
| \li DblClick |
| \li KeyDown |
| \li KeyPress |
| \li KeyUp |
| \li MouseDown |
| \li MouseUp |
| \li 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 src_activeqt_control_qaxfactory.cpp 5 |
| */ |
| |
| bool QAxFactory::isServer() |
| { |
| return qAxIsServer; |
| } |
| |
| /*! |
| Returns the directory that contains the server binary. |
| |
| For out-of-process servers this is the same as |
| \l {QCoreApplication::applicationDirPath()}. For in-process servers |
| that function returns the directory that contains the hosting |
| application. |
| */ |
| QString QAxFactory::serverDirPath() |
| { |
| return QFileInfo(QString::fromWCharArray(qAxModuleFilename)).absolutePath(); |
| } |
| |
| /*! |
| Returns the file path of the server binary. |
| |
| For out-of-process servers this is the same as |
| \l {QCoreApplication::applicationFilePath()}. For in-process servers |
| that function returns the file path of the hosting application. |
| */ |
| QString QAxFactory::serverFilePath() |
| { |
| return QString::fromWCharArray(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 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() override; |
| |
| IDispatch *wrapper; |
| DWORD cookie; |
| }; |
| |
| ActiveObject::ActiveObject(QObject *parent, QAxFactory *factory) |
| : QObject(parent), wrapper(nullptr), 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, nullptr); |
| 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::fromWCharArray(qAxModuleFilename).endsWith(QLatin1String(".exe"), Qt::CaseInsensitive)) |
| 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 |
| \deprecated |
| |
| 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 src_activeqt_control_qaxfactory.cpp 7 |
| |
| \note This class has been deprecated in favor of QAXFACTORY_BEGIN(). |
| \sa QAXFACTORY_EXPORT() |
| */ |
| |
| /*! |
| \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 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 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 |