src/activeqt/control/qaxfactory.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/activeqt/control/qaxfactory.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,592 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 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 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(QString::fromWCharArray(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 wchar_t 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::fromWCharArray(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::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 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::fromWCharArray(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