summaryrefslogtreecommitdiffstats
path: root/src/activeqt/control
diff options
context:
space:
mode:
Diffstat (limited to 'src/activeqt/control')
-rw-r--r--src/activeqt/control/control.pro43
-rw-r--r--src/activeqt/control/qaxaggregated.h93
-rw-r--r--src/activeqt/control/qaxbindable.cpp324
-rw-r--r--src/activeqt/control/qaxbindable.h87
-rw-r--r--src/activeqt/control/qaxfactory.cpp591
-rw-r--r--src/activeqt/control/qaxfactory.h310
-rw-r--r--src/activeqt/control/qaxmain.cpp54
-rw-r--r--src/activeqt/control/qaxserver.cpp1251
-rw-r--r--src/activeqt/control/qaxserver.def8
-rw-r--r--src/activeqt/control/qaxserver.icobin0 -> 766 bytes
-rw-r--r--src/activeqt/control/qaxserver.rc2
-rw-r--r--src/activeqt/control/qaxserverbase.cpp4490
-rw-r--r--src/activeqt/control/qaxserverdll.cpp138
-rw-r--r--src/activeqt/control/qaxservermain.cpp279
14 files changed, 7670 insertions, 0 deletions
diff --git a/src/activeqt/control/control.pro b/src/activeqt/control/control.pro
new file mode 100644
index 0000000..65b0251
--- /dev/null
+++ b/src/activeqt/control/control.pro
@@ -0,0 +1,43 @@
+TEMPLATE = lib
+
+TARGET = ActiveQt
+CONFIG += qt_install_headers
+SYNCQT.HEADER_FILES = qaxaggregated.h qaxbindable.h qaxfactory.h
+SYNCQT.HEADER_CLASSES = ../../../include/ActiveQt/QAxAggregated ../../../include/ActiveQt/QAxBindable ../../../include/ActiveQt/QAxFactory ../../../include/ActiveQt/QAxClass
+include(../../qt_install.pri)
+
+TARGET = QAxServer
+
+!debug_and_release|build_pass {
+ CONFIG(debug, debug|release) {
+ TARGET = $$member(TARGET, 0)d
+ }
+}
+
+CONFIG += qt warn_off staticlib
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE\lib
+
+DEFINES += QAX_SERVER
+win32-g++:DEFINES += QT_NEEDS_QMAIN
+win32-borland:DEFINES += QT_NEEDS_QMAIN
+
+LIBS += -luser32 -lole32 -loleaut32 -lgdi32
+win32-g++:LIBS += -luuid
+
+contains(QT_EDITION, OpenSource|Console) {
+ message( "You are not licensed to use ActiveQt." )
+} else {
+ HEADERS = qaxaggregated.h \
+ qaxbindable.h \
+ qaxfactory.h \
+ ../shared/qaxtypes.h
+
+ SOURCES = qaxserver.cpp \
+ qaxserverbase.cpp \
+ qaxbindable.cpp \
+ qaxfactory.cpp \
+ qaxservermain.cpp \
+ qaxserverdll.cpp \
+ qaxmain.cpp \
+ ../shared/qaxtypes.cpp
+}
diff --git a/src/activeqt/control/qaxaggregated.h b/src/activeqt/control/qaxaggregated.h
new file mode 100644
index 0000000..3e6ce44
--- /dev/null
+++ b/src/activeqt/control/qaxaggregated.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QAXAGGREGATED_H
+#define QAXAGGREGATED_H
+
+#include <QtCore/qobject.h>
+
+struct IUnknown;
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(ActiveQt)
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+struct QUuid;
+
+class QAxAggregated
+{
+ friend class QAxServerBase;
+ friend class QAxClientSite;
+public:
+ virtual long queryInterface(const QUuid &iid, void **iface) = 0;
+
+protected:
+ virtual ~QAxAggregated()
+ {}
+
+ inline IUnknown *controllingUnknown() const
+ { return controlling_unknown; }
+ inline QWidget *widget() const
+ {
+ return qobject_cast<QWidget*>(the_object);
+ }
+ inline QObject *object() const { return the_object; }
+
+private:
+ IUnknown *controlling_unknown;
+ QObject *the_object;
+};
+
+#define QAXAGG_IUNKNOWN \
+ HRESULT WINAPI QueryInterface(REFIID iid, LPVOID *iface) { \
+ return controllingUnknown()->QueryInterface(iid, iface); } \
+ ULONG WINAPI AddRef() {return controllingUnknown()->AddRef(); } \
+ ULONG WINAPI Release() {return controllingUnknown()->Release(); } \
+
+#endif // QT_NO_WIN_ACTIVEQT
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAXAGGREGATED_H
diff --git a/src/activeqt/control/qaxbindable.cpp b/src/activeqt/control/qaxbindable.cpp
new file mode 100644
index 0000000..b2e1a49
--- /dev/null
+++ b/src/activeqt/control/qaxbindable.cpp
@@ -0,0 +1,324 @@
+/****************************************************************************
+**
+** 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 "qaxbindable.h"
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+#include <qmetaobject.h>
+
+#include <qt_windows.h> // for IUnknown
+#include "../shared/qaxtypes.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAxBindable
+ \brief The QAxBindable class provides an interface between a
+ QWidget and an ActiveX client.
+
+ \inmodule QAxServer
+
+ The functions provided by this class allow an ActiveX control to
+ communicate property changes to a client application. Inherit
+ your control class from both QWidget (directly or indirectly) and
+ this class to get access to this class's functions. The
+ \l{moc}{meta-object compiler} requires you to inherit from
+ QWidget first.
+
+ \snippet doc/src/snippets/code/src_activeqt_control_qaxbindable.cpp 0
+
+ When implementing the property write function, use
+ requestPropertyChange() to get permission from the ActiveX client
+ application to change this property. When the property changes,
+ call propertyChanged() to notify the ActiveX client application
+ about the change. If a fatal error occurs in the control, use the
+ static reportError() function to notify the client.
+
+ Use the interface returned by clientSite() to call the ActiveX
+ client. To implement additional COM interfaces in your ActiveX
+ control, reimplement createAggregate() to return a new object of a
+ QAxAggregated subclass.
+
+ The ActiveQt \l{activeqt/opengl}{OpenGL} example shows how to use
+ QAxBindable to implement additional COM interfaces.
+
+ \sa QAxAggregated, QAxFactory, {ActiveQt Framework}
+*/
+
+/*!
+ Constructs an empty QAxBindable object.
+*/
+QAxBindable::QAxBindable()
+:activex(0)
+{
+}
+
+/*!
+ Destroys the QAxBindable object.
+*/
+QAxBindable::~QAxBindable()
+{
+}
+
+/*!
+ Call this function to request permission to change the property
+ \a property from the client that is hosting this ActiveX control.
+ Returns true if the client allows the change; otherwise returns
+ false.
+
+ This function is usually called first in the write function for \a
+ property, and writing is abandoned if the function returns false.
+
+ \snippet doc/src/snippets/code/src_activeqt_control_qaxbindable.cpp 1
+
+ \sa propertyChanged()
+*/
+bool QAxBindable::requestPropertyChange(const char *property)
+{
+ if (!activex)
+ return true;
+
+ return activex->emitRequestPropertyChange(property);
+}
+
+/*!
+ Call this function to notify the client that is hosting this
+ ActiveX control that the property \a property has been changed.
+
+ This function is usually called at the end of the property's write
+ function.
+
+ \sa requestPropertyChange()
+*/
+void QAxBindable::propertyChanged(const char *property)
+{
+ if (!activex)
+ return;
+
+ activex->emitPropertyChanged(property);
+}
+
+/*!
+ Returns a pointer to the client site interface for this ActiveX object,
+ or null if no client site has been set.
+
+ Call \c QueryInterface() on the returned interface to get the
+ interface you want to call.
+*/
+IUnknown *QAxBindable::clientSite() const
+{
+ if (!activex)
+ return 0;
+
+ return activex->clientSite();
+}
+
+/*!
+ Reimplement this function when you want to implement additional
+ COM interfaces in the ActiveX control, or when you want to provide
+ alternative implementations of COM interfaces. Return a new object
+ of a QAxAggregated subclass.
+
+ The default implementation returns the null pointer.
+*/
+QAxAggregated *QAxBindable::createAggregate()
+{
+ return 0;
+}
+
+/*!
+ Reports an error to the client application. \a code is a
+ control-defined error code. \a desc is a human-readable description
+ of the error intended for the application user. \a src is the name
+ of the source for the error, typically the ActiveX server name. \a
+ context can be the location of a help file with more information
+ about the error. If \a context ends with a number in brackets,
+ e.g. [12], this number will be interpreted as the context ID in
+ the help file.
+*/
+void QAxBindable::reportError(int code, const QString &src, const QString &desc, const QString &context)
+{
+ if (!activex)
+ return;
+
+ activex->reportError(code, src, desc, context);
+}
+
+/*!
+ \since 4.1
+
+ If the COM object supports a MIME type then this function is called
+ to initialize the COM object from the data \a source in \a format.
+ You have to open \a source for reading before you can read from it.
+
+ Returns true to indicate success. If the function returns false,
+ then ActiveQt will process the data by setting the properties
+ through the meta object system.
+
+ If you reimplement this function you also have to implement
+ writeData(). The default implementation does nothing and returns
+ false.
+
+ \warning ActiveX controls embedded in HTML can use either the
+ \c type and \c data attribute of the \c object tag to read data,
+ or use a list of \c param tags to initialize properties. If
+ \c param tags are used, then Internet Explorer will ignore the
+ \c data attribute, and readData will not be called.
+
+ \sa writeData()
+*/
+bool QAxBindable::readData(QIODevice *source, const QString &format)
+{
+ Q_UNUSED(source);
+ Q_UNUSED(format);
+ return false;
+}
+
+/*!
+ \since 4.1
+
+ If the COM object supports a MIME type then this function is called
+ to store the COM object into \a sink.
+ You have to open \a sink for writing before you can write to it.
+
+ Returns true to indicate success. If the function returns false,
+ then ActiveQt will serialize the object by storing the property
+ values.
+
+ If you reimplement this function you also have to implement
+ readData(). The default implementation does nothing and returns
+ false.
+
+ \sa readData()
+*/
+bool QAxBindable::writeData(QIODevice *sink)
+{
+ Q_UNUSED(sink);
+ return false;
+}
+
+/*!
+ \class QAxAggregated
+ \brief The QAxAggregated class is an abstract base class for implementations of
+ additional COM interfaces.
+
+ \inmodule QAxServer
+
+ Create a subclass of QAxAggregated and reimplement
+ queryInterface() to support additional COM interfaces. Use
+ multiple inheritance from those COM interfaces. Implement the
+ IUnknown interface of those COM interfaces by delegating the
+ calls to \c QueryInterface(), \c AddRef() and \c Release() to the
+ interface provided by controllingUnknown().
+
+ Use the widget() method if you need to make calls to the QWidget
+ implementing the ActiveX control. You must not store that pointer
+ in your subclass (unless you use QPointer), as the QWidget can
+ be destroyed by the ActiveQt framework at any time.
+
+ \sa QAxBindable, QAxFactory, {ActiveQt Framework}
+*/
+
+/*!
+ \fn QAxAggregated::~QAxAggregated()
+
+ The destructor is called internally by Qt.
+*/
+
+/*!
+ \fn long QAxAggregated::queryInterface(const QUuid &iid, void **iface)
+
+ Reimplement this pure virtual function to support additional COM
+ interfaces. Set the value of \a iface to point to this object to
+ support the interface \a iid. Note that you must cast the \c
+ this pointer to the appropriate superclass.
+
+ \snippet doc/src/snippets/code/src_activeqt_control_qaxbindable.cpp 2
+
+ Return the standard COM results \c S_OK (interface is supported)
+ or \c E_NOINTERFACE (requested interface is not supported).
+
+ \warning
+ Even though you must implement the \c IUnknown interface if you
+ implement any COM interface you must not support the \c IUnknown
+ interface in your queryInterface() implementation.
+*/
+
+/*!
+ \fn IUnknown *QAxAggregated::controllingUnknown() const
+
+ Returns the \c IUnknown interface of the ActiveX control. Implement
+ the \c IUnknown interface in your QAxAggregated subclass to
+ delegate calls to \c QueryInterface(), \c AddRef(), and \c
+ Release() to the interface provided by this function.
+
+ \snippet doc/src/snippets/code/src_activeqt_control_qaxbindable.cpp 3
+
+ Instead of declaring and implementing these three functions
+ manually, you can use the \c QAXAGG_IUNKNOWN macro in the class
+ declaration of your subclass.
+*/
+
+/*!
+ \fn QObject *QAxAggregated::object() const
+
+ Returns a pointer to the QObject subclass implementing the COM object.
+ This function might return 0.
+
+ \warning
+ You must not store the returned pointer, unless you use a
+ QPointer, since the QObject can be destroyed by ActiveQt at any
+ time.
+*/
+
+/*!
+ \fn QWidget *QAxAggregated::widget() const
+
+ Returns a pointer to the QWidget subclass implementing the ActiveX control.
+ This function might return 0.
+
+ \warning
+ You must not store the returned pointer, unless you use a
+ QPointer, since the QWidget can be destroyed by ActiveQt at any
+ time.
+*/
+
+QT_END_NAMESPACE
+#endif // QT_NO_WIN_ACTIVEQT
diff --git a/src/activeqt/control/qaxbindable.h b/src/activeqt/control/qaxbindable.h
new file mode 100644
index 0000000..d3fd07a
--- /dev/null
+++ b/src/activeqt/control/qaxbindable.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QAXBINDABLE_H
+#define QAXBINDABLE_H
+
+#include <QtGui/qwidget.h>
+
+struct IUnknown;
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(ActiveQt)
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+class QAxAggregated;
+class QIODevice;
+struct IAxServerBase;
+
+class QAxBindable
+{
+ friend class QAxServerBase;
+public:
+ QAxBindable();
+ virtual ~QAxBindable();
+
+ virtual QAxAggregated *createAggregate();
+ void reportError(int code, const QString &src, const QString &desc, const QString &help = QString());
+
+ virtual bool readData(QIODevice *source, const QString &format);
+ virtual bool writeData(QIODevice *sink);
+
+protected:
+ bool requestPropertyChange(const char *property);
+ void propertyChanged(const char *property);
+
+ IUnknown *clientSite() const;
+
+private:
+ IAxServerBase *activex;
+};
+
+QT_END_NAMESPACE
+#endif // QT_NO_WIN_ACTIVEQT
+
+QT_END_HEADER
+
+#endif // QAXBINDABLE_H
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
diff --git a/src/activeqt/control/qaxfactory.h b/src/activeqt/control/qaxfactory.h
new file mode 100644
index 0000000..e5bb9c1
--- /dev/null
+++ b/src/activeqt/control/qaxfactory.h
@@ -0,0 +1,310 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QAXFACTORY_H
+#define QAXFACTORY_H
+
+#include <QtCore/qhash.h>
+#include <QtCore/quuid.h>
+#include <QtCore/qfactoryinterface.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qstringlist.h>
+
+struct IUnknown;
+struct IDispatch;
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(ActiveQt)
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+class QWidget;
+class QSettings;
+
+class QAxFactory : public QObject
+{
+public:
+ QAxFactory(const QUuid &libId, const QUuid &appId);
+ virtual ~QAxFactory();
+
+ virtual QStringList featureList() const = 0;
+
+ virtual QObject *createObject(const QString &key) = 0;
+ virtual const QMetaObject *metaObject(const QString &key) const = 0;
+ virtual bool createObjectWrapper(QObject *object, IDispatch **wrapper);
+
+ virtual QUuid classID(const QString &key) const;
+ virtual QUuid interfaceID(const QString &key) const;
+ virtual QUuid eventsID(const QString &key) const;
+
+ virtual QUuid typeLibID() const;
+ virtual QUuid appID() const;
+
+ virtual void registerClass(const QString &key, QSettings *) const;
+ virtual void unregisterClass(const QString &key, QSettings *) const;
+
+ virtual bool validateLicenseKey(const QString &key, const QString &licenseKey) const;
+
+ virtual QString exposeToSuperClass(const QString &key) const;
+ virtual bool stayTopLevel(const QString &key) const;
+ virtual bool hasStockEvents(const QString &key) const;
+ virtual bool isService() const;
+
+ enum ServerType {
+ SingleInstance,
+ MultipleInstances
+ };
+
+ static bool isServer();
+ static QString serverDirPath();
+ static QString serverFilePath();
+ static bool startServer(ServerType type = MultipleInstances);
+ static bool stopServer();
+
+ static bool registerActiveObject(QObject *object);
+
+private:
+ QUuid typelib;
+ QUuid app;
+};
+
+extern QAxFactory *qAxFactory();
+
+extern bool qax_startServer(QAxFactory::ServerType);
+
+inline bool QAxFactory::startServer(ServerType type)
+{
+ // implementation in qaxservermain.cpp
+ return qax_startServer(type);
+}
+
+extern bool qax_stopServer();
+
+inline bool QAxFactory::stopServer()
+{
+ // implementation in qaxservermain.cpp
+ return qax_stopServer();
+}
+
+#define QAXFACTORY_EXPORT(IMPL, TYPELIB, APPID) \
+ QT_BEGIN_NAMESPACE \
+ QAxFactory *qax_instantiate() \
+ { \
+ IMPL *impl = new IMPL(QUuid(TYPELIB), QUuid(APPID)); \
+ return impl; \
+ } \
+ QT_END_NAMESPACE
+
+#define QAXFACTORY_DEFAULT(Class, IIDClass, IIDInterface, IIDEvents, IIDTypeLib, IIDApp) \
+ QT_BEGIN_NAMESPACE \
+ class QAxDefaultFactory : public QAxFactory \
+ { \
+ public: \
+ QAxDefaultFactory(const QUuid &app, const QUuid &lib) \
+ : QAxFactory(app, lib), className(QLatin1String(#Class)) {} \
+ QStringList featureList() const \
+ { \
+ QStringList list; \
+ list << className; \
+ return list; \
+ } \
+ const QMetaObject *metaObject(const QString &key) const \
+ { \
+ if (key == className) \
+ return &Class::staticMetaObject; \
+ return 0; \
+ } \
+ QObject *createObject(const QString &key) \
+ { \
+ if (key == className) \
+ return new Class(0); \
+ return 0; \
+ } \
+ QUuid classID(const QString &key) const \
+ { \
+ if (key == className) \
+ return QUuid(IIDClass); \
+ return QUuid(); \
+ } \
+ QUuid interfaceID(const QString &key) const \
+ { \
+ if (key == className) \
+ return QUuid(IIDInterface); \
+ return QUuid(); \
+ } \
+ QUuid eventsID(const QString &key) const \
+ { \
+ if (key == className) \
+ return QUuid(IIDEvents); \
+ return QUuid(); \
+ } \
+ private: \
+ QString className; \
+ }; \
+ QT_END_NAMESPACE \
+ QAXFACTORY_EXPORT(QAxDefaultFactory, IIDTypeLib, IIDApp) \
+
+template<class T>
+class QAxClass : public QAxFactory
+{
+public:
+ QAxClass(const QString &libId, const QString &appId)
+ : QAxFactory(libId, appId)
+ {}
+
+ const QMetaObject *metaObject(const QString &) const { return &T::staticMetaObject; }
+ QStringList featureList() const { return QStringList(QString(T::staticMetaObject.className())); }
+ QObject *createObject(const QString &key)
+ {
+ const QMetaObject &mo = T::staticMetaObject;
+ if (key != QLatin1String(mo.className()))
+ return 0;
+ if (!qstrcmp(mo.classInfo(mo.indexOfClassInfo("Creatable")).value(), "no"))
+ return 0;
+ return new T(0);
+ }
+};
+
+#define QAXFACTORY_BEGIN(IDTypeLib, IDApp) \
+ QT_BEGIN_NAMESPACE \
+ class QAxFactoryList : public QAxFactory \
+ { \
+ QStringList factoryKeys; \
+ QHash<QString, QAxFactory*> factories; \
+ QHash<QString, bool> creatable; \
+ public: \
+ QAxFactoryList() \
+ : QAxFactory(IDTypeLib, IDApp) \
+ { \
+ QAxFactory *factory = 0; \
+ QStringList keys; \
+ QStringList::Iterator it; \
+
+#define QAXCLASS(Class) \
+ factory = new QAxClass<Class>(typeLibID(), appID()); \
+ qRegisterMetaType<Class*>(#Class"*"); \
+ keys = factory->featureList(); \
+ for (it = keys.begin(); it != keys.end(); ++it) { \
+ factoryKeys += *it; \
+ factories.insert(*it, factory); \
+ creatable.insert(*it, true); \
+ }\
+
+#define QAXTYPE(Class) \
+ factory = new QAxClass<Class>(typeLibID(), appID()); \
+ qRegisterMetaType<Class*>(#Class"*"); \
+ keys = factory->featureList(); \
+ for (it = keys.begin(); it != keys.end(); ++it) { \
+ factoryKeys += *it; \
+ factories.insert(*it, factory); \
+ creatable.insert(*it, false); \
+ }\
+
+#define QAXFACTORY_END() \
+ } \
+ ~QAxFactoryList() { qDeleteAll(factories); } \
+ QStringList featureList() const { return factoryKeys; } \
+ const QMetaObject *metaObject(const QString&key) const { \
+ QAxFactory *f = factories[key]; \
+ return f ? f->metaObject(key) : 0; \
+ } \
+ QObject *createObject(const QString &key) { \
+ if (!creatable.value(key)) \
+ return 0; \
+ QAxFactory *f = factories[key]; \
+ return f ? f->createObject(key) : 0; \
+ } \
+ QUuid classID(const QString &key) { \
+ QAxFactory *f = factories.value(key); \
+ return f ? f->classID(key) : QUuid(); \
+ } \
+ QUuid interfaceID(const QString &key) { \
+ QAxFactory *f = factories.value(key); \
+ return f ? f->interfaceID(key) : QUuid(); \
+ } \
+ QUuid eventsID(const QString &key) { \
+ QAxFactory *f = factories.value(key); \
+ return f ? f->eventsID(key) : QUuid(); \
+ } \
+ void registerClass(const QString &key, QSettings *s) const { \
+ QAxFactory *f = factories.value(key); \
+ if (f) f->registerClass(key, s); \
+ } \
+ void unregisterClass(const QString &key, QSettings *s) const { \
+ QAxFactory *f = factories.value(key); \
+ if (f) f->unregisterClass(key, s); \
+ } \
+ QString exposeToSuperClass(const QString &key) const { \
+ QAxFactory *f = factories.value(key); \
+ return f ? f->exposeToSuperClass(key) : QString(); \
+ } \
+ bool stayTopLevel(const QString &key) const { \
+ QAxFactory *f = factories.value(key); \
+ return f ? f->stayTopLevel(key) : false; \
+ } \
+ bool hasStockEvents(const QString &key) const { \
+ QAxFactory *f = factories.value(key); \
+ return f ? f->hasStockEvents(key) : false; \
+ } \
+ }; \
+ QAxFactory *qax_instantiate() \
+ { \
+ QAxFactoryList *impl = new QAxFactoryList(); \
+ return impl; \
+ } \
+ QT_END_NAMESPACE
+
+QT_END_NAMESPACE
+
+#ifndef Q_COM_METATYPE_DECLARED
+#define Q_COM_METATYPE_DECLARED
+
+Q_DECLARE_METATYPE(IUnknown*)
+Q_DECLARE_METATYPE(IDispatch*)
+
+#endif
+
+#endif // QT_NO_WIN_ACTIVEQT
+
+QT_END_HEADER
+
+#endif // QAXFACTORY_H
diff --git a/src/activeqt/control/qaxmain.cpp b/src/activeqt/control/qaxmain.cpp
new file mode 100644
index 0000000..27ab052
--- /dev/null
+++ b/src/activeqt/control/qaxmain.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** 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 <qapplication.h>
+#include <qaxfactory.h>
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+int main(int argc, char **argv)
+{
+ QT_USE_NAMESPACE
+ QAxFactory::startServer();
+ QApplication app(argc, argv);
+ app.setQuitOnLastWindowClosed(false);
+
+ return app.exec();
+}
+#endif // QT_NO_WIN_ACTIVEQT
diff --git a/src/activeqt/control/qaxserver.cpp b/src/activeqt/control/qaxserver.cpp
new file mode 100644
index 0000000..d919382
--- /dev/null
+++ b/src/activeqt/control/qaxserver.cpp
@@ -0,0 +1,1251 @@
+/****************************************************************************
+**
+** 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 "qaxbindable.h"
+#include "qaxfactory.h"
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+#include <qapplication.h>
+#include <qdatetime.h>
+#include <qdir.h>
+#include <qmap.h>
+#include <qmenubar.h>
+#include <qmetaobject.h>
+#include <qsettings.h>
+#include <qvariant.h>
+#include <qtextstream.h>
+
+#include <qt_windows.h>
+#include <olectl.h>
+
+QT_BEGIN_NAMESPACE
+
+#define Q_REQUIRED_RPCNDR_H_VERSION 475
+
+// Some global variables to store module information
+bool qAxIsServer = false;
+HANDLE qAxInstance = 0;
+ITypeLib *qAxTypeLibrary = 0;
+char qAxModuleFilename[MAX_PATH];
+bool qAxOutProcServer = false;
+
+// The QAxFactory instance
+static QAxFactory* qax_factory = 0;
+extern CLSID CLSID_QRect;
+extern CLSID CLSID_QSize;
+extern CLSID CLSID_QPoint;
+extern void qax_shutDown();
+extern bool qax_ownQApp;
+
+
+extern QAxFactory *qax_instantiate();
+
+QAxFactory *qAxFactory()
+{
+ if (!qax_factory) {
+ bool hadQApp = qApp != 0;
+ qax_factory = qax_instantiate();
+ // QAxFactory created a QApplication
+ if (!hadQApp && qApp)
+ qax_ownQApp = true;
+
+ // register all types with metatype system as pointers
+ QStringList keys(qax_factory->featureList());
+ for (int i = 0; i < keys.count(); ++i) {
+ QString key(keys.at(i));
+ qRegisterMetaType((key + QLatin1String("*")).toLatin1(), (void**)0);
+ }
+ }
+ return qax_factory;
+}
+
+// Some local variables to handle module lifetime
+static unsigned long qAxModuleRef = 0;
+static CRITICAL_SECTION qAxModuleSection;
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Server control
+/////////////////////////////////////////////////////////////////////////////
+
+static int initCount = 0;
+
+QString qAxInit()
+{
+ static QString libFile;
+
+ if (initCount++)
+ return libFile;
+
+ InitializeCriticalSection(&qAxModuleSection);
+
+ libFile = QString::fromLocal8Bit(qAxModuleFilename);
+ libFile = libFile.toLower();
+ if (LoadTypeLibEx((TCHAR*)libFile.utf16(), REGKIND_NONE, &qAxTypeLibrary) == S_OK)
+ return libFile;
+
+ int lastDot = libFile.lastIndexOf(QLatin1Char('.'));
+ libFile = libFile.left(lastDot) + QLatin1String(".tlb");
+ if (LoadTypeLibEx((TCHAR*)libFile.utf16(), REGKIND_NONE, &qAxTypeLibrary) == S_OK)
+ return libFile;
+
+ lastDot = libFile.lastIndexOf(QLatin1Char('.'));
+ libFile = libFile.left(lastDot) + QLatin1String(".olb");
+ if (LoadTypeLibEx((TCHAR*)libFile.utf16(), REGKIND_NONE, &qAxTypeLibrary) == S_OK)
+ return libFile;
+
+ libFile = QString();
+ return libFile;
+}
+
+void qAxCleanup()
+{
+ if (!initCount)
+ qWarning("qAxInit/qAxCleanup mismatch");
+
+ if (--initCount)
+ return;
+
+ delete qax_factory;
+ qax_factory = 0;
+
+ if (qAxTypeLibrary) {
+ qAxTypeLibrary->Release();
+ qAxTypeLibrary = 0;
+ }
+
+ DeleteCriticalSection(&qAxModuleSection);
+}
+
+unsigned long qAxLock()
+{
+ EnterCriticalSection(&qAxModuleSection);
+ unsigned long ref = ++qAxModuleRef;
+ LeaveCriticalSection(&qAxModuleSection);
+ return ref;
+}
+
+unsigned long qAxUnlock()
+{
+ if (!initCount) // cleaned up already
+ return 0;
+
+ EnterCriticalSection(&qAxModuleSection);
+ unsigned long ref = --qAxModuleRef;
+ LeaveCriticalSection(&qAxModuleSection);
+
+ if (!ref)
+ qax_shutDown();
+ return ref;
+}
+
+unsigned long qAxLockCount()
+{
+ return qAxModuleRef;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Registry
+/////////////////////////////////////////////////////////////////////////////
+
+extern bool qax_disable_inplaceframe;
+
+QString qax_clean_type(const QString &type, const QMetaObject *mo)
+{
+ if (mo) {
+ int classInfoIdx = mo->indexOfClassInfo("CoClassAlias");
+ if (classInfoIdx != -1) {
+ const QMetaClassInfo classInfo = mo->classInfo(classInfoIdx);
+ return QLatin1String(classInfo.value());
+ }
+ }
+
+ QString alias(type);
+ alias.remove(QLatin1String("::"));
+ return alias;
+}
+
+// (Un)Register the ActiveX server in the registry.
+// The QAxFactory implementation provides the information.
+HRESULT UpdateRegistry(BOOL bRegister)
+{
+ qAxIsServer = false;
+ QString file = QString::fromLocal8Bit(qAxModuleFilename);
+ QString path = file.left(file.lastIndexOf(QLatin1String("\\"))+1);
+ QString module = file.right(file.length() - path.length());
+ module = module.left(module.lastIndexOf(QLatin1String(".")));
+
+ const QString appId = qAxFactory()->appID().toString().toUpper();
+ const QString libId = qAxFactory()->typeLibID().toString().toUpper();
+
+ QString libFile = qAxInit();
+ QString typeLibVersion;
+
+ TLIBATTR *libAttr = 0;
+ if (qAxTypeLibrary)
+ qAxTypeLibrary->GetLibAttr(&libAttr);
+ if (!libAttr)
+ return SELFREG_E_TYPELIB;
+
+ DWORD major = libAttr->wMajorVerNum;
+ DWORD minor = libAttr->wMinorVerNum;
+ typeLibVersion = QString::number((uint)major) + QLatin1String(".") + QString::number((uint)minor);
+
+ if (bRegister)
+ RegisterTypeLib(qAxTypeLibrary, (TCHAR*)libFile.utf16(), 0);
+ else
+ UnRegisterTypeLib(libAttr->guid, libAttr->wMajorVerNum, libAttr->wMinorVerNum, libAttr->lcid, libAttr->syskind);
+
+ qAxTypeLibrary->ReleaseTLibAttr(libAttr);
+
+ if (typeLibVersion.isEmpty())
+ typeLibVersion = QLatin1String("1.0");
+
+ // check whether the user has permission to write to HKLM\Software\Classes
+ // if not, use HKCU\Software\Classes
+ QString keyPath(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes"));
+ QSettings test(keyPath, QSettings::NativeFormat);
+ if (!test.isWritable())
+ keyPath = QLatin1String("HKEY_CURRENT_USER\\Software\\Classes");
+
+ QSettings settings(keyPath, QSettings::NativeFormat);
+
+ // we try to create the ActiveX widgets later on...
+ bool delete_qApp = false;
+ if (!qApp) {
+ int argc = 0;
+ (void)new QApplication(argc, 0);
+ delete_qApp = true;
+ }
+
+ if (bRegister) {
+ if (qAxOutProcServer) {
+ settings.setValue(QLatin1String("/AppID/") + appId + QLatin1String("/."), module);
+ settings.setValue(QLatin1String("/AppID/") + module + QLatin1String(".EXE/AppID"), appId);
+ }
+
+ QStringList keys = qAxFactory()->featureList();
+ for (QStringList::Iterator key = keys.begin(); key != keys.end(); ++key) {
+ QString className = *key;
+ QObject *object = qAxFactory()->createObject(className);
+ const QMetaObject *mo = qAxFactory()->metaObject(className);
+ const QString classId = qAxFactory()->classID(className).toString().toUpper();
+
+ className = qax_clean_type(className, mo);
+
+ if (object) { // don't register subobject classes
+ QString classVersion = mo ? QString(QLatin1String(mo->classInfo(mo->indexOfClassInfo("Version")).value())) : QString();
+ if (classVersion.isNull())
+ classVersion = QLatin1String("1.0");
+ bool insertable = mo && !qstricmp(mo->classInfo(mo->indexOfClassInfo("Insertable")).value(), "yes");
+ bool control = object->isWidgetType();
+ const QString classMajorVersion = classVersion.left(classVersion.indexOf(QLatin1String(".")));
+ uint olemisc = OLEMISC_SETCLIENTSITEFIRST
+ |OLEMISC_ACTIVATEWHENVISIBLE
+ |OLEMISC_INSIDEOUT
+ |OLEMISC_CANTLINKINSIDE
+ |OLEMISC_RECOMPOSEONRESIZE;
+ if (!control)
+ olemisc |= OLEMISC_INVISIBLEATRUNTIME;
+ else if (qFindChild<QMenuBar*>(object) && !qax_disable_inplaceframe)
+ olemisc |= OLEMISC_WANTSTOMENUMERGE;
+
+ settings.setValue(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String(".") + classMajorVersion + QLatin1String("/."), className + QLatin1String(" Class"));
+ settings.setValue(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String(".") + classMajorVersion + QLatin1String("/CLSID/."), classId);
+ if (insertable)
+ settings.setValue(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String(".") + classMajorVersion + QLatin1String("/Insertable/."), QVariant(QLatin1String("")));
+
+ settings.setValue(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String("/."), className + QLatin1String(" Class"));
+ settings.setValue(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String("/CLSID/."), classId);
+ settings.setValue(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String("/CurVer/."), module + QLatin1String(".") + className + QLatin1String(".") + classMajorVersion);
+
+ settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/."), className + QLatin1String(" Class"));
+ if (file.right(3).toLower() == QLatin1String("exe"))
+ settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/AppID"), appId);
+ if (control)
+ settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/Control/."), QVariant(QLatin1String("")));
+ if (insertable)
+ settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/Insertable/."), QVariant(QLatin1String("")));
+ if (file.right(3).toLower() == QLatin1String("dll"))
+ settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/InProcServer32/."), file);
+ else
+ settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/LocalServer32/."),
+ QLatin1String("\"") + file + QLatin1String("\" -activex"));
+ settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/MiscStatus/."), control ? QLatin1String("1") : QLatin1String("0"));
+ settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/MiscStatus/1/."), QString::number(olemisc));
+ settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/Programmable/."), QVariant(QLatin1String("")));
+ settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/ToolboxBitmap32/."), QLatin1String("\"") +
+ file + QLatin1String("\", 101"));
+ settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/TypeLib/."), libId); settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/Version/."), classVersion);
+ settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/VersionIndependentProgID/."), module + QLatin1String(".") + className);
+ settings.setValue(QLatin1String("/CLSID/") + classId + QLatin1String("/ProgID/."), module + QLatin1String(".") + className + QLatin1String(".") + classVersion.left(classVersion.indexOf(QLatin1Char('.'))));
+
+ QString mime = QLatin1String(mo->classInfo(mo->indexOfClassInfo("MIME")).value());
+ if (!mime.isEmpty()) {
+ QStringList mimeTypes = mime.split(QLatin1Char(';'));
+ for (int m = 0; m < mimeTypes.count(); ++m) {
+ mime = mimeTypes.at(m);
+ if (mime.isEmpty())
+ continue;
+ QString extension;
+ while (mime.contains(QLatin1Char(':'))) {
+ extension = mime.mid(mime.lastIndexOf(QLatin1Char(':')) + 1);
+ mime = mime.left(mime.length() - extension.length() - 1);
+ // Prepend '.' before extension, if required.
+ extension = extension.trimmed();
+ if (extension[0] != QChar(QLatin1Char('.')))
+ extension = QLatin1String(".") + extension;
+ }
+
+ if (!extension.isEmpty()) {
+ settings.setValue(QLatin1String("/") + extension + QLatin1String("/."), module + QLatin1String(".") + className);
+ settings.setValue(QLatin1String("/") + extension + QLatin1String("/Content Type"), mime);
+
+ mime = mime.replace(QLatin1String("/"), QLatin1String("\\"));
+ settings.setValue(QLatin1String("/MIME/Database/Content Type/") + mime + QLatin1String("/CLSID"), classId);
+ settings.setValue(QLatin1String("/MIME/Database/Content Type/") + mime + QLatin1String("/Extension"), extension);
+ }
+ }
+ }
+
+ delete object;
+ }
+
+ qAxFactory()->registerClass(*key, &settings);
+ }
+ } else {
+ QStringList keys = qAxFactory()->featureList();
+ for (QStringList::Iterator key = keys.begin(); key != keys.end(); ++key) {
+ QString className = *key;
+ const QMetaObject *mo = qAxFactory()->metaObject(className);
+ const QString classId = qAxFactory()->classID(className).toString().toUpper();
+ className = qax_clean_type(className, mo);
+
+ QString classVersion = mo ? QString(QLatin1String(mo->classInfo(mo->indexOfClassInfo("Version")).value())) : QString();
+ if (classVersion.isNull())
+ classVersion = QLatin1String("1.0");
+ const QString classMajorVersion = classVersion.left(classVersion.indexOf(QLatin1String(".")));
+
+ qAxFactory()->unregisterClass(*key, &settings);
+
+ settings.remove(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String(".") + classMajorVersion + QLatin1String("/CLSID/."));
+ settings.remove(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String(".") + classMajorVersion + QLatin1String("/Insertable/."));
+ settings.remove(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String(".") + classMajorVersion + QLatin1String("/."));
+ settings.remove(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String(".") + classMajorVersion);
+
+ settings.remove(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String("/CLSID/."));
+ settings.remove(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String("/CurVer/."));
+ settings.remove(QLatin1String("/") + module + QLatin1String(".") + className + QLatin1String("/."));
+ settings.remove(QLatin1String("/") + module + QLatin1String(".") + className);
+
+ settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/AppID"));
+ settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/Control/."));
+ settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/Insertable/."));
+ settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/InProcServer32/."));
+ settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/LocalServer32/."));
+ settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/MiscStatus/1/."));
+ settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/MiscStatus/."));
+ settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/Programmable/."));
+ settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/ToolboxBitmap32/."));
+ settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/TypeLib/."));
+ settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/Version/."));
+ settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/VersionIndependentProgID/."));
+ settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/ProgID/."));
+ settings.remove(QLatin1String("/CLSID/") + classId + QLatin1String("/."));
+ settings.remove(QLatin1String("/CLSID/") + classId);
+
+ QString mime = QLatin1String(mo->classInfo(mo->indexOfClassInfo("MIME")).value());
+ if (!mime.isEmpty()) {
+ QStringList mimeTypes = mime.split(QLatin1Char(';'));
+ for (int m = 0; m < mimeTypes.count(); ++m) {
+ mime = mimeTypes.at(m);
+ if (mime.isEmpty())
+ continue;
+ QString extension;
+ while (mime.contains(QLatin1Char(':'))) {
+ extension = mime.mid(mime.lastIndexOf(QLatin1Char(':')) + 1);
+ mime = mime.left(mime.length() - extension.length() - 1);
+ // Prepend '.' before extension, if required.
+ extension = extension.trimmed();
+ if (extension[0] != QChar(QLatin1Char('.')))
+ extension = QLatin1String(".") + extension;
+ }
+ if (!extension.isEmpty()) {
+ settings.remove(QLatin1String("/") + extension + QLatin1String("/Content Type"));
+ settings.remove(QLatin1String("/") + extension + QLatin1String("/."));
+ settings.remove(QLatin1String("/") + extension);
+ mime = mime.replace(QLatin1String("/"), QLatin1String("\\"));
+ settings.remove(QLatin1String("/MIME/Database/Content Type/") + mime + QLatin1String("/Extension"));
+ settings.remove(QLatin1String("/MIME/Database/Content Type/") + mime + QLatin1String("/CLSID"));
+ settings.remove(QLatin1String("/MIME/Database/Content Type/") + mime + QLatin1String("/."));
+ settings.remove(QLatin1String("/MIME/Database/Content Type/") + mime);
+ }
+ }
+ }
+ }
+ }
+
+ if (delete_qApp)
+ delete qApp;
+
+ qAxCleanup();
+ if (settings.status() == QSettings::NoError)
+ return S_OK;
+ return SELFREG_E_CLASS;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// IDL generator
+/////////////////////////////////////////////////////////////////////////////
+
+static QList<QByteArray> enums;
+static QList<QByteArray> enumValues;
+static QList<QByteArray> subtypes;
+
+static const char* const type_map[][2] =
+{
+ // QVariant/Qt Value data types
+ { "QString", "BSTR" },
+ { "QCString", "BSTR" },
+ { "bool", "VARIANT_BOOL" },
+ { "int", "int" },
+ { "uint", "unsigned int" },
+ { "double", "double" },
+ { "QColor", "OLE_COLOR" },
+ { "QDate", "DATE" },
+ { "QTime", "DATE" },
+ { "QDateTime", "DATE" },
+ { "QFont", "IFontDisp*" },
+ { "QPixmap", "IPictureDisp*" },
+ { "QVariant", "VARIANT" },
+ { "QVariantList", "SAFEARRAY(VARIANT)" },
+ { "QList<QVariant>","SAFEARRAY(VARIANT)" },
+ { "quint64", "CY" },
+ { "qint64", "CY" },
+ { "qulonglong", "CY" },
+ { "qlonglong", "CY" },
+ { "QByteArray", "SAFEARRAY(BYTE)" },
+ { "QStringList", "SAFEARRAY(BSTR)" },
+ // Userdefined Qt datatypes - some not on Borland though
+ { "QCursor", "enum MousePointer" },
+ { "Qt::FocusPolicy","enum FocusPolicy" },
+#ifndef Q_CC_BOR
+# if __REQUIRED_RPCNDR_H_VERSION__ >= Q_REQUIRED_RPCNDR_H_VERSION
+ { "QRect", "struct QRect" },
+ { "QSize", "struct QSize" },
+ { "QPoint", "struct QPoint" },
+# endif
+#endif
+ // And we support COM data types
+ { "BOOL", "BOOL" },
+ { "BSTR", "BSTR" },
+ { "OLE_COLOR", "OLE_COLOR" },
+ { "DATE", "DATE" },
+ { "VARIANT", "VARIANT" },
+ { "IDispatch", "IDispatch*" },
+ { "IUnknown", "IUnknown*" },
+ { "IDispatch*", "IDispatch*" },
+ { "IUnknown*", "IUnknown*" },
+ { 0, 0 }
+};
+
+static QByteArray convertTypes(const QByteArray &qtype, bool *ok)
+{
+ qRegisterMetaType("IDispatch*", (void**)0);
+ qRegisterMetaType("IUnknown*", (void**)0);
+
+ *ok = false;
+
+ int i = 0;
+ while (type_map[i][0]) {
+ if (qtype == type_map[i][0] && type_map[i][1]) {
+ *ok = true;
+ return type_map[i][1];
+ }
+ ++i;
+ }
+ if (enums.contains(qtype)) {
+ *ok = true;
+ return "enum " + qtype;
+ }
+ if (subtypes.contains(qtype)) {
+ *ok = true;
+ } else if (qtype.endsWith('*')) {
+ QByteArray cleanType = qtype.left(qtype.length() - 1);
+ const QMetaObject *mo = qAxFactory()->metaObject(QString::fromLatin1(cleanType.constData()));
+ if (mo) {
+ cleanType = qax_clean_type(QString::fromLatin1(cleanType), mo).toLatin1();
+ if (subtypes.contains(cleanType)) {
+ *ok = true;
+ return cleanType + '*';
+ }
+ }
+ }
+ return qtype;
+}
+
+static const char* const keyword_map[][2] =
+{
+ { "aggregatable", "aggregating" },
+ { "allocate", "alloc" },
+ { "appobject", "appObject" },
+ { "arrays", "array" },
+ { "async", "asynchronous" },
+ { "bindable", "binding" },
+ { "Boolean", "boolval" },
+ { "boolean", "boolval" },
+ { "broadcast", "broadCast" },
+ { "callback", "callBack" },
+ { "decode", "deCode" },
+ { "default", "defaulted" },
+ { "defaultbind", "defaultBind" },
+ { "defaultvalue", "defaultValue" },
+ { "encode" "enCode" },
+ { "endpoint", "endPoint" },
+ { "hidden", "isHidden" },
+ { "ignore", "ignore_" },
+ { "local", "local_" },
+ { "notify", "notify_" },
+ { "object", "object_" },
+ { "optimize", "optimize_" },
+ { "optional", "optional_" },
+ { "out", "out_" },
+ { "pipe", "pipe_" },
+ { "proxy", "proxy_" },
+ { "ptr", "pointer" },
+ { "readonly", "readOnly" },
+ { "small", "small_" },
+ { "source", "source_" },
+ { "string", "string_" },
+ { "uuid", "uuid_" },
+ { 0, 0 }
+};
+
+static QByteArray replaceKeyword(const QByteArray &name)
+{
+ int i = 0;
+ while (keyword_map[i][0]) {
+ if (name == keyword_map[i][0] && keyword_map[i][1])
+ return keyword_map[i][1];
+ ++i;
+ }
+ return name;
+}
+
+static QMap<QByteArray, int> mapping;
+
+static QByteArray renameOverloads(const QByteArray &name)
+{
+ QByteArray newName = name;
+
+ int n = mapping.value(name);
+ if (mapping.contains(name)) {
+ int n = mapping.value(name);
+ newName = name + "_" + QByteArray::number(n);
+ mapping.insert(name, n+1);
+ } else {
+ mapping.insert(name, 1);
+ }
+
+ return newName;
+}
+
+// filter out some properties
+static const char* const ignore_props[] =
+{
+ "name",
+ "objectName",
+ "isTopLevel",
+ "isDialog",
+ "isModal",
+ "isPopup",
+ "isDesktop",
+ "geometry",
+ "pos",
+ "frameSize",
+ "frameGeometry",
+ "size",
+ "sizeHint",
+ "minimumSizeHint",
+ "microFocusHint",
+ "rect",
+ "childrenRect",
+ "childrenRegion",
+ "minimumSize",
+ "maximumSize",
+ "sizeIncrement",
+ "baseSize",
+ "ownPalette",
+ "ownFont",
+ "ownCursor",
+ "visibleRect",
+ "isActiveWindow",
+ "underMouse",
+ "visible",
+ "hidden",
+ "minimized",
+ "focus",
+ "focusEnabled",
+ "customWhatsThis",
+ "shown",
+ "windowOpacity",
+ 0
+};
+
+// filter out some slots
+static const char* const ignore_slots[] =
+{
+ "deleteLater",
+ "setMouseTracking",
+ "update",
+ "repaint",
+ "iconify",
+ "showMinimized",
+ "showMaximized",
+ "showFullScreen",
+ "showNormal",
+ "polish",
+ "constPolish",
+ "stackUnder",
+ "setShown",
+ "setHidden",
+ "move_1",
+ "resize_1",
+ "setGeometry_1",
+ 0
+};
+
+static bool ignore(const char *test, const char *const *table)
+{
+ if (!test)
+ return true;
+ int i = 0;
+ while (table[i]) {
+ if (!strcmp(test, table[i]))
+ return true;
+ ++i;
+ }
+ return false;
+}
+
+bool ignoreSlots(const char *test)
+{
+ return ignore(test, ignore_slots);
+}
+
+bool ignoreProps(const char *test)
+{
+ return ignore(test, ignore_props);
+}
+
+#define STRIPCB(x) x = x.mid(1, x.length()-2)
+
+static QByteArray prototype(const QList<QByteArray> &parameterTypes, const QList<QByteArray> &parameterNames, bool *ok)
+{
+ QByteArray prototype;
+
+ for (int p = 0; p < parameterTypes.count() && *ok; ++p) {
+ bool out = false;
+ QByteArray type(parameterTypes.at(p));
+ QByteArray name(parameterNames.at(p));
+
+ if (type.endsWith("&")) {
+ out = true;
+ type.truncate(type.length() - 1);
+ } else if (type.endsWith("**")) {
+ out = true;
+ type.truncate(type.length() - 1);
+ } else if (type.endsWith("*") && !subtypes.contains(type)) {
+ type.truncate(type.length() - 1);
+ }
+ if (type.isEmpty()) {
+ *ok = false;
+ break;
+ }
+ type = convertTypes(type, ok);
+ if (!out)
+ prototype += "[in] " + type + " ";
+ else
+ prototype += "[in,out] " + type + " ";
+
+ if (out)
+ prototype += "*";
+ if (name.isEmpty())
+ prototype += "p" + QByteArray::number(p);
+ else
+ prototype += "p_" + replaceKeyword(name);
+
+ if (p < parameterTypes.count() - 1)
+ prototype += ", ";
+ }
+
+ return prototype;
+}
+
+static QByteArray addDefaultArguments(const QByteArray &prototype, int numDefArgs)
+{
+ // nothing to do, or unsupported anyway
+ if (!numDefArgs || prototype.contains("/**"))
+ return prototype;
+
+ QByteArray ptype(prototype);
+ int in = -1;
+ while (numDefArgs) {
+ in = ptype.lastIndexOf("]", in);
+ ptype.replace(in, 1, ",optional]");
+ in = ptype.indexOf(' ', in) + 1;
+ QByteArray type = ptype.mid(in, ptype.indexOf(' ', in) - in);
+ if (type == "enum")
+ type += " " + ptype.mid(in + 5, ptype.indexOf(' ', in + 5) - in - 5);
+ ptype.replace(in, type.length(), QByteArray("VARIANT /*was: ") + type + "*/");
+ --numDefArgs;
+ }
+
+ return ptype;
+}
+
+static HRESULT classIDL(QObject *o, const QMetaObject *mo, const QString &className, bool isBindable, QTextStream &out)
+{
+ int id = 1;
+ int i = 0;
+ if (!mo)
+ return 3;
+
+ QString topclass = qAxFactory()->exposeToSuperClass(className);
+ if (topclass.isEmpty())
+ topclass = QLatin1String("QObject");
+ bool hasStockEvents = qAxFactory()->hasStockEvents(className);
+
+ const QMetaObject *pmo = mo;
+ do {
+ pmo = pmo->superClass();
+ } while (pmo && topclass != QString::fromLatin1(pmo->className()));
+
+ int enumoff = pmo ? pmo->enumeratorOffset() : mo->enumeratorOffset();
+ int methodoff = pmo ? pmo->methodOffset() : mo->methodOffset();
+ int propoff = pmo ? pmo->propertyOffset() : mo->propertyOffset();
+
+ int qtProps = 0;
+ int qtSlots = 0;
+
+ bool control = false;
+
+ if (o && o->isWidgetType()) {
+ qtProps = QWidget::staticMetaObject.propertyCount();
+ qtSlots = QWidget::staticMetaObject.methodCount();
+ control = true;
+ }
+
+ QString classID = qAxFactory()->classID(className).toString().toUpper();
+ if (QUuid(classID).isNull())
+ return 4;
+ STRIPCB(classID);
+ QString interfaceID = qAxFactory()->interfaceID(className).toString().toUpper();
+ if (QUuid(interfaceID).isNull())
+ return 5;
+ STRIPCB(interfaceID);
+ QString eventsID = qAxFactory()->eventsID(className).toString().toUpper();
+ bool hasEvents = !QUuid(eventsID).isNull();
+ STRIPCB(eventsID);
+
+ QString cleanClassName = qax_clean_type(className, mo);
+ QString defProp(QLatin1String(mo->classInfo(mo->indexOfClassInfo("DefaultProperty")).value()));
+ QString defSignal(QLatin1String(mo->classInfo(mo->indexOfClassInfo("DefaultSignal")).value()));
+
+ for (i = enumoff; i < mo->enumeratorCount(); ++i) {
+ const QMetaEnum enumerator = mo->enumerator(i);
+ if (enums.contains(enumerator.name()))
+ continue;
+
+ enums.append(enumerator.name());
+
+ out << "\tenum " << enumerator.name() << " {" << endl;
+
+ for (int j = 0; j < enumerator.keyCount(); ++j) {
+ QByteArray key(enumerator.key(j));
+ while (enumValues.contains(key)) {
+ key += "_";
+ }
+ enumValues.append(key);
+ uint value = (uint)enumerator.value(j);
+ key = key.leftJustified(20);
+ out << "\t\t" << key << "\t= ";
+ if (enumerator.isFlag())
+ out << "0x" << QByteArray::number(value, 16).rightJustified(8, '0');
+ else
+ out << value;
+ if (j < enumerator.keyCount()-1)
+ out << ", ";
+ out << endl;
+ }
+ out << "\t};" << endl << endl;
+ }
+
+ // mouse cursor enum for QCursor support
+ if (!enums.contains("MousePointer")) {
+ enums.append("MousePointer");
+ out << "\tenum MousePointer {" << endl;
+ out << "\t\tArrowCursor = " << Qt::ArrowCursor << "," << endl;
+ out << "\t\tUpArrowCursor = " << Qt::UpArrowCursor << "," << endl;
+ out << "\t\tCrossCursor = " << Qt::CrossCursor << "," << endl;
+ out << "\t\tWaitCursor = " << Qt::WaitCursor << "," << endl;
+ out << "\t\tIBeamCursor = " << Qt::IBeamCursor << "," << endl;
+ out << "\t\tSizeVerCursor = " << Qt::SizeVerCursor << "," << endl;
+ out << "\t\tSizeHorCursor = " << Qt::SizeHorCursor << "," << endl;
+ out << "\t\tSizeBDiagCursor = " << Qt::SizeBDiagCursor << "," << endl;
+ out << "\t\tSizeFDiagCursor = " << Qt::SizeFDiagCursor << "," << endl;
+ out << "\t\tSizeAllCursor = " << Qt::SizeAllCursor << "," << endl;
+ out << "\t\tBlankCursor = " << Qt::BlankCursor << "," << endl;
+ out << "\t\tSplitVCursor = " << Qt::SplitVCursor << "," << endl;
+ out << "\t\tSplitHCursor = " << Qt::SplitHCursor << "," << endl;
+ out << "\t\tPointingHandCursor = " << Qt::PointingHandCursor << "," << endl;
+ out << "\t\tForbiddenCursor = " << Qt::ForbiddenCursor << "," << endl;
+ out << "\t\tWhatsThisCursor = " << Qt::WhatsThisCursor << "," << endl;
+ out << "\t\tBusyCursor\t= " << Qt::BusyCursor << endl;
+ out << "\t};" << endl << endl;
+ }
+ if (!enums.contains("FocusPolicy")) {
+ enums.append("FocusPolicy");
+ out << "\tenum FocusPolicy {" << endl;
+ out << "\t\tNoFocus = " << Qt::NoFocus << "," << endl;
+ out << "\t\tTabFocus = " << Qt::TabFocus << "," << endl;
+ out << "\t\tClickFocus = " << Qt::ClickFocus << "," << endl;
+ out << "\t\tStrongFocus = " << Qt::StrongFocus << "," << endl;
+ out << "\t\tWheelFocus = " << Qt::WheelFocus << endl;
+ out << "\t};" << endl << endl;
+ }
+
+ out << endl;
+ out << "\t[" << endl;
+ out << "\t\tuuid(" << interfaceID << ")," << endl;
+ out << "\t\thelpstring(\"" << cleanClassName << " Interface\")" << endl;
+ out << "\t]" << endl;
+ out << "\tdispinterface I" << cleanClassName << endl;
+ out << "\t{" << endl;
+
+ out << "\tproperties:" << endl;
+ for (i = propoff; i < mo->propertyCount(); ++i) {
+ const QMetaProperty property = mo->property(i);
+ /* if (property.testFlags(QMetaProperty::Override))
+ continue;*/
+ if (i <= qtProps && ignoreProps(property.name()))
+ continue;
+ if (!property.name() || mo->indexOfProperty(property.name()) > i)
+ continue;
+
+ bool ok = true;
+ QByteArray type(convertTypes(property.typeName(), &ok));
+ QByteArray name(replaceKeyword(property.name()));
+
+ if (!ok)
+ out << "\t/****** Property is of unsupported datatype" << endl;
+
+ out << "\t\t[id(" << id << ")";
+ if (!property.isWritable())
+ out << ", readonly";
+ if (isBindable && property.isScriptable(o))
+ out << ", bindable";
+ if (!property.isDesignable(o))
+ out << ", nonbrowsable";
+ if (isBindable)
+ out << ", requestedit";
+ if (defProp == QString::fromLatin1(name.constData()))
+ out << ", uidefault";
+ out << "] " << type << " " << name << ";" << endl;
+
+ if (!ok)
+ out << "\t******/" << endl;
+ ++id;
+ }
+ out << endl;
+ out << "\tmethods:" << endl;
+ int numDefArgs = 0;
+ QByteArray outBuffer;
+ for (i = methodoff; i < mo->methodCount(); ++i) {
+ const QMetaMethod slot = mo->method(i);
+ if (slot.access() != QMetaMethod::Public || slot.methodType() == QMetaMethod::Signal)
+ continue;
+
+ if (slot.attributes() & QMetaMethod::Cloned) {
+ ++numDefArgs;
+ continue;
+ }
+ if (!outBuffer.isEmpty()) {
+ outBuffer = addDefaultArguments(outBuffer, numDefArgs);
+ numDefArgs = 0;
+ out << outBuffer;
+ outBuffer = QByteArray();
+ }
+
+ QByteArray signature(slot.signature());
+ QByteArray name(signature.left(signature.indexOf('(')));
+ if (i <= qtSlots && ignoreSlots(name))
+ continue;
+
+ signature = signature.mid(name.length() + 1);
+ signature.truncate(signature.length() - 1);
+ name = renameOverloads(replaceKeyword(name));
+ if (ignoreSlots(name))
+ continue;
+
+ QList<QByteArray> parameterTypes(slot.parameterTypes());
+ QList<QByteArray> parameterNames(slot.parameterNames());
+
+ bool ok = true;
+ QByteArray type = slot.typeName();
+ if (type.isEmpty())
+ type = "void";
+ else
+ type = convertTypes(type, &ok);
+
+ QByteArray ptype(prototype(parameterTypes, parameterNames, &ok));
+ if (!ok)
+ outBuffer += "\t/****** Slot parameter uses unsupported datatype\n";
+
+ outBuffer += "\t\t[id(" + QString::number(id).toLatin1() + ")] " + type + " " + name + "(" + ptype + ");\n";
+
+ if (!ok)
+ outBuffer += "\t******/\n";
+ ++id;
+ }
+ if (!outBuffer.isEmpty()) {
+ outBuffer = addDefaultArguments(outBuffer, numDefArgs);
+ numDefArgs = 0;
+ out << outBuffer;
+ outBuffer = QByteArray();
+ }
+ out << "\t};" << endl << endl;
+
+ mapping.clear();
+ id = 1;
+
+ if (hasEvents) {
+ out << "\t[" << endl;
+ out << "\t\tuuid(" << eventsID << ")," << endl;
+ out << "\t\thelpstring(\"" << cleanClassName << " Events Interface\")" << endl;
+ out << "\t]" << endl;
+ out << "\tdispinterface I" << cleanClassName << "Events" << endl;
+ out << "\t{" << endl;
+ out << "\tproperties:" << endl;
+ out << "\tmethods:" << endl;
+
+ if (hasStockEvents) {
+ out << "\t/****** Stock events ******/" << endl;
+ out << "\t\t[id(DISPID_CLICK)] void Click();" << endl;
+ out << "\t\t[id(DISPID_DBLCLICK)] void DblClick();" << endl;
+ out << "\t\t[id(DISPID_KEYDOWN)] void KeyDown(short* KeyCode, short Shift);" << endl;
+ out << "\t\t[id(DISPID_KEYPRESS)] void KeyPress(short* KeyAscii);" << endl;
+ out << "\t\t[id(DISPID_KEYUP)] void KeyUp(short* KeyCode, short Shift);" << endl;
+ out << "\t\t[id(DISPID_MOUSEDOWN)] void MouseDown(short Button, short Shift, OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);" << endl;
+ out << "\t\t[id(DISPID_MOUSEMOVE)] void MouseMove(short Button, short Shift, OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);" << endl;
+ out << "\t\t[id(DISPID_MOUSEUP)] void MouseUp(short Button, short Shift, OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);" << endl << endl;
+ }
+
+ for (i = methodoff; i < mo->methodCount(); ++i) {
+ const QMetaMethod signal = mo->method(i);
+ if (signal.methodType() != QMetaMethod::Signal)
+ continue;
+
+ QByteArray signature(signal.signature());
+ QByteArray name(signature.left(signature.indexOf('(')));
+ signature = signature.mid(name.length() + 1);
+ signature.truncate(signature.length() - 1);
+
+ QList<QByteArray> parameterTypes(signal.parameterTypes());
+ QList<QByteArray> parameterNames(signal.parameterNames());
+
+ bool isDefault = defSignal == QString::fromLatin1(name.constData());
+ name = renameOverloads(replaceKeyword(name));
+ bool ok = true;
+
+ QByteArray type = signal.typeName();
+ if (!type.isEmpty()) // signals with return value not supported
+ continue;
+
+ QByteArray ptype(prototype(parameterTypes, parameterNames, &ok));
+ if (!ok)
+ out << "\t/****** Signal parameter uses unsupported datatype" << endl;
+
+ out << "\t\t[id(" << id << ")";
+ if (isDefault)
+ out << ", uidefault";
+ out << "] void " << name << "(" << ptype << ");" << endl;
+
+ if (!ok)
+ out << "\t******/" << endl;
+ ++id;
+ }
+ out << "\t};" << endl << endl;
+ }
+
+ out << "\t[" << endl;
+
+ if (qstricmp(mo->classInfo(mo->indexOfClassInfo("Aggregatable")).value(), "no"))
+ out << "\t\taggregatable," << endl;
+ if (!qstricmp(mo->classInfo(mo->indexOfClassInfo("RegisterObject")).value(), "yes"))
+ out << "\t\tappobject," << endl;
+ if (mo->classInfo(mo->indexOfClassInfo("LicenseKey")).value())
+ out << "\t\tlicensed," << endl;
+ const char *helpString = mo->classInfo(mo->indexOfClassInfo("Description")).value();
+ if (helpString)
+ out << "\t\thelpstring(\"" << helpString << "\")," << endl;
+ else
+ out << "\t\thelpstring(\"" << cleanClassName << " Class\")," << endl;
+ const char *classVersion = mo->classInfo(mo->indexOfClassInfo("Version")).value();
+ if (classVersion)
+ out << "\t\tversion(" << classVersion << ")," << endl;
+ out << "\t\tuuid(" << classID << ")";
+ if (control) {
+ out << ", " << endl;
+ out << "\t\tcontrol";
+ } else if (!o) {
+ out << ", " << endl;
+ out << "\t\tnoncreatable";
+ }
+ out << endl;
+ out << "\t]" << endl;
+ out << "\tcoclass " << cleanClassName << endl;
+ out << "\t{" << endl;
+ out << "\t\t[default] dispinterface I" << cleanClassName << ";" << endl;
+ if (hasEvents)
+ out << "\t\t[default, source] dispinterface I" << cleanClassName << "Events;" << endl;
+ out << "\t};" << endl;
+
+ return S_OK;
+}
+
+#if defined(Q_CC_BOR)
+extern "C" __stdcall HRESULT DumpIDL(const QString &outfile, const QString &ver)
+#else
+extern "C" HRESULT __stdcall DumpIDL(const QString &outfile, const QString &ver)
+#endif
+{
+ qAxIsServer = false;
+ QTextStream out;
+ if (outfile.contains(QLatin1String("\\"))) {
+ QString outpath = outfile.left(outfile.lastIndexOf(QLatin1String("\\")));
+ QDir dir;
+ dir.mkpath(outpath);
+ }
+ QFile file(outfile);
+ file.remove();
+
+ QString filebase = QString::fromLocal8Bit(qAxModuleFilename);
+ filebase = filebase.left(filebase.lastIndexOf(QLatin1String(".")));
+
+ QString appID = qAxFactory()->appID().toString().toUpper();
+ if (QUuid(appID).isNull())
+ return 1;
+ STRIPCB(appID);
+ QString typeLibID = qAxFactory()->typeLibID().toString().toUpper();
+ if (QUuid(typeLibID).isNull())
+ return 2;
+ STRIPCB(typeLibID);
+ QString typelib = filebase.right(filebase.length() - filebase.lastIndexOf(QLatin1String("\\"))-1);
+
+ if (!file.open(QIODevice::WriteOnly))
+ return -1;
+
+ out.setDevice(&file);
+
+ QString version(ver.unicode(), ver.length());
+ while (version.count(QLatin1Char('.')) > 1) {
+ int lastdot = version.lastIndexOf(QLatin1Char('.'));
+ version = version.left(lastdot) + version.right(version.length() - lastdot - 1);
+ }
+ if (version.isEmpty())
+ version = QLatin1String("1.0");
+
+ QString idQRect(QUuid(CLSID_QRect).toString());
+ STRIPCB(idQRect);
+ QString idQSize(QUuid(CLSID_QSize).toString());
+ STRIPCB(idQSize);
+ QString idQPoint(QUuid(CLSID_QPoint).toString());
+ STRIPCB(idQPoint);
+
+ out << "/****************************************************************************" << endl;
+ out << "** Interface definition generated for ActiveQt project" << endl;
+ out << "**" << endl;
+ out << "** '" << qAxModuleFilename << "'" << endl;
+ out << "**" << endl;
+ out << "** Created: " << QDateTime::currentDateTime().toString() << endl;
+ out << "**" << endl;
+ out << "** WARNING! All changes made in this file will be lost!" << endl;
+ out << "****************************************************************************/" << endl << endl;
+
+ out << "import \"ocidl.idl\";" << endl;
+ out << "#include <olectl.h>" << endl << endl;
+
+ // dummy application to create widgets
+ bool delete_qApp = false;
+ if (!qApp) {
+ int argc;
+ (void)new QApplication(argc, 0);
+ delete_qApp = true;
+ }
+
+ out << "[" << endl;
+ out << "\tuuid(" << typeLibID << ")," << endl;
+ out << "\tversion(" << version << ")," << endl;
+ out << "\thelpstring(\"" << typelib << " " << version << " Type Library\")" << endl;
+ out << "]" << endl;
+ out << "library " << typelib << "Lib" << endl;
+ out << "{" << endl;
+ out << "\timportlib(\"stdole32.tlb\");" << endl;
+ out << "\timportlib(\"stdole2.tlb\");" << endl << endl;
+
+ QStringList keys = qAxFactory()->featureList();
+ QStringList::ConstIterator key;
+
+ out << "\t/************************************************************************" << endl;
+ out << "\t** If this causes a compile error in MIDL you need to upgrade the" << endl;
+ out << "\t** Platform SDK you are using. Download the SDK from msdn.microsoft.com" << endl;
+ out << "\t** and make sure that both the system and the Visual Studio environment" << endl;
+ out << "\t** use the correct files." << endl;
+ out << "\t**" << endl;
+
+#ifndef Q_CC_BOR
+#if __REQUIRED_RPCNDR_H_VERSION__ < Q_REQUIRED_RPCNDR_H_VERSION
+ out << "\t** Required version of MIDL could not be verified. QRect, QSize and QPoint" << endl;
+ out << "\t** support needs an updated Platform SDK to be installed." << endl;
+ out << "\t*************************************************************************" << endl;
+#else
+ out << "\t************************************************************************/" << endl;
+#endif
+
+ out << endl;
+ out << "\t[uuid(" << idQRect << ")]" << endl;
+ out << "\tstruct QRect {" << endl;
+ out << "\t\tint left;" << endl;
+ out << "\t\tint top;" << endl;
+ out << "\t\tint right;" << endl;
+ out << "\t\tint bottom;" << endl;
+ out << "\t};" << endl << endl;
+
+ out << "\t[uuid(" << idQSize << ")]" << endl;
+ out << "\tstruct QSize {" << endl;
+ out << "\t\tint width;" << endl;
+ out << "\t\tint height;" << endl;
+ out << "\t};" << endl << endl;
+
+ out << "\t[uuid(" << idQPoint << ")]" << endl;
+ out << "\tstruct QPoint {" << endl;
+ out << "\t\tint x;" << endl;
+ out << "\t\tint y;" << endl;
+ out << "\t};" << endl;
+#if __REQUIRED_RPCNDR_H_VERSION__ < Q_REQUIRED_RPCNDR_H_VERSION
+ out << "\t*/" << endl;
+#endif
+#else
+ out << "\t** Custom data types not supported with Borland." << endl;
+ out << "\t*************************************************************************" << endl;
+#endif
+ out << endl;
+
+ out << "\t/* Forward declaration of classes that might be used as parameters */" << endl << endl;
+
+ int res = S_OK;
+ for (key = keys.begin(); key != keys.end(); ++key) {
+ QByteArray className = (*key).toLatin1();
+ const QMetaObject *mo = qAxFactory()->metaObject(QString::fromLatin1(className.constData()));
+ // We have meta object information for this type. Forward declare it.
+ if (mo) {
+ QByteArray cleanType = qax_clean_type(*key, mo).toLatin1();
+ out << "\tcoclass " << cleanType << ";" << endl;
+ subtypes.append(cleanType);
+ subtypes.append(cleanType + "*");
+ qRegisterMetaType(cleanType, (void**)0);
+ qRegisterMetaType(cleanType + "*", (void**)0);
+ }
+ }
+ out << endl;
+
+ for (key = keys.begin(); key != keys.end(); ++key) {
+ QByteArray className = (*key).toLatin1();
+ const QMetaObject *mo = qAxFactory()->metaObject(QString::fromLatin1(className.constData()));
+ // We have meta object information for this type. Define it.
+ if (mo) {
+ QObject *o = qAxFactory()->createObject(QString::fromLatin1(className.constData()));
+ // It's not a control class, so it is actually a subtype. Define it.
+ if (!o)
+ res = classIDL(0, mo, QString::fromLatin1(className), false, out);
+ delete o;
+ }
+ }
+
+ out << endl;
+ if (res != S_OK)
+ goto ErrorInClass;
+
+ for (key = keys.begin(); key != keys.end(); ++key) {
+ QByteArray className = (*key).toLatin1();
+ QObject *o = qAxFactory()->createObject(QString::fromLatin1(className.constData()));
+ if (!o)
+ continue;
+ const QMetaObject *mo = o->metaObject();
+ QAxBindable *bind = (QAxBindable*)o->qt_metacast("QAxBindable");
+ bool isBindable = bind != 0;
+
+ QByteArray cleanType = qax_clean_type(*key, mo).toLatin1();
+ subtypes.append(cleanType);
+ subtypes.append(cleanType + "*");
+ res = classIDL(o, mo, QString::fromLatin1(className.constData()), isBindable, out);
+ delete o;
+ if (res != S_OK)
+ break;
+ }
+
+ out << "};" << endl;
+ out.flush();
+
+ErrorInClass:
+ if (delete_qApp)
+ delete qApp;
+
+ if (res != S_OK) {
+ file.close();
+ file.remove();
+ }
+
+ return res;
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_WIN_ACTIVEQT
diff --git a/src/activeqt/control/qaxserver.def b/src/activeqt/control/qaxserver.def
new file mode 100644
index 0000000..a00638d
--- /dev/null
+++ b/src/activeqt/control/qaxserver.def
@@ -0,0 +1,8 @@
+; mfc_test.def : Declares the module parameters.
+
+EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
+ DumpIDL PRIVATE
diff --git a/src/activeqt/control/qaxserver.ico b/src/activeqt/control/qaxserver.ico
new file mode 100644
index 0000000..c80d36a
--- /dev/null
+++ b/src/activeqt/control/qaxserver.ico
Binary files differ
diff --git a/src/activeqt/control/qaxserver.rc b/src/activeqt/control/qaxserver.rc
new file mode 100644
index 0000000..390e481
--- /dev/null
+++ b/src/activeqt/control/qaxserver.rc
@@ -0,0 +1,2 @@
+1 TYPELIB "qaxserver.rc"
+1 ICON DISCARDABLE "qaxserver.ico"
diff --git a/src/activeqt/control/qaxserverbase.cpp b/src/activeqt/control/qaxserverbase.cpp
new file mode 100644
index 0000000..f3e1dff
--- /dev/null
+++ b/src/activeqt/control/qaxserverbase.cpp
@@ -0,0 +1,4490 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#define QT_NO_CAST_TO_ASCII
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+#include <qabstracteventdispatcher.h>
+#include <qapplication.h>
+#include <qbuffer.h>
+#include <qdatastream.h>
+#include <qdebug.h>
+#include <qevent.h>
+#include <qeventloop.h>
+#include <qfile.h>
+#include <qpointer.h>
+#include <qhash.h>
+#include <qmap.h>
+#include <qmenubar.h>
+#include <qmenu.h>
+#include <qmetaobject.h>
+#include <qpixmap.h>
+#include <qstatusbar.h>
+#include <qwhatsthis.h>
+#include <ocidl.h>
+#include <olectl.h>
+#include <private/qcoreapplication_p.h>
+
+#include "qaxfactory.h"
+#include "qaxbindable.h"
+#include "qaxaggregated.h"
+
+#include "../shared/qaxtypes.h"
+
+#if defined Q_CC_GNU
+# include <w32api.h>
+#endif
+
+#ifndef Q_OS_WIN64
+#define ULONG_PTR DWORD
+#endif
+
+QT_BEGIN_NAMESPACE
+
+extern HHOOK qax_hhook;
+
+// in qaxserver.cpp
+extern ITypeLib *qAxTypeLibrary;
+extern QAxFactory *qAxFactory();
+extern unsigned long qAxLock();
+extern unsigned long qAxUnlock();
+extern HANDLE qAxInstance;
+extern bool qAxOutProcServer;
+
+static int invokeCount = 0;
+
+#ifdef QT_DEBUG
+unsigned long qaxserverbase_instance_count = 0;
+#endif
+
+// in qaxserverdll.cpp
+extern bool qax_ownQApp;
+
+struct QAxExceptInfo
+{
+ QAxExceptInfo(int c, const QString &s, const QString &d, const QString &x)
+ : code(c), src(s), desc(d), context(x)
+ {
+ }
+ int code;
+ QString src;
+ QString desc;
+ QString context;
+};
+
+
+bool qt_sendSpontaneousEvent(QObject*, QEvent*);
+
+/*
+ \class QAxServerBase
+ \brief The QAxServerBase class is an ActiveX control hosting a QWidget.
+
+ \internal
+*/
+class QAxServerBase :
+ public QObject,
+ public IAxServerBase,
+ public IDispatch,
+ public IOleObject,
+ public IOleControl,
+#if defined Q_CC_GNU
+# if (__W32API_MAJOR_VERSION < 2 || (__W32API_MAJOR_VERSION == 2 && __W32API_MINOR_VERSION < 5))
+ public IViewObject, // this should not be needed as IViewObject2 is meant to inherit from this,
+ // untill the mingw headers are fixed this will need to stay.
+# endif
+#endif
+ public IViewObject2,
+ public IOleInPlaceObject,
+ public IOleInPlaceActiveObject,
+ public IProvideClassInfo2,
+ public IConnectionPointContainer,
+ public IPersistStream,
+ public IPersistStreamInit,
+ public IPersistStorage,
+ public IPersistPropertyBag,
+ public IPersistFile,
+ public IDataObject
+{
+public:
+ typedef QMap<QUuid,IConnectionPoint*> ConnectionPoints;
+ typedef QMap<QUuid,IConnectionPoint*>::Iterator ConnectionPointsIterator;
+
+ QAxServerBase(const QString &classname, IUnknown *outerUnknown);
+ QAxServerBase(QObject *o);
+
+ void init();
+
+ ~QAxServerBase();
+
+// Window creation
+ HWND create(HWND hWndParent, RECT& rcPos);
+ HMENU createPopup(QMenu *popup, HMENU oldMenu = 0);
+ void createMenu(QMenuBar *menuBar);
+ void removeMenu();
+
+ static LRESULT CALLBACK ActiveXProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+// Object registration with OLE
+ void registerActiveObject(IUnknown *object);
+ void revokeActiveObject();
+
+// IUnknown
+ unsigned long WINAPI AddRef()
+ {
+ if (m_outerUnknown)
+ return m_outerUnknown->AddRef();
+
+ EnterCriticalSection(&refCountSection);
+ unsigned long r = ++ref;
+ LeaveCriticalSection(&refCountSection);
+
+ return r;
+ }
+ unsigned long WINAPI Release()
+ {
+ if (m_outerUnknown)
+ return m_outerUnknown->Release();
+
+ EnterCriticalSection(&refCountSection);
+ unsigned long r = --ref;
+ LeaveCriticalSection(&refCountSection);
+
+ if (!r) {
+ delete this;
+ return 0;
+ }
+ return r;
+ }
+ HRESULT WINAPI QueryInterface(REFIID iid, void **iface);
+ HRESULT InternalQueryInterface(REFIID iid, void **iface);
+
+// IAxServerBase
+ IUnknown *clientSite() const
+ {
+ return m_spClientSite;
+ }
+
+ void emitPropertyChanged(const char*);
+ bool emitRequestPropertyChange(const char*);
+ QObject *qObject() const
+ {
+ return theObject;
+ }
+ void ensureMetaData();
+ bool isPropertyExposed(int index);
+
+ void reportError(int code, const QString &src, const QString &desc, const QString &context)
+ {
+ if (exception)
+ delete exception;
+ exception = new QAxExceptInfo(code, src, desc, context);
+ }
+
+// IDispatch
+ STDMETHOD(GetTypeInfoCount)(UINT* pctinfo);
+ STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo);
+ STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid);
+ STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
+ LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
+ EXCEPINFO* pexcepinfo, UINT* puArgErr);
+
+// IProvideClassInfo
+ STDMETHOD(GetClassInfo)(ITypeInfo** pptinfo);
+
+// IProvideClassInfo2
+ STDMETHOD(GetGUID)(DWORD dwGuidKind, GUID* pGUID);
+
+// IOleObject
+ STDMETHOD(Advise)(IAdviseSink* pAdvSink, DWORD* pdwConnection);
+ STDMETHOD(Close)(DWORD dwSaveOption);
+ STDMETHOD(DoVerb)(LONG iVerb, LPMSG lpmsg, IOleClientSite* pActiveSite, LONG lindex, HWND hwndParent, LPCRECT lprcPosRect);
+ STDMETHOD(EnumAdvise)(IEnumSTATDATA** ppenumAdvise);
+ STDMETHOD(EnumVerbs)(IEnumOLEVERB** ppEnumOleVerb);
+ STDMETHOD(GetClientSite)(IOleClientSite** ppClientSite);
+ STDMETHOD(GetClipboardData)(DWORD dwReserved, IDataObject** ppDataObject);
+ STDMETHOD(GetExtent)(DWORD dwDrawAspect, SIZEL* psizel);
+ STDMETHOD(GetMiscStatus)(DWORD dwAspect, DWORD *pdwStatus);
+ STDMETHOD(GetMoniker)(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker** ppmk);
+ STDMETHOD(GetUserClassID)(CLSID* pClsid);
+ STDMETHOD(GetUserType)(DWORD dwFormOfType, LPOLESTR *pszUserType);
+ STDMETHOD(InitFromData)(IDataObject* pDataObject, BOOL fCreation, DWORD dwReserved);
+ STDMETHOD(IsUpToDate)();
+ STDMETHOD(SetClientSite)(IOleClientSite* pClientSite);
+ STDMETHOD(SetColorScheme)(LOGPALETTE* pLogPal);
+ STDMETHOD(SetExtent)(DWORD dwDrawAspect, SIZEL* psizel);
+ STDMETHOD(SetHostNames)(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj);
+ STDMETHOD(SetMoniker)(DWORD dwWhichMoniker, IMoniker* ppmk);
+ STDMETHOD(Unadvise)(DWORD dwConnection);
+ STDMETHOD(Update)();
+
+// IViewObject
+ STDMETHOD(Draw)(DWORD dwAspect, LONG lIndex, void *pvAspect, DVTARGETDEVICE *ptd,
+ HDC hicTargetDevice, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds,
+ BOOL(__stdcall*pfnContinue)(ULONG_PTR), ULONG_PTR dwContinue);
+ STDMETHOD(GetColorSet)(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd,
+ HDC hicTargetDev, LOGPALETTE **ppColorSet);
+ STDMETHOD(Freeze)(DWORD dwAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze);
+ STDMETHOD(Unfreeze)(DWORD dwFreeze);
+ STDMETHOD(SetAdvise)(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink);
+ STDMETHOD(GetAdvise)(DWORD *aspects, DWORD *advf, IAdviseSink **pAdvSink);
+
+// IViewObject2
+ STDMETHOD(GetExtent)(DWORD dwAspect, LONG lindex, DVTARGETDEVICE *ptd, LPSIZEL lpsizel);
+
+// IOleControl
+ STDMETHOD(FreezeEvents)(BOOL);
+ STDMETHOD(GetControlInfo)(LPCONTROLINFO);
+ STDMETHOD(OnAmbientPropertyChange)(DISPID);
+ STDMETHOD(OnMnemonic)(LPMSG);
+
+// IOleWindow
+ STDMETHOD(GetWindow)(HWND *pHwnd);
+ STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode);
+
+// IOleInPlaceObject
+ STDMETHOD(InPlaceDeactivate)();
+ STDMETHOD(UIDeactivate)();
+ STDMETHOD(SetObjectRects)(LPCRECT lprcPosRect, LPCRECT lprcClipRect);
+ STDMETHOD(ReactivateAndUndo)();
+
+// IOleInPlaceActiveObject
+ STDMETHOD(TranslateAcceleratorW)(MSG *pMsg);
+ STDMETHOD(TranslateAcceleratorA)(MSG *pMsg);
+ STDMETHOD(OnFrameWindowActivate)(BOOL);
+ STDMETHOD(OnDocWindowActivate)(BOOL fActivate);
+ STDMETHOD(ResizeBorder)(LPCRECT prcBorder, IOleInPlaceUIWindow *pUIWindow, BOOL fFrameWindow);
+ STDMETHOD(EnableModeless)(BOOL);
+
+// IConnectionPointContainer
+ STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints**);
+ STDMETHOD(FindConnectionPoint)(REFIID, IConnectionPoint**);
+
+// IPersist
+ STDMETHOD(GetClassID)(GUID*clsid)
+ {
+ *clsid = qAxFactory()->classID(class_name);
+ return S_OK;
+ }
+
+// IPersistStreamInit
+ STDMETHOD(InitNew)(VOID);
+ STDMETHOD(IsDirty)();
+ STDMETHOD(Load)(IStream *pStm);
+ STDMETHOD(Save)(IStream *pStm, BOOL fClearDirty);
+ STDMETHOD(GetSizeMax)(ULARGE_INTEGER *pcbSize);
+
+// IPersistPropertyBag
+ STDMETHOD(Load)(IPropertyBag *, IErrorLog *);
+ STDMETHOD(Save)(IPropertyBag *, BOOL, BOOL);
+
+// IPersistStorage
+ STDMETHOD(InitNew)(IStorage *pStg);
+ STDMETHOD(Load)(IStorage *pStg);
+ STDMETHOD(Save)(IStorage *pStg, BOOL fSameAsLoad);
+ STDMETHOD(SaveCompleted)(IStorage *pStgNew);
+ STDMETHOD(HandsOffStorage)();
+
+// IPersistFile
+ STDMETHOD(SaveCompleted)(LPCOLESTR fileName);
+ STDMETHOD(GetCurFile)(LPOLESTR *currentFile);
+ STDMETHOD(Load)(LPCOLESTR fileName, DWORD mode);
+ STDMETHOD(Save)(LPCOLESTR fileName, BOOL fRemember);
+
+// IDataObject
+ STDMETHOD(GetData)(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
+ STDMETHOD(GetDataHere)(FORMATETC* /* pformatetc */, STGMEDIUM* /* pmedium */);
+ STDMETHOD(QueryGetData)(FORMATETC* /* pformatetc */);
+ STDMETHOD(GetCanonicalFormatEtc)(FORMATETC* /* pformatectIn */,FORMATETC* /* pformatetcOut */);
+ STDMETHOD(SetData)(FORMATETC* /* pformatetc */, STGMEDIUM* /* pmedium */, BOOL /* fRelease */);
+ STDMETHOD(EnumFormatEtc)(DWORD /* dwDirection */, IEnumFORMATETC** /* ppenumFormatEtc */);
+ STDMETHOD(DAdvise)(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
+ STDMETHOD(DUnadvise)(DWORD dwConnection);
+ STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppenumAdvise);
+
+// QObject
+ int qt_metacall(QMetaObject::Call, int index, void **argv);
+
+ bool eventFilter(QObject *o, QEvent *e);
+private:
+ void update();
+ void resize(const QSize &newSize);
+ void updateGeometry();
+ void updateMask();
+ bool internalCreate();
+ void internalBind();
+ void internalConnect();
+ HRESULT internalActivate();
+
+ friend class QAxBindable;
+ friend class QAxPropertyPage;
+
+ QAxAggregated *aggregatedObject;
+ ConnectionPoints points;
+
+ union {
+ QWidget *widget;
+ QObject *object;
+ } qt;
+ QPointer<QObject> theObject;
+ unsigned isWidget :1;
+ unsigned ownObject :1;
+ unsigned initNewCalled :1;
+ unsigned dirtyflag :1;
+ unsigned hasStockEvents :1;
+ unsigned stayTopLevel :1;
+ unsigned isInPlaceActive :1;
+ unsigned isUIActive :1;
+ unsigned wasUIActive :1;
+ unsigned inDesignMode :1;
+ unsigned canTakeFocus :1;
+ short freezeEvents;
+
+ HWND m_hWnd;
+
+ HMENU hmenuShared;
+ HOLEMENU holemenu;
+ HWND hwndMenuOwner;
+ QMap<HMENU, QMenu*> menuMap;
+ QMap<UINT, QAction*> actionMap;
+ QPointer<QMenuBar> menuBar;
+ QPointer<QStatusBar> statusBar;
+ QPointer<QMenu> currentPopup;
+ QAxExceptInfo *exception;
+
+ CRITICAL_SECTION refCountSection;
+ CRITICAL_SECTION createWindowSection;
+
+ unsigned long ref;
+ unsigned long ole_ref;
+
+ QString class_name;
+ QString currentFileName;
+
+ QHash<long, int> indexCache;
+ QHash<int,DISPID> signalCache;
+
+ IUnknown *m_outerUnknown;
+ IAdviseSink *m_spAdviseSink;
+ QList<STATDATA> adviseSinks;
+ IOleClientSite *m_spClientSite;
+ IOleInPlaceSiteWindowless *m_spInPlaceSite;
+ IOleInPlaceFrame *m_spInPlaceFrame;
+ ITypeInfo *m_spTypeInfo;
+ IStorage *m_spStorage;
+ QSize m_currentExtent;
+};
+
+class QAxServerAggregate : public IUnknown
+{
+public:
+ QAxServerAggregate(const QString &className, IUnknown *outerUnknown)
+ : m_outerUnknown(outerUnknown), ref(0)
+ {
+ object = new QAxServerBase(className, outerUnknown);
+ object->registerActiveObject(this);
+
+ InitializeCriticalSection(&refCountSection);
+ InitializeCriticalSection(&createWindowSection);
+ }
+ ~QAxServerAggregate()
+ {
+ DeleteCriticalSection(&refCountSection);
+ DeleteCriticalSection(&createWindowSection);
+
+ delete object;
+ }
+
+// IUnknown
+ unsigned long WINAPI AddRef()
+ {
+ EnterCriticalSection(&refCountSection);
+ unsigned long r = ++ref;
+ LeaveCriticalSection(&refCountSection);
+
+ return r;
+ }
+ unsigned long WINAPI Release()
+ {
+ EnterCriticalSection(&refCountSection);
+ unsigned long r = --ref;
+ LeaveCriticalSection(&refCountSection);
+
+ if (!r) {
+ delete this;
+ return 0;
+ }
+ return r;
+ }
+ HRESULT WINAPI QueryInterface(REFIID iid, void **iface)
+ {
+ *iface = 0;
+
+ HRESULT res = E_NOINTERFACE;
+ if (iid == IID_IUnknown) {
+ *iface = (IUnknown*)this;
+ AddRef();
+ return S_OK;
+ }
+ return object->InternalQueryInterface(iid, iface);
+ }
+
+private:
+ QAxServerBase *object;
+ IUnknown *m_outerUnknown;
+ unsigned long ref;
+
+ CRITICAL_SECTION refCountSection;
+ CRITICAL_SECTION createWindowSection;
+};
+
+bool QAxFactory::createObjectWrapper(QObject *object, IDispatch **wrapper)
+{
+ *wrapper = 0;
+ QAxServerBase *obj = new QAxServerBase(object);
+ obj->QueryInterface(IID_IDispatch, (void**)wrapper);
+ if (*wrapper)
+ return true;
+
+ delete obj;
+ return false;
+}
+
+
+/*
+ Helper class to enumerate all supported event interfaces.
+*/
+class QAxSignalVec : public IEnumConnectionPoints
+{
+public:
+ QAxSignalVec(const QAxServerBase::ConnectionPoints &points)
+ : cpoints(points), ref(0)
+ {
+ InitializeCriticalSection(&refCountSection);
+ for (QAxServerBase::ConnectionPointsIterator i = cpoints.begin(); i != cpoints.end(); ++i)
+ (*i)->AddRef();
+ }
+ QAxSignalVec(const QAxSignalVec &old)
+ {
+ InitializeCriticalSection(&refCountSection);
+ ref = 0;
+ cpoints = old.cpoints;
+ for (QAxServerBase::ConnectionPointsIterator i = cpoints.begin(); i != cpoints.end(); ++i)
+ (*i)->AddRef();
+ it = old.it;
+ }
+ ~QAxSignalVec()
+ {
+ for (QAxServerBase::ConnectionPointsIterator i = cpoints.begin(); i != cpoints.end(); ++i)
+ (*i)->Release();
+
+ DeleteCriticalSection(&refCountSection);
+ }
+
+ unsigned long __stdcall AddRef()
+ {
+ EnterCriticalSection(&refCountSection);
+ unsigned long r = ++ref;
+ LeaveCriticalSection(&refCountSection);
+ return ++r;
+ }
+ unsigned long __stdcall Release()
+ {
+ EnterCriticalSection(&refCountSection);
+ unsigned long r = --ref;
+ LeaveCriticalSection(&refCountSection);
+
+ if (!r) {
+ delete this;
+ return 0;
+ }
+ return r;
+ }
+ STDMETHOD(QueryInterface)(REFIID iid, void **iface)
+ {
+ *iface = 0;
+ if (iid == IID_IUnknown)
+ *iface = this;
+ else if (iid == IID_IEnumConnectionPoints)
+ *iface = this;
+ else
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+ }
+ STDMETHOD(Next)(ULONG cConnections, IConnectionPoint **cpoint, ULONG *pcFetched)
+ {
+ unsigned long i;
+ for (i = 0; i < cConnections; i++) {
+ if (it == cpoints.end())
+ break;
+ IConnectionPoint *cp = *it;
+ cp->AddRef();
+ cpoint[i] = cp;
+ ++it;
+ }
+ *pcFetched = i;
+ return i == cConnections ? S_OK : S_FALSE;
+ }
+ STDMETHOD(Skip)(ULONG cConnections)
+ {
+ while (cConnections) {
+ ++it;
+ --cConnections;
+ if (it == cpoints.end())
+ return S_FALSE;
+ }
+ return S_OK;
+ }
+ STDMETHOD(Reset)()
+ {
+ it = cpoints.begin();
+
+ return S_OK;
+ }
+ STDMETHOD(Clone)(IEnumConnectionPoints **ppEnum)
+ {
+ *ppEnum = new QAxSignalVec(*this);
+ (*ppEnum)->AddRef();
+
+ return S_OK;
+ }
+
+ QAxServerBase::ConnectionPoints cpoints;
+ QAxServerBase::ConnectionPointsIterator it;
+
+private:
+ CRITICAL_SECTION refCountSection;
+
+ unsigned long ref;
+};
+
+/*
+ Helper class to store and enumerate all connected event listeners.
+*/
+class QAxConnection : public IConnectionPoint,
+ public IEnumConnections
+{
+public:
+ typedef QList<CONNECTDATA> Connections;
+ typedef QList<CONNECTDATA>::Iterator Iterator;
+
+ QAxConnection(QAxServerBase *parent, const QUuid &uuid)
+ : that(parent), iid(uuid), ref(1)
+ {
+ InitializeCriticalSection(&refCountSection);
+ }
+ QAxConnection(const QAxConnection &old)
+ {
+ InitializeCriticalSection(&refCountSection);
+ ref = 0;
+ connections = old.connections;
+ it = old.it;
+ that = old.that;
+ iid = old.iid;
+ QList<CONNECTDATA>::Iterator it = connections.begin();
+ while (it != connections.end()) {
+ CONNECTDATA connection = *it;
+ ++it;
+ connection.pUnk->AddRef();
+ }
+ }
+ ~QAxConnection()
+ {
+ DeleteCriticalSection(&refCountSection);
+ }
+
+ unsigned long __stdcall AddRef()
+ {
+ EnterCriticalSection(&refCountSection);
+ unsigned long r = ++ref;
+ LeaveCriticalSection(&refCountSection);
+ return r;
+ }
+ unsigned long __stdcall Release()
+ {
+ EnterCriticalSection(&refCountSection);
+ unsigned long r = --ref;
+ LeaveCriticalSection(&refCountSection);
+
+ if (!r) {
+ delete this;
+ return 0;
+ }
+ return r;
+ }
+ STDMETHOD(QueryInterface)(REFIID iid, void **iface)
+ {
+ *iface = 0;
+ if (iid == IID_IUnknown)
+ *iface = (IConnectionPoint*)this;
+ else if (iid == IID_IConnectionPoint)
+ *iface = this;
+ else if (iid == IID_IEnumConnections)
+ *iface = this;
+ else
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+ }
+ STDMETHOD(GetConnectionInterface)(IID *pIID)
+ {
+ *pIID = iid;
+ return S_OK;
+ }
+ STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer **ppCPC)
+ {
+ return that->QueryInterface(IID_IConnectionPointContainer, (void**)ppCPC);
+ }
+ STDMETHOD(Advise)(IUnknown*pUnk, DWORD *pdwCookie)
+ {
+ {
+ IDispatch *checkImpl = 0;
+ pUnk->QueryInterface(iid, (void**)&checkImpl);
+ if (!checkImpl)
+ return CONNECT_E_CANNOTCONNECT;
+ checkImpl->Release();
+ }
+
+ CONNECTDATA cd;
+ cd.dwCookie = connections.count()+1;
+ cd.pUnk = pUnk;
+ cd.pUnk->AddRef();
+ connections.append(cd);
+
+ *pdwCookie = cd.dwCookie;
+ return S_OK;
+ }
+ STDMETHOD(Unadvise)(DWORD dwCookie)
+ {
+ QList<CONNECTDATA>::Iterator it = connections.begin();
+ while (it != connections.end()) {
+ CONNECTDATA cd = *it;
+ if (cd.dwCookie == dwCookie) {
+ cd.pUnk->Release();
+ connections.erase(it);
+ return S_OK;
+ }
+ ++it;
+ }
+ return CONNECT_E_NOCONNECTION;
+ }
+ STDMETHOD(EnumConnections)(IEnumConnections **ppEnum)
+ {
+ *ppEnum = this;
+ AddRef();
+
+ return S_OK;
+ }
+ STDMETHOD(Next)(ULONG cConnections, CONNECTDATA *cd, ULONG *pcFetched)
+ {
+ unsigned long i;
+ for (i = 0; i < cConnections; i++) {
+ if (it == connections.end())
+ break;
+ cd[i] = *it;
+ cd[i].pUnk->AddRef();
+ ++it;
+ }
+ if (pcFetched)
+ *pcFetched = i;
+ return i == cConnections ? S_OK : S_FALSE;
+ }
+ STDMETHOD(Skip)(ULONG cConnections)
+ {
+ while (cConnections) {
+ ++it;
+ --cConnections;
+ if (it == connections.end())
+ return S_FALSE;
+ }
+ return S_OK;
+ }
+ STDMETHOD(Reset)()
+ {
+ it = connections.begin();
+
+ return S_OK;
+ }
+ STDMETHOD(Clone)(IEnumConnections **ppEnum)
+ {
+ *ppEnum = new QAxConnection(*this);
+ (*ppEnum)->AddRef();
+
+ return S_OK;
+ }
+
+private:
+ QAxServerBase *that;
+ QUuid iid;
+ Connections connections;
+ Iterator it;
+
+ CRITICAL_SECTION refCountSection;
+ unsigned long ref;
+};
+
+// callback for DLL server to hook into non-Qt eventloop
+LRESULT CALLBACK axs_FilterProc(int nCode, WPARAM wParam, LPARAM lParam)
+{
+ if (qApp && !invokeCount)
+ qApp->sendPostedEvents();
+
+ return CallNextHookEx(qax_hhook, nCode, wParam, lParam);
+}
+
+// filter for executable case to hook into Qt eventloop
+// for DLLs the client calls TranslateAccelerator
+bool qax_winEventFilter(void *message)
+{
+ MSG *pMsg = (MSG*)message;
+ if (pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST)
+ return false;
+
+ bool ret = false;
+ QWidget *aqt = QWidget::find(pMsg->hwnd);
+ if (!aqt)
+ return ret;
+
+ HWND baseHwnd = ::GetParent(aqt->winId());
+ QAxServerBase *axbase = 0;
+ while (!axbase && baseHwnd) {
+#ifdef GWLP_USERDATA
+ QT_WA({
+ axbase = (QAxServerBase*)GetWindowLongPtrW(baseHwnd, GWLP_USERDATA);
+ }, {
+ axbase = (QAxServerBase*)GetWindowLongPtrA(baseHwnd, GWLP_USERDATA);
+ });
+#else
+ QT_WA({
+ axbase = (QAxServerBase*)GetWindowLongW(baseHwnd, GWL_USERDATA);
+ }, {
+ axbase = (QAxServerBase*)GetWindowLongA(baseHwnd, GWL_USERDATA);
+ });
+#endif
+
+ baseHwnd = ::GetParent(baseHwnd);
+ }
+ if (!axbase)
+ return ret;
+
+ HRESULT hres = axbase->TranslateAcceleratorW(pMsg);
+ return hres == S_OK;
+}
+
+extern void qWinMsgHandler(QtMsgType t, const char* str);
+
+// COM Factory class, mapping COM requests to ActiveQt requests.
+// One instance of this class for each ActiveX the server can provide.
+class QClassFactory : public IClassFactory2
+{
+public:
+ QClassFactory(CLSID clsid)
+ : ref(0), licensed(false)
+ {
+ InitializeCriticalSection(&refCountSection);
+
+ // COM only knows the CLSID, but QAxFactory is class name based...
+ QStringList keys = qAxFactory()->featureList();
+ for (QStringList::Iterator key = keys.begin(); key != keys.end(); ++key) {
+ if (qAxFactory()->classID(*key) == clsid) {
+ className = *key;
+ break;
+ }
+ }
+
+ const QMetaObject *mo = qAxFactory()->metaObject(className);
+ if (mo) {
+ classKey = QLatin1String(mo->classInfo(mo->indexOfClassInfo("LicenseKey")).value());
+ licensed = !classKey.isEmpty();
+ }
+ }
+
+ ~QClassFactory()
+ {
+ DeleteCriticalSection(&refCountSection);
+ }
+
+ // IUnknown
+ unsigned long WINAPI AddRef()
+ {
+ EnterCriticalSection(&refCountSection);
+ unsigned long r = ++ref;
+ LeaveCriticalSection(&refCountSection);
+ return ++r;
+ }
+ unsigned long WINAPI Release()
+ {
+ EnterCriticalSection(&refCountSection);
+ unsigned long r = --ref;
+ LeaveCriticalSection(&refCountSection);
+
+ if (!r) {
+ delete this;
+ return 0;
+ }
+ return r;
+ }
+ HRESULT WINAPI QueryInterface(REFIID iid, LPVOID *iface)
+ {
+ *iface = 0;
+ if (iid == IID_IUnknown)
+ *iface = (IUnknown*)this;
+ else if (iid == IID_IClassFactory)
+ *iface = (IClassFactory*)this;
+ else if (iid == IID_IClassFactory2 && licensed)
+ *iface = (IClassFactory2*)this;
+ else
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+ }
+
+ HRESULT WINAPI CreateInstanceHelper(IUnknown *pUnkOuter, REFIID iid, void **ppObject)
+ {
+ if (pUnkOuter) {
+ if (iid != IID_IUnknown)
+ return CLASS_E_NOAGGREGATION;
+ const QMetaObject *mo = qAxFactory()->metaObject(className);
+ if (mo && !qstricmp(mo->classInfo(mo->indexOfClassInfo("Aggregatable")).value(), "no"))
+ return CLASS_E_NOAGGREGATION;
+ }
+
+ // Make sure a QApplication instance is present (inprocess case)
+ if (!qApp) {
+ qInstallMsgHandler(qWinMsgHandler);
+ qax_ownQApp = true;
+ int argc = 0;
+ QApplication *app = new QApplication(argc, 0);
+ }
+ qApp->setQuitOnLastWindowClosed(false);
+
+ if (qAxOutProcServer)
+ QAbstractEventDispatcher::instance()->setEventFilter(qax_winEventFilter);
+ else
+ QApplication::instance()->d_func()->in_exec = true;
+
+ // hook into eventloop; this allows a server to create his own QApplication object
+ if (!qax_hhook && qax_ownQApp) {
+ QT_WA({
+ qax_hhook = SetWindowsHookExW(WH_GETMESSAGE, axs_FilterProc, 0, GetCurrentThreadId());
+ }, {
+ qax_hhook = SetWindowsHookExA(WH_GETMESSAGE, axs_FilterProc, 0, GetCurrentThreadId());
+ });
+ }
+
+ HRESULT res;
+ // Create the ActiveX wrapper - aggregate if requested
+ if (pUnkOuter) {
+ QAxServerAggregate *aggregate = new QAxServerAggregate(className, pUnkOuter);
+ res = aggregate->QueryInterface(iid, ppObject);
+ if (FAILED(res))
+ delete aggregate;
+ } else {
+ QAxServerBase *activeqt = new QAxServerBase(className, pUnkOuter);
+ res = activeqt->QueryInterface(iid, ppObject);
+ if (FAILED(res))
+ delete activeqt;
+ else
+ activeqt->registerActiveObject((IUnknown*)(IDispatch*)activeqt);
+ }
+ return res;
+ }
+
+ // IClassFactory
+ HRESULT WINAPI CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppObject)
+ {
+ // class is licensed
+ if (licensed && !qAxFactory()->validateLicenseKey(className, QString()))
+ return CLASS_E_NOTLICENSED;
+
+ return CreateInstanceHelper(pUnkOuter, iid, ppObject);
+ }
+ HRESULT WINAPI LockServer(BOOL fLock)
+ {
+ if (fLock)
+ qAxLock();
+ else
+ qAxUnlock();
+
+ return S_OK;
+ }
+
+ // IClassFactory2
+ HRESULT WINAPI RequestLicKey(DWORD, BSTR *pKey)
+ {
+ if (!pKey)
+ return E_POINTER;
+ *pKey = 0;
+
+ // This of course works only on fully licensed machines
+ if (!qAxFactory()->validateLicenseKey(className, QString()))
+ return CLASS_E_NOTLICENSED;
+
+ *pKey = QStringToBSTR(classKey);
+ return S_OK;
+ }
+
+ HRESULT WINAPI GetLicInfo(LICINFO *pLicInfo)
+ {
+ if (!pLicInfo)
+ return E_POINTER;
+ pLicInfo->cbLicInfo = sizeof(LICINFO);
+
+ // class specific license key?
+ const QMetaObject *mo = qAxFactory()->metaObject(className);
+ const char *key = mo->classInfo(mo->indexOfClassInfo("LicenseKey")).value();
+ pLicInfo->fRuntimeKeyAvail = key && key[0];
+
+ // machine fully licensed?
+ pLicInfo->fLicVerified = qAxFactory()->validateLicenseKey(className, QString());
+
+ return S_OK;
+ }
+
+ HRESULT WINAPI CreateInstanceLic(IUnknown *pUnkOuter, IUnknown *pUnkReserved, REFIID iid, BSTR bKey, PVOID *ppObject)
+ {
+ QString licenseKey = QString::fromUtf16((const ushort *)bKey);
+ if (!qAxFactory()->validateLicenseKey(className, licenseKey))
+ return CLASS_E_NOTLICENSED;
+ return CreateInstanceHelper(pUnkOuter, iid, ppObject);
+ }
+
+ QString className;
+
+protected:
+ CRITICAL_SECTION refCountSection;
+ unsigned long ref;
+ bool licensed;
+ QString classKey;
+};
+
+// Create a QClassFactory object for class \a iid
+HRESULT GetClassObject(REFIID clsid, REFIID iid, void **ppUnk)
+{
+ QClassFactory *factory = new QClassFactory(clsid);
+ if (!factory)
+ return E_OUTOFMEMORY;
+ if (factory->className.isEmpty()) {
+ delete factory;
+ return E_NOINTERFACE;
+ }
+ HRESULT res = factory->QueryInterface(iid, ppUnk);
+ if (res != S_OK)
+ delete factory;
+ return res;
+}
+
+
+/*!
+ Constructs a QAxServerBase object wrapping the QWidget \a
+ classname into an ActiveX control.
+
+ The constructor is called by the QClassFactory object provided by
+ the COM server for the respective CLSID.
+*/
+QAxServerBase::QAxServerBase(const QString &classname, IUnknown *outerUnknown)
+: aggregatedObject(0), ref(0), ole_ref(0), class_name(classname),
+ m_hWnd(0), hmenuShared(0), hwndMenuOwner(0),
+ m_outerUnknown(outerUnknown)
+{
+ init();
+
+ internalCreate();
+}
+
+/*!
+ Constructs a QAxServerBase object wrapping \a o.
+*/
+QAxServerBase::QAxServerBase(QObject *o)
+: aggregatedObject(0), ref(0), ole_ref(0),
+ m_hWnd(0), hmenuShared(0), hwndMenuOwner(0),
+ m_outerUnknown(0)
+{
+ init();
+
+ qt.object = o;
+ if (o) {
+ theObject = o;
+ isWidget = false;
+ class_name = QLatin1String(o->metaObject()->className());
+ }
+ internalBind();
+ internalConnect();
+}
+
+/*!
+ Initializes data members.
+*/
+void QAxServerBase::init()
+{
+ qt.object = 0;
+ isWidget = false;
+ ownObject = false;
+ initNewCalled = false;
+ dirtyflag = false;
+ hasStockEvents = false;
+ stayTopLevel = false;
+ isInPlaceActive = false;
+ isUIActive = false;
+ wasUIActive = false;
+ inDesignMode = false;
+ canTakeFocus = false;
+ freezeEvents = 0;
+ exception = 0;
+
+ m_spAdviseSink = 0;
+ m_spClientSite = 0;
+ m_spInPlaceSite = 0;
+ m_spInPlaceFrame = 0;
+ m_spTypeInfo = 0;
+ m_spStorage = 0;
+
+ InitializeCriticalSection(&refCountSection);
+ InitializeCriticalSection(&createWindowSection);
+
+#ifdef QT_DEBUG
+ EnterCriticalSection(&refCountSection);
+ ++qaxserverbase_instance_count;
+ LeaveCriticalSection(&refCountSection);
+#endif
+
+ qAxLock();
+
+ points[IID_IPropertyNotifySink] = new QAxConnection(this, IID_IPropertyNotifySink);
+}
+
+/*!
+ Destroys the QAxServerBase object, releasing all allocated
+ resources and interfaces.
+*/
+QAxServerBase::~QAxServerBase()
+{
+#ifdef QT_DEBUG
+ EnterCriticalSection(&refCountSection);
+ --qaxserverbase_instance_count;
+ LeaveCriticalSection(&refCountSection);
+#endif
+
+ revokeActiveObject();
+
+ for (QAxServerBase::ConnectionPointsIterator it = points.begin(); it != points.end(); ++it) {
+ if (it.value())
+ (*it)->Release();
+ }
+ delete aggregatedObject;
+ aggregatedObject = 0;
+ if (theObject) {
+ qt.object->disconnect(this);
+ QObject *aqt = qt.object;
+ qt.object = 0;
+ if (ownObject)
+ delete aqt;
+ }
+
+ if (m_spAdviseSink) m_spAdviseSink->Release();
+ m_spAdviseSink = 0;
+ for (int i = 0; i < adviseSinks.count(); ++i) {
+ adviseSinks.at(i).pAdvSink->Release();
+ }
+ if (m_spClientSite) m_spClientSite->Release();
+ m_spClientSite = 0;
+ if (m_spInPlaceFrame) m_spInPlaceFrame->Release();
+ m_spInPlaceFrame = 0;
+ if (m_spInPlaceSite) m_spInPlaceSite->Release();
+ m_spInPlaceSite = 0;
+ if (m_spTypeInfo) m_spTypeInfo->Release();
+ m_spTypeInfo = 0;
+ if (m_spStorage) m_spStorage->Release();
+ m_spStorage = 0;
+
+ DeleteCriticalSection(&refCountSection);
+ DeleteCriticalSection(&createWindowSection);
+
+ qAxUnlock();
+}
+
+/*
+ Registering with OLE
+*/
+void QAxServerBase::registerActiveObject(IUnknown *object)
+{
+ if (ole_ref || !qt.object || !qAxOutProcServer)
+ return;
+
+ const QMetaObject *mo = qt.object->metaObject();
+ if (!qstricmp(mo->classInfo(mo->indexOfClassInfo("RegisterObject")).value(), "yes"))
+ RegisterActiveObject(object, qAxFactory()->classID(class_name), ACTIVEOBJECT_WEAK, &ole_ref);
+}
+
+void QAxServerBase::revokeActiveObject()
+{
+ if (!ole_ref)
+ return;
+
+ RevokeActiveObject(ole_ref, 0);
+ ole_ref = 0;
+}
+
+/*
+ QueryInterface implementation.
+*/
+HRESULT WINAPI QAxServerBase::QueryInterface(REFIID iid, void **iface)
+{
+ if (m_outerUnknown)
+ return m_outerUnknown->QueryInterface(iid, iface);
+
+ return InternalQueryInterface(iid, iface);
+}
+
+HRESULT QAxServerBase::InternalQueryInterface(REFIID iid, void **iface)
+{
+ *iface = 0;
+
+ if (iid == IID_IUnknown) {
+ *iface = (IUnknown*)(IDispatch*)this;
+ } else {
+ HRESULT res = S_OK;
+ if (aggregatedObject)
+ res = aggregatedObject->queryInterface(iid, iface);
+ if (*iface)
+ return res;
+ }
+
+ if (!(*iface)) {
+ if (iid == qAxFactory()->interfaceID(class_name))
+ *iface = (IDispatch*)this;
+ if (iid == IID_IDispatch)
+ *iface = (IDispatch*)this;
+ else if (iid == IID_IAxServerBase)
+ *iface = (IAxServerBase*)this;
+ else if (iid == IID_IOleObject)
+ *iface = (IOleObject*)this;
+ else if (iid == IID_IConnectionPointContainer)
+ *iface = (IConnectionPointContainer*)this;
+ else if (iid == IID_IProvideClassInfo)
+ *iface = (IProvideClassInfo*)this;
+ else if (iid == IID_IProvideClassInfo2)
+ *iface = (IProvideClassInfo2*)this;
+ else if (iid == IID_IPersist)
+ *iface = (IPersist*)(IPersistStream*)this;
+ else if (iid == IID_IPersistStream)
+ *iface = (IPersistStream*)this;
+ else if (iid == IID_IPersistStreamInit)
+ *iface = (IPersistStreamInit*)this;
+ else if (iid == IID_IPersistStorage)
+ *iface = (IPersistStorage*)this;
+ else if (iid == IID_IPersistPropertyBag)
+ *iface = (IPersistPropertyBag*)this;
+ else if (iid == IID_IPersistFile &&
+ qAxFactory()->metaObject(class_name)->indexOfClassInfo("MIME") != -1)
+ *iface = (IPersistFile*)this;
+ else if (iid == IID_IViewObject)
+ *iface = (IViewObject*)this;
+ else if (iid == IID_IViewObject2)
+ *iface = (IViewObject2*)this;
+ else if (isWidget) {
+ if (iid == IID_IOleControl)
+ *iface = (IOleControl*)this;
+ else if (iid == IID_IOleWindow)
+ *iface = (IOleWindow*)(IOleInPlaceObject*)this;
+ else if (iid == IID_IOleInPlaceObject)
+ *iface = (IOleInPlaceObject*)this;
+ else if (iid == IID_IOleInPlaceActiveObject)
+ *iface = (IOleInPlaceActiveObject*)this;
+ else if (iid == IID_IDataObject)
+ *iface = (IDataObject*)this;
+ }
+ }
+ if (!*iface)
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+}
+
+/*!
+ Detects and initilaizes implementation of QAxBindable in objects.
+*/
+void QAxServerBase::internalBind()
+{
+ QAxBindable *axb = (QAxBindable*)qt.object->qt_metacast("QAxBindable");
+ if (axb) {
+ // no addref; this is aggregated
+ axb->activex = this;
+ if (!aggregatedObject)
+ aggregatedObject = axb->createAggregate();
+ if (aggregatedObject) {
+ aggregatedObject->controlling_unknown = (IUnknown*)(IDispatch*)this;
+ aggregatedObject->the_object = qt.object;
+ }
+ }
+}
+
+/*!
+ Connects object signals to event dispatcher.
+*/
+void QAxServerBase::internalConnect()
+{
+ QUuid eventsID = qAxFactory()->eventsID(class_name);
+ if (!eventsID.isNull()) {
+ if (!points[eventsID])
+ points[eventsID] = new QAxConnection(this, eventsID);
+
+ // connect the generic slot to all signals of qt.object
+ const QMetaObject *mo = qt.object->metaObject();
+ for (int isignal = mo->methodCount()-1; isignal >= 0; --isignal) {
+ if (mo->method(isignal).methodType() == QMetaMethod::Signal)
+ QMetaObject::connect(qt.object, isignal, this, isignal);
+ }
+ }
+}
+
+/*!
+ Creates the QWidget for the classname passed to the c'tor.
+
+ All signals of the widget class are connected to the internal event mapper.
+ If the widget implements QAxBindable, stock events are also connected.
+*/
+bool QAxServerBase::internalCreate()
+{
+ if (qt.object)
+ return true;
+
+ qt.object = qAxFactory()->createObject(class_name);
+ Q_ASSERT(qt.object);
+ if (!qt.object)
+ return false;
+
+ theObject = qt.object;
+ ownObject = true;
+ isWidget = qt.object->isWidgetType();
+ hasStockEvents = qAxFactory()->hasStockEvents(class_name);
+ stayTopLevel = qAxFactory()->stayTopLevel(class_name);
+
+ internalBind();
+ if (isWidget) {
+ if (!stayTopLevel) {
+ QEvent e(QEvent::EmbeddingControl);
+ QApplication::sendEvent(qt.widget, &e);
+ QT_WA({
+ ::SetWindowLongW(qt.widget->winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
+ }, {
+ ::SetWindowLongA(qt.widget->winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
+ });
+ }
+ qt.widget->setAttribute(Qt::WA_QuitOnClose, false);
+ qt.widget->move(0, 0);
+
+ // initialize to sizeHint, but don't set resized flag so that container has a chance to override
+ bool wasResized = qt.widget->testAttribute(Qt::WA_Resized);
+ updateGeometry();
+ if (!wasResized && qt.widget->testAttribute(Qt::WA_Resized)
+ && qt.widget->sizePolicy() != QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)) {
+ qt.widget->setAttribute(Qt::WA_Resized, false);
+ }
+ }
+
+ internalConnect();
+ // install an event filter for stock events
+ if (isWidget) {
+ qt.object->installEventFilter(this);
+ const QList<QWidget*> children = qFindChildren<QWidget*>(qt.object);
+ QList<QWidget*>::ConstIterator it = children.constBegin();
+ while (it != children.constEnd()) {
+ (*it)->installEventFilter(this);
+ ++it;
+ }
+ }
+ return true;
+}
+
+/*
+class HackMenuData : public QMenuData
+{
+ friend class QAxServerBase;
+};
+*/
+
+class HackWidget : public QWidget
+{
+ friend class QAxServerBase;
+};
+/*
+ Message handler. \a hWnd is always the ActiveX widget hosting the Qt widget.
+ \a uMsg is handled as follows
+ \list
+ \i WM_CREATE The ActiveX control is created
+ \i WM_DESTROY The QWidget is destroyed
+ \i WM_SHOWWINDOW The QWidget is parented into the ActiveX window
+ \i WM_PAINT The QWidget is updated
+ \i WM_SIZE The QWidget is resized to the new size
+ \i WM_SETFOCUS and
+ \i WM_KILLFOCUS The client site is notified about the focus transfer
+ \i WM_MOUSEACTIVATE The ActiveX is activated
+ \endlist
+
+ The semantics of \a wParam and \a lParam depend on the value of \a uMsg.
+*/
+LRESULT CALLBACK QAxServerBase::ActiveXProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (uMsg == WM_CREATE) {
+ QAxServerBase *that;
+ QT_WA({
+ CREATESTRUCTW *cs = (CREATESTRUCTW*)lParam;
+ that = (QAxServerBase*)cs->lpCreateParams;
+ }, {
+ CREATESTRUCTA *cs = (CREATESTRUCTA*)lParam;
+ that = (QAxServerBase*)cs->lpCreateParams;
+ });
+
+#ifdef GWLP_USERDATA
+ QT_WA({
+ SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)that);
+ }, {
+ SetWindowLongPtrA(hWnd, GWLP_USERDATA, (LONG_PTR)that);
+ });
+#else
+ QT_WA({
+ SetWindowLongW(hWnd, GWL_USERDATA, (LONG)that);
+ }, {
+ SetWindowLongA(hWnd, GWL_USERDATA, (LONG)that);
+ });
+#endif
+
+ that->m_hWnd = hWnd;
+
+ QT_WA({
+ return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
+ }, {
+ return ::DefWindowProcA(hWnd, uMsg, wParam, lParam);
+ });
+ }
+
+ QAxServerBase *that = 0;
+
+#ifdef GWLP_USERDATA
+ QT_WA({
+ that = (QAxServerBase*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
+ }, {
+ that = (QAxServerBase*)GetWindowLongPtrA(hWnd, GWLP_USERDATA);
+ });
+#else
+ QT_WA({
+ that = (QAxServerBase*)GetWindowLongW(hWnd, GWL_USERDATA);
+ }, {
+ that = (QAxServerBase*)GetWindowLongA(hWnd, GWL_USERDATA);
+ });
+#endif
+
+ if (that) {
+ int width = that->qt.widget ? that->qt.widget->width() : 0;
+ int height = that->qt.widget ? that->qt.widget->height() : 0;
+ RECT rcPos = {0, 0, width + 1, height + 1};
+
+ switch (uMsg) {
+ case WM_NCDESTROY:
+ that->m_hWnd = 0;
+ break;
+
+ case WM_QUERYENDSESSION:
+ case WM_DESTROY:
+ // save the window handle
+ if (that->qt.widget) {
+ that->qt.widget->hide();
+ ::SetParent(that->qt.widget->winId(), 0);
+ }
+ break;
+
+ case WM_SHOWWINDOW:
+ if(wParam) {
+ that->internalCreate();
+ if (!that->stayTopLevel) {
+ ::SetParent(that->qt.widget->winId(), that->m_hWnd);
+ that->qt.widget->raise();
+ that->qt.widget->move(0, 0);
+ }
+ that->qt.widget->show();
+ } else if (that->qt.widget) {
+ that->qt.widget->hide();
+ }
+ break;
+
+ case WM_ERASEBKGND:
+ that->updateMask();
+ break;
+
+ case WM_SIZE:
+ that->resize(QSize(LOWORD(lParam), HIWORD(lParam)));
+ break;
+
+ case WM_SETFOCUS:
+ if (that->isInPlaceActive && that->m_spClientSite && !that->inDesignMode && that->canTakeFocus) {
+ that->DoVerb(OLEIVERB_UIACTIVATE, NULL, that->m_spClientSite, 0, that->m_hWnd, &rcPos);
+ if (that->isUIActive) {
+ IOleControlSite *spSite = 0;
+ that->m_spClientSite->QueryInterface(IID_IOleControlSite, (void**)&spSite);
+ if (spSite) {
+ spSite->OnFocus(true);
+ spSite->Release();
+ }
+ QWidget *candidate = that->qt.widget;
+ while (!(candidate->focusPolicy() & Qt::TabFocus)) {
+ candidate = candidate->nextInFocusChain();
+ if (candidate == that->qt.widget) {
+ candidate = 0;
+ break;
+ }
+ }
+ if (candidate) {
+ candidate->setFocus();
+ HackWidget *widget = (HackWidget*)that->qt.widget;
+ if (::GetKeyState(VK_SHIFT) < 0)
+ widget->focusNextPrevChild(false);
+ }
+ }
+ }
+ break;
+
+ case WM_KILLFOCUS:
+ if (that->isInPlaceActive && that->isUIActive && that->m_spClientSite) {
+ IOleControlSite *spSite = 0;
+ that->m_spClientSite->QueryInterface(IID_IOleControlSite, (void**)&spSite);
+ if (spSite) {
+ if (!::IsChild(that->m_hWnd, ::GetFocus()))
+ spSite->OnFocus(false);
+ spSite->Release();
+ }
+ }
+ break;
+
+ case WM_MOUSEACTIVATE:
+ that->DoVerb(OLEIVERB_UIACTIVATE, NULL, that->m_spClientSite, 0, that->m_hWnd, &rcPos);
+ break;
+
+ case WM_INITMENUPOPUP:
+ if (that->qt.widget) {
+ that->currentPopup = that->menuMap[(HMENU)wParam];
+ if (!that->currentPopup)
+ break;
+ const QMetaObject *mo = that->currentPopup->metaObject();
+ int index = mo->indexOfSignal("aboutToShow()");
+ if (index < 0)
+ break;
+
+ that->currentPopup->qt_metacall(QMetaObject::InvokeMetaMethod, index, 0);
+ that->createPopup(that->currentPopup, (HMENU)wParam);
+ return 0;
+ }
+ break;
+
+ case WM_MENUSELECT:
+ case WM_COMMAND:
+ if (that->qt.widget) {
+ QMenuBar *menuBar = that->menuBar;
+ if (!menuBar)
+ break;
+
+ QObject *menuObject = 0;
+ bool menuClosed = false;
+
+ if (uMsg == WM_COMMAND) {
+ menuObject = that->actionMap.value(wParam);
+ } else if (!lParam) {
+ menuClosed = true;
+ menuObject = that->currentPopup;
+ } else {
+ menuObject = that->actionMap.value(LOWORD(wParam));
+ }
+
+ if (menuObject) {
+ const QMetaObject *mo = menuObject->metaObject();
+ int index = -1;
+
+ if (uMsg == WM_COMMAND)
+ index = mo->indexOfSignal("activated()");
+ else if (menuClosed)
+ index = mo->indexOfSignal("aboutToHide()");
+ else
+ index = mo->indexOfSignal("hovered()");
+
+ if (index < 0)
+ break;
+
+ menuObject->qt_metacall(QMetaObject::InvokeMetaMethod, index, 0);
+ if (menuClosed || uMsg == WM_COMMAND)
+ that->currentPopup = 0;
+ return 0;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ QT_WA({
+ return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
+ }, {
+ return ::DefWindowProcA(hWnd, uMsg, wParam, lParam);
+ });
+}
+
+/*!
+ Creates the window hosting the QWidget.
+*/
+HWND QAxServerBase::create(HWND hWndParent, RECT& rcPos)
+{
+ Q_ASSERT(isWidget && qt.widget);
+
+ static ATOM atom = 0;
+ HINSTANCE hInst = (HINSTANCE)qAxInstance;
+ EnterCriticalSection(&createWindowSection);
+ QString cn(QLatin1String("QAxControl"));
+ cn += QString::number((int)ActiveXProc);
+ if (!atom) {
+ QT_WA({
+ WNDCLASSW wcTemp;
+ wcTemp.style = CS_DBLCLKS;
+ wcTemp.cbClsExtra = 0;
+ wcTemp.cbWndExtra = 0;
+ wcTemp.hbrBackground = 0;
+ wcTemp.hCursor = 0;
+ wcTemp.hIcon = 0;
+ wcTemp.hInstance = hInst;
+ wcTemp.lpszClassName = (wchar_t*)cn.utf16();
+ wcTemp.lpszMenuName = 0;
+ wcTemp.lpfnWndProc = ActiveXProc;
+
+ atom = RegisterClassW(&wcTemp);
+ }, {
+ QByteArray cna = cn.toLatin1();
+ WNDCLASSA wcTemp;
+ wcTemp.style = CS_DBLCLKS;
+ wcTemp.cbClsExtra = 0;
+ wcTemp.cbWndExtra = 0;
+ wcTemp.hbrBackground = 0;
+ wcTemp.hCursor = 0;
+ wcTemp.hIcon = 0;
+ wcTemp.hInstance = hInst;
+ wcTemp.lpszClassName = cna.data();
+ wcTemp.lpszMenuName = 0;
+ wcTemp.lpfnWndProc = ActiveXProc;
+
+ atom = RegisterClassA(&wcTemp);
+ });
+ }
+ LeaveCriticalSection(&createWindowSection);
+ if (!atom && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
+ return 0;
+
+ Q_ASSERT(!m_hWnd);
+ HWND hWnd = 0;
+ QT_WA({
+ hWnd = ::CreateWindowW((wchar_t*)cn.utf16(), 0,
+ WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+ rcPos.left, rcPos.top, rcPos.right - rcPos.left,
+ rcPos.bottom - rcPos.top, hWndParent, 0, hInst, this);
+ }, {
+ hWnd = ::CreateWindowA(cn.toLatin1().data(), 0,
+ WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+ rcPos.left, rcPos.top, rcPos.right - rcPos.left,
+ rcPos.bottom - rcPos.top, hWndParent, 0, hInst, this);
+ });
+
+ Q_ASSERT(m_hWnd == hWnd);
+
+ updateMask();
+ EnableWindow(m_hWnd, qt.widget->isEnabled());
+
+ return hWnd;
+}
+
+/*
+ Recoursively creates Win32 submenus.
+*/
+HMENU QAxServerBase::createPopup(QMenu *popup, HMENU oldMenu)
+{
+ HMENU popupMenu = oldMenu ? oldMenu : CreatePopupMenu();
+ menuMap.insert(popupMenu, popup);
+
+ if (oldMenu) while (GetMenuItemCount(oldMenu)) {
+ DeleteMenu(oldMenu, 0, MF_BYPOSITION);
+ }
+
+ const QList<QAction*> actions = popup->actions();
+ for (int i = 0; i < actions.count(); ++i) {
+ QAction *action = actions.at(i);
+
+ uint flags = action->isEnabled() ? MF_ENABLED : MF_GRAYED;
+ if (action->isSeparator())
+ flags |= MF_SEPARATOR;
+ else if (action->menu())
+ flags |= MF_POPUP;
+ else
+ flags |= MF_STRING;
+ if (action->isChecked())
+ flags |= MF_CHECKED;
+
+ ushort itemId;
+ if (flags & MF_POPUP) {
+ itemId = static_cast<ushort>(
+ reinterpret_cast<ulong>(createPopup(action->menu()))
+ );
+ } else {
+ itemId = static_cast<ushort>(reinterpret_cast<ulong>(action));
+ actionMap.remove(itemId);
+ actionMap.insert(itemId, action);
+ }
+ QT_WA({
+ AppendMenuW(popupMenu, flags, itemId, (TCHAR*)action->text().utf16());
+ }, {
+ AppendMenuA(popupMenu, flags, itemId, action->text().toLocal8Bit());
+ });
+ }
+ if (oldMenu)
+ DrawMenuBar(hwndMenuOwner);
+ return popupMenu;
+}
+
+/*!
+ Creates a Win32 menubar.
+*/
+void QAxServerBase::createMenu(QMenuBar *menuBar)
+{
+ hmenuShared = ::CreateMenu();
+
+ int edit = 0;
+ int object = 0;
+ int help = 0;
+
+ const QList<QAction*> actions = menuBar->actions();
+ for (int i = 0; i < actions.count(); ++i) {
+ QAction *action = actions.at(i);
+
+ uint flags = action->isEnabled() ? MF_ENABLED : MF_GRAYED;
+ if (action->isSeparator())
+ flags |= MF_SEPARATOR;
+ else if (action->menu())
+ flags |= MF_POPUP;
+ else
+ flags |= MF_STRING;
+
+ if (action->text() == QCoreApplication::translate(qt.widget->metaObject()->className(), "&Edit"))
+ edit++;
+ else if (action->text() == QCoreApplication::translate(qt.widget->metaObject()->className(), "&Help"))
+ help++;
+ else
+ object++;
+
+ ushort itemId;
+ if (flags & MF_POPUP) {
+ itemId = static_cast<ushort>(
+ reinterpret_cast<ulong>(createPopup(action->menu()))
+ );
+ } else {
+ itemId = static_cast<ushort>(reinterpret_cast<ulong>(action));
+ actionMap.insert(itemId, action);
+ }
+ QT_WA({
+ AppendMenuW(hmenuShared, flags, itemId, (TCHAR*)action->text().utf16());
+ } , {
+ AppendMenuA(hmenuShared, flags, itemId, action->text().toLocal8Bit());
+ });
+ }
+
+ OLEMENUGROUPWIDTHS menuWidths = {0,edit,0,object,0,help};
+ HRESULT hres = m_spInPlaceFrame->InsertMenus(hmenuShared, &menuWidths);
+ if (FAILED(hres)) {
+ ::DestroyMenu(hmenuShared);
+ hmenuShared = 0;
+ return;
+ }
+
+ m_spInPlaceFrame->GetWindow(&hwndMenuOwner);
+
+ holemenu = OleCreateMenuDescriptor(hmenuShared, &menuWidths);
+ hres = m_spInPlaceFrame->SetMenu(hmenuShared, holemenu, m_hWnd);
+ if (FAILED(hres)) {
+ ::DestroyMenu(hmenuShared);
+ hmenuShared = 0;
+ OleDestroyMenuDescriptor(holemenu);
+ }
+}
+
+/*!
+ Remove the Win32 menubar.
+*/
+void QAxServerBase::removeMenu()
+{
+ if (hmenuShared)
+ m_spInPlaceFrame->RemoveMenus(hmenuShared);
+ holemenu = 0;
+ m_spInPlaceFrame->SetMenu(0, 0, m_hWnd);
+ if (hmenuShared) {
+ DestroyMenu(hmenuShared);
+ hmenuShared = 0;
+ menuMap.clear();
+ }
+ hwndMenuOwner = 0;
+}
+
+extern bool ignoreSlots(const char *test);
+extern bool ignoreProps(const char *test);
+
+/*!
+ Makes sure the type info is loaded
+*/
+void QAxServerBase::ensureMetaData()
+{
+ if (!m_spTypeInfo) {
+ qAxTypeLibrary->GetTypeInfoOfGuid(qAxFactory()->interfaceID(class_name), &m_spTypeInfo);
+ m_spTypeInfo->AddRef();
+ }
+}
+
+/*!
+ \internal
+ Returns true if the property \a index is exposed to COM and should
+ be saved/loaded.
+*/
+bool QAxServerBase::isPropertyExposed(int index)
+{
+ if (!theObject)
+ return false;
+
+ bool result = false;
+ const QMetaObject *mo = theObject->metaObject();
+
+ int qtProps = 0;
+ if (theObject->isWidgetType())
+ qtProps = QWidget::staticMetaObject.propertyCount();
+ QMetaProperty property = mo->property(index);
+ if (index <= qtProps && ignoreProps(property.name()))
+ return result;
+
+ BSTR bstrNames = QStringToBSTR(QLatin1String(property.name()));
+ DISPID dispId;
+ GetIDsOfNames(IID_NULL, (BSTR*)&bstrNames, 1, LOCALE_USER_DEFAULT, &dispId);
+ result = dispId != DISPID_UNKNOWN;
+ SysFreeString(bstrNames);
+
+ return result;
+}
+
+
+/*!
+ \internal
+ Updates the view, or asks the client site to do so.
+*/
+void QAxServerBase::update()
+{
+ if (isInPlaceActive) {
+ if (m_hWnd)
+ ::InvalidateRect(m_hWnd, 0, true);
+ else if (m_spInPlaceSite)
+ m_spInPlaceSite->InvalidateRect(NULL, true);
+ } else if (m_spAdviseSink) {
+ m_spAdviseSink->OnViewChange(DVASPECT_CONTENT, -1);
+ for (int i = 0; i < adviseSinks.count(); ++i) {
+ adviseSinks.at(i).pAdvSink->OnViewChange(DVASPECT_CONTENT, -1);
+ }
+ }
+}
+
+/*!
+ Resizes the control, faking a QResizeEvent if required
+*/
+void QAxServerBase::resize(const QSize &size)
+{
+ if (!isWidget || !qt.widget || !size.isValid() || size == QSize(0, 0))
+ return;
+
+ QSize oldSize = qt.widget->size();
+ qt.widget->resize(size);
+ QSize newSize = qt.widget->size();
+ // make sure we get a resize event even if not embedded as a control
+ if (!m_hWnd && !qt.widget->isVisible() && newSize != oldSize) {
+ QResizeEvent resizeEvent(newSize, oldSize);
+#ifndef QT_DLL // import from static library
+ extern bool qt_sendSpontaneousEvent(QObject*,QEvent*);
+#endif
+ qt_sendSpontaneousEvent(qt.widget, &resizeEvent);
+ }
+ m_currentExtent = qt.widget->size();
+}
+
+/*!
+ \internal
+
+ Updates the internal size values.
+*/
+void QAxServerBase::updateGeometry()
+{
+ if (!isWidget || !qt.widget)
+ return;
+
+ const QSize sizeHint = qt.widget->sizeHint();
+ const QSize size = qt.widget->size();
+ if (sizeHint.isValid()) { // if provided, adjust to sizeHint
+ QSize newSize = size;
+ if (!qt.widget->testAttribute(Qt::WA_Resized)) {
+ newSize = sizeHint;
+ } else { // according to sizePolicy rules if already resized
+ QSizePolicy sizePolicy = qt.widget->sizePolicy();
+ if (sizeHint.width() > size.width() && !(sizePolicy.horizontalPolicy() & QSizePolicy::ShrinkFlag))
+ newSize.setWidth(sizeHint.width());
+ if (sizeHint.width() < size.width() && !(sizePolicy.horizontalPolicy() & QSizePolicy::GrowFlag))
+ newSize.setWidth(sizeHint.width());
+ if (sizeHint.height() > size.height() && !(sizePolicy.verticalPolicy() & QSizePolicy::ShrinkFlag))
+ newSize.setHeight(sizeHint.height());
+ if (sizeHint.height() < size.height() && !(sizePolicy.verticalPolicy() & QSizePolicy::GrowFlag))
+ newSize.setHeight(sizeHint.height());
+ }
+ resize(newSize);
+
+ // set an initial size suitable for embedded controls
+ } else if (!qt.widget->testAttribute(Qt::WA_Resized)) {
+ resize(QSize(100, 100));
+ qt.widget->setAttribute(Qt::WA_Resized, false);
+ }
+}
+
+/*!
+ \internal
+
+ Updates the mask of the widget parent.
+*/
+void QAxServerBase::updateMask()
+{
+ if (!isWidget || !qt.widget || qt.widget->mask().isEmpty())
+ return;
+
+ QRegion rgn = qt.widget->mask();
+ HRGN hrgn = rgn.handle();
+
+ // Since SetWindowRegion takes ownership
+ HRGN wr = CreateRectRgn(0,0,0,0);
+ CombineRgn(wr, hrgn, 0, RGN_COPY);
+ SetWindowRgn(m_hWnd, wr, true);
+}
+
+static bool checkHRESULT(HRESULT hres)
+{
+ const char *name = 0;
+ switch(hres) {
+ case S_OK:
+ return true;
+ case DISP_E_BADPARAMCOUNT:
+#if defined(QT_CHECK_STATE)
+ qWarning("QAxBase: Error calling IDispatch member %s: Bad parameter count", name);
+#endif
+ return false;
+ case DISP_E_BADVARTYPE:
+#if defined(QT_CHECK_STATE)
+ qWarning("QAxBase: Error calling IDispatch member %s: Bad variant type", name);
+#endif
+ return false;
+ case DISP_E_EXCEPTION:
+#if defined(QT_CHECK_STATE)
+ qWarning("QAxBase: Error calling IDispatch member %s: Exception thrown by server", name);
+#endif
+ return false;
+ case DISP_E_MEMBERNOTFOUND:
+#if defined(QT_CHECK_STATE)
+ qWarning("QAxBase: Error calling IDispatch member %s: Member not found", name);
+#endif
+ return false;
+ case DISP_E_NONAMEDARGS:
+#if defined(QT_CHECK_STATE)
+ qWarning("QAxBase: Error calling IDispatch member %s: No named arguments", name);
+#endif
+ return false;
+ case DISP_E_OVERFLOW:
+#if defined(QT_CHECK_STATE)
+ qWarning("QAxBase: Error calling IDispatch member %s: Overflow", name);
+#endif
+ return false;
+ case DISP_E_PARAMNOTFOUND:
+#if defined(QT_CHECK_STATE)
+ qWarning("QAxBase: Error calling IDispatch member %s: Parameter not found", name);
+#endif
+ return false;
+ case DISP_E_TYPEMISMATCH:
+#if defined(QT_CHECK_STATE)
+ qWarning("QAxBase: Error calling IDispatch member %s: Type mismatch", name);
+#endif
+ return false;
+ case DISP_E_UNKNOWNINTERFACE:
+#if defined(QT_CHECK_STATE)
+ qWarning("QAxBase: Error calling IDispatch member %s: Unknown interface", name);
+#endif
+ return false;
+ case DISP_E_UNKNOWNLCID:
+#if defined(QT_CHECK_STATE)
+ qWarning("QAxBase: Error calling IDispatch member %s: Unknown locale ID", name);
+#endif
+ return false;
+ case DISP_E_PARAMNOTOPTIONAL:
+#if defined(QT_CHECK_STATE)
+ qWarning("QAxBase: Error calling IDispatch member %s: Non-optional parameter missing", name);
+#endif
+ return false;
+ default:
+#if defined(QT_CHECK_STATE)
+ qWarning("QAxBase: Error calling IDispatch member %s: Unknown error", name);
+#endif
+ return false;
+ }
+}
+
+static inline QByteArray paramType(const QByteArray &ptype, bool *out)
+{
+ *out = ptype.endsWith('&') || ptype.endsWith("**");
+ if (*out) {
+ QByteArray res(ptype);
+ res.truncate(res.length() - 1);
+ return res;
+ }
+
+ return ptype;
+}
+
+/*!
+ Catches all signals emitted by the Qt widget and fires the respective COM event.
+
+ \a isignal is the Qt Meta Object index of the received signal, and \a _o the
+ signal parameters.
+*/
+int QAxServerBase::qt_metacall(QMetaObject::Call call, int index, void **argv)
+{
+ Q_ASSERT(call == QMetaObject::InvokeMetaMethod);
+
+ if (index == -1) {
+ if (sender() && m_spInPlaceFrame) {
+ if (qobject_cast<QStatusBar*>(sender()) != statusBar)
+ return true;
+
+ if (statusBar->isHidden()) {
+ QString message = *(QString*)argv[1];
+ m_spInPlaceFrame->SetStatusText(QStringToBSTR(message));
+ }
+ }
+ return true;
+ }
+
+ if (freezeEvents || inDesignMode)
+ return true;
+
+ ensureMetaData();
+
+ // get the signal information.
+ const QMetaObject *mo = qt.object->metaObject();
+ QMetaMethod signal;
+ DISPID eventId = index;
+ int pcount = 0;
+ QByteArray type;
+ QList<QByteArray> ptypes;
+
+ switch(index) {
+ case DISPID_KEYDOWN:
+ case DISPID_KEYUP:
+ pcount = 2;
+ ptypes << "int&" << "int";
+ break;
+ case DISPID_KEYPRESS:
+ pcount = 1;
+ ptypes << "int&";
+ break;
+ case DISPID_MOUSEDOWN:
+ case DISPID_MOUSEMOVE:
+ case DISPID_MOUSEUP:
+ pcount = 4;
+ ptypes << "int" << "int" << "int" << "int";
+ break;
+ case DISPID_CLICK:
+ pcount = 0;
+ break;
+ case DISPID_DBLCLICK:
+ pcount = 0;
+ break;
+ default:
+ {
+ signal = mo->method(index);
+ Q_ASSERT(signal.methodType() == QMetaMethod::Signal);
+ type = signal.typeName();
+ QByteArray signature(signal.signature());
+ QByteArray name(signature);
+ name.truncate(name.indexOf('('));
+
+ eventId = signalCache.value(index, -1);
+ if (eventId == -1) {
+ ITypeInfo *eventInfo = 0;
+ qAxTypeLibrary->GetTypeInfoOfGuid(qAxFactory()->eventsID(class_name), &eventInfo);
+ if (eventInfo) {
+ QString uni_name = QLatin1String(name);
+ const OLECHAR *olename = reinterpret_cast<const OLECHAR *>(uni_name.utf16());
+ eventInfo->GetIDsOfNames((OLECHAR**)&olename, 1, &eventId);
+ eventInfo->Release();
+ }
+ }
+
+ signature = signature.mid(name.length() + 1);
+ signature.truncate(signature.length() - 1);
+
+ if (!signature.isEmpty())
+ ptypes = signature.split(',');
+
+ pcount = ptypes.count();
+ }
+ break;
+ }
+ if (pcount && !argv) {
+ qWarning("QAxServerBase::qt_metacall: Missing %d arguments", pcount);
+ return false;
+ }
+ if (eventId == -1)
+ return false;
+
+ // For all connected event sinks...
+ IConnectionPoint *cpoint = 0;
+ GUID IID_QAxEvents = qAxFactory()->eventsID(class_name);
+ FindConnectionPoint(IID_QAxEvents, &cpoint);
+ if (cpoint) {
+ IEnumConnections *clist = 0;
+ cpoint->EnumConnections(&clist);
+ if (clist) {
+ clist->Reset();
+ ULONG cc = 1;
+ CONNECTDATA c[1];
+ clist->Next(cc, (CONNECTDATA*)&c, &cc);
+ if (cc) {
+ // setup parameters
+ unsigned int argErr = 0;
+ DISPPARAMS dispParams;
+ dispParams.cArgs = pcount;
+ dispParams.cNamedArgs = 0;
+ dispParams.rgdispidNamedArgs = 0;
+ dispParams.rgvarg = 0;
+
+ if (pcount) // Use malloc/free for eval package compatibility
+ dispParams.rgvarg = (VARIANTARG*)malloc(pcount * sizeof(VARIANTARG));
+ int p = 0;
+ for (p = 0; p < pcount; ++p) {
+ VARIANT *arg = dispParams.rgvarg + (pcount - p - 1);
+ VariantInit(arg);
+
+ bool out;
+ QByteArray ptype = paramType(ptypes.at(p), &out);
+ QVariant variant;
+ if (mo->indexOfEnumerator(ptype) != -1) {
+ // convert enum values to int
+ variant = QVariant(*reinterpret_cast<int *>(argv[p+1]));
+ } else {
+ QVariant::Type vt = QVariant::nameToType(ptype);
+ if (vt == QVariant::UserType) {
+ if (ptype.endsWith('*')) {
+ variant = QVariant(QMetaType::type(ptype), (void**)argv[p+1]);
+ // qVariantSetValue(variant, *(void**)(argv[p + 1]), ptype);
+ } else {
+ variant = QVariant(QMetaType::type(ptype), argv[p+1]);
+ // qVariantSetValue(variant, argv[p + 1], ptype);
+ }
+ } else {
+ variant = QVariant(vt, argv[p + 1]);
+ }
+ }
+
+ QVariantToVARIANT(variant, *arg, type, out);
+ }
+
+ VARIANT retval;
+ VariantInit(&retval);
+ VARIANT *pretval = 0;
+ if (!type.isEmpty())
+ pretval = &retval;
+
+ // call listeners (through IDispatch)
+ while (cc) {
+ if (c->pUnk) {
+ IDispatch *disp = 0;
+ c->pUnk->QueryInterface(IID_QAxEvents, (void**)&disp);
+ if (disp) {
+ disp->Invoke(eventId, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispParams, pretval, 0, &argErr);
+
+ // update out-parameters and return value
+ if (index > 0) {
+ for (p = 0; p < pcount; ++p) {
+ bool out;
+ QByteArray ptype = paramType(ptypes.at(p), &out);
+ if (out)
+ QVariantToVoidStar(VARIANTToQVariant(dispParams.rgvarg[pcount - p - 1], ptype), argv[p+1], ptype);
+ }
+ if (pretval)
+ QVariantToVoidStar(VARIANTToQVariant(retval, type), argv[0], type);
+ }
+ disp->Release();
+ }
+ c->pUnk->Release(); // AddRef'ed by clist->Next implementation
+ }
+ clist->Next(cc, (CONNECTDATA*)&c, &cc);
+ }
+
+ // clean up
+ for (p = 0; p < pcount; ++p)
+ clearVARIANT(dispParams.rgvarg+p);
+ free(dispParams.rgvarg);
+ }
+ clist->Release();
+ }
+ cpoint->Release();
+ }
+
+ return true;
+}
+
+/*!
+ Call IPropertyNotifySink of connected clients.
+ \a dispId specifies the ID of the property that changed.
+*/
+bool QAxServerBase::emitRequestPropertyChange(const char *property)
+{
+ long dispId = -1;
+
+ IConnectionPoint *cpoint = 0;
+ FindConnectionPoint(IID_IPropertyNotifySink, &cpoint);
+ if (cpoint) {
+ IEnumConnections *clist = 0;
+ cpoint->EnumConnections(&clist);
+ if (clist) {
+ clist->Reset();
+ ULONG cc = 1;
+ CONNECTDATA c[1];
+ clist->Next(cc, (CONNECTDATA*)&c, &cc);
+ if (cc) {
+ if (dispId == -1) {
+ BSTR bstr = QStringToBSTR(QLatin1String(property));
+ GetIDsOfNames(IID_NULL, &bstr, 1, LOCALE_USER_DEFAULT, &dispId);
+ SysFreeString(bstr);
+ }
+ if (dispId != -1) while (cc) {
+ if (c->pUnk) {
+ IPropertyNotifySink *sink = 0;
+ c->pUnk->QueryInterface(IID_IPropertyNotifySink, (void**)&sink);
+ bool disallows = sink && sink->OnRequestEdit(dispId) == S_FALSE;
+ sink->Release();
+ c->pUnk->Release();
+ if (disallows) { // a client disallows the property to change
+ clist->Release();
+ cpoint->Release();
+ return false;
+ }
+ }
+ clist->Next(cc, (CONNECTDATA*)&c, &cc);
+ }
+ }
+ clist->Release();
+ }
+ cpoint->Release();
+ }
+ dirtyflag = true;
+ return true;
+}
+
+/*!
+ Call IPropertyNotifySink of connected clients.
+ \a dispId specifies the ID of the property that changed.
+*/
+void QAxServerBase::emitPropertyChanged(const char *property)
+{
+ long dispId = -1;
+
+ IConnectionPoint *cpoint = 0;
+ FindConnectionPoint(IID_IPropertyNotifySink, &cpoint);
+ if (cpoint) {
+ IEnumConnections *clist = 0;
+ cpoint->EnumConnections(&clist);
+ if (clist) {
+ clist->Reset();
+ ULONG cc = 1;
+ CONNECTDATA c[1];
+ clist->Next(cc, (CONNECTDATA*)&c, &cc);
+ if (cc) {
+ if (dispId == -1) {
+ BSTR bstr = QStringToBSTR(QLatin1String(property));
+ GetIDsOfNames(IID_NULL, &bstr, 1, LOCALE_USER_DEFAULT, &dispId);
+ SysFreeString(bstr);
+ }
+ if (dispId != -1) while (cc) {
+ if (c->pUnk) {
+ IPropertyNotifySink *sink = 0;
+ c->pUnk->QueryInterface(IID_IPropertyNotifySink, (void**)&sink);
+ if (sink) {
+ sink->OnChanged(dispId);
+ sink->Release();
+ }
+ c->pUnk->Release();
+ }
+ clist->Next(cc, (CONNECTDATA*)&c, &cc);
+ }
+ }
+ clist->Release();
+ }
+ cpoint->Release();
+ }
+ dirtyflag = true;
+}
+
+//**** IProvideClassInfo
+/*
+ Provide the ITypeInfo implementation for the COM class.
+*/
+HRESULT WINAPI QAxServerBase::GetClassInfo(ITypeInfo** pptinfo)
+{
+ if (!pptinfo)
+ return E_POINTER;
+
+ *pptinfo = 0;
+ if (!qAxTypeLibrary)
+ return DISP_E_BADINDEX;
+
+ return qAxTypeLibrary->GetTypeInfoOfGuid(qAxFactory()->classID(class_name), pptinfo);
+}
+
+//**** IProvideClassInfo2
+/*
+ Provide the ID of the event interface.
+*/
+HRESULT WINAPI QAxServerBase::GetGUID(DWORD dwGuidKind, GUID* pGUID)
+{
+ if (!pGUID)
+ return E_POINTER;
+
+ if (dwGuidKind == GUIDKIND_DEFAULT_SOURCE_DISP_IID) {
+ *pGUID = qAxFactory()->eventsID(class_name);
+ return S_OK;
+ }
+ *pGUID = GUID_NULL;
+ return E_FAIL;
+}
+
+//**** IDispatch
+/*
+ Returns the number of class infos for this IDispatch.
+*/
+HRESULT WINAPI QAxServerBase::GetTypeInfoCount(UINT* pctinfo)
+{
+ if (!pctinfo)
+ return E_POINTER;
+
+ *pctinfo = qAxTypeLibrary ? 1 : 0;
+ return S_OK;
+}
+
+/*
+ Provides the ITypeInfo for this IDispatch implementation.
+*/
+HRESULT WINAPI QAxServerBase::GetTypeInfo(UINT itinfo, LCID /*lcid*/, ITypeInfo** pptinfo)
+{
+ if (!pptinfo)
+ return E_POINTER;
+
+ if (!qAxTypeLibrary)
+ return DISP_E_BADINDEX;
+
+ ensureMetaData();
+
+ *pptinfo = m_spTypeInfo;
+ (*pptinfo)->AddRef();
+
+ return S_OK;
+}
+
+/*
+ Provides the names of the methods implemented in this IDispatch implementation.
+*/
+HRESULT WINAPI QAxServerBase::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
+ LCID /*lcid*/, DISPID* rgdispid)
+{
+ if (!rgszNames || !rgdispid)
+ return E_POINTER;
+
+ if (!qAxTypeLibrary)
+ return DISP_E_UNKNOWNNAME;
+
+ ensureMetaData();
+ if (!m_spTypeInfo)
+ return DISP_E_UNKNOWNNAME;
+
+ return m_spTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
+}
+
+/*
+ Map the COM call to the Qt slot/property for \a dispidMember.
+*/
+HRESULT WINAPI QAxServerBase::Invoke(DISPID dispidMember, REFIID riid,
+ LCID /*lcid*/, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pvarResult,
+ EXCEPINFO* pexcepinfo, UINT* puArgErr)
+{
+ if (riid != IID_NULL)
+ return DISP_E_UNKNOWNINTERFACE;
+ if (!theObject)
+ return E_UNEXPECTED;
+
+ HRESULT res = DISP_E_MEMBERNOTFOUND;
+
+ bool uniqueIndex = wFlags == DISPATCH_PROPERTYGET || wFlags == DISPATCH_PROPERTYPUT || wFlags == DISPATCH_METHOD;
+
+ int index = uniqueIndex ? indexCache.value(dispidMember, -1) : -1;
+ QByteArray name;
+ if (index == -1) {
+ ensureMetaData();
+
+ // This property or method is invoked when an ActiveX client specifies
+ // the object name without a property or method. We only support property.
+ if (dispidMember == DISPID_VALUE && (wFlags == DISPATCH_PROPERTYGET || wFlags == DISPATCH_PROPERTYPUT)) {
+ const QMetaObject *mo = qt.object->metaObject();
+ index = mo->indexOfClassInfo("DefaultProperty");
+ if (index != -1) {
+ name = mo->classInfo(index).value();
+ index = mo->indexOfProperty(name);
+ }
+ } else {
+ BSTR bname;
+ UINT cname = 0;
+ if (m_spTypeInfo)
+ m_spTypeInfo->GetNames(dispidMember, &bname, 1, &cname);
+ if (!cname)
+ return res;
+
+ name = QString::fromUtf16((const ushort *)bname).toLatin1();
+ SysFreeString(bname);
+ }
+ }
+
+ const QMetaObject *mo = qt.object->metaObject();
+ QSize oldSizeHint;
+ if (isWidget)
+ oldSizeHint = qt.widget->sizeHint();
+
+ switch (wFlags) {
+ case DISPATCH_PROPERTYGET|DISPATCH_METHOD:
+ case DISPATCH_PROPERTYGET:
+ {
+ if (index == -1) {
+ index = mo->indexOfProperty(name);
+ if (index == -1 && wFlags == DISPATCH_PROPERTYGET)
+ return res;
+ }
+
+ QMetaProperty property;
+ if (index < mo->propertyCount())
+ property = mo->property(index);
+
+ if (property.isReadable()) {
+ if (!pvarResult)
+ return DISP_E_PARAMNOTOPTIONAL;
+ if (pDispParams->cArgs ||
+ pDispParams->cNamedArgs)
+ return DISP_E_BADPARAMCOUNT;
+
+ QVariant var = qt.object->property(property.name());
+ if (!var.isValid())
+ res = DISP_E_MEMBERNOTFOUND;
+ else if (!QVariantToVARIANT(var, *pvarResult))
+ res = DISP_E_TYPEMISMATCH;
+ else
+ res = S_OK;
+ break;
+ } else if (wFlags == DISPATCH_PROPERTYGET) {
+ break;
+ }
+ }
+ // FALLTHROUGH if wFlags == DISPATCH_PROPERTYGET|DISPATCH_METHOD AND not a property.
+ case DISPATCH_METHOD:
+ {
+ int nameLength = 0;
+ if (index == -1) {
+ nameLength = name.length();
+ name += "(";
+ // no parameter - shortcut
+ if (!pDispParams->cArgs)
+ index = mo->indexOfSlot((name + ")"));
+ // search
+ if (index == -1) {
+ for (int i = 0; i < mo->methodCount(); ++i) {
+ const QMetaMethod slot(mo->method(i));
+ if (slot.methodType() == QMetaMethod::Slot && QByteArray(slot.signature()).startsWith(name)) {
+ index = i;
+ break;
+ }
+ }
+ // resolve overloads
+ if (index == -1) {
+ QRegExp regexp(QLatin1String("_([0-9])\\("));
+ if (regexp.lastIndexIn(QString::fromLatin1(name.constData())) != -1) {
+ name = name.left(name.length() - regexp.cap(0).length()) + "(";
+ int overload = regexp.cap(1).toInt() + 1;
+
+ for (int s = 0; s < qt.object->metaObject()->methodCount(); ++s) {
+ QMetaMethod slot = qt.object->metaObject()->method(s);
+ if (slot.methodType() == QMetaMethod::Slot && QByteArray(slot.signature()).startsWith(name)) {
+ if (!--overload) {
+ index = s;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (index == -1)
+ return res;
+ }
+ }
+
+ int lookupIndex = index;
+
+ // get slot info
+ QMetaMethod slot(mo->method(index));
+ Q_ASSERT(slot.methodType() == QMetaMethod::Slot);
+ QByteArray type = slot.typeName();
+ name = slot.signature();
+ nameLength = name.indexOf('(');
+ QByteArray prototype = name.mid(nameLength + 1);
+ prototype.truncate(prototype.length() - 1);
+ QList<QByteArray> ptypes;
+ if (!prototype.isEmpty())
+ ptypes = prototype.split(',');
+ int pcount = ptypes.count();
+
+ // verify parameter count
+ if (pcount > pDispParams->cArgs) {
+ // count cloned slots immediately following the real thing
+ int defArgs = 0;
+ while (index < mo->methodCount()) {
+ ++index;
+ slot = mo->method(index);
+ if (!(slot.attributes() & QMetaMethod::Cloned))
+ break;
+ --pcount;
+ // found a matching overload. ptypes still valid
+ if (pcount <= pDispParams->cArgs)
+ break;
+ }
+ // still wrong :(
+ if (pcount > pDispParams->cArgs)
+ return DISP_E_PARAMNOTOPTIONAL;
+ } else if (pcount < pDispParams->cArgs) {
+ return DISP_E_BADPARAMCOUNT;
+ }
+
+ // setup parameters (pcount + return)
+ bool ok = true;
+ void *static_argv[QAX_NUM_PARAMS + 1];
+ QVariant static_varp[QAX_NUM_PARAMS + 1];
+ void *static_argv_pointer[QAX_NUM_PARAMS + 1];
+
+ int totalParam = pcount;
+ if (!type.isEmpty())
+ ++totalParam;
+
+ void **argv = 0; // the actual array passed into qt_metacall
+ void **argv_pointer = 0; // in case we need an additional level of indirection
+ QVariant *varp = 0; // QVariants to hold the temporary Qt data object for us
+
+ if (totalParam) {
+ if (totalParam <= QAX_NUM_PARAMS) {
+ argv = static_argv;
+ argv_pointer = static_argv_pointer;
+ varp = static_varp;
+ } else {
+ argv = new void*[pcount + 1];
+ argv_pointer = new void*[pcount + 1];
+ varp = new QVariant[pcount + 1];
+ }
+
+ argv_pointer[0] = 0;
+ }
+
+ for (int p = 0; p < pcount; ++p) {
+ // map the VARIANT to the void*
+ bool out;
+ QByteArray ptype = paramType(ptypes.at(p), &out);
+ varp[p + 1] = VARIANTToQVariant(pDispParams->rgvarg[pcount - p - 1], ptype);
+ argv_pointer[p + 1] = 0;
+ if (varp[p + 1].isValid()) {
+ if (varp[p + 1].type() == QVariant::UserType) {
+ argv[p + 1] = varp[p + 1].data();
+ } else if (ptype == "QVariant") {
+ argv[p + 1] = varp + p + 1;
+ } else {
+ argv[p + 1] = const_cast<void*>(varp[p + 1].constData());
+ if (ptype.endsWith("*")) {
+ argv_pointer[p + 1] = argv[p + 1];
+ argv[p + 1] = argv_pointer + p + 1;
+ }
+ }
+ } else if (ptype == "QVariant") {
+ argv[p + 1] = varp + p + 1;
+ } else {
+ if (puArgErr)
+ *puArgErr = pcount-p-1;
+ ok = false;
+ }
+ }
+
+ // return value
+ if (!type.isEmpty()) {
+ QVariant::Type vt = QVariant::nameToType(type);
+ if (vt == QVariant::UserType)
+ vt = QVariant::Invalid;
+ varp[0] = QVariant(vt);
+ if (varp[0].type() == QVariant::Invalid && mo->indexOfEnumerator(slot.typeName()) != -1)
+ varp[0] = QVariant(QVariant::Int);
+
+ if (varp[0].type() == QVariant::Invalid) {
+ if (type == "QVariant")
+ argv[0] = varp;
+ else
+ argv[0] = 0;
+ } else {
+ argv[0] = const_cast<void*>(varp[0].constData());
+ }
+ if (type.endsWith("*")) {
+ argv_pointer[0] = argv[0];
+ argv[0] = argv_pointer;
+ }
+ }
+
+ // call the slot if everthing went fine.
+ if (ok) {
+ ++invokeCount;
+ qt.object->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv);
+ if (--invokeCount < 0)
+ invokeCount = 0;
+
+ // update reference parameters and return value
+ for (int p = 0; p < pcount; ++p) {
+ bool out;
+ QByteArray ptype = paramType(ptypes.at(p), &out);
+ if (out) {
+ if (!QVariantToVARIANT(varp[p + 1], pDispParams->rgvarg[pcount - p - 1], ptype, out))
+ ok = false;
+ }
+ }
+ if (!type.isEmpty() && pvarResult) {
+ if (!varp[0].isValid() && type != "QVariant")
+ varp[0] = QVariant(QMetaType::type(type), argv_pointer);
+// qVariantSetValue(varp[0], argv_pointer[0], type);
+ ok = QVariantToVARIANT(varp[0], *pvarResult, type);
+ }
+ }
+ if (argv && argv != static_argv) {
+ delete []argv;
+ delete []argv_pointer;
+ delete []varp;
+ }
+
+ res = ok ? S_OK : DISP_E_TYPEMISMATCH;
+
+ // reset in case index changed for default-arg handling
+ index = lookupIndex;
+ }
+ break;
+ case DISPATCH_PROPERTYPUT:
+ case DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF:
+ {
+ if (index == -1) {
+ index = mo->indexOfProperty(name);
+ if (index == -1)
+ return res;
+ }
+
+ QMetaProperty property;
+ if (index < mo->propertyCount())
+ property = mo->property(index);
+ if (!property.isWritable())
+ return DISP_E_MEMBERNOTFOUND;
+ if (!pDispParams->cArgs)
+ return DISP_E_PARAMNOTOPTIONAL;
+ if (pDispParams->cArgs != 1 ||
+ pDispParams->cNamedArgs != 1 ||
+ *pDispParams->rgdispidNamedArgs != DISPID_PROPERTYPUT)
+ return DISP_E_BADPARAMCOUNT;
+
+ QVariant var = VARIANTToQVariant(*pDispParams->rgvarg, property.typeName(), property.type());
+ if (!var.isValid()) {
+ if (puArgErr)
+ *puArgErr = 0;
+ return DISP_E_BADVARTYPE;
+ }
+ if (!qt.object->setProperty(property.name(), var)) {
+ if (puArgErr)
+ *puArgErr = 0;
+ return DISP_E_TYPEMISMATCH;
+ }
+
+ res = S_OK;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // maybe calling a setter? Notify client about changes
+ switch(wFlags) {
+ case DISPATCH_METHOD:
+ case DISPATCH_PROPERTYPUT:
+ case DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF:
+ if (m_spAdviseSink || adviseSinks.count()) {
+ FORMATETC fmt;
+ fmt.cfFormat = 0;
+ fmt.ptd = 0;
+ fmt.dwAspect = DVASPECT_CONTENT;
+ fmt.lindex = -1;
+ fmt.tymed = TYMED_NULL;
+
+ STGMEDIUM stg;
+ stg.tymed = TYMED_NULL;
+ stg.pUnkForRelease = 0;
+ stg.hBitmap = 0; // initializes the whole union
+
+ if (m_spAdviseSink) {
+ m_spAdviseSink->OnViewChange(DVASPECT_CONTENT, -1);
+ m_spAdviseSink->OnDataChange(&fmt, &stg);
+ }
+ for (int i = 0; i < adviseSinks.count(); ++i) {
+ adviseSinks.at(i).pAdvSink->OnDataChange(&fmt, &stg);
+ }
+ }
+
+ dirtyflag = true;
+ break;
+ default:
+ break;
+ }
+
+ if (index != -1 && uniqueIndex)
+ indexCache.insert(dispidMember, index);
+
+ if (exception) {
+ if (pexcepinfo) {
+ memset(pexcepinfo, 0, sizeof(EXCEPINFO));
+
+ pexcepinfo->wCode = exception->code;
+ if (!exception->src.isNull())
+ pexcepinfo->bstrSource = QStringToBSTR(exception->src);
+ if (!exception->desc.isNull())
+ pexcepinfo->bstrDescription = QStringToBSTR(exception->desc);
+ if (!exception->context.isNull()) {
+ QString context = exception->context;
+ int contextID = 0;
+ int br = context.indexOf(QLatin1Char('['));
+ if (br != -1) {
+ context = context.mid(br+1);
+ context = context.left(context.length() - 1);
+ contextID = context.toInt();
+
+ context = exception->context;
+ context = context.left(br-1);
+ }
+ pexcepinfo->bstrHelpFile = QStringToBSTR(context);
+ pexcepinfo->dwHelpContext = contextID;
+ }
+ }
+ delete exception;
+ exception = 0;
+ return DISP_E_EXCEPTION;
+ } else if (isWidget) {
+ QSize sizeHint = qt.widget->sizeHint();
+ if (oldSizeHint != sizeHint) {
+ updateGeometry();
+ if (m_spInPlaceSite) {
+ RECT rect = {0, 0, sizeHint.width(), sizeHint.height()};
+ m_spInPlaceSite->OnPosRectChange(&rect);
+ }
+ }
+ updateMask();
+ }
+
+ return res;
+}
+
+//**** IConnectionPointContainer
+/*
+ Provide the IEnumConnectionPoints implemented in the QAxSignalVec class.
+*/
+HRESULT WINAPI QAxServerBase::EnumConnectionPoints(IEnumConnectionPoints **epoints)
+{
+ if (!epoints)
+ return E_POINTER;
+ *epoints = new QAxSignalVec(points);
+ (*epoints)->AddRef();
+ return S_OK;
+}
+
+/*
+ Provide the IConnectionPoint implemented in the QAxConnection for \a iid.
+*/
+HRESULT WINAPI QAxServerBase::FindConnectionPoint(REFIID iid, IConnectionPoint **cpoint)
+{
+ if (!cpoint)
+ return E_POINTER;
+
+ IConnectionPoint *cp = points[iid];
+ *cpoint = cp;
+ if (cp) {
+ cp->AddRef();
+ return S_OK;
+ }
+ return CONNECT_E_NOCONNECTION;
+}
+
+//**** IPersistStream
+/*
+ \reimp
+
+ See documentation of IPersistStorage::IsDirty.
+*/
+HRESULT WINAPI QAxServerBase::IsDirty()
+{
+ return dirtyflag ? S_OK : S_FALSE;
+}
+
+HRESULT WINAPI QAxServerBase::Load(IStream *pStm)
+{
+ STATSTG stat;
+ HRESULT hres = pStm->Stat(&stat, STATFLAG_DEFAULT);
+ bool openAsText = false;
+ QByteArray qtarray;
+ if (hres == S_OK) {
+ QString streamName = QString::fromUtf16((const ushort *)stat.pwcsName);
+ CoTaskMemFree(stat.pwcsName);
+ openAsText = streamName == QLatin1String("SomeStreamName");
+ if (stat.cbSize.HighPart) // more than 4GB - too large!
+ return S_FALSE;
+
+ qtarray.resize(stat.cbSize.LowPart);
+ ULONG read;
+ pStm->Read(qtarray.data(), stat.cbSize.LowPart, &read);
+ }
+ const QMetaObject *mo = qt.object->metaObject();
+
+ QBuffer qtbuffer(&qtarray);
+ QByteArray mimeType = mo->classInfo(mo->indexOfClassInfo("MIME")).value();
+ if (!mimeType.isEmpty()) {
+ mimeType = mimeType.left(mimeType.indexOf(':')); // first type
+ QAxBindable *axb = (QAxBindable*)qt.object->qt_metacast("QAxBindable");
+ if (axb && axb->readData(&qtbuffer, QString::fromLatin1(mimeType)))
+ return S_OK;
+ }
+
+ qtbuffer.close(); // resets
+ qtbuffer.open(openAsText ? (QIODevice::ReadOnly | QIODevice::Text) : QIODevice::ReadOnly);
+
+ QDataStream qtstream(&qtbuffer);
+ int version;
+ qtstream >> version;
+ qtstream.setVersion(version);
+ int more = 0;
+ qtstream >> more;
+
+ while (!qtbuffer.atEnd() && more) {
+ QString propname;
+ QVariant value;
+ qtstream >> propname;
+ if (propname.isEmpty())
+ break;
+ qtstream >> value;
+ qtstream >> more;
+
+ int idx = mo->indexOfProperty(propname.toLatin1());
+ QMetaProperty property = mo->property(idx);
+ if (property.isWritable())
+ qt.object->setProperty(propname.toLatin1(), value);
+ }
+ return S_OK;
+}
+
+HRESULT WINAPI QAxServerBase::Save(IStream *pStm, BOOL clearDirty)
+{
+ const QMetaObject *mo = qt.object->metaObject();
+
+ QBuffer qtbuffer;
+ bool saved = false;
+ QByteArray mimeType = mo->classInfo(mo->indexOfClassInfo("MIME")).value();
+ if (!mimeType.isEmpty()) {
+ QAxBindable *axb = (QAxBindable*)qt.object->qt_metacast("QAxBindable");
+ saved = axb && axb->writeData(&qtbuffer);
+ qtbuffer.close();
+ }
+
+ if (!saved) {
+ qtbuffer.open(QIODevice::WriteOnly);
+ QDataStream qtstream(&qtbuffer);
+ qtstream << qtstream.version();
+
+ for (int prop = 0; prop < mo->propertyCount(); ++prop) {
+ if (!isPropertyExposed(prop))
+ continue;
+ QMetaProperty metaprop = mo->property(prop);
+ if (QByteArray(metaprop.typeName()).endsWith('*'))
+ continue;
+ QString property = QLatin1String(metaprop.name());
+ QVariant qvar = qt.object->property(metaprop.name());
+ if (qvar.isValid()) {
+ qtstream << int(1);
+ qtstream << property;
+ qtstream << qvar;
+ }
+ }
+
+ qtstream << int(0);
+ qtbuffer.close();
+ }
+
+ QByteArray qtarray = qtbuffer.buffer();
+ ULONG written = 0;
+ const char *data = qtarray.constData();
+ ULARGE_INTEGER newsize;
+ newsize.HighPart = 0;
+ newsize.LowPart = qtarray.size();
+ pStm->SetSize(newsize);
+ pStm->Write(data, qtarray.size(), &written);
+ pStm->Commit(STGC_ONLYIFCURRENT);
+
+ if (clearDirty)
+ dirtyflag = false;
+ return S_OK;
+}
+
+HRESULT WINAPI QAxServerBase::GetSizeMax(ULARGE_INTEGER *pcbSize)
+{
+ const QMetaObject *mo = qt.object->metaObject();
+
+ int np = mo->propertyCount();
+ pcbSize->HighPart = 0;
+ pcbSize->LowPart = np * 50;
+
+ return S_OK;
+}
+
+//**** IPersistStorage
+
+HRESULT WINAPI QAxServerBase::InitNew(IStorage *pStg)
+{
+ if (initNewCalled)
+ return CO_E_ALREADYINITIALIZED;
+
+ dirtyflag = false;
+ initNewCalled = true;
+
+ m_spStorage = pStg;
+ if (m_spStorage)
+ m_spStorage->AddRef();
+ return S_OK;
+}
+
+HRESULT WINAPI QAxServerBase::Load(IStorage *pStg)
+{
+ if (InitNew(pStg) != S_OK)
+ return CO_E_ALREADYINITIALIZED;
+
+ IStream *spStream = 0;
+ QString streamName = QLatin1String(qt.object->metaObject()->className());
+ streamName.replace(QLatin1Char(':'), QLatin1Char('.'));
+ /* Also invalid, but not relevant
+ streamName.replace(QLatin1Char('/'), QLatin1Char('_'));
+ streamName.replace(QLatin1Char('\\'), QLatin1Char('_'));
+ */
+ streamName += QLatin1String("_Stream4.2");
+
+ pStg->OpenStream((const WCHAR *)streamName.utf16(), 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &spStream);
+ if (!spStream) // support for streams saved with 4.1 and earlier
+ pStg->OpenStream(L"SomeStreamName", 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &spStream);
+ if (!spStream)
+ return E_FAIL;
+
+ Load(spStream);
+ spStream->Release();
+
+ return S_OK;
+}
+
+HRESULT WINAPI QAxServerBase::Save(IStorage *pStg, BOOL fSameAsLoad)
+{
+ IStream *spStream = 0;
+ QString streamName = QLatin1String(qt.object->metaObject()->className());
+ streamName.replace(QLatin1Char(':'), QLatin1Char('.'));
+ /* Also invalid, but not relevant
+ streamName.replace(QLatin1Char('/'), QLatin1Char('_'));
+ streamName.replace(QLatin1Char('\\'), QLatin1Char('_'));
+ */
+ streamName += QLatin1String("_Stream4.2");
+
+ pStg->CreateStream((const WCHAR *)streamName.utf16(), STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &spStream);
+ if (!spStream)
+ return E_FAIL;
+
+ Save(spStream, true);
+
+ spStream->Release();
+ return S_OK;
+}
+
+HRESULT WINAPI QAxServerBase::SaveCompleted(IStorage *pStgNew)
+{
+ if (pStgNew) {
+ if (m_spStorage)
+ m_spStorage->Release();
+ m_spStorage = pStgNew;
+ m_spStorage->AddRef();
+ }
+ return S_OK;
+}
+
+HRESULT WINAPI QAxServerBase::HandsOffStorage()
+{
+ if (m_spStorage) m_spStorage->Release();
+ m_spStorage = 0;
+
+ return S_OK;
+}
+
+//**** IPersistPropertyBag
+/*
+ Initialize the properties of the Qt widget.
+*/
+HRESULT WINAPI QAxServerBase::InitNew()
+{
+ if (initNewCalled)
+ return CO_E_ALREADYINITIALIZED;
+
+ dirtyflag = false;
+ initNewCalled = true;
+ return S_OK;
+}
+
+/*
+ Set the properties of the Qt widget to the values provided in the \a bag.
+*/
+HRESULT WINAPI QAxServerBase::Load(IPropertyBag *bag, IErrorLog * /*log*/)
+{
+ if (!bag)
+ return E_POINTER;
+
+ if (InitNew() != S_OK)
+ return E_UNEXPECTED;
+
+ bool error = false;
+ const QMetaObject *mo = qt.object->metaObject();
+ for (int prop = 0; prop < mo->propertyCount(); ++prop) {
+ if (!isPropertyExposed(prop))
+ continue;
+ QMetaProperty property = mo->property(prop);
+ const char* pname = property.name();
+ BSTR bstr = QStringToBSTR(QLatin1String(pname));
+ VARIANT var;
+ var.vt = VT_EMPTY;
+ HRESULT res = bag->Read(bstr, &var, 0);
+ if (property.isWritable() && var.vt != VT_EMPTY) {
+ if (res != S_OK || !qt.object->setProperty(pname, VARIANTToQVariant(var, property.typeName(), property.type())))
+ error = true;
+ }
+ SysFreeString(bstr);
+ }
+
+ updateGeometry();
+
+ return /*error ? E_FAIL :*/ S_OK;
+}
+
+/*
+ Save the properties of the Qt widget into the \a bag.
+*/
+HRESULT WINAPI QAxServerBase::Save(IPropertyBag *bag, BOOL clearDirty, BOOL /*saveAll*/)
+{
+ if (!bag)
+ return E_POINTER;
+
+ if (clearDirty)
+ dirtyflag = false;
+ bool error = false;
+ const QMetaObject *mo = qt.object->metaObject();
+ for (int prop = 0; prop < mo->propertyCount(); ++prop) {
+ if (!isPropertyExposed(prop))
+ continue;
+ QMetaProperty property = mo->property(prop);
+ if (QByteArray(property.typeName()).endsWith('*'))
+ continue;
+
+ BSTR bstr = QStringToBSTR(QLatin1String(property.name()));
+ QVariant qvar = qt.object->property(property.name());
+ if (!qvar.isValid())
+ error = true;
+ VARIANT var;
+ QVariantToVARIANT(qvar, var);
+ bag->Write(bstr, &var);
+ SysFreeString(bstr);
+ }
+ return /*error ? E_FAIL :*/ S_OK;
+}
+
+//**** IPersistFile
+/*
+*/
+HRESULT WINAPI QAxServerBase::SaveCompleted(LPCOLESTR fileName)
+{
+ if (qt.object->metaObject()->indexOfClassInfo("MIME") == -1)
+ return E_NOTIMPL;
+
+ currentFileName = QString::fromUtf16(reinterpret_cast<const ushort *>(fileName));
+ return S_OK;
+}
+
+HRESULT WINAPI QAxServerBase::GetCurFile(LPOLESTR *currentFile)
+{
+ if (qt.object->metaObject()->indexOfClassInfo("MIME") == -1)
+ return E_NOTIMPL;
+
+ if (currentFileName.isEmpty()) {
+ *currentFile = 0;
+ return S_FALSE;
+ }
+ IMalloc *malloc = 0;
+ CoGetMalloc(1, &malloc);
+ if (!malloc)
+ return E_OUTOFMEMORY;
+
+ *currentFile = static_cast<WCHAR *>(malloc->Alloc(currentFileName.length() * 2));
+ malloc->Release();
+ memcpy(*currentFile, currentFileName.unicode(), currentFileName.length() * 2);
+
+ return S_OK;
+}
+
+HRESULT WINAPI QAxServerBase::Load(LPCOLESTR fileName, DWORD mode)
+{
+ const QMetaObject *mo = qt.object->metaObject();
+ int mimeIndex = mo->indexOfClassInfo("MIME");
+ if (mimeIndex == -1)
+ return E_NOTIMPL;
+
+ QAxBindable *axb = (QAxBindable*)qt.object->qt_metacast("QAxBindable");
+ if (!axb) {
+ qWarning() << class_name << ": No QAxBindable implementation for mime-type handling";
+ return E_NOTIMPL;
+ }
+
+ QString loadFileName = QString::fromUtf16(reinterpret_cast<const ushort *>(fileName));
+ QString fileExtension = loadFileName.mid(loadFileName.lastIndexOf(QLatin1Char('.')) + 1);
+ QFile file(loadFileName);
+
+ QString mimeType = QLatin1String(mo->classInfo(mimeIndex).value());
+ QStringList mimeTypes = mimeType.split(QLatin1Char(';'));
+ for (int m = 0; m < mimeTypes.count(); ++m) {
+ QString mime = mimeTypes.at(m);
+ if (mime.count(QLatin1Char(':')) != 2) {
+ qWarning() << class_name << ": Invalid syntax in Q_CLASSINFO for MIME";
+ continue;
+ }
+
+ mimeType = mime.left(mimeType.indexOf(QLatin1Char(':'))); // first type
+ if (mimeType.isEmpty()) {
+ qWarning() << class_name << ": Invalid syntax in Q_CLASSINFO for MIME";
+ continue;
+ }
+ QString mimeExtension = mime.mid(mimeType.length() + 1);
+ mimeExtension = mimeExtension.left(mimeExtension.indexOf(QLatin1Char(':')));
+ if (mimeExtension != fileExtension)
+ continue;
+
+ if (axb->readData(&file, mimeType)) {
+ currentFileName = loadFileName;
+ return S_OK;
+ }
+ }
+
+ return E_FAIL;
+}
+
+HRESULT WINAPI QAxServerBase::Save(LPCOLESTR fileName, BOOL fRemember)
+{
+ const QMetaObject *mo = qt.object->metaObject();
+ int mimeIndex = mo->indexOfClassInfo("MIME");
+ if (mimeIndex == -1)
+ return E_NOTIMPL;
+
+ QAxBindable *axb = (QAxBindable*)qt.object->qt_metacast("QAxBindable");
+ if (!axb) {
+ qWarning() << class_name << ": No QAxBindable implementation for mime-type handling";
+ return E_NOTIMPL;
+ }
+
+ QString saveFileName = QString::fromUtf16(reinterpret_cast<const ushort *>(fileName));
+ QString fileExtension = saveFileName.mid(saveFileName.lastIndexOf(QLatin1Char('.')) + 1);
+ QFile file(saveFileName);
+
+ QString mimeType = QLatin1String(mo->classInfo(mimeIndex).value());
+ QStringList mimeTypes = mimeType.split(QLatin1Char(';'));
+ for (int m = 0; m < mimeTypes.count(); ++m) {
+ QString mime = mimeTypes.at(m);
+ if (mime.count(QLatin1Char(':')) != 2) {
+ qWarning() << class_name << ": Invalid syntax in Q_CLASSINFO for MIME";
+ continue;
+ }
+ mimeType = mime.left(mimeType.indexOf(QLatin1Char(':'))); // first type
+ if (mimeType.isEmpty()) {
+ qWarning() << class_name << ": Invalid syntax in Q_CLASSINFO for MIME";
+ continue;
+ }
+ QString mimeExtension = mime.mid(mimeType.length() + 1);
+ mimeExtension = mimeExtension.left(mimeExtension.indexOf(QLatin1Char(':')));
+ if (mimeExtension != fileExtension)
+ continue;
+ if (axb->writeData(&file)) {
+ if (fRemember)
+ currentFileName = saveFileName;
+ return S_OK;
+ }
+ }
+ return E_FAIL;
+}
+
+//**** IViewObject
+/*
+ Draws the widget into the provided device context.
+*/
+HRESULT WINAPI QAxServerBase::Draw(DWORD dwAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd,
+ HDC hicTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL /*lprcWBounds*/,
+ BOOL(__stdcall* /*pfnContinue*/)(ULONG_PTR), ULONG_PTR /*dwContinue*/)
+{
+ if (!lprcBounds)
+ return E_INVALIDARG;
+
+ internalCreate();
+ if (!isWidget || !qt.widget)
+ return OLE_E_BLANK;
+
+ switch (dwAspect) {
+ case DVASPECT_CONTENT:
+ case DVASPECT_OPAQUE:
+ case DVASPECT_TRANSPARENT:
+ break;
+ default:
+ return DV_E_DVASPECT;
+ }
+ if (!ptd)
+ hicTargetDev = 0;
+
+ bool bDeleteDC = false;
+ if (!hicTargetDev) {
+ hicTargetDev = ::CreateDCA("DISPLAY", NULL, NULL, NULL);
+ bDeleteDC = (hicTargetDev != hdcDraw);
+ }
+
+ RECTL rc = *lprcBounds;
+ bool bMetaFile = GetDeviceCaps(hdcDraw, TECHNOLOGY) == DT_METAFILE;
+ if (!bMetaFile)
+ ::LPtoDP(hicTargetDev, (LPPOINT)&rc, 2);
+
+ QPixmap pm = QPixmap::grabWidget(qt.widget);
+ HBITMAP hbm = pm.toWinHBITMAP();
+ HDC hdc = CreateCompatibleDC(0);
+ SelectObject(hdc, hbm);
+ ::StretchBlt(hdcDraw, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0,pm.width(), pm.height(), SRCCOPY);
+ DeleteDC(hdc);
+ DeleteObject(hbm);
+
+ if (bDeleteDC)
+ DeleteDC(hicTargetDev);
+
+ return S_OK;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd,
+ HDC hicTargetDev, LOGPALETTE **ppColorSet)
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::Freeze(DWORD dwAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::Unfreeze(DWORD dwFreeze)
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Stores the provided advise sink.
+*/
+HRESULT WINAPI QAxServerBase::SetAdvise(DWORD /*aspects*/, DWORD /*advf*/, IAdviseSink *pAdvSink)
+{
+ if (m_spAdviseSink) m_spAdviseSink->Release();
+
+ m_spAdviseSink = pAdvSink;
+ if (m_spAdviseSink) m_spAdviseSink->AddRef();
+ return S_OK;
+}
+
+/*
+ Returns the advise sink.
+*/
+HRESULT WINAPI QAxServerBase::GetAdvise(DWORD* /*aspects*/, DWORD* /*advf*/, IAdviseSink **ppAdvSink)
+{
+ if (!ppAdvSink)
+ return E_POINTER;
+
+ *ppAdvSink = m_spAdviseSink;
+ if (*ppAdvSink)
+ (*ppAdvSink)->AddRef();
+ return S_OK;
+}
+
+//**** IViewObject2
+/*
+ Returns the current size ONLY if the widget has already been sized.
+*/
+HRESULT WINAPI QAxServerBase::GetExtent(DWORD dwAspect, LONG /*lindex*/, DVTARGETDEVICE* /*ptd*/, LPSIZEL lpsizel)
+{
+ if (!isWidget || !qt.widget || !qt.widget->testAttribute(Qt::WA_Resized))
+ return OLE_E_BLANK;
+
+ return GetExtent(dwAspect, lpsizel);
+}
+
+//**** IOleControl
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::GetControlInfo(LPCONTROLINFO)
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Turns event firing on and off.
+*/
+HRESULT WINAPI QAxServerBase::FreezeEvents(BOOL bFreeze)
+{
+ // member of CComControl
+ if (bFreeze)
+ freezeEvents++;
+ else
+ freezeEvents--;
+
+ return S_OK;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::OnMnemonic(LPMSG)
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Update the ambient properties of the Qt widget.
+*/
+HRESULT WINAPI QAxServerBase::OnAmbientPropertyChange(DISPID dispID)
+{
+ if (!m_spClientSite || !theObject)
+ return S_OK;
+
+ IDispatch *disp = 0;
+ m_spClientSite->QueryInterface(IID_IDispatch, (void**)&disp);
+ if (!disp)
+ return S_OK;
+
+ VARIANT var;
+ VariantInit(&var);
+ DISPPARAMS params = { 0, 0, 0, 0 };
+ disp->Invoke(dispID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &params, &var, 0, 0);
+ disp->Release();
+ disp = 0;
+
+ switch(dispID) {
+ case DISPID_AMBIENT_APPEARANCE:
+ break;
+ case DISPID_AMBIENT_AUTOCLIP:
+ break;
+ case DISPID_AMBIENT_BACKCOLOR:
+ case DISPID_AMBIENT_FORECOLOR:
+ if (isWidget) {
+ long rgb;
+ if (var.vt == VT_UI4)
+ rgb = var.ulVal;
+ else if (var.vt == VT_I4)
+ rgb = var.lVal;
+ else
+ break;
+ QPalette pal = qt.widget->palette();
+ pal.setColor(dispID == DISPID_AMBIENT_BACKCOLOR ? QPalette::Window : QPalette::WindowText,
+ OLEColorToQColor(rgb));
+ qt.widget->setPalette(pal);
+ }
+ break;
+ case DISPID_AMBIENT_DISPLAYASDEFAULT:
+ break;
+ case DISPID_AMBIENT_DISPLAYNAME:
+ if (var.vt != VT_BSTR || !isWidget)
+ break;
+ qt.widget->setWindowTitle(QString::fromUtf16((const ushort *)var.bstrVal));
+ break;
+ case DISPID_AMBIENT_FONT:
+ if (var.vt != VT_DISPATCH || !isWidget)
+ break;
+ {
+ QVariant qvar = VARIANTToQVariant(var, "QFont", QVariant::Font);
+ QFont qfont = qVariantValue<QFont>(qvar);
+ qt.widget->setFont(qfont);
+ }
+ break;
+ case DISPID_AMBIENT_LOCALEID:
+ break;
+ case DISPID_AMBIENT_MESSAGEREFLECT:
+ if (var.vt != VT_BOOL)
+ break;
+ if (var.boolVal)
+ qt.widget->installEventFilter(this);
+ else
+ qt.widget->removeEventFilter(this);
+ break;
+ case DISPID_AMBIENT_PALETTE:
+ break;
+ case DISPID_AMBIENT_SCALEUNITS:
+ break;
+ case DISPID_AMBIENT_SHOWGRABHANDLES:
+ break;
+ case DISPID_AMBIENT_SHOWHATCHING:
+ break;
+ case DISPID_AMBIENT_SUPPORTSMNEMONICS:
+ break;
+ case DISPID_AMBIENT_TEXTALIGN:
+ break;
+ case DISPID_AMBIENT_UIDEAD:
+ if (var.vt != VT_BOOL || !isWidget)
+ break;
+ qt.widget->setEnabled(!var.boolVal);
+ break;
+ case DISPID_AMBIENT_USERMODE:
+ if (var.vt != VT_BOOL)
+ break;
+ inDesignMode = !var.boolVal;
+ break;
+ case DISPID_AMBIENT_RIGHTTOLEFT:
+ if (var.vt != VT_BOOL)
+ break;
+ qApp->setLayoutDirection(var.boolVal?Qt::RightToLeft:Qt::LeftToRight);
+ break;
+ }
+
+ return S_OK;
+}
+
+//**** IOleWindow
+/*
+ Returns the HWND of the control.
+*/
+HRESULT WINAPI QAxServerBase::GetWindow(HWND *pHwnd)
+{
+ if (!pHwnd)
+ return E_POINTER;
+ *pHwnd = m_hWnd;
+ return S_OK;
+}
+
+/*
+ Enters What's This mode.
+*/
+HRESULT WINAPI QAxServerBase::ContextSensitiveHelp(BOOL fEnterMode)
+{
+ if (fEnterMode)
+ QWhatsThis::enterWhatsThisMode();
+ else
+ QWhatsThis::leaveWhatsThisMode();
+ return S_OK;
+}
+
+//**** IOleInPlaceObject
+/*
+ Deactivates the control in place.
+*/
+HRESULT WINAPI QAxServerBase::InPlaceDeactivate()
+{
+ if (!isInPlaceActive)
+ return S_OK;
+ UIDeactivate();
+
+ isInPlaceActive = false;
+
+ // if we have a window, tell it to go away.
+ if (m_hWnd) {
+ if (::IsWindow(m_hWnd))
+ ::DestroyWindow(m_hWnd);
+ m_hWnd = 0;
+ }
+
+ if (m_spInPlaceSite)
+ m_spInPlaceSite->OnInPlaceDeactivate();
+
+ return S_OK;
+}
+
+/*
+ Deactivates the control's user interface.
+*/
+HRESULT WINAPI QAxServerBase::UIDeactivate()
+{
+ // if we're not UIActive, not much to do.
+ if (!isUIActive || !m_spInPlaceSite)
+ return S_OK;
+
+ isUIActive = false;
+
+ // notify frame windows, if appropriate, that we're no longer ui-active.
+ HWND hwndParent;
+ if (m_spInPlaceSite->GetWindow(&hwndParent) == S_OK) {
+ if (m_spInPlaceFrame) m_spInPlaceFrame->Release();
+ m_spInPlaceFrame = 0;
+ IOleInPlaceUIWindow *spInPlaceUIWindow = 0;
+ RECT rcPos, rcClip;
+ OLEINPLACEFRAMEINFO frameInfo;
+ frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO);
+
+ m_spInPlaceSite->GetWindowContext(&m_spInPlaceFrame, &spInPlaceUIWindow, &rcPos, &rcClip, &frameInfo);
+ if (spInPlaceUIWindow) {
+ spInPlaceUIWindow->SetActiveObject(0, 0);
+ spInPlaceUIWindow->Release();
+ }
+ if (m_spInPlaceFrame) {
+ removeMenu();
+ if (menuBar) {
+ menuBar->removeEventFilter(this);
+ menuBar = 0;
+ }
+ if (statusBar) {
+ statusBar->removeEventFilter(this);
+ const int index = statusBar->metaObject()->indexOfSignal("messageChanged(QString)");
+ QMetaObject::disconnect(statusBar, index, this, -1);
+ statusBar = 0;
+ }
+ m_spInPlaceFrame->SetActiveObject(0, 0);
+ m_spInPlaceFrame->Release();
+ m_spInPlaceFrame = 0;
+ }
+ }
+ // we don't need to explicitly release the focus here since somebody
+ // else grabbing the focus is usually why we are getting called at all
+ m_spInPlaceSite->OnUIDeactivate(false);
+
+ return S_OK;
+}
+
+/*
+ Positions the control, and applies requested clipping.
+*/
+HRESULT WINAPI QAxServerBase::SetObjectRects(LPCRECT prcPos, LPCRECT prcClip)
+{
+ if (prcPos == 0 || prcClip == 0)
+ return E_POINTER;
+
+ if (m_hWnd) {
+ // the container wants us to clip, so figure out if we really need to
+ RECT rcIXect;
+ BOOL b = IntersectRect(&rcIXect, prcPos, prcClip);
+ HRGN tempRgn = 0;
+ if (b && !EqualRect(&rcIXect, prcPos)) {
+ OffsetRect(&rcIXect, -(prcPos->left), -(prcPos->top));
+ tempRgn = CreateRectRgnIndirect(&rcIXect);
+ }
+
+ ::SetWindowRgn(m_hWnd, tempRgn, true);
+ ::SetWindowPos(m_hWnd, 0, prcPos->left, prcPos->top,
+ prcPos->right - prcPos->left, prcPos->bottom - prcPos->top,
+ SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+
+ //Save the new extent.
+ m_currentExtent.rwidth() = qBound(qt.widget->minimumWidth(), int(prcPos->right - prcPos->left), qt.widget->maximumWidth());
+ m_currentExtent.rheight() = qBound(qt.widget->minimumHeight(), int(prcPos->bottom - prcPos->top), qt.widget->maximumHeight());
+
+ return S_OK;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::ReactivateAndUndo()
+{
+ return E_NOTIMPL;
+}
+
+//**** IOleInPlaceActiveObject
+
+Q_GUI_EXPORT int qt_translateKeyCode(int);
+
+HRESULT WINAPI QAxServerBase::TranslateAcceleratorW(MSG *pMsg)
+{
+ if (pMsg->message != WM_KEYDOWN || !isWidget)
+ return S_FALSE;
+
+ DWORD dwKeyMod = 0;
+ if (::GetKeyState(VK_SHIFT) < 0)
+ dwKeyMod |= 1; // KEYMOD_SHIFT
+ if (::GetKeyState(VK_CONTROL) < 0)
+ dwKeyMod |= 2; // KEYMOD_CONTROL
+ if (::GetKeyState(VK_MENU) < 0)
+ dwKeyMod |= 4; // KEYMOD_ALT
+
+ switch (LOWORD(pMsg->wParam)) {
+ case VK_TAB:
+ if (isUIActive) {
+ bool shift = ::GetKeyState(VK_SHIFT) < 0;
+ bool giveUp = true;
+ QWidget *curFocus = qt.widget->focusWidget();
+ if (curFocus) {
+ if (shift) {
+ if (!curFocus->isWindow()) {
+ QWidget *nextFocus = curFocus->nextInFocusChain();
+ QWidget *prevFocus = 0;
+ QWidget *topLevel = 0;
+ while (nextFocus != curFocus) {
+ if (nextFocus->focusPolicy() & Qt::TabFocus) {
+ prevFocus = nextFocus;
+ topLevel = 0;
+ } else if (nextFocus->isWindow()) {
+ topLevel = nextFocus;
+ }
+ nextFocus = nextFocus->nextInFocusChain();
+ }
+
+ if (!topLevel) {
+ giveUp = false;
+ ((HackWidget*)curFocus)->focusNextPrevChild(false);
+ }
+ }
+ } else {
+ QWidget *nextFocus = curFocus;
+ while (1) {
+ nextFocus = nextFocus->nextInFocusChain();
+ if (nextFocus->isWindow())
+ break;
+ if (nextFocus->focusPolicy() & Qt::TabFocus) {
+ giveUp = false;
+ ((HackWidget*)curFocus)->focusNextPrevChild(true);
+ break;
+ }
+ }
+ }
+ }
+ if (giveUp) {
+ HWND hwnd = ::GetParent(m_hWnd);
+ ::SetFocus(hwnd);
+ } else {
+ return S_OK;
+ }
+
+ }
+ break;
+
+ case VK_LEFT:
+ case VK_RIGHT:
+ case VK_UP:
+ case VK_DOWN:
+ if (isUIActive)
+ return S_FALSE;
+ break;
+
+ default:
+ if (isUIActive && qt.widget->focusWidget()) {
+ int state = Qt::NoButton;
+ if (dwKeyMod & 1)
+ state |= Qt::ShiftModifier;
+ if (dwKeyMod & 2)
+ state |= Qt::ControlModifier;
+ if (dwKeyMod & 4)
+ state |= Qt::AltModifier;
+
+ int key = pMsg->wParam;
+ if (!(key >= 'A' && key <= 'Z') && !(key >= '0' && key <= '9'))
+ key = qt_translateKeyCode(pMsg->wParam);
+
+ QKeyEvent override(QEvent::ShortcutOverride, key, (Qt::KeyboardModifiers)state);
+ override.ignore();
+ QApplication::sendEvent(qt.widget->focusWidget(), &override);
+ if (override.isAccepted())
+ return S_FALSE;
+ }
+ break;
+ }
+
+ if (!m_spClientSite)
+ return S_FALSE;
+
+ IOleControlSite *controlSite = 0;
+ m_spClientSite->QueryInterface(IID_IOleControlSite, (void**)&controlSite);
+ if (!controlSite)
+ return S_FALSE;
+
+ HRESULT hres = controlSite->TranslateAcceleratorW(pMsg, dwKeyMod);
+
+ controlSite->Release();
+
+ return hres;
+}
+
+HRESULT WINAPI QAxServerBase::TranslateAcceleratorA(MSG *pMsg)
+{
+ return TranslateAcceleratorW(pMsg);
+}
+
+HRESULT WINAPI QAxServerBase::OnFrameWindowActivate(BOOL fActivate)
+{
+ if (fActivate) {
+ if (wasUIActive)
+ ::SetFocus(m_hWnd);
+ } else {
+ wasUIActive = isUIActive;
+ }
+ return S_OK;
+}
+
+HRESULT WINAPI QAxServerBase::OnDocWindowActivate(BOOL fActivate)
+{
+ return S_OK;
+}
+
+HRESULT WINAPI QAxServerBase::ResizeBorder(LPCRECT prcBorder, IOleInPlaceUIWindow *pUIWindow, BOOL fFrameWindow)
+{
+ return S_OK;
+}
+
+HRESULT WINAPI QAxServerBase::EnableModeless(BOOL fEnable)
+{
+ if (!isWidget)
+ return S_OK;
+
+ EnableWindow(qt.widget->winId(), fEnable);
+ return S_OK;
+}
+
+//**** IOleObject
+
+static inline LPOLESTR QStringToOLESTR(const QString &qstring)
+{
+ LPOLESTR olestr = (wchar_t*)CoTaskMemAlloc(qstring.length()*2+2);
+ memcpy(olestr, (ushort*)qstring.unicode(), qstring.length()*2);
+ olestr[qstring.length()] = 0;
+ return olestr;
+}
+
+/*
+ \reimp
+
+ See documentation of IOleObject::GetUserType.
+*/
+HRESULT WINAPI QAxServerBase::GetUserType(DWORD dwFormOfType, LPOLESTR *pszUserType)
+{
+ if (!pszUserType)
+ return E_POINTER;
+
+ switch (dwFormOfType) {
+ case USERCLASSTYPE_FULL:
+ *pszUserType = QStringToOLESTR(class_name);
+ break;
+ case USERCLASSTYPE_SHORT:
+ if (!qt.widget || !isWidget || qt.widget->windowTitle().isEmpty())
+ *pszUserType = QStringToOLESTR(class_name);
+ else
+ *pszUserType = QStringToOLESTR(qt.widget->windowTitle());
+ break;
+ case USERCLASSTYPE_APPNAME:
+ *pszUserType = QStringToOLESTR(qApp->objectName());
+ break;
+ }
+
+ return S_OK;
+}
+
+/*
+ Returns the status flags registered for this control.
+*/
+HRESULT WINAPI QAxServerBase::GetMiscStatus(DWORD dwAspect, DWORD *pdwStatus)
+{
+ return OleRegGetMiscStatus(qAxFactory()->classID(class_name), dwAspect, pdwStatus);
+}
+
+/*
+ Stores the provided advise sink.
+*/
+HRESULT WINAPI QAxServerBase::Advise(IAdviseSink* pAdvSink, DWORD* pdwConnection)
+{
+ *pdwConnection = adviseSinks.count() + 1;
+ STATDATA data = { {0, 0, DVASPECT_CONTENT, -1, TYMED_NULL} , 0, pAdvSink, *pdwConnection };
+ adviseSinks.append(data);
+ pAdvSink->AddRef();
+ return S_OK;
+}
+
+/*
+ Closes the control.
+*/
+HRESULT WINAPI QAxServerBase::Close(DWORD dwSaveOption)
+{
+ if (dwSaveOption != OLECLOSE_NOSAVE && m_spClientSite)
+ m_spClientSite->SaveObject();
+ if (isInPlaceActive) {
+ HRESULT hr = InPlaceDeactivate();
+ if (FAILED(hr))
+ return hr;
+ }
+ if (m_hWnd) {
+ if (IsWindow(m_hWnd))
+ DestroyWindow(m_hWnd);
+ m_hWnd = 0;
+ if (m_spClientSite)
+ m_spClientSite->OnShowWindow(false);
+ }
+
+ if (m_spInPlaceSite) m_spInPlaceSite->Release();
+ m_spInPlaceSite = 0;
+
+ if (m_spAdviseSink)
+ m_spAdviseSink->OnClose();
+ for (int i = 0; i < adviseSinks.count(); ++i) {
+ adviseSinks.at(i).pAdvSink->OnClose();
+ }
+
+ return S_OK;
+}
+
+bool qax_disable_inplaceframe = true;
+
+/*
+ Executes the steps to activate the control.
+*/
+HRESULT QAxServerBase::internalActivate()
+{
+ if (!m_spClientSite)
+ return S_OK;
+ if (!m_spInPlaceSite)
+ m_spClientSite->QueryInterface(IID_IOleInPlaceSite, (void**)&m_spInPlaceSite);
+ if (!m_spInPlaceSite)
+ return E_FAIL;
+
+ HRESULT hr = E_FAIL;
+ if (!isInPlaceActive) {
+ BOOL bNoRedraw = false;
+ hr = m_spInPlaceSite->CanInPlaceActivate();
+ if (FAILED(hr))
+ return hr;
+ if (hr != S_OK)
+ return E_FAIL;
+ m_spInPlaceSite->OnInPlaceActivate();
+ }
+
+ isInPlaceActive = true;
+ OnAmbientPropertyChange(DISPID_AMBIENT_USERMODE);
+
+ if (isWidget) {
+ IOleInPlaceUIWindow *spInPlaceUIWindow = 0;
+ HWND hwndParent;
+ if (m_spInPlaceSite->GetWindow(&hwndParent) == S_OK) {
+ // get location in the parent window, as well as some information about the parent
+ if (m_spInPlaceFrame) m_spInPlaceFrame->Release();
+ m_spInPlaceFrame = 0;
+ RECT rcPos, rcClip;
+ OLEINPLACEFRAMEINFO frameInfo;
+ frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO);
+ m_spInPlaceSite->GetWindowContext(&m_spInPlaceFrame, &spInPlaceUIWindow, &rcPos, &rcClip, &frameInfo);
+ if (m_hWnd) {
+ ::ShowWindow(m_hWnd, SW_SHOW);
+ if (!::IsChild(m_hWnd, ::GetFocus()) && qt.widget->focusPolicy() != Qt::NoFocus)
+ ::SetFocus(m_hWnd);
+ } else {
+ create(hwndParent, rcPos);
+ }
+ }
+
+ // Gone active by now, take care of UIACTIVATE
+ canTakeFocus = qt.widget->focusPolicy() != Qt::NoFocus && !inDesignMode;
+ if (!canTakeFocus && !inDesignMode) {
+ QList<QWidget*> widgets = qFindChildren<QWidget*>(qt.widget);
+ for (int w = 0; w < widgets.count(); ++w) {
+ QWidget *widget = widgets[w];
+ canTakeFocus = widget->focusPolicy() != Qt::NoFocus;
+ if (canTakeFocus)
+ break;
+ }
+ }
+ if (!isUIActive && canTakeFocus) {
+ isUIActive = true;
+ hr = m_spInPlaceSite->OnUIActivate();
+ if (FAILED(hr)) {
+ if (m_spInPlaceFrame) m_spInPlaceFrame->Release();
+ m_spInPlaceFrame = 0;
+ if (spInPlaceUIWindow) spInPlaceUIWindow->Release();
+ return hr;
+ }
+
+ if (isInPlaceActive) {
+ if (!::IsChild(m_hWnd, ::GetFocus()))
+ ::SetFocus(m_hWnd);
+ }
+
+ if (m_spInPlaceFrame) {
+ hr = m_spInPlaceFrame->SetActiveObject(this, QStringToBSTR(class_name));
+ if (!FAILED(hr)) {
+ menuBar = (qt.widget && !qax_disable_inplaceframe) ? qFindChild<QMenuBar*>(qt.widget) : 0;
+ if (menuBar && !menuBar->isVisible()) {
+ createMenu(menuBar);
+ menuBar->hide();
+ menuBar->installEventFilter(this);
+ }
+ statusBar = qt.widget ? qFindChild<QStatusBar*>(qt.widget) : 0;
+ if (statusBar && !statusBar->isVisible()) {
+ const int index = statusBar->metaObject()->indexOfSignal("messageChanged(QString)");
+ QMetaObject::connect(statusBar, index, this, -1);
+ statusBar->hide();
+ statusBar->installEventFilter(this);
+ }
+ }
+ }
+ if (spInPlaceUIWindow) {
+ spInPlaceUIWindow->SetActiveObject(this, QStringToBSTR(class_name));
+ spInPlaceUIWindow->SetBorderSpace(0);
+ }
+ }
+ if (spInPlaceUIWindow) spInPlaceUIWindow->Release();
+ ShowWindow(m_hWnd, SW_NORMAL);
+ }
+
+ m_spClientSite->ShowObject();
+
+ return S_OK;
+}
+
+/*
+ Executes the "verb" \a iVerb.
+*/
+HRESULT WINAPI QAxServerBase::DoVerb(LONG iVerb, LPMSG /*lpmsg*/, IOleClientSite* /*pActiveSite*/, LONG /*lindex*/,
+ HWND /*hwndParent*/, LPCRECT /*prcPosRect*/)
+{
+ HRESULT hr = E_NOTIMPL;
+ switch (iVerb)
+ {
+ case OLEIVERB_SHOW:
+ hr = internalActivate();
+ if (SUCCEEDED(hr))
+ hr = S_OK;
+ break;
+
+ case OLEIVERB_PRIMARY:
+ case OLEIVERB_INPLACEACTIVATE:
+ hr = internalActivate();
+ if (SUCCEEDED(hr)) {
+ hr = S_OK;
+ update();
+ }
+ break;
+
+ case OLEIVERB_UIACTIVATE:
+ if (!isUIActive) {
+ hr = internalActivate();
+ if (SUCCEEDED(hr))
+ hr = S_OK;
+ }
+ break;
+
+ case OLEIVERB_HIDE:
+ UIDeactivate();
+ if (m_hWnd)
+ ::ShowWindow(m_hWnd, SW_HIDE);
+ hr = S_OK;
+ return hr;
+
+ default:
+ break;
+ }
+ return hr;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::EnumAdvise(IEnumSTATDATA** /*ppenumAdvise*/)
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Returns an enumerator for the verbs registered for this class.
+*/
+HRESULT WINAPI QAxServerBase::EnumVerbs(IEnumOLEVERB** ppEnumOleVerb)
+{
+ if (!ppEnumOleVerb)
+ return E_POINTER;
+ return OleRegEnumVerbs(qAxFactory()->classID(class_name), ppEnumOleVerb);
+}
+
+/*
+ Returns the current client site..
+*/
+HRESULT WINAPI QAxServerBase::GetClientSite(IOleClientSite** ppClientSite)
+{
+ if (!ppClientSite)
+ return E_POINTER;
+ *ppClientSite = m_spClientSite;
+ if (*ppClientSite)
+ (*ppClientSite)->AddRef();
+ return S_OK;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::GetClipboardData(DWORD, IDataObject**)
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Returns the current extent.
+*/
+HRESULT WINAPI QAxServerBase::GetExtent(DWORD dwDrawAspect, SIZEL* psizel)
+{
+ if (dwDrawAspect != DVASPECT_CONTENT || !isWidget || !qt.widget)
+ return E_FAIL;
+ if (!psizel)
+ return E_POINTER;
+
+ psizel->cx = MAP_PIX_TO_LOGHIM(m_currentExtent.width(), qt.widget->logicalDpiX());
+ psizel->cy = MAP_PIX_TO_LOGHIM(m_currentExtent.height(), qt.widget->logicalDpiY());
+ return S_OK;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::GetMoniker(DWORD, DWORD, IMoniker** )
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Returns the CLSID of this class.
+*/
+HRESULT WINAPI QAxServerBase::GetUserClassID(CLSID* pClsid)
+{
+ if (!pClsid)
+ return E_POINTER;
+ *pClsid = qAxFactory()->classID(class_name);
+ return S_OK;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::InitFromData(IDataObject*, BOOL, DWORD)
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::IsUpToDate()
+{
+ return S_OK;
+}
+
+/*
+ Stores the client site.
+*/
+HRESULT WINAPI QAxServerBase::SetClientSite(IOleClientSite* pClientSite)
+{
+ // release all client site interfaces
+ if (m_spClientSite) m_spClientSite->Release();
+ if (m_spInPlaceSite) m_spInPlaceSite->Release();
+ m_spInPlaceSite = 0;
+ if (m_spInPlaceFrame) m_spInPlaceFrame->Release();
+ m_spInPlaceFrame = 0;
+
+ m_spClientSite = pClientSite;
+ if (m_spClientSite) {
+ m_spClientSite->AddRef();
+ m_spClientSite->QueryInterface(IID_IOleInPlaceSite, (void **)&m_spInPlaceSite);
+ }
+
+ return S_OK;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::SetColorScheme(LOGPALETTE*)
+{
+ return E_NOTIMPL;
+}
+
+
+#ifdef QT_DLL // avoid conflict with symbol in static lib
+bool qt_sendSpontaneousEvent(QObject *o, QEvent *e)
+{
+ return QCoreApplication::sendSpontaneousEvent(o, e);
+}
+#endif
+
+/*
+ Tries to set the size of the control.
+*/
+HRESULT WINAPI QAxServerBase::SetExtent(DWORD dwDrawAspect, SIZEL* psizel)
+{
+ if (dwDrawAspect != DVASPECT_CONTENT)
+ return DV_E_DVASPECT;
+ if (!psizel)
+ return E_POINTER;
+
+ if (!isWidget || !qt.widget) // nothing to do
+ return S_OK;
+
+ QSize proposedSize(MAP_LOGHIM_TO_PIX(psizel->cx, qt.widget->logicalDpiX()),
+ MAP_LOGHIM_TO_PIX(psizel->cy, qt.widget->logicalDpiY()));
+
+ // can the widget be resized at all?
+ if (qt.widget->minimumSize() == qt.widget->maximumSize() && qt.widget->minimumSize() != proposedSize)
+ return E_FAIL;
+ //Save the extent, bound to the widget restrictions.
+ m_currentExtent.rwidth() = qBound(qt.widget->minimumWidth(), proposedSize.width(), qt.widget->maximumWidth());
+ m_currentExtent.rheight() = qBound(qt.widget->minimumHeight(), proposedSize.height(), qt.widget->maximumHeight());
+
+ resize(proposedSize);
+ return S_OK;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::SetHostNames(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
+{
+ return S_OK;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::SetMoniker(DWORD, IMoniker*)
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Disconnects an advise sink.
+*/
+HRESULT WINAPI QAxServerBase::Unadvise(DWORD dwConnection)
+{
+ for (int i = 0; i < adviseSinks.count(); ++i) {
+ STATDATA entry = adviseSinks.at(i);
+ if (entry.dwConnection == dwConnection) {
+ entry.pAdvSink->Release();
+ adviseSinks.removeAt(i);
+ return S_OK;
+ }
+ }
+ return OLE_E_NOCONNECTION;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::Update()
+{
+ return S_OK;
+}
+
+//**** IDataObject
+/*
+ Calls IViewObject::Draw after setting up the parameters.
+*/
+HRESULT WINAPI QAxServerBase::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
+{
+ if (!pmedium)
+ return E_POINTER;
+ if ((pformatetcIn->tymed & TYMED_MFPICT) == 0)
+ return DATA_E_FORMATETC;
+
+ internalCreate();
+ if (!isWidget || !qt.widget)
+ return E_UNEXPECTED;
+
+ // Container wants to draw, but the size is not defined yet - ask container
+ if (m_spInPlaceSite && !qt.widget->testAttribute(Qt::WA_Resized)) {
+ IOleInPlaceUIWindow *spInPlaceUIWindow = 0;
+ RECT rcPos, rcClip;
+ OLEINPLACEFRAMEINFO frameInfo;
+ frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO);
+
+ HRESULT hres = m_spInPlaceSite->GetWindowContext(&m_spInPlaceFrame, &spInPlaceUIWindow, &rcPos, &rcClip, &frameInfo);
+ if (hres == S_OK) {
+ QSize size(rcPos.right - rcPos.left, rcPos.bottom - rcPos.top);
+ resize(size);
+ } else {
+ qt.widget->adjustSize();
+ }
+ if (spInPlaceUIWindow) spInPlaceUIWindow->Release(); // no need for it
+ }
+
+ int width = qt.widget->width();
+ int height = qt.widget->height();
+ RECTL rectl = {0, 0, width, height};
+
+ HDC hdc = CreateMetaFile(0);
+ SaveDC(hdc);
+ SetWindowOrgEx(hdc, 0, 0, 0);
+ SetWindowExtEx(hdc, rectl.right, rectl.bottom, 0);
+
+ Draw(pformatetcIn->dwAspect, pformatetcIn->lindex, 0, pformatetcIn->ptd, 0, hdc, &rectl, &rectl, 0, 0);
+
+ RestoreDC(hdc, -1);
+ HMETAFILE hMF = CloseMetaFile(hdc);
+ if (!hMF)
+ return E_UNEXPECTED;
+
+ HGLOBAL hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, sizeof(METAFILEPICT));
+ if (!hMem) {
+ DeleteMetaFile(hMF);
+ return ResultFromScode(STG_E_MEDIUMFULL);
+ }
+
+ LPMETAFILEPICT pMF = (LPMETAFILEPICT)GlobalLock(hMem);
+ pMF->hMF = hMF;
+ pMF->mm = MM_ANISOTROPIC;
+ pMF->xExt = MAP_PIX_TO_LOGHIM(width, qt.widget->logicalDpiX());
+ pMF->yExt = MAP_PIX_TO_LOGHIM(height, qt.widget->logicalDpiY());
+ GlobalUnlock(hMem);
+
+ memset(pmedium, 0, sizeof(STGMEDIUM));
+ pmedium->tymed = TYMED_MFPICT;
+ pmedium->hGlobal = hMem;
+ pmedium->pUnkForRelease = 0;
+
+ return S_OK;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::DAdvise(FORMATETC *pformatetc, DWORD advf,
+ IAdviseSink *pAdvSink, DWORD *pdwConnection)
+{
+ if (pformatetc->dwAspect != DVASPECT_CONTENT)
+ return E_FAIL;
+
+ *pdwConnection = adviseSinks.count() + 1;
+ STATDATA data = {
+ {pformatetc->cfFormat,pformatetc->ptd,pformatetc->dwAspect,pformatetc->lindex,pformatetc->tymed},
+ advf, pAdvSink, *pdwConnection
+ };
+ adviseSinks.append(data);
+ pAdvSink->AddRef();
+ return S_OK;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::DUnadvise(DWORD dwConnection)
+{
+ return Unadvise(dwConnection);
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::EnumDAdvise(IEnumSTATDATA ** /*ppenumAdvise*/)
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::GetDataHere(FORMATETC* /* pformatetc */, STGMEDIUM* /* pmedium */)
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::QueryGetData(FORMATETC* /* pformatetc */)
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::GetCanonicalFormatEtc(FORMATETC* /* pformatectIn */,FORMATETC* /* pformatetcOut */)
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::SetData(FORMATETC* /* pformatetc */, STGMEDIUM* /* pmedium */, BOOL /* fRelease */)
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Not implemented.
+*/
+HRESULT WINAPI QAxServerBase::EnumFormatEtc(DWORD /* dwDirection */, IEnumFORMATETC** /* ppenumFormatEtc */)
+{
+ return E_NOTIMPL;
+}
+
+
+
+static int mapModifiers(int state)
+{
+ int ole = 0;
+ if (state & Qt::ShiftModifier)
+ ole |= 1;
+ if (state & Qt::ControlModifier)
+ ole |= 2;
+ if (state & Qt::AltModifier)
+ ole |= 4;
+
+ return ole;
+}
+
+/*
+ \reimp
+*/
+bool QAxServerBase::eventFilter(QObject *o, QEvent *e)
+{
+ if (!theObject)
+ return QObject::eventFilter(o, e);
+
+ if ((e->type() == QEvent::Show || e->type() == QEvent::Hide) && (o == statusBar || o == menuBar)) {
+ if (o == menuBar) {
+ if (e->type() == QEvent::Hide) {
+ createMenu(menuBar);
+ } else if (e->type() == QEvent::Show) {
+ removeMenu();
+ }
+ } else if (statusBar) {
+ statusBar->setSizeGripEnabled(false);
+ }
+ updateGeometry();
+ if (m_spInPlaceSite && qt.widget->sizeHint().isValid()) {
+ RECT rect = {0, 0, qt.widget->sizeHint().width(), qt.widget->sizeHint().height()};
+ m_spInPlaceSite->OnPosRectChange(&rect);
+ }
+ }
+ switch (e->type()) {
+ case QEvent::ChildAdded:
+ static_cast<QChildEvent*>(e)->child()->installEventFilter(this);
+ break;
+ case QEvent::ChildRemoved:
+ static_cast<QChildEvent*>(e)->child()->removeEventFilter(this);
+ break;
+ case QEvent::KeyPress:
+ if (o == qt.object && hasStockEvents) {
+ QKeyEvent *ke = (QKeyEvent*)e;
+ int key = ke->key();
+ int state = ke->modifiers();
+ void *argv[] = {
+ 0,
+ &key,
+ &state
+ };
+ qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_KEYDOWN, argv);
+ if (!ke->text().isEmpty())
+ qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_KEYPRESS, argv);
+ }
+ break;
+ case QEvent::KeyRelease:
+ if (o == qt.object && hasStockEvents) {
+ QKeyEvent *ke = (QKeyEvent*)e;
+ int key = ke->key();
+ int state = ke->modifiers();
+ void *argv[] = {
+ 0,
+ &key,
+ &state
+ };
+ qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_KEYUP, argv);
+ }
+ break;
+ case QEvent::MouseMove:
+ if (o == qt.object && hasStockEvents) {
+ QMouseEvent *me = (QMouseEvent*)e;
+ int button = me->buttons() & Qt::MouseButtonMask;
+ int state = mapModifiers(me->modifiers());
+ int x = me->x();
+ int y = me->y();
+ void *argv[] = {
+ 0,
+ &button,
+ &state,
+ &x,
+ &y
+ };
+ qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_MOUSEMOVE, argv);
+ }
+ break;
+ case QEvent::MouseButtonRelease:
+ if (o == qt.object && hasStockEvents) {
+ QMouseEvent *me = (QMouseEvent*)e;
+ int button = me->button();
+ int state = mapModifiers(me->modifiers());
+ int x = me->x();
+ int y = me->y();
+ void *argv[] = {
+ 0,
+ &button,
+ &state,
+ &x,
+ &y
+ };
+ qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_MOUSEUP, argv);
+ qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_CLICK, 0);
+ }
+ break;
+ case QEvent::MouseButtonDblClick:
+ if (o == qt.object && hasStockEvents) {
+ qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_DBLCLICK, 0);
+ }
+ break;
+ case QEvent::MouseButtonPress:
+ if (m_spInPlaceSite && !isUIActive) {
+ internalActivate();
+ }
+ if (o == qt.widget && hasStockEvents) {
+ QMouseEvent *me = (QMouseEvent*)e;
+ int button = me->button();
+ int state = mapModifiers(me->modifiers());
+ int x = me->x();
+ int y = me->y();
+ void *argv[] = {
+ 0,
+ &button,
+ &state,
+ &x,
+ &y
+ };
+ qt_metacall(QMetaObject::InvokeMetaMethod, DISPID_MOUSEDOWN, argv);
+ }
+ break;
+ case QEvent::Show:
+ if (m_hWnd && o == qt.widget)
+ ShowWindow(m_hWnd, SW_SHOW);
+ updateMask();
+ break;
+ case QEvent::Hide:
+ if (m_hWnd && o == qt.widget)
+ ShowWindow(m_hWnd, SW_HIDE);
+ break;
+
+ case QEvent::EnabledChange:
+ if (m_hWnd && o == qt.widget)
+ EnableWindow(m_hWnd, qt.widget->isEnabled());
+ // Fall Through
+ case QEvent::FontChange:
+ case QEvent::ActivationChange:
+ case QEvent::StyleChange:
+ case QEvent::IconTextChange:
+ case QEvent::ModifiedChange:
+ case QEvent::Resize:
+ updateMask();
+ break;
+ case QEvent::WindowBlocked: {
+ if (!m_spInPlaceFrame)
+ break;
+ m_spInPlaceFrame->EnableModeless(FALSE);
+ MSG msg;
+ // Visual Basic 6.0 posts the message WM_USER+3078 from the EnableModeless().
+ // While handling this message, VB will disable all current top-levels. After
+ // this we have to re-enable the Qt modal widget to receive input events.
+ if (PeekMessage(&msg, 0, WM_USER+3078, WM_USER+3078, PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ QWidget *modalWidget = QApplication::activeModalWidget();
+ if (modalWidget && modalWidget->isVisible() && modalWidget->isEnabled()
+ && !IsWindowEnabled(modalWidget->effectiveWinId()))
+ EnableWindow(modalWidget->effectiveWinId(), TRUE);
+ }
+ break;
+ }
+ case QEvent::WindowUnblocked:
+ if (!m_spInPlaceFrame)
+ break;
+ m_spInPlaceFrame->EnableModeless(TRUE);
+ break;
+ default:
+ break;
+ }
+ return QObject::eventFilter(o, e);
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_WIN_ACTIVEQT
diff --git a/src/activeqt/control/qaxserverdll.cpp b/src/activeqt/control/qaxserverdll.cpp
new file mode 100644
index 0000000..1263863
--- /dev/null
+++ b/src/activeqt/control/qaxserverdll.cpp
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+#include <qapplication.h>
+#include <qwidget.h>
+
+#include <qt_windows.h>
+
+QT_BEGIN_NAMESPACE
+
+bool qax_ownQApp = false;
+HHOOK qax_hhook = 0;
+
+// in qaxserver.cpp
+extern char qAxModuleFilename[MAX_PATH];
+extern bool qAxIsServer;
+extern ITypeLib *qAxTypeLibrary;
+extern unsigned long qAxLockCount();
+extern QString qAxInit();
+extern void qAxCleanup();
+extern HANDLE qAxInstance;
+static uint qAxThreadId = 0;
+
+extern HRESULT UpdateRegistry(int bRegister);
+extern HRESULT GetClassObject(const GUID &clsid, const GUID &iid, void **ppUnk);
+
+STDAPI DllRegisterServer()
+{
+ return UpdateRegistry(true);
+}
+
+STDAPI DllUnregisterServer()
+{
+ return UpdateRegistry(false);
+}
+
+STDAPI DllGetClassObject(const GUID &clsid, const GUID &iid, void** ppv)
+{
+ if (!qAxThreadId)
+ qAxThreadId = GetCurrentThreadId();
+ else if (GetCurrentThreadId() != qAxThreadId)
+ return E_FAIL;
+
+ GetClassObject(clsid, iid, ppv);
+ if (!*ppv)
+ return CLASS_E_CLASSNOTAVAILABLE;
+ return S_OK;
+}
+
+STDAPI DllCanUnloadNow()
+{
+ if (GetCurrentThreadId() != qAxThreadId)
+ return S_FALSE;
+ if (qAxLockCount())
+ return S_FALSE;
+ if (!qax_ownQApp)
+ return S_OK;
+
+ // check if qApp still runs widgets (in other DLLs)
+ QWidgetList widgets = qApp->allWidgets();
+ int count = widgets.count();
+ for (int w = 0; w < widgets.count(); ++w) {
+ // remove all Qt generated widgets
+ QWidget *widget = widgets.at(w);
+ if (widget->windowType() == Qt::Desktop || widget->objectName() == QLatin1String("Qt internal tablet widget"))
+ count--;
+ }
+ if (count)
+ return S_FALSE;
+
+ // no widgets left - destroy qApp
+ if (qax_hhook)
+ UnhookWindowsHookEx(qax_hhook);
+
+ delete qApp;
+ qax_ownQApp = false;
+
+ // never allow unloading - safety net for Internet Explorer
+ return S_FALSE;
+}
+
+
+EXTERN_C BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved)
+{
+ GetModuleFileNameA(hInstance, qAxModuleFilename, MAX_PATH-1);
+ qAxInstance = hInstance;
+ qAxIsServer = true;
+
+ if (dwReason == DLL_PROCESS_ATTACH) {
+ DisableThreadLibraryCalls(hInstance);
+ qAxInit();
+ } else if (dwReason == DLL_PROCESS_DETACH) {
+ qAxCleanup();
+ }
+
+ return true;
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_WIN_ACTIVEQT
diff --git a/src/activeqt/control/qaxservermain.cpp b/src/activeqt/control/qaxservermain.cpp
new file mode 100644
index 0000000..a50fef0
--- /dev/null
+++ b/src/activeqt/control/qaxservermain.cpp
@@ -0,0 +1,279 @@
+/****************************************************************************
+**
+** 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 <qstringlist.h>
+#include <qvector.h>
+
+#include "qaxfactory.h"
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+#include <qt_windows.h>
+
+QT_BEGIN_NAMESPACE
+
+static DWORD *classRegistration = 0;
+static DWORD dwThreadID;
+static bool qAxActivity = false;
+static HANDLE hEventShutdown;
+
+#ifdef QT_DEBUG
+QT_STATIC_CONST DWORD dwTimeOut = 1000;
+QT_STATIC_CONST DWORD dwPause = 500;
+#else
+QT_STATIC_CONST DWORD dwTimeOut = 5000; // time for EXE to be idle before shutting down
+QT_STATIC_CONST DWORD dwPause = 1000; // time to wait for threads to finish up
+#endif
+
+extern HANDLE hEventShutdown;
+extern bool qAxActivity;
+extern HANDLE qAxInstance;
+extern bool qAxIsServer;
+extern bool qAxOutProcServer;
+extern char qAxModuleFilename[MAX_PATH];
+extern QString qAxInit();
+extern void qAxCleanup();
+extern HRESULT UpdateRegistry(BOOL bRegister);
+extern HRESULT GetClassObject(const GUID &clsid, const GUID &iid, void **ppUnk);
+extern ulong qAxLockCount();
+extern bool qax_winEventFilter(void *message);
+
+#if defined(Q_CC_BOR)
+extern "C" __stdcall HRESULT DumpIDL(const QString &outfile, const QString &ver);
+#else
+STDAPI DumpIDL(const QString &outfile, const QString &ver);
+#endif
+
+// Monitors the shutdown event
+static DWORD WINAPI MonitorProc(void* pv)
+{
+ while (1) {
+ WaitForSingleObject(hEventShutdown, INFINITE);
+ DWORD dwWait=0;
+ do {
+ qAxActivity = false;
+ dwWait = WaitForSingleObject(hEventShutdown, dwTimeOut);
+ } while (dwWait == WAIT_OBJECT_0);
+ // timed out
+ if (!qAxActivity && !qAxLockCount()) // if no activity let's really bail
+ break;
+ }
+ CloseHandle(hEventShutdown);
+ PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
+ PostQuitMessage(0);
+
+ return 0;
+}
+
+// Starts the monitoring thread
+static bool StartMonitor()
+{
+ dwThreadID = GetCurrentThreadId();
+ hEventShutdown = CreateEventA(0, false, false, 0);
+ if (hEventShutdown == 0)
+ return false;
+ DWORD dwThreadID;
+ HANDLE h = CreateThread(0, 0, MonitorProc, 0, 0, &dwThreadID);
+ return (h != NULL);
+}
+
+void qax_shutDown()
+{
+ qAxActivity = true;
+ if (hEventShutdown)
+ SetEvent(hEventShutdown); // tell monitor that we transitioned to zero
+}
+
+/*
+ Start the COM server (if necessary).
+*/
+bool qax_startServer(QAxFactory::ServerType type)
+{
+ if (qAxIsServer)
+ return true;
+
+ const QStringList keys = qAxFactory()->featureList();
+ if (!keys.count())
+ return false;
+
+ if (!qAxFactory()->isService())
+ StartMonitor();
+
+ classRegistration = new DWORD[keys.count()];
+ int object = 0;
+ for (QStringList::ConstIterator key = keys.begin(); key != keys.end(); ++key, ++object) {
+ IUnknown* p = 0;
+ CLSID clsid = qAxFactory()->classID(*key);
+
+ // Create a QClassFactory (implemented in qaxserverbase.cpp)
+ HRESULT hRes = GetClassObject(clsid, IID_IClassFactory, (void**)&p);
+ if (SUCCEEDED(hRes))
+ hRes = CoRegisterClassObject(clsid, p, CLSCTX_LOCAL_SERVER,
+ type == QAxFactory::MultipleInstances ? REGCLS_MULTIPLEUSE : REGCLS_SINGLEUSE,
+ classRegistration+object);
+ if (p)
+ p->Release();
+ }
+
+ qAxIsServer = true;
+ return true;
+}
+
+/*
+ Stop the COM server (if necessary).
+*/
+bool qax_stopServer()
+{
+ if (!qAxIsServer || !classRegistration)
+ return true;
+
+ qAxIsServer = false;
+
+ const QStringList keys = qAxFactory()->featureList();
+ int object = 0;
+ for (QStringList::ConstIterator key = keys.begin(); key != keys.end(); ++key, ++object)
+ CoRevokeClassObject(classRegistration[object]);
+
+ delete []classRegistration;
+ classRegistration = 0;
+
+ Sleep(dwPause); //wait for any threads to finish
+
+ return true;
+}
+
+#if defined(Q_OS_WINCE)
+extern void __cdecl qWinMain(HINSTANCE, HINSTANCE, LPSTR, int, int &, QVector<char *> &);
+#else
+extern void qWinMain(HINSTANCE, HINSTANCE, LPSTR, int, int &, QVector<char *> &);
+#endif
+
+QT_END_NAMESPACE
+
+#if defined(QT_NEEDS_QMAIN)
+int qMain(int, char **);
+#define main qMain
+#else
+#if defined(Q_OS_WINCE)
+extern "C" int __cdecl main(int, char **);
+#else
+extern "C" int main(int, char **);
+#endif
+#endif
+
+
+EXTERN_C int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR, int nShowCmd)
+{
+ QT_USE_NAMESPACE
+
+ qAxOutProcServer = true;
+ GetModuleFileNameA(0, qAxModuleFilename, MAX_PATH-1);
+ qAxInstance = hInstance;
+
+ QByteArray cmdParam;
+ QT_WA({
+ LPTSTR cmdline = GetCommandLineW();
+ cmdParam = QString::fromUtf16((const ushort *)cmdline).toLocal8Bit();
+ }, {
+ cmdParam = GetCommandLineA();
+ });
+
+ QList<QByteArray> cmds = cmdParam.split(' ');
+ QByteArray unprocessed;
+
+ int nRet = 0;
+ bool run = true;
+ bool runServer = false;
+ for (int i = 0; i < cmds.count(); ++i) {
+ QByteArray cmd = cmds.at(i).toLower();
+ if (cmd == "-activex" || cmd == "/activex" || cmd == "-embedding" || cmd == "/embedding") {
+ runServer = true;
+ } else if (cmd == "-unregserver" || cmd == "/unregserver") {
+ nRet = UpdateRegistry(false);
+ run = false;
+ break;
+ } else if (cmd == "-regserver" || cmd == "/regserver") {
+ nRet = UpdateRegistry(true);
+ run = false;
+ break;
+ } else if (cmd == "-dumpidl" || cmd == "/dumpidl") {
+ ++i;
+ if (i < cmds.count()) {
+ QByteArray outfile = cmds.at(i);
+ ++i;
+ QByteArray version;
+ if (i < cmds.count() && (cmds.at(i) == "-version" || cmds.at(i) == "/version")) {
+ ++i;
+ if (i < cmds.count())
+ version = cmds.at(i);
+ else
+ version = "1.0";
+ }
+
+ nRet = DumpIDL(QString::fromLatin1(outfile.constData()), QString::fromLatin1(version.constData()));
+ } else {
+ qWarning("Wrong commandline syntax: <app> -dumpidl <idl file> [-version <x.y.z>]");
+ }
+ run = false;
+ break;
+ } else {
+ unprocessed += cmds.at(i) + " ";
+ }
+ }
+
+ if (run) {
+ HRESULT hRes = CoInitialize(0);
+
+ int argc;
+ QVector<char*> argv(8);
+ qWinMain(hInstance, hPrevInstance, unprocessed.data(), nShowCmd, argc, argv);
+ qAxInit();
+ if (runServer)
+ QAxFactory::startServer();
+ nRet = ::main(argc, argv.data());
+ QAxFactory::stopServer();
+ qAxCleanup();
+ CoUninitialize();
+
+ }
+
+ return nRet;
+}
+
+#endif // QT_NO_WIN_ACTIVEQT