summaryrefslogtreecommitdiffstats
path: root/src/activeqt/container
diff options
context:
space:
mode:
authorAlexis Menard <alexis.menard@nokia.com>2009-04-17 14:06:06 (GMT)
committerAlexis Menard <alexis.menard@nokia.com>2009-04-17 14:06:06 (GMT)
commitf15b8a83e2e51955776a3f07cb85ebfc342dd8ef (patch)
treec5dc684986051654898db11ce73e03b9fec8db99 /src/activeqt/container
downloadQt-f15b8a83e2e51955776a3f07cb85ebfc342dd8ef.zip
Qt-f15b8a83e2e51955776a3f07cb85ebfc342dd8ef.tar.gz
Qt-f15b8a83e2e51955776a3f07cb85ebfc342dd8ef.tar.bz2
Initial import of statemachine branch from the old kinetic repository
Diffstat (limited to 'src/activeqt/container')
-rw-r--r--src/activeqt/container/container.pro45
-rw-r--r--src/activeqt/container/qaxbase.cpp4465
-rw-r--r--src/activeqt/container/qaxbase.h226
-rw-r--r--src/activeqt/container/qaxdump.cpp404
-rw-r--r--src/activeqt/container/qaxobject.cpp213
-rw-r--r--src/activeqt/container/qaxobject.h105
-rw-r--r--src/activeqt/container/qaxscript.cpp1293
-rw-r--r--src/activeqt/container/qaxscript.h248
-rw-r--r--src/activeqt/container/qaxscriptwrapper.cpp64
-rw-r--r--src/activeqt/container/qaxselect.cpp164
-rw-r--r--src/activeqt/container/qaxselect.h75
-rw-r--r--src/activeqt/container/qaxselect.ui173
-rw-r--r--src/activeqt/container/qaxwidget.cpp2228
-rw-r--r--src/activeqt/container/qaxwidget.h125
14 files changed, 9828 insertions, 0 deletions
diff --git a/src/activeqt/container/container.pro b/src/activeqt/container/container.pro
new file mode 100644
index 0000000..ceedacf
--- /dev/null
+++ b/src/activeqt/container/container.pro
@@ -0,0 +1,45 @@
+TEMPLATE = lib
+
+TARGET = ActiveQt
+CONFIG += qt_install_headers
+SYNCQT.HEADER_FILES = qaxbase.h qaxobject.h qaxscript.h qaxselect.h qaxwidget.h
+SYNCQT.HEADER_CLASSES = ../../../include/ActiveQt/QAxBase ../../../include/ActiveQt/QAxObject ../../../include/ActiveQt/QAxScriptEngine ../../../include/ActiveQt/QAxScript ../../../include/ActiveQt/QAxScriptManager ../../../include/ActiveQt/QAxSelect ../../../include/ActiveQt/QAxWidget
+include(../../qt_install.pri)
+
+TARGET = QAxContainer
+
+!debug_and_release|build_pass {
+ CONFIG(debug, debug|release) {
+ TARGET = $$member(TARGET, 0)d
+ }
+}
+
+CONFIG += qt warn_on staticlib
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/lib
+
+LIBS += -lole32 -loleaut32
+!wince*:LIBS += -luser32 -lgdi32 -ladvapi32
+win32-g++:LIBS += -luuid
+
+contains(QT_EDITION, OpenSource|Console) {
+ message( "You are not licensed to use ActiveQt." )
+} else {
+ HEADERS = ../control/qaxaggregated.h \
+ qaxbase.h \
+ qaxwidget.h \
+ qaxobject.h \
+ qaxscript.h \
+ qaxselect.h \
+ ../shared/qaxtypes.h
+
+ SOURCES = qaxbase.cpp \
+ qaxdump.cpp \
+ qaxwidget.cpp \
+ qaxobject.cpp \
+ qaxscript.cpp \
+ qaxscriptwrapper.cpp \
+ qaxselect.cpp \
+ ../shared/qaxtypes.cpp
+
+ FORMS = qaxselect.ui
+}
diff --git a/src/activeqt/container/qaxbase.cpp b/src/activeqt/container/qaxbase.cpp
new file mode 100644
index 0000000..1ec704a
--- /dev/null
+++ b/src/activeqt/container/qaxbase.cpp
@@ -0,0 +1,4465 @@
+/****************************************************************************
+**
+** 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 QAX_NO_CLASSINFO
+
+#ifndef UNICODE
+#define UNICODE
+#endif
+
+#define QT_CHECK_STATE
+
+#include "qaxobject.h"
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+#include <qfile.h>
+#include <qwidget.h>
+
+#include <quuid.h>
+#include <qhash.h>
+#include <qset.h>
+#include <qpair.h>
+#include <qmetaobject.h>
+#include <qsettings.h>
+
+#ifndef QT_NO_THREAD
+# include <qmutex.h>
+#endif
+
+#include <qt_windows.h>
+#include <ocidl.h>
+#include <ctype.h>
+
+#include "../shared/qaxtypes.h"
+
+QT_BEGIN_NAMESPACE
+
+/*
+ \internal
+ \class QAxMetaObject
+
+ \brief The QAxMetaObject class stores extended information
+*/
+struct QAxMetaObject : public QMetaObject
+{
+ QAxMetaObject()
+ {
+ d.data = 0;
+ d.stringdata = 0;
+ }
+ ~QAxMetaObject()
+ {
+ delete [] (int*)d.data;
+ delete [] (char*)d.stringdata;
+ }
+
+ int numParameter(const QByteArray &prototype);
+ QByteArray paramType(const QByteArray &signature, int index, bool *out = 0);
+ QByteArray propertyType(const QByteArray &propertyName);
+ void parsePrototype(const QByteArray &prototype);
+ DISPID dispIDofName(const QByteArray &name, IDispatch *disp);
+
+private:
+ friend class MetaObjectGenerator;
+ // save information about QAxEventSink connections, and connect when found in cache
+ QList<QUuid> connectionInterfaces;
+ // DISPID -> signal name
+ QMap< QUuid, QMap<DISPID, QByteArray> > sigs;
+ // DISPID -> property changed signal name
+ QMap< QUuid, QMap<DISPID, QByteArray> > propsigs;
+ // DISPID -> property name
+ QMap< QUuid, QMap<DISPID, QByteArray> > props;
+
+ // Prototype -> member info
+ QHash<QByteArray, QList<QByteArray> > memberInfo;
+ QMap<QByteArray, QByteArray> realPrototype;
+
+ // DISPID cache
+ QHash<QByteArray, DISPID> dispIDs;
+};
+
+void QAxMetaObject::parsePrototype(const QByteArray &prototype)
+{
+ QByteArray realProto = realPrototype.value(prototype, prototype);
+ QByteArray parameters = realProto.mid(realProto.indexOf('(') + 1);
+ parameters.truncate(parameters.length() - 1);
+
+ if (parameters.isEmpty()) {
+ memberInfo.insert(prototype, QList<QByteArray>());
+ } else {
+ QList<QByteArray> plist = parameters.split(',');
+ memberInfo.insert(prototype, plist);
+ }
+}
+
+inline QByteArray QAxMetaObject::propertyType(const QByteArray &propertyName)
+{
+ return realPrototype.value(propertyName);
+}
+
+int QAxMetaObject::numParameter(const QByteArray &prototype)
+{
+ if (!memberInfo.contains(prototype))
+ parsePrototype(prototype);
+
+ return memberInfo.value(prototype).count();
+}
+
+QByteArray QAxMetaObject::paramType(const QByteArray &prototype, int index, bool *out)
+{
+ if (!memberInfo.contains(prototype))
+ parsePrototype(prototype);
+
+ if (out)
+ *out = false;
+
+ QList<QByteArray> plist = memberInfo.value(prototype);
+ if (index > plist.count() - 1)
+ return QByteArray();
+
+ QByteArray param(plist.at(index));
+ if (param.isEmpty())
+ return QByteArray();
+
+ bool byRef = param.endsWith('&') || param.endsWith("**");
+ if (byRef) {
+ param.truncate(param.length() - 1);
+ if (out)
+ *out = true;
+ }
+
+ return param;
+}
+
+inline DISPID QAxMetaObject::dispIDofName(const QByteArray &name, IDispatch *disp)
+{
+ DISPID dispid = dispIDs.value(name, DISPID_UNKNOWN);
+ if (dispid == DISPID_UNKNOWN) {
+ // get the Dispatch ID from the object
+ QString unicodeName = QLatin1String(name);
+ OLECHAR *names = (TCHAR*)unicodeName.utf16();
+ disp->GetIDsOfNames(IID_NULL, &names, 1, LOCALE_USER_DEFAULT, &dispid);
+ if (dispid != DISPID_UNKNOWN)
+ dispIDs.insert(name, dispid);
+ }
+ return dispid;
+}
+
+
+static QHash<QString, QAxMetaObject*> mo_cache;
+static QHash<QUuid, QMap<QByteArray, QList<QPair<QByteArray, int> > > > enum_cache;
+static int mo_cache_ref = 0;
+static QMutex cache_mutex;
+
+
+static const char *const type_conversion[][2] =
+{
+ { "float", "double"},
+ { "short", "int"},
+ { "char", "int"},
+ { "QList<int>", "QVariantList" },
+ { "QList<uint>", "QVariantList" },
+ { "QList<double>", "QVariantList" },
+ { "QList<bool>", "QVariantList" },
+ { "QList<QDateTime>", "QVariantList" },
+ { "QList<qlonglong>", "QVariantList" },
+ { 0, 0 }
+};
+
+/*
+ \internal
+ \class QAxEventSink
+
+ \brief The QAxEventSink class implements the event sink for all
+ IConnectionPoints implemented in the COM object.
+*/
+
+class QAxEventSink : public IDispatch, public IPropertyNotifySink
+{
+public:
+ QAxEventSink(QAxBase *com)
+ : cpoint(0), ciid(IID_NULL), combase(com), ref(1)
+ {}
+ virtual ~QAxEventSink()
+ {
+ Q_ASSERT(!cpoint);
+ }
+
+ QUuid connectionInterface() const
+ {
+ return ciid;
+ }
+ QMap<DISPID, QByteArray> signalMap() const
+ {
+ return sigs;
+ }
+ QMap<DISPID, QByteArray> propertyMap() const
+ {
+ return props;
+ }
+ QMap<DISPID, QByteArray> propSignalMap() const
+ {
+ return propsigs;
+ }
+
+ // add a connection
+ void advise(IConnectionPoint *cp, IID iid)
+ {
+ cpoint = cp;
+ cpoint->AddRef();
+ ciid = iid;
+ cpoint->Advise((IUnknown*)(IDispatch*)this, &cookie);
+ }
+
+ // disconnect from all connection points
+ void unadvise()
+ {
+ combase = 0;
+ if (cpoint) {
+ cpoint->Unadvise(cookie);
+ cpoint->Release();
+ cpoint = 0;
+ }
+ }
+
+ void addSignal(DISPID memid, const char *name)
+ {
+ QByteArray signalname = name;
+ int pi = signalname.indexOf('(');
+ int i = 0;
+ while (type_conversion[i][0]) {
+ int ti = pi;
+ int len = int(strlen(type_conversion[i][0]));
+ while ((ti = signalname.indexOf(type_conversion[i][0], ti)) != -1)
+ signalname.replace(ti, len, type_conversion[i][1]);
+ ++i;
+ }
+
+ sigs.insert(memid, signalname);
+ QMap<DISPID,QByteArray>::ConstIterator it;
+ DISPID id = -1;
+ for (it = propsigs.constBegin(); it!= propsigs.constEnd(); ++it) {
+ if (it.value() == signalname) {
+ id = it.key();
+ break;
+ }
+ }
+ if (id != -1)
+ propsigs.remove(id);
+ }
+ void addProperty(DISPID propid, const char *name, const char *signal)
+ {
+ props.insert(propid, name);
+ propsigs.insert(propid, signal);
+ }
+
+ // IUnknown
+ unsigned long __stdcall AddRef()
+ {
+ return ref++;
+ }
+ unsigned long __stdcall Release()
+ {
+ if (!--ref) {
+ delete this;
+ return 0;
+ }
+ return ref;
+ }
+ HRESULT __stdcall QueryInterface(REFIID riid, void **ppvObject)
+ {
+ *ppvObject = 0;
+ if (riid == IID_IUnknown)
+ *ppvObject = (IUnknown*)(IDispatch*)this;
+ else if (riid == IID_IDispatch)
+ *ppvObject = (IDispatch*)this;
+ else if (riid == IID_IPropertyNotifySink)
+ *ppvObject = (IPropertyNotifySink*)this;
+ else if (ciid == riid)
+ *ppvObject = (IDispatch*)this;
+ else
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+ }
+
+ // IDispatch
+ HRESULT __stdcall GetTypeInfoCount(unsigned int *) { return E_NOTIMPL; }
+ HRESULT __stdcall GetTypeInfo(UINT, LCID, ITypeInfo **) { return E_NOTIMPL; }
+ HRESULT __stdcall GetIDsOfNames(const _GUID &, wchar_t **, unsigned int, unsigned long, long *) { return E_NOTIMPL; }
+
+ HRESULT __stdcall Invoke(DISPID dispIdMember,
+ REFIID riid,
+ LCID,
+ WORD wFlags,
+ DISPPARAMS *pDispParams,
+ VARIANT*,
+ EXCEPINFO*,
+ UINT*)
+ {
+ // verify input
+ if (riid != IID_NULL)
+ return DISP_E_UNKNOWNINTERFACE;
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+ if (!combase)
+ return E_UNEXPECTED;
+
+ QByteArray signame = sigs.value(dispIdMember);
+ if (signame.isEmpty())
+ return DISP_E_MEMBERNOTFOUND;
+
+ QObject *qobject = combase->qObject();
+ if (qobject->signalsBlocked())
+ return S_OK;
+
+ QAxMetaObject *axmeta = combase->internalMetaObject();
+ const QMetaObject *meta = combase->metaObject();
+
+ int index = -1;
+ // emit the generic signal "as is"
+ if (signalHasReceivers(qobject, "signal(QString,int,void*)")) {
+ index = meta->indexOfSignal("signal(QString,int,void*)");
+ Q_ASSERT(index != -1);
+
+ QString nameString = QLatin1String(signame);
+ void *argv[] = {0, &nameString, &pDispParams->cArgs, &pDispParams->rgvarg};
+ combase->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv);
+ }
+
+ HRESULT hres = S_OK;
+
+ // get the signal information from the metaobject
+ index = -1;
+ if (signalHasReceivers(qobject, signame)) {
+ index = meta->indexOfSignal(signame);
+ Q_ASSERT(index != -1);
+ const QMetaMethod signal = meta->method(index);
+ Q_ASSERT(signal.methodType() == QMetaMethod::Signal);
+ Q_ASSERT(signame == signal.signature());
+ // verify parameter count
+ int pcount = axmeta->numParameter(signame);
+ int argcount = pDispParams->cArgs;
+ if (pcount > argcount)
+ return DISP_E_PARAMNOTOPTIONAL;
+ else if (pcount < argcount)
+ return DISP_E_BADPARAMCOUNT;
+
+ // setup parameters (no return values in signals)
+ bool ok = true;
+ void *static_argv[QAX_NUM_PARAMS + 1];
+ void *static_argv_pointer[QAX_NUM_PARAMS + 1];
+ QVariant static_varp[QAX_NUM_PARAMS + 1];
+
+ void **argv = 0;
+ void **argv_pointer = 0; // in case we need an additional level of indirection
+ QVariant *varp = 0;
+
+ if (pcount) {
+ if (pcount <= 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[0] = 0;
+ argv_pointer[0] = 0;
+ }
+
+ int p;
+ for (p = 0; p < pcount && ok; ++p) {
+ // map the VARIANT to the void*
+ QByteArray ptype = axmeta->paramType(signame, p);
+ 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 {
+ ok = false;
+ }
+ }
+
+ if (ok) {
+ // emit the generated signal if everything went well
+ combase->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv);
+ // update the VARIANT for references and free memory
+ for (p = 0; p < pcount; ++p) {
+ bool out;
+ QByteArray ptype = axmeta->paramType(signame, p, &out);
+ if (out) {
+ if (!QVariantToVARIANT(varp[p + 1], pDispParams->rgvarg[pcount - p - 1], ptype, out))
+ ok = false;
+ }
+ }
+ }
+
+ if (argv != static_argv) {
+ delete [] argv;
+ delete [] argv_pointer;
+ delete [] varp;
+ }
+ hres = ok ? S_OK : (ok ? DISP_E_MEMBERNOTFOUND : DISP_E_TYPEMISMATCH);
+ }
+
+ return hres;
+ }
+
+ QByteArray findProperty(DISPID dispID);
+
+ // IPropertyNotifySink
+ HRESULT __stdcall OnChanged(DISPID dispID)
+ {
+ // verify input
+ if (dispID == DISPID_UNKNOWN || !combase)
+ return S_OK;
+
+ const QMetaObject *meta = combase->metaObject();
+ if (!meta)
+ return S_OK;
+
+ QByteArray propname(findProperty(dispID));
+ if (propname.isEmpty())
+ return S_OK;
+
+ QObject *qobject = combase->qObject();
+ if (qobject->signalsBlocked())
+ return S_OK;
+
+ // emit the generic signal
+ int index = meta->indexOfSignal("propertyChanged(QString)");
+ if (index != -1) {
+ QString propnameString = QString::fromLatin1(propname);
+ void *argv[] = {0, &propnameString};
+ combase->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv);
+ }
+
+ QByteArray signame = propsigs.value(dispID);
+ if (signame.isEmpty())
+ return S_OK;
+
+ index = meta->indexOfSignal(signame);
+ if (index == -1) // bindable but not marked as bindable in typelib
+ return S_OK;
+
+ // get the signal information from the metaobject
+ if (signalHasReceivers(qobject, signame)) {
+ index = meta->indexOfSignal(signame);
+ Q_ASSERT(index != -1);
+ // setup parameters
+ QVariant var = qobject->property(propname);
+ if (!var.isValid())
+ return S_OK;
+
+ const QMetaProperty metaProp = meta->property(meta->indexOfProperty(propname));
+ void *argv[] = {0, var.data()};
+ if (metaProp.type() == QVariant::LastType)
+ argv[1] = &var;
+
+ // emit the "changed" signal
+ combase->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv);
+ }
+ return S_OK;
+ }
+ HRESULT __stdcall OnRequestEdit(DISPID dispID)
+ {
+ if (dispID == DISPID_UNKNOWN || !combase)
+ return S_OK;
+
+ QByteArray propname(findProperty(dispID));
+ if (propname.isEmpty())
+ return S_OK;
+
+ return combase->propertyWritable(propname) ? S_OK : S_FALSE;
+ }
+
+ static bool signalHasReceivers(QObject *qobject, const char *signalName)
+ {
+ Q_ASSERT(qobject);
+ return ((QAxObject*)qobject)->receivers(QByteArray::number(QSIGNAL_CODE) + signalName);
+ }
+
+ IConnectionPoint *cpoint;
+ IID ciid;
+ ULONG cookie;
+
+ QMap<DISPID, QByteArray> sigs;
+ QMap<DISPID, QByteArray> propsigs;
+ QMap<DISPID, QByteArray> props;
+
+ QAxBase *combase;
+ long ref;
+};
+
+/*
+ \internal
+ \class QAxBasePrivate
+*/
+
+class QAxBasePrivate
+{
+public:
+ QAxBasePrivate()
+ : useEventSink(true), useMetaObject(true), useClassInfo(true),
+ cachedMetaObject(false), initialized(false), tryCache(false),
+ ptr(0), disp(0), metaobj(0)
+ {
+ // protect initialization
+ QMutexLocker locker(&cache_mutex);
+ mo_cache_ref++;
+
+ qRegisterMetaType<IUnknown*>("IUnknown*", &ptr);
+ qRegisterMetaType<IDispatch*>("IDispatch*", &disp);
+ }
+
+ ~QAxBasePrivate()
+ {
+ Q_ASSERT(!ptr);
+ Q_ASSERT(!disp);
+
+ // protect cleanup
+ QMutexLocker locker(&cache_mutex);
+ if (!--mo_cache_ref) {
+ qDeleteAll(mo_cache);
+ mo_cache.clear();
+ }
+
+ CoFreeUnusedLibraries();
+ }
+
+ inline IDispatch *dispatch() const
+ {
+ if (disp)
+ return disp;
+
+ if (ptr)
+ ptr->QueryInterface(IID_IDispatch, (void**)&disp);
+ return disp;
+ }
+
+ QString ctrl;
+
+ QHash<QUuid, QAxEventSink*> eventSink;
+ uint useEventSink :1;
+ uint useMetaObject :1;
+ uint useClassInfo :1;
+ uint cachedMetaObject :1;
+ uint initialized :1;
+ uint tryCache :1;
+
+ IUnknown *ptr;
+ mutable IDispatch *disp;
+
+ QMap<QByteArray, bool> propWritable;
+
+ inline QAxMetaObject *metaObject()
+ {
+ if (!metaobj)
+ metaobj = new QAxMetaObject;
+ return metaobj;
+ }
+
+ mutable QMap<QString, LONG> verbs;
+
+ QAxMetaObject *metaobj;
+};
+
+
+QByteArray QAxEventSink::findProperty(DISPID dispID)
+{
+ // look up in cache, and fall back to
+ // type info for precompiled metaobjects
+ QByteArray propname(props.value(dispID));
+
+ if (!propname.isEmpty())
+ return propname;
+
+ IDispatch *dispatch = combase->d->dispatch();
+ ITypeInfo *typeinfo = 0;
+ if (dispatch)
+ dispatch->GetTypeInfo(0, LOCALE_USER_DEFAULT, &typeinfo);
+ if (!typeinfo)
+ return propname;
+
+ BSTR names;
+ UINT cNames;
+ typeinfo->GetNames(dispID, &names, 1, &cNames);
+ if (cNames) {
+ propname = QString::fromUtf16((const ushort *)names).toLatin1();
+ SysFreeString(names);
+ }
+ typeinfo->Release();
+
+ QByteArray propsignal(propname + "Changed(");
+ const QMetaObject *mo = combase->metaObject();
+ int index = mo->indexOfProperty(propname);
+ const QMetaProperty prop = mo->property(index);
+ propsignal += prop.typeName();
+ propsignal += ")";
+ addProperty(dispID, propname, propsignal);
+
+ return propname;
+}
+
+/*!
+ \class QAxBase
+ \brief The QAxBase class is an abstract class that provides an API
+ to initialize and access a COM object.
+
+ \inmodule QAxContainer
+
+ QAxBase is an abstract class that cannot be used directly, and is
+ instantiated through the subclasses QAxObject and QAxWidget. This
+ class provides the API to access the COM object directly
+ through its IUnknown implementation. If the COM object implements
+ the IDispatch interface, the properties and methods of that object
+ become available as Qt properties and slots.
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 0
+
+ Properties exposed by the object's IDispatch implementation can
+ be read and written through the property system provided by the
+ Qt Object Model (both subclasses are QObjects, so you can use
+ QObject::setProperty() and QObject::property()). Properties with
+ multiple parameters are not supported.
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 1
+
+ Write-functions for properties and other methods exposed by the
+ object's IDispatch implementation can be called directly using
+ dynamicCall(), or indirectly as slots connected to a signal.
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 2
+
+ Outgoing events supported by the COM object are emitted as
+ standard Qt signals.
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 3
+
+ QAxBase transparently converts between COM data types and the
+ equivalent Qt data types. Some COM types have no equivalent Qt data structure.
+
+ Supported COM datatypes are listed in the first column of following table.
+ The second column is the Qt type that can be used with the QObject property
+ functions. The third column is the Qt type that is used in the prototype of
+ generated signals and slots for in-parameters, and the last column is the Qt
+ type that is used in the prototype of signals and slots for out-parameters.
+ \table
+ \header
+ \i COM type
+ \i Qt property
+ \i in-parameter
+ \i out-parameter
+ \row
+ \i VARIANT_BOOL
+ \i bool
+ \i bool
+ \i bool&
+ \row
+ \i BSTR
+ \i QString
+ \i const QString&
+ \i QString&
+ \row
+ \i char, short, int, long
+ \i int
+ \i int
+ \i int&
+ \row
+ \i uchar, ushort, uint, ulong
+ \i uint
+ \i uint
+ \i uint&
+ \row
+ \i float, double
+ \i double
+ \i double
+ \i double&
+ \row
+ \i DATE
+ \i QDateTime
+ \i const QDateTime&
+ \i QDateTime&
+ \row
+ \i CY
+ \i qlonglong
+ \i qlonglong
+ \i qlonglong&
+ \row
+ \i OLE_COLOR
+ \i QColor
+ \i const QColor&
+ \i QColor&
+ \row
+ \i SAFEARRAY(VARIANT)
+ \i QList\<QVariant\>
+ \i const QList\<QVariant\>&
+ \i QList\<QVariant\>&
+ \row
+ \i SAFEARRAY(int), SAFEARRAY(double), SAFEARRAY(Date)
+ \i QList\<QVariant\>
+ \i const QList\<QVariant\>&
+ \i QList\<QVariant\>&
+ \row
+ \i SAFEARRAY(BYTE)
+ \i QByteArray
+ \i const QByteArray&
+ \i QByteArray&
+ \row
+ \i SAFEARRAY(BSTR)
+ \i QStringList
+ \i const QStringList&
+ \i QStringList&
+ \row
+ \i VARIANT
+ \i type-dependent
+ \i const QVariant&
+ \i QVariant&
+ \row
+ \i IFontDisp*
+ \i QFont
+ \i const QFont&
+ \i QFont&
+ \row
+ \i IPictureDisp*
+ \i QPixmap
+ \i const QPixmap&
+ \i QPixmap&
+ \row
+ \i IDispatch*
+ \i QAxObject*
+ \i \c QAxBase::asVariant()
+ \i QAxObject* (return value)
+ \row
+ \i IUnknown*
+ \i QAxObject*
+ \i \c QAxBase::asVariant()
+ \i QAxObject* (return value)
+ \row
+ \i SCODE, DECIMAL
+ \i \e unsupported
+ \i \e unsupported
+ \i \e unsupported
+ \row
+ \i VARIANT* (Since Qt 4.5)
+ \i \e unsupported
+ \i \e QVariant&
+ \i \e QVariant&
+ \endtable
+
+ Supported are also enumerations, and typedefs to supported types.
+
+ To call the methods of a COM interface described by the following IDL
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 4
+
+ use the QAxBase API like this:
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 5
+
+ Note that the QList the object should fill has to be provided as an
+ element in the parameter list of \l{QVariant}s.
+
+ If you need to access properties or pass parameters of
+ unsupported datatypes you must access the COM object directly
+ through its \c IDispatch implementation or other interfaces.
+ Those interfaces can be retrieved through queryInterface().
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 6
+
+ To get the definition of the COM interfaces you will have to use the header
+ files provided with the component you want to use. Some compilers can also
+ import type libraries using the #import compiler directive. See the component
+ documentation to find out which type libraries you have to import, and how to use
+ them.
+
+ If you need to react to events that pass parameters of unsupported
+ datatypes you can use the generic signal that delivers the event
+ data as provided by the COM event.
+
+ \sa QAxObject, QAxWidget, QAxScript, {ActiveQt Framework}
+*/
+
+/*!
+ \typedef QAxBase::PropertyBag
+
+ A QMap<QString,QVariant> that can store properties as name:value pairs.
+*/
+
+/*!
+ Creates a QAxBase object that wraps the COM object \a iface. If \a
+ iface is 0 (the default), use setControl() to instantiate a COM
+ object.
+*/
+QAxBase::QAxBase(IUnknown *iface)
+{
+ d = new QAxBasePrivate();
+ d->ptr = iface;
+ if (d->ptr) {
+ d->ptr->AddRef();
+ d->initialized = true;
+ }
+#if defined(Q_OS_WINCE)
+ CoInitializeEx(0, COINIT_MULTITHREADED);
+#endif
+}
+
+/*!
+ Shuts down the COM object and destroys the QAxBase object.
+
+ \sa clear()
+*/
+QAxBase::~QAxBase()
+{
+#if defined(Q_OS_WINCE)
+ CoUninitialize();
+#endif
+
+ clear();
+
+ delete d;
+ d = 0;
+}
+
+/*!
+ \internal
+
+ Used by subclasses generated with dumpcpp to balance reference count.
+*/
+void QAxBase::internalRelease()
+{
+ if (d->ptr)
+ d->ptr->Release();
+}
+
+/*!
+ \internal
+
+ Used by subclasses generated with dumpcpp to implement cast-operators.
+*/
+void QAxBase::initializeFrom(QAxBase *that)
+{
+ if (d->ptr)
+ return;
+
+ d->ptr = that->d->ptr;
+ if (d->ptr) {
+ d->ptr->AddRef();
+ d->initialized = true;
+ }
+}
+
+
+QAxMetaObject *QAxBase::internalMetaObject() const
+{
+ return d->metaObject();
+}
+
+/*!
+ \property QAxBase::control
+ \brief the name of the COM object wrapped by this QAxBase object.
+
+ Setting this property initilializes the COM object. Any COM object
+ previously set is shut down.
+
+ The most efficient way to set this property is by using the
+ registered component's UUID, e.g.
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 7
+
+ The second fastest way is to use the registered control's class
+ name (with or without version number), e.g.
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 8
+
+ The slowest, but easiest way to use is to use the control's full
+ name, e.g.
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 9
+
+ It is also possible to initialize the object from a file, e.g.
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 10
+
+ If the component's UUID is used the following patterns can be used
+ to initialize the control on a remote machine, to initialize a
+ licensed control or to connect to a running object:
+ \list
+ \i To initialize the control on a different machine use the following
+ pattern:
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 11
+
+ \i To initialize a licensed control use the following pattern:
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 12
+
+ \i To connect to an already running object use the following pattern:
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 13
+
+ \endlist
+ The first two patterns can be combined, e.g. to initialize a licensed
+ control on a remote machine:
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 14
+
+ The control's read function always returns the control's UUID, if provided including the license
+ key, and the name of the server, but not including the username, the domain or the password.
+*/
+bool QAxBase::setControl(const QString &c)
+{
+ if (c.toLower() == d->ctrl.toLower())
+ return !d->ctrl.isEmpty();
+
+ QString search = c;
+ // don't waste time for DCOM requests
+ int dcomIDIndex = search.indexOf(QLatin1String("/{"));
+ if ((dcomIDIndex == -1 || dcomIDIndex != search.length()-39) && !search.endsWith(QLatin1String("}&"))) {
+ QUuid uuid(search);
+ if (uuid.isNull()) {
+ CLSID clsid;
+ HRESULT res = CLSIDFromProgID((WCHAR*)c.utf16(), &clsid);
+ if (res == S_OK)
+ search = QUuid(clsid).toString();
+ else {
+ QSettings controls(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes\\"), QSettings::NativeFormat);
+ search = controls.value(c + QLatin1String("/CLSID/Default")).toString();
+ if (search.isEmpty()) {
+ controls.beginGroup(QLatin1String("/CLSID"));
+ QStringList clsids = controls.childGroups();
+ for (QStringList::Iterator it = clsids.begin(); it != clsids.end(); ++it) {
+ QString clsid = *it;
+ QString name = controls.value(clsid + QLatin1String("/Default")).toString();
+ if (name == c) {
+ search = clsid;
+ break;
+ }
+ }
+ controls.endGroup();
+ }
+ }
+ }
+ if (search.isEmpty())
+ search = c;
+ }
+
+ if (search.toLower() == d->ctrl.toLower())
+ return !d->ctrl.isEmpty();
+
+ clear();
+ d->ctrl = search;
+
+ d->tryCache = true;
+ if (!initialize(&d->ptr))
+ d->initialized = true;
+ if (isNull()) {
+ qWarning("QAxBase::setControl: requested control %s could not be instantiated", c.toLatin1().data());
+ clear();
+ return false;
+ }
+ return true;
+}
+
+QString QAxBase::control() const
+{
+ return d->ctrl;
+}
+
+/*!
+ Disables the event sink implementation for this ActiveX container.
+ If you don't intend to listen to the ActiveX control's events use
+ this function to speed up the meta object generation.
+
+ Some ActiveX controls might be unstable when connected to an event
+ sink. To get OLE events you must use standard COM methods to
+ register your own event sink. Use queryInterface() to get access
+ to the raw COM object.
+
+ Note that this function should be called immediately after
+ construction of the object.
+*/
+void QAxBase::disableEventSink()
+{
+ d->useEventSink = false;
+}
+
+/*!
+ Disables the meta object generation for this ActiveX container.
+ This also disables the event sink and class info generation. If
+ you don't intend to use the Qt meta object implementation call
+ this function to speed up instantiation of the control. You will
+ still be able to call the object through \l dynamicCall(), but
+ signals, slots and properties will not be available with QObject
+ APIs.
+
+ Some ActiveX controls might be unstable when used with OLE
+ automation. Use standard COM methods to use those controls through
+ the COM interfaces provided by queryInterface().
+
+ Note that this function must be called immediately after
+ construction of the object.
+*/
+void QAxBase::disableMetaObject()
+{
+ d->useMetaObject = false;
+ d->useEventSink = false;
+ d->useClassInfo = false;
+}
+
+/*!
+ Disables the class info generation for this ActiveX container. If
+ you don't require any class information about the ActiveX control
+ use this function to speed up the meta object generation.
+
+ Note that this function must be called immediately after
+ construction of the object
+*/
+void QAxBase::disableClassInfo()
+{
+ d->useClassInfo = false;
+}
+
+/*!
+ Disconnects and destroys the COM object.
+
+ If you reimplement this function you must also reimplement the
+ destructor to call clear(), and call this implementation at the
+ end of your clear() function.
+*/
+void QAxBase::clear()
+{
+ QHash<QUuid, QAxEventSink*>::Iterator it = d->eventSink.begin();
+ while (it != d->eventSink.end()) {
+ QAxEventSink *eventSink = it.value();
+ ++it;
+ if (eventSink) {
+ eventSink->unadvise();
+ eventSink->Release();
+ }
+ }
+ d->eventSink.clear();
+ if (d->disp) {
+ d->disp->Release();
+ d->disp = 0;
+ }
+ if (d->ptr) {
+ d->ptr->Release();
+ d->ptr = 0;
+ d->initialized = false;
+ }
+
+ d->ctrl.clear();
+
+ if (!d->cachedMetaObject)
+ delete d->metaobj;
+ d->metaobj = 0;
+}
+
+/*!
+ \since 4.1
+
+ Returns the list of verbs that the COM object can execute. If
+ the object does not implement IOleObject, or does not support
+ any verbs, then this function returns an empty stringlist.
+
+ Note that the OLE default verbs (OLEIVERB_SHOW etc) are not
+ included in the list.
+*/
+QStringList QAxBase::verbs() const
+{
+ if (!d->ptr)
+ return QStringList();
+
+ if (d->verbs.isEmpty()) {
+ IOleObject *ole = 0;
+ d->ptr->QueryInterface(IID_IOleObject, (void**)&ole);
+ if (ole) {
+ IEnumOLEVERB *enumVerbs = 0;
+ ole->EnumVerbs(&enumVerbs);
+ if (enumVerbs) {
+ enumVerbs->Reset();
+ ULONG c;
+ OLEVERB verb;
+ while (enumVerbs->Next(1, &verb, &c) == S_OK) {
+ if (!verb.lpszVerbName)
+ continue;
+ QString verbName = QString::fromUtf16((const ushort *)verb.lpszVerbName);
+ if (!verbName.isEmpty())
+ d->verbs.insert(verbName, verb.lVerb);
+ }
+ enumVerbs->Release();
+ }
+ ole->Release();
+ }
+ }
+
+ return d->verbs.keys();
+}
+
+/*!
+ \internal
+*/
+
+long QAxBase::indexOfVerb(const QString &verb) const
+{
+ return d->verbs.value(verb);
+}
+
+/*!
+ This virtual function is called by setControl() and creates the
+ requested COM object. \a ptr is set to the object's IUnknown
+ implementation. The function returns true if the object
+ initialization succeeded; otherwise the function returns false.
+
+ The default implementation interprets the string returned by
+ control(), and calls initializeRemote(), initializeLicensed()
+ or initializeActive() if the string matches the respective
+ patterns. If control() is the name of an existing file,
+ initializeFromFile() is called. If no pattern is matched, or
+ if remote or licensed initialization fails, CoCreateInstance
+ is used directly to create the object.
+
+ See the \l control property documentation for details about
+ supported patterns.
+
+ The interface returned in \a ptr must be referenced exactly once
+ when this function returns. The interface provided by e.g.
+ CoCreateInstance is already referenced, and there is no need to
+ reference it again.
+*/
+bool QAxBase::initialize(IUnknown **ptr)
+{
+ if (*ptr || control().isEmpty())
+ return false;
+
+ *ptr = 0;
+
+ bool res = false;
+
+ const QString ctrl(d->ctrl);
+ if (ctrl.contains(QLatin1String("/{"))) // DCOM request
+ res = initializeRemote(ptr);
+ else if (ctrl.contains(QLatin1String("}:"))) // licensed control
+ res = initializeLicensed(ptr);
+ else if (ctrl.contains(QLatin1String("}&"))) // running object
+ res = initializeActive(ptr);
+ else if (QFile::exists(ctrl)) // existing file
+ res = initializeFromFile(ptr);
+
+ if (!res) { // standard
+ HRESULT hres = CoCreateInstance(QUuid(ctrl), 0, CLSCTX_SERVER, IID_IUnknown, (void**)ptr);
+ res = S_OK == hres;
+#ifndef QT_NO_DEBUG
+ if (!res)
+ qErrnoWarning(hres, "CoCreateInstance failure");
+#endif
+ }
+
+ return *ptr != 0;
+}
+
+/*!
+ Creates an instance of a licensed control, and returns the IUnknown interface
+ to the object in \a ptr. This functions returns true if successful, otherwise
+ returns false.
+
+ This function is called by initialize() if the control string contains the
+ substring "}:". The license key needs to follow this substring.
+
+ \sa initialize()
+*/
+bool QAxBase::initializeLicensed(IUnknown** ptr)
+{
+ int at = control().lastIndexOf(QLatin1String("}:"));
+
+ QString clsid(control().left(at));
+ QString key(control().mid(at+2));
+
+ IClassFactory *factory = 0;
+ CoGetClassObject(QUuid(clsid), CLSCTX_SERVER, 0, IID_IClassFactory, (void**)&factory);
+ if (!factory)
+ return false;
+ initializeLicensedHelper(factory, key, ptr);
+ factory->Release();
+
+ return *ptr != 0;
+}
+
+/* \internal
+ Called by initializeLicensed and initializedRemote to create an object
+ via IClassFactory2.
+*/
+bool QAxBase::initializeLicensedHelper(void *f, const QString &key, IUnknown **ptr)
+{
+ IClassFactory *factory = (IClassFactory*)f;
+ IClassFactory2 *factory2 = 0;
+ factory->QueryInterface(IID_IClassFactory2, (void**)&factory2);
+ if (factory2) {
+ BSTR bkey = QStringToBSTR(key);
+ HRESULT hres = factory2->CreateInstanceLic(0, 0, IID_IUnknown, bkey, (void**)ptr);
+ SysFreeString(bkey);
+#ifdef QT_DEBUG
+ LICINFO licinfo;
+ licinfo.cbLicInfo = sizeof(LICINFO);
+ factory2->GetLicInfo(&licinfo);
+
+ if (hres != S_OK) {
+ SetLastError(hres);
+ qErrnoWarning("CreateInstanceLic failed");
+ if (!licinfo.fLicVerified) {
+ qWarning("Wrong license key specified, and machine is not fully licensed.");
+ } else if (licinfo.fRuntimeKeyAvail) {
+ BSTR licenseKey;
+ factory2->RequestLicKey(0, &licenseKey);
+ QString qlicenseKey = QString::fromUtf16((const ushort *)licenseKey);
+ SysFreeString(licenseKey);
+ qWarning("Use license key is '%s' to create object on unlicensed machine.",
+ qlicenseKey.toLatin1().constData());
+ }
+ } else if (licinfo.fLicVerified) {
+ qWarning("Machine is fully licensed for '%s'", control().toLatin1().constData());
+ if (licinfo.fRuntimeKeyAvail) {
+ BSTR licenseKey;
+ factory2->RequestLicKey(0, &licenseKey);
+ QString qlicenseKey = QString::fromUtf16((const ushort *)licenseKey);
+ SysFreeString(licenseKey);
+
+ if (qlicenseKey != key)
+ qWarning("Runtime license key is '%s'", qlicenseKey.toLatin1().constData());
+ }
+ }
+#else
+ Q_UNUSED(hres);
+#endif
+ factory2->Release();
+ } else { // give it a shot without license
+ factory->CreateInstance(0, IID_IUnknown, (void**)ptr);
+ }
+ return *ptr != 0;
+}
+
+
+/*!
+ Connects to an active instance running on the current machine, and returns the
+ IUnknown interface to the running object in \a ptr. This function returns true
+ if successful, otherwise returns false.
+
+ This function is called by initialize() if the control string contains the
+ substring "}&".
+
+ \sa initialize()
+*/
+bool QAxBase::initializeActive(IUnknown** ptr)
+{
+#if defined(Q_OS_WINCE)
+ Q_UNUSED(ptr);
+ return false;
+#else
+ int at = control().lastIndexOf(QLatin1String("}&"));
+ QString clsid(control().left(at));
+
+ GetActiveObject(QUuid(clsid), 0, ptr);
+
+ return *ptr != 0;
+#endif
+}
+
+#ifdef Q_CC_GNU
+# ifndef OLEPENDER_NONE
+# define OLERENDER_NONE 0
+# endif
+#endif
+
+/*!
+ Creates the COM object handling the filename in the control property, and
+ returns the IUnknown interface to the object in \a ptr. This function returns
+ true if successful, otherwise returns false.
+
+ This function is called by initialize() if the control string is the name of
+ an existing file.
+
+ \sa initialize()
+*/
+bool QAxBase::initializeFromFile(IUnknown** ptr)
+{
+#if defined(Q_OS_WINCE)
+ Q_UNUSED(ptr);
+ return false;
+#else
+ IStorage *storage = 0;
+ ILockBytes * bytes = 0;
+ HRESULT hres = ::CreateILockBytesOnHGlobal(0, TRUE, &bytes);
+ hres = ::StgCreateDocfileOnILockBytes(bytes, STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &storage);
+
+ hres = OleCreateFromFile(CLSID_NULL, reinterpret_cast<const wchar_t*>(control().utf16()), IID_IUnknown, OLERENDER_NONE, 0, 0, storage, (void**)ptr);
+
+ storage->Release();
+ bytes->Release();
+
+ return hres == S_OK;
+#endif
+}
+
+
+// There seams to be a naming problem in mingw headers
+#ifdef Q_CC_GNU
+#ifndef COAUTHIDENTITY
+#define COAUTHIDENTITY AUTH_IDENTITY
+#endif
+#endif
+
+
+/*!
+ Creates the instance on a remote server, and returns the IUnknown interface
+ to the object in \a ptr. This function returns true if successful, otherwise
+ returns false.
+
+ This function is called by initialize() if the control string contains the
+ substring "/{". The information about the remote machine needs to be provided
+ in front of the substring.
+
+ \sa initialize()
+*/
+bool QAxBase::initializeRemote(IUnknown** ptr)
+{
+ int at = control().lastIndexOf(QLatin1String("/{"));
+
+ QString server(control().left(at));
+ QString clsid(control().mid(at+1));
+
+ QString user;
+ QString domain;
+ QString passwd;
+ QString key;
+
+ at = server.indexOf(QChar::fromLatin1('@'));
+ if (at != -1) {
+ user = server.left(at);
+ server = server.mid(at+1);
+
+ at = user.indexOf(QChar::fromLatin1(':'));
+ if (at != -1) {
+ passwd = user.mid(at+1);
+ user = user.left(at);
+ }
+ at = user.indexOf(QChar::fromLatin1('/'));
+ if (at != -1) {
+ domain = user.left(at);
+ user = user.mid(at+1);
+ }
+ }
+
+ at = clsid.lastIndexOf(QLatin1String("}:"));
+ if (at != -1) {
+ key = clsid.mid(at+2);
+ clsid = clsid.left(at);
+ }
+
+ d->ctrl = server + QChar::fromLatin1('/') + clsid;
+ if (!key.isEmpty())
+ d->ctrl = d->ctrl + QChar::fromLatin1(':') + key;
+
+ COAUTHIDENTITY authIdentity;
+ authIdentity.UserLength = user.length();
+ authIdentity.User = authIdentity.UserLength ? (ushort*)user.utf16() : 0;
+ authIdentity.DomainLength = domain.length();
+ authIdentity.Domain = authIdentity.DomainLength ? (ushort*)domain.utf16() : 0;
+ authIdentity.PasswordLength = passwd.length();
+ authIdentity.Password = authIdentity.PasswordLength ? (ushort*)passwd.utf16() : 0;
+ authIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
+
+ COAUTHINFO authInfo;
+ authInfo.dwAuthnSvc = RPC_C_AUTHN_WINNT;
+ authInfo.dwAuthzSvc = RPC_C_AUTHZ_NONE;
+ authInfo.pwszServerPrincName = 0;
+ authInfo.dwAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT;
+ authInfo.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
+ authInfo.pAuthIdentityData = &authIdentity;
+ authInfo.dwCapabilities = 0;
+
+ COSERVERINFO serverInfo;
+ serverInfo.dwReserved1 = 0;
+ serverInfo.dwReserved2 = 0;
+ serverInfo.pAuthInfo = &authInfo;
+ serverInfo.pwszName = (WCHAR*)server.utf16();
+
+ IClassFactory *factory = 0;
+ HRESULT res = CoGetClassObject(QUuid(clsid), CLSCTX_REMOTE_SERVER, &serverInfo, IID_IClassFactory, (void**)&factory);
+ if (factory) {
+ if (!key.isEmpty())
+ initializeLicensedHelper(factory, key, ptr);
+ else
+ res = factory->CreateInstance(0, IID_IUnknown, (void**)ptr);
+ factory->Release();
+ }
+#ifndef QT_NO_DEBUG
+ if (res != S_OK)
+ qErrnoWarning(res, "initializeRemote Failed");
+#endif
+
+ return res == S_OK;
+}
+
+/*!
+ Requests the interface \a uuid from the COM object and sets the
+ value of \a iface to the provided interface, or to 0 if the
+ requested interface could not be provided.
+
+ Returns the result of the QueryInterface implementation of the COM object.
+
+ \sa control
+*/
+long QAxBase::queryInterface(const QUuid &uuid, void **iface) const
+{
+ *iface = 0;
+ if (!d->ptr) {
+ ((QAxBase*)this)->initialize(&d->ptr);
+ d->initialized = true;
+ }
+
+ if (d->ptr && !uuid.isNull())
+ return d->ptr->QueryInterface(uuid, iface);
+
+ return E_NOTIMPL;
+}
+
+class MetaObjectGenerator
+{
+public:
+ MetaObjectGenerator(QAxBase *ax, QAxBasePrivate *dptr);
+ MetaObjectGenerator(ITypeLib *typelib, ITypeInfo *typeinfo);
+ ~MetaObjectGenerator();
+
+ QMetaObject *metaObject(const QMetaObject *parentObject, const QByteArray &className = QByteArray());
+
+ void readClassInfo();
+ void readEnumInfo();
+ void readInterfaceInfo();
+ void readFuncsInfo(ITypeInfo *typeinfo, ushort nFuncs);
+ void readVarsInfo(ITypeInfo *typeinfo, ushort nVars);
+ void readEventInfo();
+ void readEventInterface(ITypeInfo *eventinfo, IConnectionPoint *cpoint);
+
+ inline void addClassInfo(const char *key, const char *value)
+ {
+ classinfo_list.insert(key, value);
+ }
+
+private:
+ void init();
+
+
+ QMetaObject *tryCache();
+
+ QByteArray createPrototype(FUNCDESC *funcdesc, ITypeInfo *typeinfo, const QList<QByteArray> &names,
+ QByteArray &type, QList<QByteArray> &parameters);
+
+ QByteArray usertypeToString(const TYPEDESC &tdesc, ITypeInfo *info, const QByteArray &function);
+ QByteArray guessTypes(const TYPEDESC &tdesc, ITypeInfo *info, const QByteArray &function);
+
+ // ### from qmetaobject.cpp
+ enum ProperyFlags {
+ Invalid = 0x00000000,
+ Readable = 0x00000001,
+ Writable = 0x00000002,
+ Resettable = 0x00000004,
+ EnumOrFlag = 0x00000008,
+ StdCppSet = 0x00000100,
+// Override = 0x00000200,
+ Designable = 0x00001000,
+ ResolveDesignable = 0x00002000,
+ Scriptable = 0x00004000,
+ ResolveScriptable = 0x00008000,
+ Stored = 0x00010000,
+ ResolveStored = 0x00020000,
+ Editable = 0x00040000,
+ ResolveEditable = 0x00080000,
+ User = 0x00100000,
+ ResolveUser = 0x00200000,
+ // And our own - don't use the upper byte, as it's used for the property type
+ RequestingEdit = 0x00400000,
+ Bindable = 0x00800000
+ };
+ enum MemberFlags {
+ AccessPrivate = 0x00,
+ AccessProtected = 0x01,
+ AccessPublic = 0x02,
+ MemberMethod = 0x00,
+ MemberSignal = 0x04,
+ MemberSlot = 0x08,
+ MemberCompatibility = 0x10,
+ MemberCloned = 0x20,
+ MemberScriptable = 0x40,
+ };
+
+ inline QList<QByteArray> paramList(const QByteArray &proto)
+ {
+ QByteArray prototype(proto);
+ QByteArray parameters = prototype.mid(prototype.indexOf('(') + 1);
+ parameters.truncate(parameters.length() - 1);
+
+ QList<QByteArray> plist = parameters.split(',');
+ return plist;
+ }
+
+ inline QByteArray replaceType(const QByteArray &type)
+ {
+ int i = 0;
+ while (type_conversion[i][0]) {
+ int len = int(strlen(type_conversion[i][0]));
+ int ti;
+ if ((ti = type.indexOf(type_conversion[i][0])) != -1) {
+ QByteArray rtype(type);
+ rtype.replace(ti, len, type_conversion[i][1]);
+ return rtype;
+ }
+ ++i;
+ }
+ return type;
+ }
+
+ QByteArray replacePrototype(const QByteArray &prototype)
+ {
+ QByteArray proto(prototype);
+
+ QList<QByteArray> plist = paramList(prototype);
+ for (int p = 0; p < plist.count(); ++p) {
+ QByteArray param(plist.at(p));
+ if (param != replaceType(param)) {
+ int type = 0;
+ while (type_conversion[type][0]) {
+ int paren = proto.indexOf('(');
+ while ((paren = proto.indexOf(type_conversion[type][0])) != -1) {
+ proto.replace(paren, qstrlen(type_conversion[type][0]), type_conversion[type][1]);
+ }
+ ++type;
+ }
+ break;
+ }
+ }
+
+ return proto;
+ }
+
+ QMap<QByteArray, QByteArray> classinfo_list;
+
+ inline bool hasClassInfo(const char *key)
+ {
+ return classinfo_list.contains(key);
+ }
+
+ struct Method {
+ Method() : flags(0)
+ {}
+ QByteArray type;
+ QByteArray parameters;
+ int flags;
+ QByteArray realPrototype;
+ };
+ QMap<QByteArray, Method> signal_list;
+ inline void addSignal(const QByteArray &prototype, const QByteArray &parameters)
+ {
+ QByteArray proto(replacePrototype(prototype));
+
+ Method &signal = signal_list[proto];
+ signal.type = 0;
+ signal.parameters = parameters;
+ signal.flags = QMetaMethod::Public | MemberSignal;
+ if (proto != prototype)
+ signal.realPrototype = prototype;
+ }
+
+ void addChangedSignal(const QByteArray &function, const QByteArray &type, int memid);
+
+ inline bool hasSignal(const QByteArray &prototype)
+ {
+ return signal_list.contains(prototype);
+ }
+
+ QMap<QByteArray, Method> slot_list;
+ inline void addSlot(const QByteArray &type, const QByteArray &prototype, const QByteArray &parameters, int flags = QMetaMethod::Public)
+ {
+ QByteArray proto = replacePrototype(prototype);
+
+ Method &slot = slot_list[proto];
+ slot.type = replaceType(type);
+ slot.parameters = parameters;
+ slot.flags = flags | MemberSlot;
+ if (proto != prototype)
+ slot.realPrototype = prototype;
+ }
+
+ void addSetterSlot(const QByteArray &property);
+
+ inline bool hasSlot(const QByteArray &prototype)
+ {
+ return slot_list.contains(prototype);
+ }
+
+ struct Property {
+ Property() : typeId(0)
+ {}
+ QByteArray type;
+ uint typeId;
+ QByteArray realType;
+ };
+ QMap<QByteArray, Property> property_list;
+ void addProperty(const QByteArray &type, const QByteArray &name, uint flags)
+ {
+ Property &prop = property_list[name];
+ if (!type.isEmpty() && type != "HRESULT") {
+ prop.type = replaceType(type);
+ if (prop.type != type)
+ prop.realType = type;
+ }
+ if (flags & Writable)
+ flags |= Stored;
+ prop.typeId |= flags;
+ QVariant::Type vartype = QVariant::nameToType(prop.type);
+ switch(vartype) {
+ case QVariant::Invalid:
+ if (prop.type == "QVariant") {
+ prop.typeId |= 0xff << 24;
+ break;
+ }
+ // fall through
+ case QVariant::UserType:
+ if (QMetaType::type(prop.type) == -1)
+ qWarning("QAxBase: Unsupported property type: %s", prop.type.data());
+ break;
+ default:
+ prop.typeId |= vartype << 24;
+ break;
+ }
+ }
+
+ inline bool hasProperty(const QByteArray &name)
+ {
+ return property_list.contains(name);
+ }
+
+ inline QByteArray propertyType(const QByteArray &name)
+ {
+ return property_list.value(name).type;
+ }
+
+ QMap<QByteArray, QList<QPair<QByteArray, int> > > enum_list;
+ inline void addEnumValue(const QByteArray &enumname, const QByteArray &key, int value)
+ {
+ enum_list[enumname].append(QPair<QByteArray, int>(key, value));
+ }
+
+ inline bool hasEnum(const QByteArray &enumname)
+ {
+ return enum_list.contains(enumname);
+ }
+
+ QAxBase *that;
+ QAxBasePrivate *d;
+
+ IDispatch *disp;
+ ITypeInfo *dispInfo;
+ ITypeInfo *classInfo;
+ ITypeLib *typelib;
+ QByteArray current_typelib;
+
+ QSettings iidnames;
+ QString cacheKey;
+ QByteArray debugInfo;
+
+ QUuid iid_propNotifySink;
+
+ friend QMetaObject *qax_readClassInfo(ITypeLib *typeLib, ITypeInfo *classInfo, const QMetaObject *parentObject);
+};
+
+QMetaObject *qax_readEnumInfo(ITypeLib *typeLib, const QMetaObject *parentObject)
+{
+ MetaObjectGenerator generator(typeLib, 0);
+
+ generator.readEnumInfo();
+ return generator.metaObject(parentObject, "EnumInfo");
+}
+
+QMetaObject *qax_readInterfaceInfo(ITypeLib *typeLib, ITypeInfo *typeInfo, const QMetaObject *parentObject)
+{
+ MetaObjectGenerator generator(typeLib, typeInfo);
+
+ QString className;
+ BSTR bstr;
+ if (S_OK != typeInfo->GetDocumentation(-1, &bstr, 0, 0, 0))
+ return 0;
+
+ className = QString::fromUtf16((const ushort *)bstr);
+ SysFreeString(bstr);
+
+ generator.readEnumInfo();
+ generator.readFuncsInfo(typeInfo, 0);
+ generator.readVarsInfo(typeInfo, 0);
+
+ return generator.metaObject(parentObject, className.toLatin1());
+}
+
+QMetaObject *qax_readClassInfo(ITypeLib *typeLib, ITypeInfo *classInfo, const QMetaObject *parentObject)
+{
+ MetaObjectGenerator generator(typeLib, 0);
+ generator.addSignal("exception(int,QString,QString,QString)", "code,source,disc,help");
+ generator.addSignal("propertyChanged(QString)", "name");
+
+ QString className;
+ BSTR bstr;
+ if (S_OK != classInfo->GetDocumentation(-1, &bstr, 0, 0, 0))
+ return 0;
+
+ className = QString::fromUtf16((const ushort *)bstr);
+ SysFreeString(bstr);
+
+ generator.readEnumInfo();
+
+ TYPEATTR *typeattr;
+ classInfo->GetTypeAttr(&typeattr);
+ if (typeattr) {
+ int nInterfaces = typeattr->cImplTypes;
+ classInfo->ReleaseTypeAttr(typeattr);
+
+ for (int index = 0; index < nInterfaces; ++index) {
+ HREFTYPE refType;
+ if (S_OK != classInfo->GetRefTypeOfImplType(index, &refType))
+ continue;
+
+ int flags = 0;
+ classInfo->GetImplTypeFlags(index, &flags);
+ if (flags & IMPLTYPEFLAG_FRESTRICTED)
+ continue;
+
+ ITypeInfo *interfaceInfo = 0;
+ classInfo->GetRefTypeInfo(refType, &interfaceInfo);
+ if (!interfaceInfo)
+ continue;
+
+ interfaceInfo->GetDocumentation(-1, &bstr, 0, 0, 0);
+ QString interfaceName = QString::fromUtf16((const ushort *)bstr);
+ SysFreeString(bstr);
+ QByteArray key;
+
+ TYPEATTR *typeattr = 0;
+ interfaceInfo->GetTypeAttr(&typeattr);
+
+ if (flags & IMPLTYPEFLAG_FSOURCE) {
+ if (typeattr && !(typeattr->wTypeFlags & TYPEFLAG_FHIDDEN))
+ key = "Event Interface " + QByteArray::number(index);
+ generator.readEventInterface(interfaceInfo, 0);
+ } else {
+ if (typeattr && !(typeattr->wTypeFlags & TYPEFLAG_FHIDDEN))
+ key = "Interface " + QByteArray::number(index);
+ generator.readFuncsInfo(interfaceInfo, 0);
+ generator.readVarsInfo(interfaceInfo, 0);
+ }
+ if (!key.isEmpty())
+ generator.addClassInfo(key.data(), interfaceName.toLatin1());
+
+ if (typeattr)
+ interfaceInfo->ReleaseTypeAttr(typeattr);
+ interfaceInfo->Release();
+ }
+ }
+
+ return generator.metaObject(parentObject, className.toLatin1());
+}
+
+MetaObjectGenerator::MetaObjectGenerator(QAxBase *ax, QAxBasePrivate *dptr)
+: that(ax), d(dptr), disp(0), dispInfo(0), classInfo(0), typelib(0),
+ iidnames(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes"), QSettings::NativeFormat)
+{
+ init();
+}
+
+MetaObjectGenerator::MetaObjectGenerator(ITypeLib *tlib, ITypeInfo *tinfo)
+: that(0), d(0), disp(0), dispInfo(tinfo), classInfo(0), typelib(tlib),
+ iidnames(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes"), QSettings::NativeFormat)
+{
+ init();
+
+ if (dispInfo)
+ dispInfo->AddRef();
+ if (typelib) {
+ typelib->AddRef();
+ BSTR bstr;
+ typelib->GetDocumentation(-1, &bstr, 0, 0, 0);
+ current_typelib = QString::fromUtf16((const ushort *)bstr).toLatin1();
+ SysFreeString(bstr);
+ }
+ readClassInfo();
+}
+
+void MetaObjectGenerator::init()
+{
+ if (d)
+ disp = d->dispatch();
+
+ iid_propNotifySink = IID_IPropertyNotifySink;
+
+ addSignal("signal(QString,int,void*)", "name,argc,argv");
+ addSignal("exception(int,QString,QString,QString)", "code,source,disc,help");
+ addSignal("propertyChanged(QString)", "name");
+ if (d || dispInfo) {
+ addProperty("QString", "control", Readable|Writable|Designable|Scriptable|Stored|Editable|StdCppSet);
+ }
+}
+
+MetaObjectGenerator::~MetaObjectGenerator()
+{
+ if (dispInfo) dispInfo->Release();
+ if (classInfo) classInfo->Release();
+ if (typelib) typelib->Release();
+}
+
+bool qax_dispatchEqualsIDispatch = true;
+QList<QByteArray> qax_qualified_usertypes;
+
+QByteArray MetaObjectGenerator::usertypeToString(const TYPEDESC &tdesc, ITypeInfo *info, const QByteArray &function)
+{
+ HREFTYPE usertype = tdesc.hreftype;
+ if (tdesc.vt != VT_USERDEFINED)
+ return 0;
+
+ QByteArray typeName;
+ ITypeInfo *usertypeinfo = 0;
+ info->GetRefTypeInfo(usertype, &usertypeinfo);
+ if (usertypeinfo) {
+ ITypeLib *usertypelib = 0;
+ UINT index;
+ usertypeinfo->GetContainingTypeLib(&usertypelib, &index);
+ if (usertypelib) {
+ // get type library name
+ BSTR typelibname = 0;
+ usertypelib->GetDocumentation(-1, &typelibname, 0, 0, 0);
+ QByteArray typeLibName = QString::fromUtf16((const ushort *)typelibname).toLatin1();
+ SysFreeString(typelibname);
+
+ // get type name
+ BSTR usertypename = 0;
+ usertypelib->GetDocumentation(index, &usertypename, 0, 0, 0);
+ QByteArray userTypeName = QString::fromUtf16((const ushort *)usertypename).toLatin1();
+ SysFreeString(usertypename);
+
+ if (hasEnum(userTypeName)) // known enum?
+ typeName = userTypeName;
+ else if (userTypeName == "OLE_COLOR" || userTypeName == "VB_OLE_COLOR")
+ typeName = "QColor";
+ else if (userTypeName == "IFontDisp" || userTypeName == "IFontDisp*" || userTypeName == "IFont" || userTypeName == "IFont*")
+ typeName = "QFont";
+ else if (userTypeName == "Picture" || userTypeName == "Picture*")
+ typeName = "QPixmap";
+
+ if (typeName.isEmpty()) {
+ TYPEATTR *typeattr = 0;
+ usertypeinfo->GetTypeAttr(&typeattr);
+ if (typeattr) {
+ switch(typeattr->typekind) {
+ case TKIND_ALIAS:
+ userTypeName = guessTypes(typeattr->tdescAlias, usertypeinfo, function);
+ break;
+ case TKIND_DISPATCH:
+ case TKIND_COCLASS:
+ if (qax_dispatchEqualsIDispatch) {
+ userTypeName = "IDispatch";
+ } else {
+ if (typeLibName != current_typelib)
+ userTypeName = typeLibName + "::" + userTypeName;
+ if (!qax_qualified_usertypes.contains(userTypeName))
+ qax_qualified_usertypes << userTypeName;
+ }
+ break;
+ case TKIND_ENUM:
+ if (typeLibName != current_typelib)
+ userTypeName = typeLibName + "::" + userTypeName;
+ if (!qax_qualified_usertypes.contains("enum " + userTypeName))
+ qax_qualified_usertypes << "enum " + userTypeName;
+ break;
+ case TKIND_INTERFACE:
+ if (typeLibName != current_typelib)
+ userTypeName = typeLibName + "::" + userTypeName;
+ if (!qax_qualified_usertypes.contains(userTypeName))
+ qax_qualified_usertypes << userTypeName;
+ break;
+ case TKIND_RECORD:
+ if (!qax_qualified_usertypes.contains("struct " + userTypeName))
+ qax_qualified_usertypes << "struct "+ userTypeName;
+ break;
+ default:
+ break;
+ }
+ }
+
+ usertypeinfo->ReleaseTypeAttr(typeattr);
+ typeName = userTypeName;
+ }
+ usertypelib->Release();
+ }
+ usertypeinfo->Release();
+ }
+
+ return typeName;
+}
+
+#define VT_UNHANDLED(x) case VT_##x: qWarning("QAxBase: Unhandled type %s", #x); str = #x; break;
+
+QByteArray MetaObjectGenerator::guessTypes(const TYPEDESC &tdesc, ITypeInfo *info, const QByteArray &function)
+{
+ QByteArray str;
+ switch (tdesc.vt) {
+ case VT_EMPTY:
+ case VT_VOID:
+ break;
+ case VT_LPWSTR:
+ str = "wchar_t *";
+ break;
+ case VT_BSTR:
+ str = "QString";
+ break;
+ case VT_BOOL:
+ str = "bool";
+ break;
+ case VT_I1:
+ str = "char";
+ break;
+ case VT_I2:
+ str = "short";
+ break;
+ case VT_I4:
+ case VT_INT:
+ str = "int";
+ break;
+ case VT_I8:
+ str = "qlonglong";
+ break;
+ case VT_UI1:
+ case VT_UI2:
+ case VT_UI4:
+ case VT_UINT:
+ str = "uint";
+ break;
+ case VT_UI8:
+ str = "qulonglong";
+ break;
+ case VT_CY:
+ str = "qlonglong";
+ break;
+ case VT_R4:
+ str = "float";
+ break;
+ case VT_R8:
+ str = "double";
+ break;
+ case VT_DATE:
+ str = "QDateTime";
+ break;
+ case VT_DISPATCH:
+ str = "IDispatch*";
+ break;
+ case VT_VARIANT:
+ str = "QVariant";
+ break;
+ case VT_UNKNOWN:
+ str = "IUnknown*";
+ break;
+ case VT_HRESULT:
+ str = "HRESULT";
+ break;
+ case VT_PTR:
+ str = guessTypes(*tdesc.lptdesc, info, function);
+ switch(tdesc.lptdesc->vt) {
+ case VT_VOID:
+ str = "void*";
+ break;
+ case VT_VARIANT:
+ case VT_BSTR:
+ case VT_I1:
+ case VT_I2:
+ case VT_I4:
+ case VT_I8:
+ case VT_UI1:
+ case VT_UI2:
+ case VT_UI4:
+ case VT_UI8:
+ case VT_BOOL:
+ case VT_R4:
+ case VT_R8:
+ case VT_INT:
+ case VT_UINT:
+ case VT_CY:
+ str += "&";
+ break;
+ case VT_PTR:
+ if (str == "QFont" || str == "QPixmap") {
+ str += "&";
+ break;
+ } else if (str == "void*") {
+ str = "void **";
+ break;
+ }
+ // FALLTHROUGH
+ default:
+ if (str == "QColor")
+ str += "&";
+ else if (str == "QDateTime")
+ str += "&";
+ else if (str == "QVariantList")
+ str += "&";
+ else if (str == "QByteArray")
+ str += "&";
+ else if (str == "QStringList")
+ str += "&";
+ else if (!str.isEmpty() && hasEnum(str))
+ str += "&";
+ else if (!str.isEmpty() && str != "QFont" && str != "QPixmap" && str != "QVariant")
+ str += "*";
+ }
+ break;
+ case VT_SAFEARRAY:
+ switch(tdesc.lpadesc->tdescElem.vt) {
+ // some shortcuts, and generic support for lists of QVariant-supported types
+ case VT_UI1:
+ str = "QByteArray";
+ break;
+ case VT_BSTR:
+ str = "QStringList";
+ break;
+ case VT_VARIANT:
+ str = "QVariantList";
+ break;
+ default:
+ str = guessTypes(tdesc.lpadesc->tdescElem, info, function);
+ if (!str.isEmpty())
+ str = "QList<" + str + ">";
+ break;
+ }
+ break;
+ case VT_CARRAY:
+ str = guessTypes(tdesc.lpadesc->tdescElem, info, function);
+ if (!str.isEmpty()) {
+ for (int index = 0; index < tdesc.lpadesc->cDims; ++index)
+ str += "[" + QByteArray::number((int)tdesc.lpadesc->rgbounds[index].cElements) + "]";
+ }
+ break;
+ case VT_USERDEFINED:
+ str = usertypeToString(tdesc, info, function);
+ break;
+
+ VT_UNHANDLED(FILETIME);
+ VT_UNHANDLED(BLOB);
+ VT_UNHANDLED(ERROR);
+ VT_UNHANDLED(DECIMAL);
+ VT_UNHANDLED(LPSTR);
+ default:
+ break;
+ }
+
+ if (tdesc.vt & VT_BYREF)
+ str += "&";
+
+ str.replace("&*", "**");
+ return str;
+}
+
+void MetaObjectGenerator::readClassInfo()
+{
+ // Read class information
+ IProvideClassInfo *provideClassInfo = 0;
+ if (d)
+ d->ptr->QueryInterface(IID_IProvideClassInfo, (void**)&provideClassInfo);
+ if (provideClassInfo) {
+ provideClassInfo->GetClassInfo(&classInfo);
+ TYPEATTR *typeattr = 0;
+ if (classInfo)
+ classInfo->GetTypeAttr(&typeattr);
+
+ QString coClassID;
+ if (typeattr) {
+ QUuid clsid(typeattr->guid);
+ coClassID = clsid.toString().toUpper();
+#ifndef QAX_NO_CLASSINFO
+ // UUID
+ if (d->useClassInfo && !hasClassInfo("CoClass")) {
+ QString coClassIDstr = iidnames.value(QLatin1String("/CLSID/") + coClassID + QLatin1String("/Default"), coClassID).toString();
+ addClassInfo("CoClass", coClassIDstr.isEmpty() ? coClassID.toLatin1() : coClassIDstr.toLatin1());
+ QByteArray version = QByteArray::number(typeattr->wMajorVerNum) + "." + QByteArray::number(typeattr->wMinorVerNum);
+ if (version != "0.0")
+ addClassInfo("Version", version);
+ }
+#endif
+ classInfo->ReleaseTypeAttr(typeattr);
+ }
+ provideClassInfo->Release();
+ provideClassInfo = 0;
+
+ if (d->tryCache && !coClassID.isEmpty())
+ cacheKey = QString::fromLatin1("%1$%2$%3$%4").arg(coClassID)
+ .arg((int)d->useEventSink).arg((int)d->useClassInfo).arg((int)qax_dispatchEqualsIDispatch);
+ }
+
+ UINT index = 0;
+ if (disp && !dispInfo)
+ disp->GetTypeInfo(index, LOCALE_USER_DEFAULT, &dispInfo);
+
+ if (dispInfo && !typelib)
+ dispInfo->GetContainingTypeLib(&typelib, &index);
+
+ if (!typelib) {
+ QSettings controls(QLatin1String("HKEY_LOCAL_MACHINE\\Software"), QSettings::NativeFormat);
+ QString tlid = controls.value(QLatin1String("/Classes/CLSID/") + that->control() + QLatin1String("/TypeLib/.")).toString();
+ QString tlfile;
+ if (!tlid.isEmpty()) {
+ controls.beginGroup(QLatin1String("/Classes/TypeLib/") + tlid);
+ QStringList versions = controls.childGroups();
+ QStringList::Iterator vit = versions.begin();
+ while (tlfile.isEmpty() && vit != versions.end()) {
+ QString version = *vit;
+ ++vit;
+ tlfile = controls.value(QLatin1String("/") + version + QLatin1String("/0/win32/.")).toString();
+ }
+ controls.endGroup();
+ } else {
+ tlfile = controls.value(QLatin1String("/Classes/CLSID/") + that->control() + QLatin1String("/InprocServer32/.")).toString();
+ if (tlfile.isEmpty())
+ tlfile = controls.value(QLatin1String("/Classes/CLSID/") + that->control() + QLatin1String("/LocalServer32/.")).toString();
+ }
+ if (!tlfile.isEmpty()) {
+ LoadTypeLib((OLECHAR*)tlfile.utf16(), &typelib);
+ if (!typelib) {
+ tlfile = tlfile.left(tlfile.lastIndexOf(QLatin1Char('.'))) + QLatin1String(".tlb");
+ LoadTypeLib((OLECHAR*)tlfile.utf16(), &typelib);
+ }
+ if (!typelib) {
+ tlfile = tlfile.left(tlfile.lastIndexOf(QLatin1Char('.'))) + QLatin1String(".olb");
+ LoadTypeLib((OLECHAR*)tlfile.utf16(), &typelib);
+ }
+ }
+ }
+
+ if (!classInfo && typelib && that)
+ typelib->GetTypeInfoOfGuid(QUuid(that->control()), &classInfo);
+
+ if (classInfo && !dispInfo) {
+ TYPEATTR *classAttr;
+ classInfo->GetTypeAttr(&classAttr);
+ if (classAttr) {
+ for (int i = 0; i < classAttr->cImplTypes; ++i) {
+ int typeFlags = 0;
+ classInfo->GetImplTypeFlags(i, &typeFlags);
+ if (typeFlags & IMPLTYPEFLAG_FSOURCE)
+ continue;
+
+ HREFTYPE hrefType;
+ if (S_OK == classInfo->GetRefTypeOfImplType(i, &hrefType))
+ classInfo->GetRefTypeInfo(hrefType, &dispInfo);
+ if (dispInfo) {
+ TYPEATTR *ifaceAttr;
+ dispInfo->GetTypeAttr(&ifaceAttr);
+ WORD typekind = ifaceAttr->typekind;
+ dispInfo->ReleaseTypeAttr(ifaceAttr);
+
+ if (typekind & TKIND_DISPATCH) {
+ break;
+ } else {
+ dispInfo->Release();
+ dispInfo = 0;
+ }
+ }
+ }
+ classInfo->ReleaseTypeAttr(classAttr);
+ }
+ }
+
+ if (!d || !dispInfo || !cacheKey.isEmpty() || !d->tryCache)
+ return;
+
+ TYPEATTR *typeattr = 0;
+ dispInfo->GetTypeAttr(&typeattr);
+
+ QString interfaceID;
+ if (typeattr) {
+ QUuid iid(typeattr->guid);
+ interfaceID = iid.toString().toUpper();
+
+ dispInfo->ReleaseTypeAttr(typeattr);
+ // ### event interfaces!!
+ if (!interfaceID.isEmpty())
+ cacheKey = QString::fromLatin1("%1$%2$%3$%4").arg(interfaceID)
+ .arg((int)d->useEventSink).arg((int)d->useClassInfo).arg((int)qax_dispatchEqualsIDispatch);
+ }
+}
+
+void MetaObjectGenerator::readEnumInfo()
+{
+ if (!typelib)
+ return;
+
+ QUuid libUuid;
+
+ if (d && d->tryCache) {
+ TLIBATTR *libAttr = 0;
+ typelib->GetLibAttr(&libAttr);
+ if (libAttr) {
+ libUuid = QUuid(libAttr->guid);
+ typelib->ReleaseTLibAttr(libAttr);
+ enum_list = enum_cache.value(libUuid);
+ if (!enum_list.isEmpty())
+ return;
+ }
+ }
+
+ int valueindex = 0;
+ QSet<QString> clashCheck;
+ int clashIndex = 0;
+
+ int enum_serial = 0;
+ UINT index = typelib->GetTypeInfoCount();
+ for (UINT i = 0; i < index; ++i) {
+ TYPEKIND typekind;
+ typelib->GetTypeInfoType(i, &typekind);
+ if (typekind == TKIND_ENUM) {
+ // Get the type information for the enum
+ ITypeInfo *enuminfo = 0;
+ typelib->GetTypeInfo(i, &enuminfo);
+ if (!enuminfo)
+ continue;
+
+ // Get the name of the enumeration
+ BSTR enumname;
+ QByteArray enumName;
+ if (typelib->GetDocumentation(i, &enumname, 0, 0, 0) == S_OK) {
+ enumName = QString::fromUtf16((const ushort *)enumname).toLatin1();
+ SysFreeString(enumname);
+ } else {
+ enumName = "enum" + QByteArray::number(++enum_serial);
+ }
+
+ // Get the attributes of the enum type
+ TYPEATTR *typeattr = 0;
+ enuminfo->GetTypeAttr(&typeattr);
+ if (typeattr) {
+ // Get all values of the enumeration
+ for (UINT vd = 0; vd < (UINT)typeattr->cVars; ++vd) {
+ VARDESC *vardesc = 0;
+ enuminfo->GetVarDesc(vd, &vardesc);
+ if (vardesc && vardesc->varkind == VAR_CONST) {
+ int value = vardesc->lpvarValue->lVal;
+ int memid = vardesc->memid;
+ // Get the name of the value
+ BSTR valuename;
+ QByteArray valueName;
+ UINT maxNamesOut;
+ enuminfo->GetNames(memid, &valuename, 1, &maxNamesOut);
+ if (maxNamesOut) {
+ valueName = QString::fromUtf16((const ushort *)valuename).toLatin1();
+ SysFreeString(valuename);
+ } else {
+ valueName = "value" + QByteArray::number(valueindex++);
+ }
+
+ if (clashCheck.contains(QString::fromLatin1(valueName)))
+ valueName += QByteArray::number(++clashIndex);
+
+ clashCheck.insert(QString::fromLatin1(valueName));
+ addEnumValue(enumName, valueName, value);
+ }
+ enuminfo->ReleaseVarDesc(vardesc);
+ }
+ }
+ enuminfo->ReleaseTypeAttr(typeattr);
+ enuminfo->Release();
+ }
+ }
+
+ if (!libUuid.isNull())
+ enum_cache.insert(libUuid, enum_list);
+}
+
+void MetaObjectGenerator::addChangedSignal(const QByteArray &function, const QByteArray &type, int memid)
+{
+ QAxEventSink *eventSink = 0;
+ if (d) {
+ eventSink = d->eventSink.value(iid_propNotifySink);
+ if (!eventSink && d->useEventSink) {
+ eventSink = new QAxEventSink(that);
+ d->eventSink.insert(iid_propNotifySink, eventSink);
+ }
+ }
+ // generate changed signal
+ QByteArray signalName(function);
+ signalName += "Changed";
+ QByteArray signalProto = signalName + "(" + replaceType(type) + ")";
+ if (!hasSignal(signalProto))
+ addSignal(signalProto, function);
+ if (eventSink)
+ eventSink->addProperty(memid, function, signalProto);
+}
+
+void MetaObjectGenerator::addSetterSlot(const QByteArray &property)
+{
+ QByteArray set;
+ QByteArray prototype(property);
+ if (isupper(prototype.at(0))) {
+ set = "Set";
+ } else {
+ set = "set";
+ prototype[0] = toupper(prototype[0]);
+ }
+ prototype = set + prototype + "(" + propertyType(property) + ")";
+ if (!hasSlot(prototype))
+ addSlot(0, prototype, property);
+}
+
+QByteArray MetaObjectGenerator::createPrototype(FUNCDESC *funcdesc, ITypeInfo *typeinfo, const QList<QByteArray> &names,
+ QByteArray &type, QList<QByteArray> &parameters)
+{
+ QByteArray prototype;
+ QByteArray function(names.at(0));
+ const QByteArray hresult("HRESULT");
+ // get function prototype
+ type = guessTypes(funcdesc->elemdescFunc.tdesc, typeinfo, function);
+ if ((type.isEmpty() || type == hresult) && funcdesc->invkind == INVOKE_PROPERTYPUT && funcdesc->lprgelemdescParam) {
+ type = guessTypes(funcdesc->lprgelemdescParam->tdesc, typeinfo, function);
+ }
+
+ prototype = function + "(";
+ if (funcdesc->invkind == INVOKE_FUNC && type == hresult)
+ type = 0;
+
+ int p;
+ for (p = 1; p < names.count(); ++p) {
+ // parameter
+ QByteArray paramName = names.at(p);
+ bool optional = p > (funcdesc->cParams - funcdesc->cParamsOpt);
+ TYPEDESC tdesc = funcdesc->lprgelemdescParam[p-1].tdesc;
+ PARAMDESC pdesc = funcdesc->lprgelemdescParam[p-1].paramdesc;
+
+ QByteArray ptype = guessTypes(tdesc, typeinfo, function);
+ if (pdesc.wParamFlags & PARAMFLAG_FRETVAL) {
+ if (ptype.endsWith("&")) {
+ ptype.truncate(ptype.length() - 1);
+ } else if (ptype.endsWith("**")) {
+ ptype.truncate(ptype.length() - 1);
+ }
+ type = ptype;
+ } else {
+ prototype += ptype;
+ if (pdesc.wParamFlags & PARAMFLAG_FOUT && !ptype.endsWith("&") && !ptype.endsWith("**"))
+ prototype += "&";
+ if (optional || pdesc.wParamFlags & PARAMFLAG_FOPT)
+ paramName += "=0";
+ else if (pdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) {
+ // ### get the value from pdesc.pparamdescex
+ paramName += "=0";
+ }
+ parameters << paramName;
+ }
+ if (p < funcdesc->cParams && !(pdesc.wParamFlags & PARAMFLAG_FRETVAL))
+ prototype += ",";
+ }
+
+ if (!prototype.isEmpty()) {
+ if (prototype.right(1) == ",") {
+ if (funcdesc->invkind == INVOKE_PROPERTYPUT && p == funcdesc->cParams) {
+ TYPEDESC tdesc = funcdesc->lprgelemdescParam[p-1].tdesc;
+ QByteArray ptype = guessTypes(tdesc, typeinfo, function);
+ prototype += ptype;
+ prototype += ")";
+ parameters << "rhs";
+ } else {
+ prototype[prototype.length()-1] = ')';
+ }
+ } else {
+ prototype += ")";
+ }
+ }
+
+ return prototype;
+}
+
+void MetaObjectGenerator::readFuncsInfo(ITypeInfo *typeinfo, ushort nFuncs)
+{
+ if (!nFuncs) {
+ TYPEATTR *typeattr = 0;
+ typeinfo->GetTypeAttr(&typeattr);
+ if (typeattr) {
+ nFuncs = typeattr->cFuncs;
+ typeinfo->ReleaseTypeAttr(typeattr);
+ }
+ }
+
+ // get information about all functions
+ for (ushort fd = 0; fd < nFuncs ; ++fd) {
+ FUNCDESC *funcdesc = 0;
+ typeinfo->GetFuncDesc(fd, &funcdesc);
+ if (!funcdesc)
+ break;
+
+ QByteArray function;
+ QByteArray type;
+ QByteArray prototype;
+ QList<QByteArray> parameters;
+
+ // parse function description
+ BSTR bstrNames[256];
+ UINT maxNames = 255;
+ UINT maxNamesOut;
+ typeinfo->GetNames(funcdesc->memid, (BSTR*)&bstrNames, maxNames, &maxNamesOut);
+ QList<QByteArray> names;
+ int p;
+ for (p = 0; p < (int)maxNamesOut; ++p) {
+ names << QString::fromUtf16((const ushort *)bstrNames[p]).toLatin1();
+ SysFreeString(bstrNames[p]);
+ }
+
+ // function name
+ function = names.at(0);
+ if ((maxNamesOut == 3 && function == "QueryInterface") ||
+ (maxNamesOut == 1 && function == "AddRef") ||
+ (maxNamesOut == 1 && function == "Release") ||
+ (maxNamesOut == 9 && function == "Invoke") ||
+ (maxNamesOut == 6 && function == "GetIDsOfNames") ||
+ (maxNamesOut == 2 && function == "GetTypeInfoCount") ||
+ (maxNamesOut == 4 && function == "GetTypeInfo")) {
+ typeinfo->ReleaseFuncDesc(funcdesc);
+ continue;
+ }
+
+ prototype = createPrototype(/*in*/ funcdesc, typeinfo, names, /*out*/type, parameters);
+
+ // get type of function
+ switch(funcdesc->invkind) {
+ case INVOKE_PROPERTYGET: // property
+ case INVOKE_PROPERTYPUT:
+ if (funcdesc->cParams - funcdesc->cParamsOpt <= 1) {
+ bool dontBreak = false;
+ // getter with non-default-parameters -> fall through to function handling
+ if (funcdesc->invkind == INVOKE_PROPERTYGET && parameters.count() && funcdesc->cParams - funcdesc->cParamsOpt) {
+ dontBreak = true;
+ } else {
+ uint flags = Readable;
+ if (funcdesc->invkind != INVOKE_PROPERTYGET)
+ flags |= Writable;
+ if (!(funcdesc->wFuncFlags & (FUNCFLAG_FNONBROWSABLE | FUNCFLAG_FHIDDEN)))
+ flags |= Designable;
+ if (!(funcdesc->wFuncFlags & FUNCFLAG_FRESTRICTED))
+ flags |= Scriptable;
+ if (funcdesc->wFuncFlags & FUNCFLAG_FREQUESTEDIT)
+ flags |= RequestingEdit;
+ if (hasEnum(type))
+ flags |= EnumOrFlag;
+
+ if (funcdesc->wFuncFlags & FUNCFLAG_FBINDABLE && funcdesc->invkind == INVOKE_PROPERTYGET) {
+ addChangedSignal(function, type, funcdesc->memid);
+ flags |= Bindable;
+ }
+ // Don't generate code for properties without type
+ if (type.isEmpty())
+ break;
+ addProperty(type, function, flags);
+
+ // more parameters -> function handling
+ if (funcdesc->invkind == INVOKE_PROPERTYGET && funcdesc->cParams)
+ dontBreak = true;
+ }
+
+ if (!funcdesc->cParams) {
+ // don't generate slots for incomplete properties
+ if (type.isEmpty())
+ break;
+
+ // Done for getters
+ if (funcdesc->invkind == INVOKE_PROPERTYGET)
+ break;
+
+ // generate setter slot
+ if (funcdesc->invkind == INVOKE_PROPERTYPUT && hasProperty(function)) {
+ addSetterSlot(function);
+ break;
+ }
+ } else if (funcdesc->invkind == INVOKE_PROPERTYPUT && hasProperty(function)) {
+ addSetterSlot(function);
+ // more parameters -> function handling
+ if (funcdesc->cParams > 1)
+ dontBreak = true;
+ }
+ if (!dontBreak)
+ break;
+ }
+ if (funcdesc->invkind == INVOKE_PROPERTYPUT) {
+ QByteArray set;
+ if (isupper(prototype.at(0))) {
+ set = "Set";
+ } else {
+ set = "set";
+ prototype[0] = toupper(prototype[0]);
+ }
+
+ prototype = set + prototype;
+ }
+ // FALL THROUGH to support multi-variat properties
+ case INVOKE_FUNC: // method
+ {
+ bool cloned = false;
+ bool defargs;
+ do {
+ QByteArray pnames;
+ for (p = 0; p < parameters.count(); ++p) {
+ pnames += parameters.at(p);
+ if (p < parameters.count() - 1)
+ pnames += ',';
+ }
+ defargs = pnames.contains("=0");
+ int flags = QMetaMethod::Public;
+ if (cloned)
+ flags |= QMetaMethod::Cloned << 4;
+ cloned |= defargs;
+ addSlot(type, prototype, pnames.replace("=0", ""), flags);
+
+ if (defargs) {
+ parameters.takeLast();
+ int lastParam = prototype.lastIndexOf(",");
+ if (lastParam == -1)
+ lastParam = prototype.indexOf("(") + 1;
+ prototype.truncate(lastParam);
+ prototype += ")";
+ }
+ } while (defargs);
+ }
+ break;
+
+ default:
+ break;
+ }
+#if 0 // documentation in metaobject would be cool?
+ // get function documentation
+ BSTR bstrDocu;
+ info->GetDocumentation(funcdesc->memid, 0, &bstrDocu, 0, 0);
+ QString strDocu = QString::fromUtf16((const ushort*)bstrDocu);
+ SysFreeString(bstrDocu);
+ if (!!strDocu)
+ desc += "[" + strDocu + "]";
+ desc += "\n";
+#endif
+ typeinfo->ReleaseFuncDesc(funcdesc);
+ }
+}
+
+void MetaObjectGenerator::readVarsInfo(ITypeInfo *typeinfo, ushort nVars)
+{
+ if (!nVars) {
+ TYPEATTR *typeattr = 0;
+ typeinfo->GetTypeAttr(&typeattr);
+ if (typeattr) {
+ nVars = typeattr->cVars;
+ typeinfo->ReleaseTypeAttr(typeattr);
+ }
+ }
+
+ // get information about all variables
+ for (ushort vd = 0; vd < nVars; ++vd) {
+ VARDESC *vardesc;
+ typeinfo->GetVarDesc(vd, &vardesc);
+ if (!vardesc)
+ break;
+
+ // no use if it's not a dispatched variable
+ if (vardesc->varkind != VAR_DISPATCH) {
+ typeinfo->ReleaseVarDesc(vardesc);
+ continue;
+ }
+
+ // get variable name
+ BSTR bstrName;
+ UINT maxNames = 1;
+ UINT maxNamesOut;
+ typeinfo->GetNames(vardesc->memid, &bstrName, maxNames, &maxNamesOut);
+ if (maxNamesOut != 1 || !bstrName) {
+ typeinfo->ReleaseVarDesc(vardesc);
+ continue;
+ }
+ QByteArray variableType;
+ QByteArray variableName;
+ uint flags = 0;
+
+ variableName = QString::fromUtf16((const ushort *)bstrName).toLatin1();
+ SysFreeString(bstrName);
+
+ // get variable type
+ TYPEDESC typedesc = vardesc->elemdescVar.tdesc;
+ variableType = guessTypes(typedesc, typeinfo, variableName);
+
+ // generate meta property
+ if (!hasProperty(variableName)) {
+ flags = Readable;
+ if (!(vardesc->wVarFlags & VARFLAG_FREADONLY))
+ flags |= Writable;
+ if (!(vardesc->wVarFlags & (VARFLAG_FNONBROWSABLE | VARFLAG_FHIDDEN)))
+ flags |= Designable;
+ if (!(vardesc->wVarFlags & VARFLAG_FRESTRICTED))
+ flags |= Scriptable;
+ if (vardesc->wVarFlags & VARFLAG_FREQUESTEDIT)
+ flags |= RequestingEdit;
+ if (hasEnum(variableType))
+ flags |= EnumOrFlag;
+
+ if (vardesc->wVarFlags & VARFLAG_FBINDABLE) {
+ addChangedSignal(variableName, variableType, vardesc->memid);
+ flags |= Bindable;
+ }
+ addProperty(variableType, variableName, flags);
+ }
+
+ // generate a set slot
+ if (!(vardesc->wVarFlags & VARFLAG_FREADONLY))
+ addSetterSlot(variableName);
+
+#if 0 // documentation in metaobject would be cool?
+ // get function documentation
+ BSTR bstrDocu;
+ info->GetDocumentation(vardesc->memid, 0, &bstrDocu, 0, 0);
+ QString strDocu = QString::fromUtf16((const ushort*)bstrDocu);
+ SysFreeString(bstrDocu);
+ if (!!strDocu)
+ desc += "[" + strDocu + "]";
+ desc += "\n";
+#endif
+ typeinfo->ReleaseVarDesc(vardesc);
+ }
+}
+
+void MetaObjectGenerator::readInterfaceInfo()
+{
+ ITypeInfo *typeinfo = dispInfo;
+ if (!typeinfo)
+ return;
+ typeinfo->AddRef();
+ int interface_serial = 0;
+ while (typeinfo) {
+ ushort nFuncs = 0;
+ ushort nVars = 0;
+ ushort nImpl = 0;
+ // get information about type
+ TYPEATTR *typeattr;
+ typeinfo->GetTypeAttr(&typeattr);
+ bool interesting = true;
+ if (typeattr) {
+ // get number of functions, variables, and implemented interfaces
+ nFuncs = typeattr->cFuncs;
+ nVars = typeattr->cVars;
+ nImpl = typeattr->cImplTypes;
+
+ if ((typeattr->typekind == TKIND_DISPATCH || typeattr->typekind == TKIND_INTERFACE) &&
+ (typeattr->guid != IID_IDispatch && typeattr->guid != IID_IUnknown)) {
+#ifndef QAX_NO_CLASSINFO
+ if (d && d->useClassInfo) {
+ // UUID
+ QUuid uuid(typeattr->guid);
+ QString uuidstr = uuid.toString().toUpper();
+ uuidstr = iidnames.value(QLatin1String("/Interface/") + uuidstr + QLatin1String("/Default"), uuidstr).toString();
+ addClassInfo("Interface " + QByteArray::number(++interface_serial), uuidstr.toLatin1());
+ }
+#endif
+ typeinfo->ReleaseTypeAttr(typeattr);
+ } else {
+ interesting = false;
+ typeinfo->ReleaseTypeAttr(typeattr);
+ }
+ }
+
+ if (interesting) {
+ readFuncsInfo(typeinfo, nFuncs);
+ readVarsInfo(typeinfo, nVars);
+ }
+
+ if (!nImpl) {
+ typeinfo->Release();
+ typeinfo = 0;
+ break;
+ }
+
+ // go up one base class
+ HREFTYPE pRefType;
+ typeinfo->GetRefTypeOfImplType(0, &pRefType);
+ ITypeInfo *baseInfo = 0;
+ typeinfo->GetRefTypeInfo(pRefType, &baseInfo);
+ typeinfo->Release();
+ if (typeinfo == baseInfo) { // IUnknown inherits IUnknown ???
+ baseInfo->Release();
+ typeinfo = 0;
+ break;
+ }
+ typeinfo = baseInfo;
+ }
+}
+
+void MetaObjectGenerator::readEventInterface(ITypeInfo *eventinfo, IConnectionPoint *cpoint)
+{
+ TYPEATTR *eventattr;
+ eventinfo->GetTypeAttr(&eventattr);
+ if (!eventattr)
+ return;
+ if (eventattr->typekind != TKIND_DISPATCH) {
+ eventinfo->ReleaseTypeAttr(eventattr);
+ return;
+ }
+
+ QAxEventSink *eventSink = 0;
+ if (d) {
+ IID conniid;
+ cpoint->GetConnectionInterface(&conniid);
+ eventSink = d->eventSink.value(QUuid(conniid));
+ if (!eventSink) {
+ eventSink = new QAxEventSink(that);
+ d->eventSink.insert(QUuid(conniid), eventSink);
+ eventSink->advise(cpoint, conniid);
+ }
+ }
+
+ // get information about all event functions
+ for (UINT fd = 0; fd < (UINT)eventattr->cFuncs; ++fd) {
+ FUNCDESC *funcdesc;
+ eventinfo->GetFuncDesc(fd, &funcdesc);
+ if (!funcdesc)
+ break;
+ if (funcdesc->invkind != INVOKE_FUNC ||
+ funcdesc->funckind != FUNC_DISPATCH) {
+ eventinfo->ReleaseTypeAttr(eventattr);
+ eventinfo->ReleaseFuncDesc(funcdesc);
+ continue;
+ }
+
+ QByteArray function;
+ QByteArray prototype;
+ QList<QByteArray> parameters;
+
+ // parse event function description
+ BSTR bstrNames[256];
+ UINT maxNames = 255;
+ UINT maxNamesOut;
+ eventinfo->GetNames(funcdesc->memid, (BSTR*)&bstrNames, maxNames, &maxNamesOut);
+ QList<QByteArray> names;
+ int p;
+ for (p = 0; p < (int)maxNamesOut; ++p) {
+ names << QString::fromUtf16((const ushort *)bstrNames[p]).toLatin1();
+ SysFreeString(bstrNames[p]);
+ }
+
+ // get event function prototype
+ function = names.at(0);
+ QByteArray type; // dummy - we don't care about return values for signals
+ prototype = createPrototype(/*in*/ funcdesc, eventinfo, names, /*out*/type, parameters);
+ if (!hasSignal(prototype)) {
+ QByteArray pnames;
+ for (p = 0; p < parameters.count(); ++p) {
+ pnames += parameters.at(p);
+ if (p < parameters.count() - 1)
+ pnames += ',';
+ }
+ addSignal(prototype, pnames);
+ }
+ if (eventSink)
+ eventSink->addSignal(funcdesc->memid, prototype);
+
+#if 0 // documentation in metaobject would be cool?
+ // get function documentation
+ BSTR bstrDocu;
+ eventinfo->GetDocumentation(funcdesc->memid, 0, &bstrDocu, 0, 0);
+ QString strDocu = QString::fromUtf16((const ushort*)bstrDocu);
+ SysFreeString(bstrDocu);
+ if (!!strDocu)
+ desc += "[" + strDocu + "]";
+ desc += "\n";
+#endif
+ eventinfo->ReleaseFuncDesc(funcdesc);
+ }
+ eventinfo->ReleaseTypeAttr(eventattr);
+}
+
+void MetaObjectGenerator::readEventInfo()
+{
+ int event_serial = 0;
+ IConnectionPointContainer *cpoints = 0;
+ if (d && d->useEventSink)
+ d->ptr->QueryInterface(IID_IConnectionPointContainer, (void**)&cpoints);
+ if (cpoints) {
+ // Get connection point enumerator
+ IEnumConnectionPoints *epoints = 0;
+ cpoints->EnumConnectionPoints(&epoints);
+ if (epoints) {
+ ULONG c = 1;
+ IConnectionPoint *cpoint = 0;
+ epoints->Reset();
+ QList<QUuid> cpointlist;
+ do {
+ if (cpoint) cpoint->Release();
+ cpoint = 0;
+ HRESULT hr = epoints->Next(c, &cpoint, &c);
+ if (!c || hr != S_OK)
+ break;
+
+ IID conniid;
+ cpoint->GetConnectionInterface(&conniid);
+ // workaround for typelibrary bug of Word.Application
+ QUuid connuuid(conniid);
+ if (cpointlist.contains(connuuid))
+ break;
+
+#ifndef QAX_NO_CLASSINFO
+ if (d->useClassInfo) {
+ QString uuidstr = connuuid.toString().toUpper();
+ uuidstr = iidnames.value(QLatin1String("/Interface/") + uuidstr + QLatin1String("/Default"), uuidstr).toString();
+ addClassInfo("Event Interface " + QByteArray::number(++event_serial), uuidstr.toLatin1());
+ }
+#endif
+
+ // get information about type
+ if (conniid == IID_IPropertyNotifySink) {
+ // test whether property notify sink has been created already, and advise on it
+ QAxEventSink *eventSink = d->eventSink.value(iid_propNotifySink);
+ if (eventSink)
+ eventSink->advise(cpoint, conniid);
+ continue;
+ }
+
+ ITypeInfo *eventinfo = 0;
+ if (typelib)
+ typelib->GetTypeInfoOfGuid(conniid, &eventinfo);
+
+ if (eventinfo) {
+ // avoid recursion (see workaround above)
+ cpointlist.append(connuuid);
+
+ readEventInterface(eventinfo, cpoint);
+ eventinfo->Release();
+ }
+ } while (c);
+ if (cpoint) cpoint->Release();
+ epoints->Release();
+ } else if (classInfo) { // no enumeration - search source interfaces and ask for those
+ TYPEATTR *typeattr = 0;
+ classInfo->GetTypeAttr(&typeattr);
+ if (typeattr) {
+ for (int i = 0; i < typeattr->cImplTypes; ++i) {
+ int flags = 0;
+ classInfo->GetImplTypeFlags(i, &flags);
+ if (!(flags & IMPLTYPEFLAG_FSOURCE))
+ continue;
+ HREFTYPE reference;
+ if (S_OK != classInfo->GetRefTypeOfImplType(i, &reference))
+ continue;
+ ITypeInfo *eventInfo = 0;
+ classInfo->GetRefTypeInfo(reference, &eventInfo);
+ if (!eventInfo)
+ continue;
+ TYPEATTR *eventattr = 0;
+ eventInfo->GetTypeAttr(&eventattr);
+ if (eventattr) {
+ IConnectionPoint *cpoint = 0;
+ cpoints->FindConnectionPoint(eventattr->guid, &cpoint);
+ if (cpoint) {
+ if (eventattr->guid == IID_IPropertyNotifySink) {
+ // test whether property notify sink has been created already, and advise on it
+ QAxEventSink *eventSink = d->eventSink.value(iid_propNotifySink);
+ if (eventSink)
+ eventSink->advise(cpoint, eventattr->guid);
+ continue;
+ }
+
+ readEventInterface(eventInfo, cpoint);
+ cpoint->Release();
+ }
+ eventInfo->ReleaseTypeAttr(eventattr);
+ }
+ eventInfo->Release();
+ }
+ classInfo->ReleaseTypeAttr(typeattr);
+ }
+ }
+ cpoints->Release();
+ }
+}
+
+QMetaObject *MetaObjectGenerator::tryCache()
+{
+ if (!cacheKey.isEmpty()) {
+ d->metaobj = mo_cache.value(cacheKey);
+ if (d->metaobj) {
+ d->cachedMetaObject = true;
+
+ IConnectionPointContainer *cpoints = 0;
+ d->ptr->QueryInterface(IID_IConnectionPointContainer, (void**)&cpoints);
+ if (cpoints) {
+ QList<QUuid>::ConstIterator it = d->metaobj->connectionInterfaces.begin();
+ while (it != d->metaobj->connectionInterfaces.end()) {
+ QUuid iid = *it;
+ ++it;
+
+ IConnectionPoint *cpoint = 0;
+ cpoints->FindConnectionPoint(iid, &cpoint);
+ if (cpoint) {
+ QAxEventSink *sink = new QAxEventSink(that);
+ sink->advise(cpoint, iid);
+ d->eventSink.insert(iid, sink);
+ sink->sigs = d->metaobj->sigs.value(iid);
+ sink->props = d->metaobj->props.value(iid);
+ sink->propsigs = d->metaobj->propsigs.value(iid);
+ cpoint->Release();
+ }
+ }
+ cpoints->Release();
+ }
+
+ return d->metaobj;
+ }
+ }
+ return 0;
+}
+
+QMetaObject *MetaObjectGenerator::metaObject(const QMetaObject *parentObject, const QByteArray &className)
+{
+ if (that) {
+ readClassInfo();
+ if (typelib) {
+ BSTR bstr;
+ typelib->GetDocumentation(-1, &bstr, 0, 0, 0);
+ current_typelib = QString::fromUtf16((const ushort *)bstr).toLatin1();
+ SysFreeString(bstr);
+ }
+ if (d->tryCache && tryCache())
+ return d->metaobj;
+ readEnumInfo();
+ readInterfaceInfo();
+ readEventInfo();
+ }
+
+ current_typelib = QByteArray();
+
+#ifndef QAX_NO_CLASSINFO
+ if (!debugInfo.isEmpty() && d->useClassInfo)
+ addClassInfo("debugInfo", debugInfo);
+#endif
+
+ QAxMetaObject *metaobj = new QAxMetaObject;
+
+ // revision + classname + table + zero terminator
+ uint int_data_size = 1+1+2+2+2+2+1;
+
+ int_data_size += classinfo_list.count() * 2;
+ int_data_size += signal_list.count() * 5;
+ int_data_size += slot_list.count() * 5;
+ int_data_size += property_list.count() * 3;
+ int_data_size += enum_list.count() * 4;
+ for (QMap<QByteArray, QList<QPair<QByteArray, int> > >::ConstIterator it = enum_list.begin();
+ it != enum_list.end(); ++it) {
+ int_data_size += (*it).count() * 2;
+ }
+
+ uint *int_data = new uint[int_data_size];
+ int_data[0] = 1; // revision number
+ int_data[1] = 0; // classname index
+ int_data[2] = classinfo_list.count(); // num_classinfo
+ int_data[3] = 10; // idx_classinfo
+ int_data[4] = signal_list.count() + slot_list.count(); // num_methods
+ int_data[5] = int_data[3] + int_data[2] * 2; // idx_signals
+ int_data[6] = property_list.count(); // num_properties
+ int_data[7] = int_data[5] + int_data[4] * 5; // idx_properties
+ int_data[8] = enum_list.count(); // num_enums
+ int_data[9] = int_data[7] + int_data[6] * 3; // idx_enums
+ int_data[int_data_size - 1] = 0; // eod;
+
+ char null('\0');
+ // data + zero-terminator
+ QByteArray stringdata = that ? QByteArray(that->className()) : className;
+ stringdata += null;
+ stringdata.reserve(8192);
+
+ uint offset = int_data[3]; //idx_classinfo
+
+ // each class info in form key\0value\0
+ for (QMap<QByteArray, QByteArray>::ConstIterator it = classinfo_list.begin(); it != classinfo_list.end(); ++it) {
+ QByteArray key(it.key());
+ QByteArray value(it.value());
+ int_data[offset++] = stringdata.length();
+ stringdata += key;
+ stringdata += null;
+ int_data[offset++] = stringdata.length();
+ stringdata += value;
+ stringdata += null;
+ }
+ Q_ASSERT(offset == int_data[5]);
+
+ // each signal in form prototype\0parameters\0type\0tag\0
+ for (QMap<QByteArray, Method>::ConstIterator it = signal_list.begin(); it != signal_list.end(); ++it) {
+ QByteArray prototype(QMetaObject::normalizedSignature(it.key()));
+ QByteArray type(it.value().type);
+ QByteArray parameters(it.value().parameters);
+ if (!it.value().realPrototype.isEmpty())
+ metaobj->realPrototype.insert(prototype, it.value().realPrototype);
+ QByteArray tag;
+ int flags = it.value().flags;
+
+ int_data[offset++] = stringdata.length();
+ stringdata += prototype;
+ stringdata += null;
+ int_data[offset++] = stringdata.length();
+ stringdata += parameters;
+ stringdata += null;
+ int_data[offset++] = stringdata.length();
+ stringdata += type;
+ stringdata += null;
+ int_data[offset++] = stringdata.length();
+ stringdata += tag;
+ stringdata += null;
+ int_data[offset++] = flags;
+ }
+
+ // each slot in form prototype\0parameters\0type\0tag\0
+ for (QMap<QByteArray, Method>::ConstIterator it = slot_list.begin(); it != slot_list.end(); ++it) {
+ QByteArray prototype(QMetaObject::normalizedSignature(it.key()));
+ QByteArray type(it.value().type);
+ QByteArray parameters(it.value().parameters);
+ if (!it.value().realPrototype.isEmpty())
+ metaobj->realPrototype.insert(prototype, it.value().realPrototype);
+ QByteArray tag;
+ int flags = it.value().flags;
+
+ int_data[offset++] = stringdata.length();
+ stringdata += prototype;
+ stringdata += null;
+ int_data[offset++] = stringdata.length();
+ stringdata += parameters;
+ stringdata += null;
+ int_data[offset++] = stringdata.length();
+ stringdata += type;
+ stringdata += null;
+ int_data[offset++] = stringdata.length();
+ stringdata += tag;
+ stringdata += null;
+ int_data[offset++] = flags;
+ }
+ Q_ASSERT(offset == int_data[7]);
+
+ // each property in form name\0type\0
+ for (QMap<QByteArray, Property>::ConstIterator it = property_list.begin(); it != property_list.end(); ++it) {
+ QByteArray name(it.key());
+ QByteArray type(it.value().type);
+ QByteArray realType(it.value().realType);
+ if (!realType.isEmpty() && realType != type)
+ metaobj->realPrototype.insert(name, realType);
+ uint flags = it.value().typeId;
+
+ int_data[offset++] = stringdata.length();
+ stringdata += name;
+ stringdata += null;
+ int_data[offset++] = stringdata.length();
+ stringdata += type;
+ stringdata += null;
+ int_data[offset++] = flags;
+ }
+ Q_ASSERT(offset == int_data[9]);
+
+ int value_offset = offset + enum_list.count() * 4;
+ // each enum in form name\0
+ for (QMap<QByteArray, QList<QPair<QByteArray, int> > >::ConstIterator it = enum_list.begin(); it != enum_list.end(); ++it) {
+ QByteArray name(it.key());
+ int flags = 0x0; // 0x1 for flag?
+ int count = it.value().count();
+
+ int_data[offset++] = stringdata.length();
+ stringdata += name;
+ stringdata += null;
+ int_data[offset++] = flags;
+ int_data[offset++] = count;
+ int_data[offset++] = value_offset;
+ value_offset += count * 2;
+ }
+ Q_ASSERT(offset == int_data[9] + enum_list.count() * 4);
+
+ // each enum value in form key\0
+ for (QMap<QByteArray, QList<QPair<QByteArray, int> > >::ConstIterator it = enum_list.begin(); it != enum_list.end(); ++it) {
+ for (QList<QPair<QByteArray,int> >::ConstIterator it2 = it.value().begin(); it2 != it.value().end(); ++it2) {
+ QByteArray key((*it2).first);
+ int value = (*it2).second;
+ int_data[offset++] = stringdata.length();
+ stringdata += key;
+ stringdata += null;
+ int_data[offset++] = value;
+ }
+ }
+ Q_ASSERT(offset == int_data_size-1);
+
+ char *string_data = new char[stringdata.length()];
+ memset(string_data, 0, sizeof(string_data));
+ memcpy(string_data, stringdata, stringdata.length());
+
+ // put the metaobject together
+ metaobj->d.data = int_data;
+ metaobj->d.extradata = 0;
+ metaobj->d.stringdata = string_data;
+ metaobj->d.superdata = parentObject;
+
+ if (d)
+ d->metaobj = metaobj;
+
+ if (!cacheKey.isEmpty()) {
+ mo_cache.insert(cacheKey, d->metaobj);
+ d->cachedMetaObject = true;
+ for (QHash<QUuid, QAxEventSink*>::Iterator it = d->eventSink.begin(); it != d->eventSink.end(); ++it) {
+ QAxEventSink *sink = it.value();
+ if (sink) {
+ QUuid ciid = sink->connectionInterface();
+
+ d->metaobj->connectionInterfaces.append(ciid);
+ d->metaobj->sigs.insert(ciid, sink->signalMap());
+ d->metaobj->props.insert(ciid, sink->propertyMap());
+ d->metaobj->propsigs.insert(ciid, sink->propSignalMap());
+ }
+ }
+ }
+
+ return metaobj;
+}
+
+static const uint qt_meta_data_QAxBase[] = {
+
+ // content:
+ 1, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 3, 10, // methods
+ 1, 25, // properties
+ 0, 0, // enums/sets
+
+ // signals: signature, parameters, type, tag, flags
+ 24, 9, 8, 8, 0x05,
+ 55, 50, 8, 8, 0x05,
+ 102, 80, 8, 8, 0x05,
+
+ // properties: name, type, flags
+ 149, 141, 0x0a095103,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_QAxBase[] = {
+ "QAxBase\0\0name,argc,argv\0signal(QString,int,void*)\0name\0"
+ "propertyChanged(QString)\0code,source,desc,help\0"
+ "exception(int,QString,QString,QString)\0QString\0control\0"
+};
+
+static QMetaObject qaxobject_staticMetaObject = {
+ &QObject::staticMetaObject, qt_meta_stringdata_QAxBase,
+ qt_meta_data_QAxBase, 0
+};
+static QMetaObject qaxwidget_staticMetaObject = {
+ &QWidget::staticMetaObject, qt_meta_stringdata_QAxBase,
+ qt_meta_data_QAxBase, 0
+};
+
+/*!
+ \internal
+
+ The metaobject is generated on the fly from the information
+ provided by the IDispatch and ITypeInfo interface implementations
+ in the COM object.
+*/
+const QMetaObject *QAxBase::metaObject() const
+{
+ if (d->metaobj)
+ return d->metaobj;
+ const QMetaObject* parentObject = parentMetaObject();
+
+ if (!d->ptr && !d->initialized) {
+ ((QAxBase*)this)->initialize(&d->ptr);
+ d->initialized = true;
+ }
+
+#ifndef QT_NO_THREAD
+ // only one thread at a time can generate meta objects
+ QMutexLocker locker(&cache_mutex);
+#endif
+
+ // return the default meta object if not yet initialized
+ if (!d->ptr || !d->useMetaObject) {
+ if (qObject()->isWidgetType())
+ return &qaxwidget_staticMetaObject;
+ return &qaxobject_staticMetaObject;
+ }
+ MetaObjectGenerator generator((QAxBase*)this, d);
+ return generator.metaObject(parentObject);
+}
+
+/*!
+ \internal
+
+ Connects to all event interfaces of the object.
+
+ Called by the subclasses' connectNotify() reimplementations, so
+ at this point the connection as actually been created already.
+*/
+void QAxBase::connectNotify()
+{
+ if (d->eventSink.count()) // already listening
+ return;
+
+ IEnumConnectionPoints *epoints = 0;
+ if (d->ptr && d->useEventSink) {
+ IConnectionPointContainer *cpoints = 0;
+ d->ptr->QueryInterface(IID_IConnectionPointContainer, (void**)&cpoints);
+ if (!cpoints)
+ return;
+
+ cpoints->EnumConnectionPoints(&epoints);
+ cpoints->Release();
+ }
+
+ if (!epoints)
+ return;
+
+ UINT index;
+ IDispatch *disp = d->dispatch();
+ ITypeInfo *typeinfo = 0;
+ ITypeLib *typelib = 0;
+ if (disp)
+ disp->GetTypeInfo(0, LOCALE_USER_DEFAULT, &typeinfo);
+ if (typeinfo)
+ typeinfo->GetContainingTypeLib(&typelib, &index);
+
+ if (!typelib) {
+ epoints->Release();
+ return;
+ }
+
+ MetaObjectGenerator generator(this, d);
+ bool haveEnumInfo = false;
+
+ ULONG c = 1;
+ IConnectionPoint *cpoint = 0;
+ epoints->Reset();
+ do {
+ if (cpoint) cpoint->Release();
+ cpoint = 0;
+ epoints->Next(c, &cpoint, &c);
+ if (!c || !cpoint)
+ break;
+
+ IID conniid;
+ cpoint->GetConnectionInterface(&conniid);
+ // workaround for typelibrary bug of Word.Application
+ QString connuuid(QUuid(conniid).toString());
+ if (d->eventSink.contains(connuuid))
+ break;
+
+ // Get ITypeInfo for source-interface, and skip if not supporting IDispatch
+ ITypeInfo *eventinfo = 0;
+ typelib->GetTypeInfoOfGuid(conniid, &eventinfo);
+ if (eventinfo) {
+ TYPEATTR *eventAttr;
+ eventinfo->GetTypeAttr(&eventAttr);
+ if (!eventAttr) {
+ eventinfo->Release();
+ break;
+ }
+
+ TYPEKIND eventKind = eventAttr->typekind;
+ eventinfo->ReleaseTypeAttr(eventAttr);
+ if (eventKind != TKIND_DISPATCH) {
+ eventinfo->Release();
+ break;
+ }
+ }
+
+ // always into the cache to avoid recoursion
+ QAxEventSink *eventSink = eventinfo ? new QAxEventSink(this) : 0;
+ d->eventSink.insert(connuuid, eventSink);
+
+ if (!eventinfo)
+ continue;
+
+ // have to get type info to support signals with enum parameters
+ if (!haveEnumInfo) {
+ bool wasTryCache = d->tryCache;
+ d->tryCache = true;
+ generator.readClassInfo();
+ generator.readEnumInfo();
+ d->tryCache = wasTryCache;
+ haveEnumInfo = true;
+ }
+ generator.readEventInterface(eventinfo, cpoint);
+ eventSink->advise(cpoint, conniid);
+
+ eventinfo->Release();
+ } while (c);
+ if (cpoint) cpoint->Release();
+ epoints->Release();
+
+ typelib->Release();
+
+ // make sure we don't try again
+ if (!d->eventSink.count())
+ d->eventSink.insert(QString(), 0);
+}
+
+/*!
+ \fn QString QAxBase::generateDocumentation()
+
+ Returns a rich text string with documentation for the
+ wrapped COM object. Dump the string to an HTML-file,
+ or use it in e.g. a QTextBrowser widget.
+*/
+
+static bool checkHRESULT(HRESULT hres, EXCEPINFO *exc, QAxBase *that, const QString &name, uint argerr)
+{
+ switch(hres) {
+ case S_OK:
+ return true;
+ case DISP_E_BADPARAMCOUNT:
+ qWarning("QAxBase: Error calling IDispatch member %s: Bad parameter count", name.toLatin1().data());
+ return false;
+ case DISP_E_BADVARTYPE:
+ qWarning("QAxBase: Error calling IDispatch member %s: Bad variant type", name.toLatin1().data());
+ return false;
+ case DISP_E_EXCEPTION:
+ {
+ bool printWarning = true;
+ unsigned short code = -1;
+ QString source, desc, help;
+ const QMetaObject *mo = that->metaObject();
+ int exceptionSignal = mo->indexOfSignal("exception(int,QString,QString,QString)");
+ if (exceptionSignal >= 0) {
+ if (exc->pfnDeferredFillIn)
+ exc->pfnDeferredFillIn(exc);
+
+ code = exc->wCode ? exc->wCode : exc->scode;
+ source = QString::fromUtf16((const ushort *)exc->bstrSource);
+ desc = QString::fromUtf16((const ushort *)exc->bstrDescription);
+ help = QString::fromUtf16((const ushort *)exc->bstrHelpFile);
+ uint helpContext = exc->dwHelpContext;
+
+ if (helpContext && !help.isEmpty())
+ help += QString::fromLatin1(" [%1]").arg(helpContext);
+
+ if (QAxEventSink::signalHasReceivers(that->qObject(), "exception(int,QString,QString,QString)")) {
+ void *argv[] = {0, &code, &source, &desc, &help};
+ that->qt_metacall(QMetaObject::InvokeMetaMethod, exceptionSignal, argv);
+ printWarning = false;
+ }
+ }
+ if (printWarning) {
+ qWarning("QAxBase: Error calling IDispatch member %s: Exception thrown by server", name.toLatin1().data());
+ qWarning(" Code : %d", code);
+ qWarning(" Source : %s", source.toLatin1().data());
+ qWarning(" Description: %s", desc.toLatin1().data());
+ qWarning(" Help : %s", help.toLatin1().data());
+ qWarning(" Connect to the exception(int,QString,QString,QString) signal to catch this exception");
+ }
+ }
+ return false;
+ case DISP_E_MEMBERNOTFOUND:
+ qWarning("QAxBase: Error calling IDispatch member %s: Member not found", name.toLatin1().data());
+ return false;
+ case DISP_E_NONAMEDARGS:
+ qWarning("QAxBase: Error calling IDispatch member %s: No named arguments", name.toLatin1().data());
+ return false;
+ case DISP_E_OVERFLOW:
+ qWarning("QAxBase: Error calling IDispatch member %s: Overflow", name.toLatin1().data());
+ return false;
+ case DISP_E_PARAMNOTFOUND:
+ qWarning("QAxBase: Error calling IDispatch member %s: Parameter %d not found", name.toLatin1().data(), argerr);
+ return false;
+ case DISP_E_TYPEMISMATCH:
+ qWarning("QAxBase: Error calling IDispatch member %s: Type mismatch in parameter %d", name.toLatin1().data(), argerr);
+ return false;
+ case DISP_E_UNKNOWNINTERFACE:
+ qWarning("QAxBase: Error calling IDispatch member %s: Unknown interface", name.toLatin1().data());
+ return false;
+ case DISP_E_UNKNOWNLCID:
+ qWarning("QAxBase: Error calling IDispatch member %s: Unknown locale ID", name.toLatin1().data());
+ return false;
+ case DISP_E_PARAMNOTOPTIONAL:
+ qWarning("QAxBase: Error calling IDispatch member %s: Non-optional parameter missing", name.toLatin1().data());
+ return false;
+ default:
+ qWarning("QAxBase: Error calling IDispatch member %s: Unknown error", name.toLatin1().data());
+ return false;
+ }
+}
+
+/*!
+ \internal
+*/
+int QAxBase::internalProperty(QMetaObject::Call call, int index, void **v)
+{
+ const QMetaObject *mo = metaObject();
+ const QMetaProperty prop = mo->property(index + mo->propertyOffset());
+ QByteArray propname = prop.name();
+
+ // hardcoded control property
+ if (propname == "control") {
+ switch(call) {
+ case QMetaObject::ReadProperty:
+ *(QString*)*v = control();
+ break;
+ case QMetaObject::WriteProperty:
+ setControl(*(QString*)*v);
+ break;
+ case QMetaObject::ResetProperty:
+ clear();
+ break;
+ default:
+ break;
+ }
+ return index - mo->propertyCount();
+ }
+
+ // get the IDispatch
+ if (!d->ptr || !prop.isValid())
+ return index;
+ IDispatch *disp = d->dispatch();
+ if (!disp)
+ return index;
+
+ DISPID dispid = d->metaObject()->dispIDofName(propname, disp);
+ if (dispid == DISPID_UNKNOWN)
+ return index;
+
+ Q_ASSERT(d->metaobj);
+ // property found, so everthing that goes wrong now should not bother the caller
+ index -= mo->propertyCount();
+
+ VARIANTARG arg;
+ VariantInit(&arg);
+ DISPPARAMS params;
+ EXCEPINFO excepinfo;
+ memset(&excepinfo, 0, sizeof(excepinfo));
+ UINT argerr = 0;
+ HRESULT hres = E_FAIL;
+
+ QByteArray proptype(prop.typeName());
+ switch (call) {
+ case QMetaObject::ReadProperty:
+ {
+ params.cArgs = 0;
+ params.cNamedArgs = 0;
+ params.rgdispidNamedArgs = 0;
+ params.rgvarg = 0;
+
+ hres = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &params, &arg, &excepinfo, 0);
+
+ // map result VARIANTARG to void*
+ uint type = QVariant::Int;
+ if (!prop.isEnumType())
+ type = prop.type();
+ QVariantToVoidStar(VARIANTToQVariant(arg, proptype, type), *v, proptype, type);
+ if ((arg.vt != VT_DISPATCH && arg.vt != VT_UNKNOWN) || type == QVariant::Pixmap || type == QVariant::Font)
+ clearVARIANT(&arg);
+ }
+ break;
+
+ case QMetaObject::WriteProperty:
+ {
+ QVariant::Type t = (QVariant::Type)prop.type();
+
+ DISPID dispidNamed = DISPID_PROPERTYPUT;
+ params.cArgs = 1;
+ params.cNamedArgs = 1;
+ params.rgdispidNamedArgs = &dispidNamed;
+ params.rgvarg = &arg;
+
+ arg.vt = VT_ERROR;
+ arg.scode = DISP_E_TYPEMISMATCH;
+
+ // map void* to VARIANTARG via QVariant
+ QVariant qvar;
+ if (prop.isEnumType()) {
+ qvar = *(int*)v[0];
+ proptype = 0;
+ } else {
+ if (t == QVariant::LastType) {
+ qvar = *(QVariant*)v[0];
+ proptype = 0;
+ } else if (t == QVariant::UserType) {
+ qvar = QVariant(qRegisterMetaType<void*>(prop.typeName()), (void**)v[0]);
+// qVariantSetValue(qvar, *(void**)v[0], prop.typeName());
+ } else {
+ proptype = d->metaObject()->propertyType(propname);
+ qvar = QVariant(t, v[0]);
+ }
+ }
+
+ QVariantToVARIANT(qvar, arg, proptype);
+ if (arg.vt == VT_EMPTY || arg.vt == VT_ERROR) {
+ qWarning("QAxBase::setProperty: Unhandled property type %s", prop.typeName());
+ break;
+ }
+ }
+ hres = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, &params, 0, &excepinfo, &argerr);
+ clearVARIANT(&arg);
+ break;
+
+ default:
+ break;
+ }
+
+ checkHRESULT(hres, &excepinfo, this, QLatin1String(propname), argerr);
+ return index;
+}
+
+int QAxBase::internalInvoke(QMetaObject::Call call, int index, void **v)
+{
+ Q_ASSERT(call == QMetaObject::InvokeMetaMethod);
+ Q_UNUSED(call);
+
+ // get the IDispatch
+ IDispatch *disp = d->dispatch();
+ if (!disp)
+ return index;
+
+ const QMetaObject *mo = metaObject();
+ // get the slot information
+ const QMetaMethod slot = mo->method(index + mo->methodOffset());
+ Q_ASSERT(slot.methodType() == QMetaMethod::Slot);
+
+ QByteArray signature(slot.signature());
+ QByteArray slotname(signature);
+ slotname.truncate(slotname.indexOf('('));
+
+ // Get the Dispatch ID of the method to be called
+ bool isProperty = false;
+ DISPID dispid = d->metaObject()->dispIDofName(slotname, disp);
+
+ Q_ASSERT(d->metaobj);
+
+ if (dispid == DISPID_UNKNOWN && slotname.toLower().startsWith("set")) {
+ // see if we are calling a property set function as a slot
+ slotname = slotname.right(slotname.length() - 3);
+ dispid = d->metaobj->dispIDofName(slotname, disp);
+ isProperty = true;
+ }
+ if (dispid == DISPID_UNKNOWN)
+ return index;
+
+ // slot found, so everthing that goes wrong now should not bother the caller
+ index -= mo->methodCount();
+
+ // setup the parameters
+ DISPPARAMS params;
+ DISPID dispidNamed = DISPID_PROPERTYPUT;
+ params.cArgs = d->metaobj->numParameter(signature);
+ params.cNamedArgs = isProperty ? 1 : 0;
+ params.rgdispidNamedArgs = isProperty ? &dispidNamed : 0;
+ params.rgvarg = 0;
+ VARIANTARG static_rgvarg[QAX_NUM_PARAMS];
+ if (params.cArgs) {
+ if (params.cArgs <= QAX_NUM_PARAMS)
+ params.rgvarg = static_rgvarg;
+ else
+ params.rgvarg = new VARIANTARG[params.cArgs];
+ }
+
+ int p;
+ for (p = 0; p < (int)params.cArgs; ++p) {
+ bool out;
+ QByteArray type = d->metaobj->paramType(signature, p, &out);
+ QVariant::Type vt = QVariant::nameToType(type);
+ QVariant qvar;
+ if (vt != QVariant::UserType)
+ qvar = QVariant(vt, v[p + 1]);
+
+ if (!qvar.isValid()) {
+ if (type == "IDispatch*")
+ qVariantSetValue(qvar, *(IDispatch**)v[p+1]);
+ else if (type == "IUnknown*")
+ qVariantSetValue(qvar, *(IUnknown**)v[p+1]);
+ else if (type == "QVariant")
+ qvar = *(QVariant*)v[p + 1];
+ else if (mo->indexOfEnumerator(type) != -1)
+ qvar = *(int*)v[p + 1];
+ else
+ qvar = QVariant(QMetaType::type(type), v[p + 1]);
+ }
+
+ QVariantToVARIANT(qvar, params.rgvarg[params.cArgs - p - 1], type, out);
+ }
+
+ // call the method
+ VARIANT ret;
+ VariantInit(&ret);
+ UINT argerr = 0;
+ HRESULT hres = E_FAIL;
+ EXCEPINFO excepinfo;
+ memset(&excepinfo, 0, sizeof(excepinfo));
+
+ WORD wFlags = isProperty ? DISPATCH_PROPERTYPUT : DISPATCH_METHOD | DISPATCH_PROPERTYGET;
+ hres = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, wFlags, &params, &ret, &excepinfo, &argerr);
+
+ // get return value
+ if (hres == S_OK && ret.vt != VT_EMPTY)
+ QVariantToVoidStar(VARIANTToQVariant(ret, slot.typeName()), v[0], slot.typeName());
+
+ // update out parameters
+ for (p = 0; p < (int)params.cArgs; ++p) {
+ bool out;
+ QByteArray ptype = d->metaobj->paramType(signature, p, &out);
+ if (out)
+ QVariantToVoidStar(VARIANTToQVariant(params.rgvarg[params.cArgs - p - 1], ptype), v[p+1], ptype);
+ }
+ // clean up
+ for (p = 0; p < (int)params.cArgs; ++p)
+ clearVARIANT(params.rgvarg+p);
+ if (params.rgvarg != static_rgvarg)
+ delete [] params.rgvarg;
+
+ checkHRESULT(hres, &excepinfo, this, QString::fromLatin1(slotname), params.cArgs-argerr-1);
+ return index;
+}
+
+/*!
+ \internal
+*/
+int QAxBase::qt_metacall(QMetaObject::Call call, int id, void **v)
+{
+ const QMetaObject *mo = metaObject();
+ if (isNull() && mo->property(id + mo->propertyOffset()).name() != QByteArray("control")) {
+ qWarning("QAxBase::qt_metacall: Object is not initialized, or initialization failed");
+ return id;
+ }
+
+ switch(call) {
+ case QMetaObject::InvokeMetaMethod:
+ switch (mo->method(id + mo->methodOffset()).methodType()) {
+ case QMetaMethod::Signal:
+ QMetaObject::activate(qObject(), mo, id, v);
+ id -= mo->methodCount();
+ break;
+ case QMetaMethod::Method:
+ case QMetaMethod::Slot:
+ id = internalInvoke(call, id, v);
+ break;
+ }
+ break;
+ case QMetaObject::ReadProperty:
+ case QMetaObject::WriteProperty:
+ case QMetaObject::ResetProperty:
+ id = internalProperty(call, id, v);
+ break;
+ case QMetaObject::QueryPropertyScriptable:
+ case QMetaObject::QueryPropertyDesignable:
+ case QMetaObject::QueryPropertyStored:
+ case QMetaObject::QueryPropertyEditable:
+ case QMetaObject::QueryPropertyUser:
+ id -= mo->propertyCount();
+ break;
+ }
+ Q_ASSERT(id < 0);
+ return id;
+}
+
+#ifdef QT_CHECK_STATE
+static void qax_noSuchFunction(int disptype, const QByteArray &name, const QByteArray &function, const QAxBase *that)
+{
+ const QMetaObject *metaObject = that->metaObject();
+ const char *coclass = metaObject->classInfo(metaObject->indexOfClassInfo("CoClass")).value();
+
+ if (disptype == DISPATCH_METHOD) {
+ qWarning("QAxBase::dynamicCallHelper: %s: No such method in %s [%s]", name.data(), that->control().toLatin1().data(), coclass ? coclass: "unknown");
+ qWarning("\tCandidates are:");
+ for (int i = 0; i < metaObject->methodCount(); ++i) {
+ const QMetaMethod slot(metaObject->method(i));
+ if (slot.methodType() != QMetaMethod::Slot)
+ continue;
+ QByteArray signature = slot.signature();
+ if (signature.toLower().startsWith(function.toLower()))
+ qWarning("\t\t%s", signature.data());
+ }
+ } else {
+ qWarning("QAxBase::dynamicCallHelper: %s: No such property in %s [%s]", name.data(), that->control().toLatin1().data(), coclass ? coclass: "unknown");
+ if (!function.isEmpty()) {
+ qWarning("\tCandidates are:");
+ char f0 = function.toLower().at(0);
+ for (int i = metaObject->propertyOffset(); i < metaObject->propertyCount(); ++i) {
+ QByteArray signature(metaObject->property(i).name());
+ if (!signature.isEmpty() && signature.toLower().at(0) == f0)
+ qWarning("\t\t%s", signature.data());
+ }
+ }
+ }
+}
+#endif
+
+/*!
+ \internal
+
+ \a name is already normalized?
+*/
+bool QAxBase::dynamicCallHelper(const char *name, void *inout, QList<QVariant> &vars, QByteArray &type)
+{
+ if (isNull()) {
+ qWarning("QAxBase::dynamicCallHelper: Object is not initialized, or initialization failed");
+ return false;
+ }
+
+ IDispatch *disp = d->dispatch();
+ if (!disp) {
+ qWarning("QAxBase::dynamicCallHelper: Object does not support automation");
+ return false;
+ }
+
+ const QMetaObject *mo = metaObject();
+ d->metaObject();
+ Q_ASSERT(d->metaobj);
+
+ int varc = vars.count();
+
+ QByteArray normFunction = QMetaObject::normalizedSignature(name);
+ QByteArray function(normFunction);
+ VARIANT staticarg[QAX_NUM_PARAMS];
+ VARIANT *arg = 0;
+ VARIANTARG *res = (VARIANTARG*)inout;
+
+ unsigned short disptype;
+
+ int id = -1;
+ bool parse = false;
+
+ if (function.contains('(')) {
+ disptype = DISPATCH_METHOD | DISPATCH_PROPERTYGET;
+ if (d->useMetaObject)
+ id = mo->indexOfSlot(function);
+ if (id >= 0) {
+ const QMetaMethod slot = mo->method(id);
+ Q_ASSERT(slot.methodType() == QMetaMethod::Slot);
+ function = slot.signature();
+ type = slot.typeName();
+ }
+ function.truncate(function.indexOf('('));
+ parse = !varc && normFunction.length() > function.length() + 2;
+ if (parse) {
+ QString args = QLatin1String(normFunction);
+ args = args.mid(function.length() + 1);
+ // parse argument string int list of arguments
+ QString curArg;
+ const QChar *c = args.unicode();
+ int index = 0;
+ bool inString = false;
+ bool inEscape = false;
+ while (index < (int)args.length()) {
+ QChar cc = *c;
+ ++c;
+ ++index;
+ switch(cc.toLatin1()) {
+ case 'n':
+ if (inEscape)
+ cc = QLatin1Char('\n');
+ break;
+ case 'r':
+ if (inEscape)
+ cc = QLatin1Char('\r');
+ break;
+ case 't':
+ if (inEscape)
+ cc = QLatin1Char('\t');
+ break;
+ case '\\':
+ if (!inEscape && inString) {
+ inEscape = true;
+ continue;
+ }
+ break;
+ case '"':
+ if (!inEscape) {
+ inString = !inString;
+ curArg += cc;
+ continue;
+ }
+ break;
+ case ' ':
+ if (!inString && curArg.isEmpty())
+ continue;
+ break;
+ case ',':
+ case ')':
+ if (inString)
+ break;
+ curArg = curArg.trimmed();
+ if (curArg.at(0) == QLatin1Char('\"') && curArg.at(curArg.length()-1) == QLatin1Char('\"')) {
+ vars << curArg.mid(1, curArg.length() - 2);
+ } else {
+ bool isNumber = false;
+ bool isDouble = false;
+ int number = curArg.toInt(&isNumber);
+ double dbl = curArg.toDouble(&isDouble);
+ if (isNumber) {
+ vars << number;
+ } else if (isDouble) {
+ vars << dbl;
+ } else {
+ bool isEnum = false;
+ for (int enumIndex = 0; enumIndex < mo->enumeratorCount(); ++enumIndex) {
+ QMetaEnum metaEnum =mo->enumerator(enumIndex);
+ int value = metaEnum.keyToValue(curArg.toLatin1());
+ if (value != -1 && !QByteArray(metaEnum.valueToKey(value)).isEmpty()) {
+ vars << value;
+ isEnum = true;
+ break;
+ }
+ }
+ if (!isEnum)
+ vars << curArg;
+ }
+ }
+ curArg.clear();
+ continue;
+ default:
+ break;
+ }
+ inEscape = false;
+ curArg += cc;
+ }
+
+ varc = vars.count();
+ }
+ } else {
+ if (d->useMetaObject)
+ id = mo->indexOfProperty(normFunction);
+
+ if (id >= 0) {
+ const QMetaProperty prop =mo->property(id);
+ type = prop.typeName();
+ }
+ if (varc == 1) {
+ res = 0;
+ disptype = DISPATCH_PROPERTYPUT;
+ } else {
+ disptype = DISPATCH_PROPERTYGET;
+ }
+ }
+ if (varc) {
+ varc = qMin(varc, d->metaobj->numParameter(normFunction));
+ arg = varc <= QAX_NUM_PARAMS ? staticarg : new VARIANT[varc];
+ for (int i = 0; i < varc; ++i) {
+ QVariant var(vars.at(i));
+ VariantInit(arg + (varc - i - 1));
+ bool out = false;
+ QByteArray paramType;
+ if (disptype == DISPATCH_PROPERTYPUT)
+ paramType = type;
+ else if (parse || disptype == DISPATCH_PROPERTYGET)
+ paramType = 0;
+ else
+ paramType = d->metaobj->paramType(normFunction, i, &out);
+
+ if (!parse && d->useMetaObject && var.type() == QVariant::String || var.type() == QVariant::ByteArray) {
+ int enumIndex =mo->indexOfEnumerator(paramType);
+ if (enumIndex != -1) {
+ QMetaEnum metaEnum =mo->enumerator(enumIndex);
+ QVariantToVARIANT(metaEnum.keyToValue(var.toByteArray()), arg[varc - i - 1], "int", out);
+ }
+ }
+
+ if (arg[varc - i - 1].vt == VT_EMPTY)
+ QVariantToVARIANT(var, arg[varc - i - 1], paramType, out);
+ }
+ }
+
+ DISPID dispid = d->metaobj->dispIDofName(function, disp);
+ if (dispid == DISPID_UNKNOWN && function.toLower().startsWith("set")) {
+ function = function.mid(3);
+ dispid = d->metaobj->dispIDofName(function, disp);
+ disptype = DISPATCH_PROPERTYPUT;
+ }
+
+ if (dispid == DISPID_UNKNOWN) {
+#ifdef QT_CHECK_STATE
+ qax_noSuchFunction(disptype, normFunction, function, this);
+#endif
+ return false;
+ }
+
+ DISPPARAMS params;
+ DISPID dispidNamed = DISPID_PROPERTYPUT;
+
+ params.cArgs = varc;
+ params.cNamedArgs = (disptype == DISPATCH_PROPERTYPUT) ? 1 : 0;
+ params.rgdispidNamedArgs = (disptype == DISPATCH_PROPERTYPUT) ? &dispidNamed : 0;
+ params.rgvarg = arg;
+ EXCEPINFO excepinfo;
+ memset(&excepinfo, 0, sizeof(excepinfo));
+ UINT argerr = 0;
+
+ HRESULT hres = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, disptype, &params, res, &excepinfo, &argerr);
+
+ if (disptype == (DISPATCH_METHOD|DISPATCH_PROPERTYGET) && hres == S_OK && varc) {
+ for (int i = 0; i < varc; ++i)
+ if (arg[varc-i-1].vt & VT_BYREF) // update out-parameters
+ vars[i] = VARIANTToQVariant(arg[varc-i-1], vars.at(i).typeName());
+ }
+
+ // clean up
+ for (int i = 0; i < varc; ++i)
+ clearVARIANT(params.rgvarg+i);
+ if (arg && arg != staticarg)
+ delete[] arg;
+
+ return checkHRESULT(hres, &excepinfo, this, QLatin1String(function), varc-argerr-1);
+}
+
+
+/*!
+ Calls the COM object's method \a function, passing the
+ parameters \a var1, \a var1, \a var2, \a var3, \a var4, \a var5,
+ \a var6, \a var7 and \a var8, and returns the value returned by
+ the method, or an invalid QVariant if the method does not return
+ a value or when the function call failed.
+
+ If \a function is a method of the object the string must be provided
+ as the full prototype, for example as it would be written in a
+ QObject::connect() call.
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 15
+
+ Alternatively a function can be called passing the parameters embedded
+ in the string, e.g. above function can also be invoked using
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 16
+
+ All parameters are passed as strings; it depends on the control whether
+ they are interpreted correctly, and is slower than using the prototype
+ with correctly typed parameters.
+
+ If \a function is a property the string has to be the name of the
+ property. The property setter is called when \a var1 is a valid QVariant,
+ otherwise the getter is called.
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 17
+
+ Note that it is faster to get and set properties using
+ QObject::property() and QObject::setProperty().
+
+ dynamicCall() can also be used to call objects with a
+ \l{QAxBase::disableMetaObject()}{disabled metaobject} wrapper,
+ which can improve performance significantely, esp. when calling many
+ different objects of different types during an automation process.
+ ActiveQt will then however not validate parameters.
+
+ It is only possible to call functions through dynamicCall() that
+ have parameters or return values of datatypes supported by
+ QVariant. See the QAxBase class documentation for a list of
+ supported and unsupported datatypes. If you want to call functions
+ that have unsupported datatypes in the parameter list, use
+ queryInterface() to retrieve the appropriate COM interface, and
+ use the function directly.
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 18
+
+ This is also more efficient.
+*/
+QVariant QAxBase::dynamicCall(const char *function,
+ const QVariant &var1,
+ const QVariant &var2,
+ const QVariant &var3,
+ const QVariant &var4,
+ const QVariant &var5,
+ const QVariant &var6,
+ const QVariant &var7,
+ const QVariant &var8)
+{
+ QList<QVariant> vars;
+ QVariant var = var1;
+ int argc = 1;
+ while(var.isValid()) {
+ vars << var;
+ switch(++argc) {
+ case 2: var = var2; break;
+ case 3: var = var3; break;
+ case 4: var = var4; break;
+ case 5: var = var5; break;
+ case 6: var = var6; break;
+ case 7: var = var7; break;
+ case 8: var = var8; break;
+ default:var = QVariant(); break;
+ }
+ }
+
+ return dynamicCall(function, vars);
+}
+
+/*!
+ \overload
+
+ Calls the COM object's method \a function, passing the
+ parameters in \a vars, and returns the value returned by
+ the method. If the method does not return a value or when
+ the function call failed this function returns an invalid
+ QVariant object.
+
+ The QVariant objects in \a vars are updated when the method has
+ out-parameters.
+*/
+QVariant QAxBase::dynamicCall(const char *function, QList<QVariant> &vars)
+{
+ VARIANTARG res;
+ VariantInit(&res);
+
+ QByteArray rettype;
+ if (!dynamicCallHelper(function, &res, vars, rettype))
+ return QVariant();
+
+ QVariant qvar = VARIANTToQVariant(res, rettype);
+ if ((res.vt != VT_DISPATCH && res.vt != VT_UNKNOWN) || qvar.type() == QVariant::Pixmap || qvar.type() == QVariant::Font)
+ clearVARIANT(&res);
+
+ return qvar;
+}
+
+/*!
+ Returns a pointer to a QAxObject wrapping the COM object provided
+ by the method or property \a name, passing passing the parameters
+ \a var1, \a var1, \a var2, \a var3, \a var4, \a var5, \a var6,
+ \a var7 and \a var8.
+
+ If \a name is provided by a method the string must include the
+ full function prototype.
+
+ If \a name is a property the string must be the name of the property,
+ and \a var1, ... \a var8 are ignored.
+
+ The returned QAxObject is a child of this object (which is either of
+ type QAxObject or QAxWidget), and is deleted when this object is
+ deleted. It is however safe to delete the returned object yourself,
+ and you should do so when you iterate over lists of subobjects.
+
+ COM enabled applications usually have an object model publishing
+ certain elements of the application as dispatch interfaces. Use
+ this method to navigate the hierarchy of the object model, e.g.
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 19
+*/
+QAxObject *QAxBase::querySubObject(const char *name,
+ const QVariant &var1,
+ const QVariant &var2,
+ const QVariant &var3,
+ const QVariant &var4,
+ const QVariant &var5,
+ const QVariant &var6,
+ const QVariant &var7,
+ const QVariant &var8)
+{
+ QList<QVariant> vars;
+ QVariant var = var1;
+ int argc = 1;
+ while(var.isValid()) {
+ vars << var;
+ switch(++argc) {
+ case 2: var = var2; break;
+ case 3: var = var3; break;
+ case 4: var = var4; break;
+ case 5: var = var5; break;
+ case 6: var = var6; break;
+ case 7: var = var7; break;
+ case 8: var = var8; break;
+ default:var = QVariant(); break;
+ }
+ }
+
+ return querySubObject(name, vars);
+}
+
+/*!
+ \overload
+
+ The QVariant objects in \a vars are updated when the method has
+ out-parameters.
+*/
+QAxObject *QAxBase::querySubObject(const char *name, QList<QVariant> &vars)
+{
+ QAxObject *object = 0;
+ VARIANTARG res;
+ VariantInit(&res);
+
+ QByteArray rettype;
+ if (!dynamicCallHelper(name, &res, vars, rettype))
+ return 0;
+
+ switch (res.vt) {
+ case VT_DISPATCH:
+ if (res.pdispVal) {
+ if (rettype.isEmpty() || rettype == "IDispatch*" || rettype == "QVariant") {
+ object = new QAxObject(res.pdispVal, qObject());
+ } else if (QMetaType::type(rettype)) {
+ QVariant qvar = VARIANTToQVariant(res, rettype, 0);
+ object = *(QAxObject**)qvar.constData();
+// qVariantGet(qvar, object, rettype);
+ res.pdispVal->AddRef();
+ }
+ if (object)
+ ((QAxBase*)object)->d->tryCache = true;
+ }
+ break;
+ case VT_UNKNOWN:
+ if (res.punkVal) {
+ if (rettype.isEmpty() || rettype == "IUnknown*") {
+ object = new QAxObject(res.punkVal, qObject());
+ } else if (QMetaType::type(rettype)) {
+ QVariant qvar = VARIANTToQVariant(res, rettype, 0);
+ object = *(QAxObject**)qvar.constData();
+// qVariantGet(qvar, object, rettype);
+ res.punkVal->AddRef();
+ }
+ if (object)
+ ((QAxBase*)object)->d->tryCache = true;
+ }
+ break;
+ case VT_EMPTY:
+#ifdef QT_CHECK_STATE
+ {
+ const char *coclass = metaObject()->classInfo(metaObject()->indexOfClassInfo("CoClass")).value();
+ qWarning("QAxBase::querySubObject: %s: Error calling function or property in %s (%s)"
+ , name, control().toLatin1().data(), coclass ? coclass: "unknown");
+ }
+#endif
+ break;
+ default:
+#ifdef QT_CHECK_STATE
+ {
+ const char *coclass = metaObject()->classInfo(metaObject()->indexOfClassInfo("CoClass")).value();
+ qWarning("QAxBase::querySubObject: %s: Method or property is not of interface type in %s (%s)"
+ , name, control().toLatin1().data(), coclass ? coclass: "unknown");
+ }
+#endif
+ break;
+ }
+
+ clearVARIANT(&res);
+ return object;
+}
+
+class QtPropertyBag : public IPropertyBag
+{
+public:
+ QtPropertyBag() :ref(0) {}
+ virtual ~QtPropertyBag() {}
+
+ HRESULT __stdcall QueryInterface(REFIID iid, LPVOID *iface)
+ {
+ *iface = 0;
+ if (iid == IID_IUnknown)
+ *iface = this;
+ else if (iid == IID_IPropertyBag)
+ *iface = this;
+ else
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+ }
+ unsigned long __stdcall AddRef() { return ++ref; }
+ unsigned long __stdcall Release()
+ {
+ if (!--ref) {
+ delete this;
+ return 0;
+ }
+ return ref;
+ }
+
+ HRESULT __stdcall Read(LPCOLESTR name, VARIANT *var, IErrorLog *)
+ {
+ if (!var)
+ return E_POINTER;
+
+ QString property = QString::fromUtf16((const ushort *)name);
+ QVariant qvar = map.value(property);
+ QVariantToVARIANT(qvar, *var);
+ return S_OK;
+ }
+ HRESULT __stdcall Write(LPCOLESTR name, VARIANT *var)
+ {
+ if (!var)
+ return E_POINTER;
+ QString property = QString::fromUtf16((const ushort *)name);
+ QVariant qvar = VARIANTToQVariant(*var, 0);
+ map[property] = qvar;
+
+ return S_OK;
+ }
+
+ QAxBase::PropertyBag map;
+
+private:
+ unsigned long ref;
+};
+
+/*!
+ Returns a name:value map of all the properties exposed by the COM
+ object.
+
+ This is more efficient than getting multiple properties
+ individually if the COM object supports property bags.
+
+ \warning It is not guaranteed that the property bag implementation
+ of the COM object returns all properties, or that the properties
+ returned are the same as those available through the IDispatch
+ interface.
+*/
+QAxBase::PropertyBag QAxBase::propertyBag() const
+{
+ PropertyBag result;
+
+ if (!d->ptr && !d->initialized) {
+ ((QAxBase*)this)->initialize(&d->ptr);
+ d->initialized = true;
+ }
+
+ if (isNull())
+ return result;
+ IPersistPropertyBag *persist = 0;
+ d->ptr->QueryInterface(IID_IPersistPropertyBag, (void**)&persist);
+ if (persist) {
+ QtPropertyBag *pbag = new QtPropertyBag();
+ pbag->AddRef();
+ persist->Save(pbag, false, true);
+ result = pbag->map;
+ pbag->Release();
+ persist->Release();
+ return result;
+ } else {
+ const QMetaObject *mo = metaObject();
+ for (int p = mo->propertyOffset(); p < mo->propertyCount(); ++p) {
+ const QMetaProperty property = mo->property(p);
+ QVariant var = qObject()->property(property.name());
+ result.insert(QLatin1String(property.name()), var);
+ }
+ }
+ return result;
+}
+
+/*!
+ Sets the properties of the COM object to the corresponding values
+ in \a bag.
+
+ \warning
+ You should only set property bags that have been returned by the
+ propertyBag function, as it cannot be guaranteed that the property
+ bag implementation of the COM object supports the same properties
+ that are available through the IDispatch interface.
+
+ \sa propertyBag()
+*/
+void QAxBase::setPropertyBag(const PropertyBag &bag)
+{
+ if (!d->ptr && !d->initialized) {
+ initialize(&d->ptr);
+ d->initialized = true;
+ }
+
+ if (isNull())
+ return;
+ IPersistPropertyBag *persist = 0;
+ d->ptr->QueryInterface(IID_IPersistPropertyBag, (void**)&persist);
+ if (persist) {
+ QtPropertyBag *pbag = new QtPropertyBag();
+ pbag->map = bag;
+ pbag->AddRef();
+ persist->Load(pbag, 0);
+ pbag->Release();
+ persist->Release();
+ } else {
+ const QMetaObject *mo = metaObject();
+ for (int p = mo->propertyOffset(); p < mo->propertyCount(); ++p) {
+ const QMetaProperty property = mo->property(p);
+ QVariant var = bag.value(QLatin1String(property.name()));
+ qObject()->setProperty(property.name(), var);
+ }
+ }
+}
+
+/*!
+ Returns true if the property \a prop is writable; otherwise
+ returns false. By default, all properties are writable.
+
+ \warning
+ Depending on the control implementation this setting might be
+ ignored for some properties.
+
+ \sa setPropertyWritable(), propertyChanged()
+*/
+bool QAxBase::propertyWritable(const char *prop) const
+{
+ return d->propWritable.value(prop, true);
+}
+
+/*!
+ Sets the property \a prop to writable if \a ok is true, otherwise
+ sets \a prop to be read-only. By default, all properties are
+ writable.
+
+ \warning
+ Depending on the control implementation this setting might be
+ ignored for some properties.
+
+ \sa propertyWritable(), propertyChanged()
+*/
+void QAxBase::setPropertyWritable(const char *prop, bool ok)
+{
+ d->propWritable[prop] = ok;
+}
+
+/*!
+ Returns true if there is no COM object loaded by this wrapper;
+ otherwise return false.
+
+ \sa control
+*/
+bool QAxBase::isNull() const
+{
+ return !d->ptr;
+}
+
+/*!
+ Returns a QVariant that wraps the COM object. The variant can
+ then be used as a parameter in e.g. dynamicCall().
+*/
+QVariant QAxBase::asVariant() const
+{
+ if (!d->ptr && !d->initialized) {
+ ((QAxBase*)this)->initialize(&d->ptr);
+ d->initialized = true;
+ }
+
+ QVariant qvar;
+ QByteArray cn(className());
+ if (cn == "QAxObject" || cn == "QAxWidget" || cn == "QAxBase") {
+ if (d->dispatch())
+ qVariantSetValue(qvar, d->dispatch());
+ else if (d->ptr)
+ qVariantSetValue(qvar, d->ptr);
+ } else {
+ cn = cn.mid(cn.lastIndexOf(':') + 1);
+ QObject *object = qObject();
+ if (QMetaType::type(cn))
+ qvar = QVariant(qRegisterMetaType<QObject*>(cn + "*"), &object);
+// qVariantSetValue(qvar, qObject(), cn + "*");
+ }
+
+ return qvar;
+}
+
+// internal function that creates a QAxObject from an iface
+// used by type-conversion code (types.cpp)
+void *qax_createObjectWrapper(int metaType, IUnknown *iface)
+{
+ if (!iface)
+ return 0;
+
+ QAxObject *object = (QAxObject*)QMetaType::construct(metaType, 0);
+ QAxBasePrivate *d = object->d;
+
+ d->ptr = iface;
+ d->initialized = true;
+
+ // no release, since no addref
+
+ return object;
+}
+
+/*!
+ \fn void QAxBase::signal(const QString &name, int argc, void *argv)
+
+ This generic signal gets emitted when the COM object issues the
+ event \a name. \a argc is the number of parameters provided by the
+ event (DISPPARAMS.cArgs), and \a argv is the pointer to the
+ parameter values (DISPPARAMS.rgvarg). Note that the order of parameter
+ values is turned around, ie. the last element of the array is the first
+ parameter in the function.
+
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 20
+
+ Use this signal if the event has parameters of unsupported data
+ types. Otherwise, connect directly to the signal \a name.
+*/
+
+/*!
+ \fn void QAxBase::propertyChanged(const QString &name)
+
+ If the COM object supports property notification, this signal gets
+ emitted when the property called \a name is changed.
+*/
+
+/*!
+ \fn void QAxBase::exception(int code, const QString &source, const QString &desc, const QString &help)
+
+ This signal is emitted when the COM object throws an exception while called using the OLE automation
+ interface IDispatch. \a code, \a source, \a desc and \a help provide information about the exception as
+ provided by the COM server and can be used to provide useful feedback to the end user. \a help includes
+ the help file, and the help context ID in brackets, e.g. "filename [id]".
+*/
+
+/*!
+ \fn QObject *QAxBase::qObject() const
+ \internal
+*/
+
+/*!
+ \fn const char *QAxBase::className() const
+ \internal
+*/
+
+QT_END_NAMESPACE
+#endif //QT_NO_WIN_ACTIVEQT
diff --git a/src/activeqt/container/qaxbase.h b/src/activeqt/container/qaxbase.h
new file mode 100644
index 0000000..7e128e5
--- /dev/null
+++ b/src/activeqt/container/qaxbase.h
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** 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 QAXBASE_H
+#define QAXBASE_H
+
+#include <QtCore/qdatastream.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qvariant.h>
+
+struct IUnknown;
+struct IDispatch;
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(ActiveQt)
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+struct QUuid;
+class QAxEventSink;
+class QAxObject;
+class QAxBasePrivate;
+struct QAxMetaObject;
+
+class QAxBase
+{
+ QDOC_PROPERTY(QString control READ control WRITE setControl)
+
+public:
+ typedef QMap<QString, QVariant> PropertyBag;
+
+ QAxBase(IUnknown *iface = 0);
+ virtual ~QAxBase();
+
+ QString control() const;
+
+ long queryInterface(const QUuid &, void**) const;
+
+ QVariant dynamicCall(const char *name, const QVariant &v1 = QVariant(),
+ const QVariant &v2 = QVariant(),
+ const QVariant &v3 = QVariant(),
+ const QVariant &v4 = QVariant(),
+ const QVariant &v5 = QVariant(),
+ const QVariant &v6 = QVariant(),
+ const QVariant &v7 = QVariant(),
+ const QVariant &v8 = QVariant());
+ QVariant dynamicCall(const char *name, QList<QVariant> &vars);
+ QAxObject *querySubObject(const char *name, const QVariant &v1 = QVariant(),
+ const QVariant &v2 = QVariant(),
+ const QVariant &v3 = QVariant(),
+ const QVariant &v4 = QVariant(),
+ const QVariant &v5 = QVariant(),
+ const QVariant &v6 = QVariant(),
+ const QVariant &v7 = QVariant(),
+ const QVariant &v8 = QVariant());
+ QAxObject* querySubObject(const char *name, QList<QVariant> &vars);
+
+ virtual const QMetaObject *metaObject() const;
+ virtual int qt_metacall(QMetaObject::Call, int, void **);
+
+ virtual QObject *qObject() const = 0;
+ virtual const char *className() const = 0;
+
+ PropertyBag propertyBag() const;
+ void setPropertyBag(const PropertyBag&);
+
+ QString generateDocumentation();
+
+ virtual bool propertyWritable(const char*) const;
+ virtual void setPropertyWritable(const char*, bool);
+
+ bool isNull() const;
+
+ QStringList verbs() const;
+
+ QVariant asVariant() const;
+
+#ifdef qdoc
+Q_SIGNALS:
+ void signal(const QString&,int,void*);
+ void propertyChanged(const QString&);
+ void exception(int,const QString&,const QString&,const QString&);
+#endif
+
+public:
+ virtual void clear();
+ bool setControl(const QString&);
+
+ void disableMetaObject();
+ void disableClassInfo();
+ void disableEventSink();
+
+protected:
+ virtual bool initialize(IUnknown** ptr);
+ bool initializeRemote(IUnknown** ptr);
+ bool initializeLicensed(IUnknown** ptr);
+ bool initializeActive(IUnknown** ptr);
+ bool initializeFromFile(IUnknown** ptr);
+
+ void internalRelease();
+ void initializeFrom(QAxBase *that);
+ void connectNotify();
+ long indexOfVerb(const QString &verb) const;
+
+private:
+ friend class QAxEventSink;
+ friend void *qax_createObjectWrapper(int, IUnknown*);
+ bool initializeLicensedHelper(void *factory, const QString &key, IUnknown **ptr);
+ QAxBasePrivate *d;
+ QAxMetaObject *internalMetaObject() const;
+
+ virtual const QMetaObject *parentMetaObject() const = 0;
+ int internalProperty(QMetaObject::Call, int index, void **v);
+ int internalInvoke(QMetaObject::Call, int index, void **v);
+ bool dynamicCallHelper(const char *name, void *out, QList<QVariant> &var, QByteArray &type);
+
+ static QMetaObject staticMetaObject;
+};
+
+#if defined Q_CC_MSVC && _MSC_VER < 1300
+template <> inline QAxBase *qobject_cast_helper<QAxBase*>(const QObject *o, QAxBase *)
+#else
+template <> inline QAxBase *qobject_cast<QAxBase*>(const QObject *o)
+#endif
+{
+ void *result = o ? const_cast<QObject *>(o)->qt_metacast("QAxBase") : 0;
+ return (QAxBase*)(result);
+}
+
+#if defined Q_CC_MSVC && _MSC_VER < 1300
+template <> inline QAxBase *qobject_cast_helper<QAxBase*>(QObject *o, QAxBase *)
+#else
+template <> inline QAxBase *qobject_cast<QAxBase*>(QObject *o)
+#endif
+{
+ void *result = o ? o->qt_metacast("QAxBase") : 0;
+ return (QAxBase*)(result);
+}
+
+extern QString qax_generateDocumentation(QAxBase *);
+
+inline QString QAxBase::generateDocumentation()
+{
+ return qax_generateDocumentation(this);
+}
+
+#ifndef QT_NO_DATASTREAM
+inline QDataStream &operator >>(QDataStream &s, QAxBase &c)
+{
+ QAxBase::PropertyBag bag;
+ c.qObject()->blockSignals(true);
+ QString control;
+ s >> control;
+ c.setControl(control);
+ s >> bag;
+ c.setPropertyBag(bag);
+ c.qObject()->blockSignals(false);
+
+ return s;
+}
+
+inline QDataStream &operator <<(QDataStream &s, const QAxBase &c)
+{
+ QAxBase::PropertyBag bag = c.propertyBag();
+ s << c.control();
+ s << bag;
+
+ return s;
+}
+#endif // QT_NO_DATASTREAM
+
+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 // QAXBASE_H
diff --git a/src/activeqt/container/qaxdump.cpp b/src/activeqt/container/qaxdump.cpp
new file mode 100644
index 0000000..62ef0a4
--- /dev/null
+++ b/src/activeqt/container/qaxdump.cpp
@@ -0,0 +1,404 @@
+/****************************************************************************
+**
+** 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 "qaxbase.h"
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+#include <qmetaobject.h>
+#include <quuid.h>
+#include <qt_windows.h>
+#include <qtextstream.h>
+
+#include <ctype.h>
+
+#include "../shared/qaxtypes.h"
+
+QT_BEGIN_NAMESPACE
+
+QString qax_docuFromName(ITypeInfo *typeInfo, const QString &name)
+{
+ QString docu;
+ if (!typeInfo)
+ return docu;
+
+ MEMBERID memId;
+ BSTR names = QStringToBSTR(name);
+ typeInfo->GetIDsOfNames((BSTR*)&names, 1, &memId);
+ SysFreeString(names);
+ if (memId != DISPID_UNKNOWN) {
+ BSTR docStringBstr, helpFileBstr;
+ ulong helpContext;
+ HRESULT hres = typeInfo->GetDocumentation(memId, 0, &docStringBstr, &helpContext, &helpFileBstr);
+ QString docString = QString::fromUtf16((const ushort *)docStringBstr);
+ QString helpFile = QString::fromUtf16((const ushort *)helpFileBstr);
+ SysFreeString(docStringBstr);
+ SysFreeString(helpFileBstr);
+ if (hres == S_OK) {
+ if (!docString.isEmpty())
+ docu += docString + QLatin1String("\n");
+ if (!helpFile.isEmpty())
+ docu += QString::fromLatin1("For more information, see help context %1 in %2.").arg((uint)helpContext).arg(helpFile);
+ }
+ }
+
+ return docu;
+}
+
+static inline QString docuFromName(ITypeInfo *typeInfo, const QString &name)
+{
+ return QLatin1String("<p>") + qax_docuFromName(typeInfo, name) + QLatin1String("\n");
+}
+
+static QByteArray namedPrototype(const QList<QByteArray> &parameterTypes, const QList<QByteArray> &parameterNames, int numDefArgs = 0)
+{
+ QByteArray prototype("(");
+ for (int p = 0; p < parameterTypes.count(); ++p) {
+ QByteArray type(parameterTypes.at(p));
+ prototype += type;
+
+ if (p < parameterNames.count())
+ prototype += " " + parameterNames.at(p);
+
+ if (numDefArgs >= parameterTypes.count() - p)
+ prototype += " = 0";
+ if (p < parameterTypes.count() - 1)
+ prototype += ", ";
+ }
+ prototype += ")";
+
+ return prototype;
+}
+
+static QByteArray toType(const QByteArray &t)
+{
+ QByteArray type = t;
+ int vartype = QVariant::nameToType(type);
+ if (vartype == QVariant::Invalid)
+ type = "int";
+
+ if (type.at(0) == 'Q')
+ type = type.mid(1);
+ type[0] = toupper(type.at(0));
+ if (type == "VariantList")
+ type = "List";
+ else if (type == "Map<QVariant,QVariant>")
+ type = "Map";
+ else if (type == "Uint")
+ type = "UInt";
+
+ return "to" + type + "()";
+}
+
+QString qax_generateDocumentation(QAxBase *that)
+{
+ that->metaObject();
+
+ if (that->isNull())
+ return QString();
+
+ ITypeInfo *typeInfo = 0;
+ IDispatch *dispatch = 0;
+ that->queryInterface(IID_IDispatch, (void**)&dispatch);
+ if (dispatch)
+ dispatch->GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, &typeInfo);
+
+ QString docu;
+ QTextStream stream(&docu, QIODevice::WriteOnly);
+
+ const QMetaObject *mo = that->metaObject();
+ QString coClass = QLatin1String(mo->classInfo(mo->indexOfClassInfo("CoClass")).value());
+
+ stream << "<h1 align=center>" << coClass << " Reference</h1>" << endl;
+ stream << "<p>The " << coClass << " COM object is a " << that->qObject()->metaObject()->className();
+ stream << " with the CLSID " << that->control() << ".</p>" << endl;
+
+ stream << "<h3>Interfaces</h3>" << endl;
+ stream << "<ul>" << endl;
+ const char *inter = 0;
+ int interCount = 1;
+ while ((inter = mo->classInfo(mo->indexOfClassInfo("Interface " + QByteArray::number(interCount))).value())) {
+ stream << "<li>" << inter << endl;
+ interCount++;
+ }
+ stream << "</ul>" << endl;
+
+ stream << "<h3>Event Interfaces</h3>" << endl;
+ stream << "<ul>" << endl;
+ interCount = 1;
+ while ((inter = mo->classInfo(mo->indexOfClassInfo("Event Interface " + QByteArray::number(interCount))).value())) {
+ stream << "<li>" << inter << endl;
+ interCount++;
+ }
+ stream << "</ul>" << endl;
+
+ QList<QString> methodDetails, propDetails;
+
+ const int slotCount = mo->methodCount();
+ if (slotCount) {
+ stream << "<h2>Public Slots:</h2>" << endl;
+ stream << "<ul>" << endl;
+
+ int defArgCount = 0;
+ for (int islot = mo->methodOffset(); islot < slotCount; ++islot) {
+ const QMetaMethod slot = mo->method(islot);
+ if (slot.methodType() != QMetaMethod::Slot)
+ continue;
+
+ if (slot.attributes() & QMetaMethod::Cloned) {
+ ++defArgCount;
+ continue;
+ }
+
+ QByteArray returntype(slot.typeName());
+ if (returntype.isEmpty())
+ returntype = "void";
+ QByteArray prototype = namedPrototype(slot.parameterTypes(), slot.parameterNames(), defArgCount);
+ QByteArray signature = slot.signature();
+ QByteArray name = signature.left(signature.indexOf('('));
+ stream << "<li>" << returntype << " <a href=\"#" << name << "\"><b>" << name << "</b></a>" << prototype << ";</li>" << endl;
+
+ prototype = namedPrototype(slot.parameterTypes(), slot.parameterNames());
+ QString detail = QString::fromLatin1("<h3><a name=") + QString::fromLatin1(name.constData()) + QLatin1String("></a>") +
+ QString::fromLatin1(returntype.constData()) + QLatin1String(" ") +
+ QString::fromLatin1(name.constData()) + QLatin1String(" ") +
+ QString::fromLatin1(prototype.constData()) + QLatin1String("<tt> [slot]</tt></h3>\n");
+ prototype = namedPrototype(slot.parameterTypes(), QList<QByteArray>());
+ detail += docuFromName(typeInfo, QString::fromLatin1(name.constData()));
+ detail += QLatin1String("<p>Connect a signal to this slot:<pre>\n");
+ detail += QString::fromLatin1("\tQObject::connect(sender, SIGNAL(someSignal") + QString::fromLatin1(prototype.constData()) +
+ QLatin1String("), object, SLOT(") + QString::fromLatin1(name.constData()) +
+ QString::fromLatin1(prototype.constData()) + QLatin1String("));");
+ detail += QLatin1String("</pre>\n");
+
+ if (1) {
+ detail += QLatin1String("<p>Or call the function directly:<pre>\n");
+
+ bool hasParams = slot.parameterTypes().count() != 0;
+ if (hasParams)
+ detail += QLatin1String("\tQVariantList params = ...\n");
+ detail += QLatin1String("\t");
+ QByteArray functionToCall = "dynamicCall";
+ if (returntype == "IDispatch*" || returntype == "IUnknown*") {
+ functionToCall = "querySubObject";
+ returntype = "QAxObject *";
+ }
+ if (returntype != "void")
+ detail += QString::fromLatin1(returntype.constData()) + QLatin1String(" result = ");
+ detail += QLatin1String("object->") + QString::fromLatin1(functionToCall.constData()) +
+ QLatin1String("(\"" + name + prototype + "\"");
+ if (hasParams)
+ detail += QLatin1String(", params");
+ detail += QLatin1String(")");
+ if (returntype != "void" && returntype != "QAxObject *" && returntype != "QVariant")
+ detail += QLatin1String(".") + QString::fromLatin1(toType(returntype));
+ detail += QLatin1String(";</pre>\n");
+ } else {
+ detail += QLatin1String("<p>This function has parameters of unsupported types and cannot be called directly.");
+ }
+
+ methodDetails << detail;
+ defArgCount = 0;
+ }
+
+ stream << "</ul>" << endl;
+ }
+ int signalCount = mo->methodCount();
+ if (signalCount) {
+ ITypeLib *typeLib = 0;
+ if (typeInfo) {
+ UINT index = 0;
+ typeInfo->GetContainingTypeLib(&typeLib, &index);
+ typeInfo->Release();
+ }
+ typeInfo = 0;
+
+ stream << "<h2>Signals:</h2>" << endl;
+ stream << "<ul>" << endl;
+
+ for (int isignal = mo->methodOffset(); isignal < signalCount; ++isignal) {
+ const QMetaMethod signal(mo->method(isignal));
+ if (signal.methodType() != QMetaMethod::Signal)
+ continue;
+
+ QByteArray prototype = namedPrototype(signal.parameterTypes(), signal.parameterNames());
+ QByteArray signature = signal.signature();
+ QByteArray name = signature.left(signature.indexOf('('));
+ stream << "<li>void <a href=\"#" << name << "\"><b>" << name << "</b></a>" << prototype << ";</li>" << endl;
+
+ QString detail = QLatin1String("<h3><a name=") + QString::fromLatin1(name.constData()) + QLatin1String("></a>void ") +
+ QString::fromLatin1(name.constData()) + QLatin1String(" ") +
+ QString::fromLatin1(prototype.constData()) + QLatin1String("<tt> [signal]</tt></h3>\n");
+ if (typeLib) {
+ interCount = 0;
+ do {
+ if (typeInfo)
+ typeInfo->Release();
+ typeInfo = 0;
+ typeLib->GetTypeInfo(++interCount, &typeInfo);
+ QString typeLibDocu = docuFromName(typeInfo, QString::fromLatin1(name.constData()));
+ if (!typeLibDocu.isEmpty()) {
+ detail += typeLibDocu;
+ break;
+ }
+ } while (typeInfo);
+ }
+ prototype = namedPrototype(signal.parameterTypes(), QList<QByteArray>());
+ detail += QLatin1String("<p>Connect a slot to this signal:<pre>\n");
+ detail += QLatin1String("\tQObject::connect(object, SIGNAL(") + QString::fromLatin1(name.constData()) +
+ QString::fromLatin1(prototype.constData()) +
+ QLatin1String("), receiver, SLOT(someSlot") + QString::fromLatin1(prototype.constData()) + QLatin1String("));");
+ detail += QLatin1String("</pre>\n");
+
+ methodDetails << detail;
+ if (typeInfo)
+ typeInfo->Release();
+ typeInfo = 0;
+ }
+ stream << "</ul>" << endl;
+
+ if (typeLib)
+ typeLib->Release();
+ }
+
+ const int propCount = mo->propertyCount();
+ if (propCount) {
+ if (dispatch)
+ dispatch->GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, &typeInfo);
+ stream << "<h2>Properties:</h2>" << endl;
+ stream << "<ul>" << endl;
+
+ for (int iprop = 0; iprop < propCount; ++iprop) {
+ const QMetaProperty prop = mo->property(iprop);
+ QByteArray name(prop.name());
+ QByteArray type(prop.typeName());
+
+ stream << "<li>" << type << " <a href=\"#" << name << "\"><b>" << name << "</b></a>;</li>" << endl;
+ QString detail = QLatin1String("<h3><a name=") + QString::fromLatin1(name.constData()) + QLatin1String("></a>") +
+ QString::fromLatin1(type.constData()) +
+ QLatin1String(" ") + QString::fromLatin1(name.constData()) + QLatin1String("</h3>\n");
+ detail += docuFromName(typeInfo, QString::fromLatin1(name));
+ QVariant::Type vartype = QVariant::nameToType(type);
+ if (!prop.isReadable())
+ continue;
+
+ if (prop.isEnumType())
+ vartype = QVariant::Int;
+
+ if (vartype != QVariant::Invalid) {
+ detail += QLatin1String("<p>Read this property's value using QObject::property:<pre>\n");
+ if (prop.isEnumType())
+ detail += QLatin1String("\tint val = ");
+ else
+ detail += QLatin1String("\t") + QString::fromLatin1(type.constData()) + QLatin1String(" val = ");
+ detail += QLatin1String("object->property(\"") + QString::fromLatin1(name.constData()) +
+ QLatin1String("\").") + QString::fromLatin1(toType(type).constData()) + QLatin1String(";\n");
+ detail += QLatin1String("</pre>\n");
+ } else if (type == "IDispatch*" || type == "IUnknown*") {
+ detail += QLatin1String("<p>Get the subobject using querySubObject:<pre>\n");
+ detail += QLatin1String("\tQAxObject *") + QString::fromLatin1(name.constData()) +
+ QLatin1String(" = object->querySubObject(\"") + QString::fromLatin1(name.constData()) + QLatin1String("\");\n");
+ detail += QLatin1String("</pre>\n");
+ } else {
+ detail += QLatin1String("<p>This property is of an unsupported type.\n");
+ }
+ if (prop.isWritable()) {
+ detail += QLatin1String("Set this property' value using QObject::setProperty:<pre>\n");
+ if (prop.isEnumType()) {
+ detail += QLatin1String("\tint newValue = ... // string representation of values also supported\n");
+ } else {
+ detail += QLatin1String("\t") + QString::fromLatin1(type.constData()) + QLatin1String(" newValue = ...\n");
+ }
+ detail += QLatin1String("\tobject->setProperty(\"") + QString::fromLatin1(name) + QLatin1String("\", newValue);\n");
+ detail += QLatin1String("</pre>\n");
+ detail += QLatin1String("Or using the ");
+ QByteArray setterSlot;
+ if (isupper(name.at(0))) {
+ setterSlot = "Set" + name;
+ } else {
+ QByteArray nameUp = name;
+ nameUp[0] = toupper(nameUp.at(0));
+ setterSlot = "set" + nameUp;
+ }
+ detail += QLatin1String("<a href=\"#") + QString::fromLatin1(setterSlot) + QLatin1String("\">") +
+ QString::fromLatin1(setterSlot.constData()) + QLatin1String("</a> slot.\n");
+ }
+ if (prop.isEnumType()) {
+ detail += QLatin1String("<p>See also <a href=\"#") + QString::fromLatin1(type) +
+ QLatin1String("\">") + QString::fromLatin1(type) + QLatin1String("</a>.\n");
+ }
+
+ propDetails << detail;
+ }
+ stream << "</ul>" << endl;
+ }
+
+ const int enumCount = mo->enumeratorCount();
+ if (enumCount) {
+ stream << "<hr><h2>Member Type Documentation</h2>" << endl;
+ for (int i = 0; i < enumCount; ++i) {
+ const QMetaEnum enumdata = mo->enumerator(i);
+ stream << "<h3><a name=" << enumdata.name() << "></a>" << enumdata.name() << "</h3>" << endl;
+ stream << "<ul>" << endl;
+ for (int e = 0; e < enumdata.keyCount(); ++e) {
+ stream << "<li>" << enumdata.key(e) << "\t=" << enumdata.value(e) << "</li>" << endl;
+ }
+ stream << "</ul>" << endl;
+ }
+ }
+ if (methodDetails.count()) {
+ stream << "<hr><h2>Member Function Documentation</h2>" << endl;
+ for (int i = 0; i < methodDetails.count(); ++i)
+ stream << methodDetails.at(i) << endl;
+ }
+ if (propDetails.count()) {
+ stream << "<hr><h2>Property Documentation</h2>" << endl;
+ for (int i = 0; i < propDetails.count(); ++i)
+ stream << propDetails.at(i) << endl;
+ }
+
+ if (typeInfo)
+ typeInfo->Release();
+ if (dispatch)
+ dispatch->Release();
+ return docu;
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_WIN_ACTIVEQT
diff --git a/src/activeqt/container/qaxobject.cpp b/src/activeqt/container/qaxobject.cpp
new file mode 100644
index 0000000..bd71dfa
--- /dev/null
+++ b/src/activeqt/container/qaxobject.cpp
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** 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 UNICODE
+#define UNICODE
+#endif
+
+#include "qaxobject.h"
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+#include <quuid.h>
+#include <qmetaobject.h>
+#include <qstringlist.h>
+
+#include <windows.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAxObject
+ \brief The QAxObject class provides a QObject that wraps a COM object.
+
+ \inmodule QAxContainer
+
+ A QAxObject can be instantiated as an empty object, with the name
+ of the COM object it should wrap, or with a pointer to the
+ IUnknown that represents an existing COM object. If the COM object
+ implements the \c IDispatch interface, the properties, methods and
+ events of that object become available as Qt properties, slots and
+ signals. The base class, QAxBase, provides an API to access the
+ COM object directly through the IUnknown pointer.
+
+ QAxObject is a QObject and can be used as such, e.g. it can be
+ organized in an object hierarchy, receive events and connect to
+ signals and slots.
+
+ QAxObject also inherits most of its ActiveX-related functionality
+ from QAxBase, notably dynamicCall() and querySubObject().
+
+ \warning
+ You can subclass QAxObject, but you cannot use the Q_OBJECT macro
+ in the subclass (the generated moc-file will not compile), so you
+ cannot add further signals, slots or properties. This limitation is
+ due to the metaobject information generated in runtime.
+ To work around this problem, aggregate the QAxObject as a member of
+ the QObject subclass.
+
+ \sa QAxBase, QAxWidget, QAxScript, {ActiveQt Framework}
+*/
+
+/*!
+ Creates an empty COM object and propagates \a parent to the
+ QObject constructor. To initialize the object, call \link
+ QAxBase::setControl() setControl \endlink.
+*/
+QAxObject::QAxObject(QObject *parent)
+: QObject(parent)
+{
+}
+
+/*!
+ Creates a QAxObject that wraps the COM object \a c. \a parent is
+ propagated to the QObject constructor.
+
+ \sa setControl()
+*/
+QAxObject::QAxObject(const QString &c, QObject *parent)
+: QObject(parent)
+{
+ setControl(c);
+}
+
+/*!
+ Creates a QAxObject that wraps the COM object referenced by \a
+ iface. \a parent is propagated to the QObject constructor.
+*/
+QAxObject::QAxObject(IUnknown *iface, QObject *parent)
+: QObject(parent), QAxBase(iface)
+{
+}
+
+/*!
+ Releases the COM object and destroys the QAxObject,
+ cleaning up all allocated resources.
+*/
+QAxObject::~QAxObject()
+{
+ clear();
+}
+
+/*!
+ \reimp
+*/
+const QMetaObject *QAxObject::metaObject() const
+{
+ return QAxBase::metaObject();
+}
+
+/*!
+ \reimp
+*/
+const QMetaObject *QAxObject::parentMetaObject() const
+{
+ return &QObject::staticMetaObject;
+}
+
+/*!
+ \internal
+*/
+void *QAxObject::qt_metacast(const char *cname)
+{
+ if (!qstrcmp(cname, "QAxObject")) return (void*)this;
+ if (!qstrcmp(cname, "QAxBase")) return (QAxBase*)this;
+ return QObject::qt_metacast(cname);
+}
+
+/*!
+ \reimp
+*/
+const char *QAxObject::className() const
+{
+ return "QAxObject";
+}
+
+/*!
+ \reimp
+*/
+int QAxObject::qt_metacall(QMetaObject::Call call, int id, void **v)
+{
+ id = QObject::qt_metacall(call, id, v);
+ if (id < 0)
+ return id;
+ return QAxBase::qt_metacall(call, id, v);
+}
+
+/*!
+ \fn QObject *QAxObject::qObject() const
+ \internal
+*/
+
+/*!
+ \reimp
+*/
+void QAxObject::connectNotify(const char *)
+{
+ QAxBase::connectNotify();
+}
+
+/*!
+ \since 4.1
+
+ Requests the COM object to perform the action \a verb. The
+ possible verbs are returned by verbs().
+
+ The function returns true if the object could perform the action, otherwise returns false.
+*/
+bool QAxObject::doVerb(const QString &verb)
+{
+ if (!verbs().contains(verb))
+ return false;
+ IOleObject *ole = 0;
+ queryInterface(IID_IOleObject, (void**)&ole);
+ if (!ole)
+ return false;
+
+ LONG index = indexOfVerb(verb);
+
+ HRESULT hres = ole->DoVerb(index, 0, 0, 0, 0, 0);
+
+ ole->Release();
+
+ return hres == S_OK;
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_WIN_ACTIVEQT
diff --git a/src/activeqt/container/qaxobject.h b/src/activeqt/container/qaxobject.h
new file mode 100644
index 0000000..ffa2087
--- /dev/null
+++ b/src/activeqt/container/qaxobject.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** 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 QAXOBJECT_H
+#define QAXOBJECT_H
+
+#include <ActiveQt/qaxbase.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(ActiveQt)
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+class QAxObject : public QObject, public QAxBase
+{
+ friend class QAxEventSink;
+public:
+ const QMetaObject *metaObject() const;
+ void* qt_metacast(const char*);
+ int qt_metacall(QMetaObject::Call, int, void **);
+ QObject* qObject() const { return (QObject*)this; }
+ const char *className() const;
+
+ QAxObject(QObject *parent = 0);
+ QAxObject(const QString &c, QObject *parent = 0);
+ QAxObject(IUnknown *iface, QObject *parent = 0);
+ ~QAxObject();
+
+ bool doVerb(const QString &verb);
+
+protected:
+ void connectNotify(const char *signal);
+
+private:
+ const QMetaObject *parentMetaObject() const;
+ static QMetaObject staticMetaObject;
+};
+
+#if defined Q_CC_MSVC && _MSC_VER < 1300
+template <> inline QAxObject *qobject_cast_helper<QAxObject*>(const QObject *o, QAxObject *)
+#else
+template <> inline QAxObject *qobject_cast<QAxObject*>(const QObject *o)
+#endif
+{
+ void *result = o ? const_cast<QObject *>(o)->qt_metacast("QAxObject") : 0;
+ return (QAxObject*)(result);
+}
+
+#if defined Q_CC_MSVC && _MSC_VER < 1300
+template <> inline QAxObject *qobject_cast_helper<QAxObject*>(QObject *o, QAxObject *)
+#else
+template <> inline QAxObject *qobject_cast<QAxObject*>(QObject *o)
+#endif
+{
+ void *result = o ? o->qt_metacast("QAxObject") : 0;
+ return (QAxObject*)(result);
+}
+
+QT_END_NAMESPACE
+Q_DECLARE_METATYPE(QAxObject*)
+
+#endif // QT_NO_WIN_ACTIVEQT
+
+QT_END_HEADER
+
+#endif // QAXOBJECT_H
diff --git a/src/activeqt/container/qaxscript.cpp b/src/activeqt/container/qaxscript.cpp
new file mode 100644
index 0000000..c69fea0
--- /dev/null
+++ b/src/activeqt/container/qaxscript.cpp
@@ -0,0 +1,1293 @@
+/****************************************************************************
+**
+** 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 UNICODE
+#define UNICODE
+#endif
+
+#include "qaxscript.h"
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+#if defined(Q_CC_GNU)
+# define QT_NO_QAXSCRIPT
+#elif defined(Q_CC_BOR) && __BORLANDC__ < 0x560
+# define QT_NO_QAXSCRIPT
+#endif
+
+#include <qapplication.h>
+#include <qfile.h>
+#include <qhash.h>
+#include <qmetaobject.h>
+#include <quuid.h>
+#include <qwidget.h>
+
+#include <qt_windows.h>
+#ifndef QT_NO_QAXSCRIPT
+#include <initguid.h>
+#include <activscp.h>
+#endif
+
+#include "../shared/qaxtypes.h"
+
+QT_BEGIN_NAMESPACE
+
+struct QAxEngineDescriptor { QString name, extension, code; };
+static QList<QAxEngineDescriptor> engines;
+
+class QAxScriptManagerPrivate
+{
+public:
+ QHash<QString, QAxScript*> scriptDict;
+ QHash<QString, QAxBase*> objectDict;
+};
+
+/*
+ \class QAxScriptSite
+ \brief The QAxScriptSite class implements a Windows Scripting Host
+ \internal
+
+ The QAxScriptSite is used internally to communicate callbacks from the script
+ engine to the script manager.
+*/
+
+#ifndef QT_NO_QAXSCRIPT
+
+class QAxScriptSite : public IActiveScriptSite, public IActiveScriptSiteWindow
+{
+public:
+ QAxScriptSite(QAxScript *script);
+
+ ULONG WINAPI AddRef();
+ ULONG WINAPI Release();
+ HRESULT WINAPI QueryInterface(REFIID iid, void **ppvObject);
+
+ HRESULT WINAPI GetLCID(LCID *plcid);
+ HRESULT WINAPI GetItemInfo(LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti);
+ HRESULT WINAPI GetDocVersionString(BSTR *pbstrVersion);
+
+ HRESULT WINAPI OnScriptTerminate(const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo);
+ HRESULT WINAPI OnStateChange(SCRIPTSTATE ssScriptState);
+ HRESULT WINAPI OnScriptError(IActiveScriptError *pscripterror);
+ HRESULT WINAPI OnEnterScript();
+ HRESULT WINAPI OnLeaveScript();
+
+ HRESULT WINAPI GetWindow(HWND *phwnd);
+ HRESULT WINAPI EnableModeless(BOOL fEnable);
+
+protected:
+ QWidget *window() const;
+
+private:
+ QAxScript *script;
+ unsigned long ref;
+};
+
+/*
+ Constructs the site for the \a s.
+*/
+QAxScriptSite::QAxScriptSite(QAxScript *s)
+: script(s), ref(1)
+{
+}
+
+/*
+ Implements IUnknown::AddRef
+*/
+ULONG WINAPI QAxScriptSite::AddRef()
+{
+ return ++ref;
+}
+
+/*
+ Implements IUnknown::Release
+*/
+ULONG WINAPI QAxScriptSite::Release()
+{
+ if (!--ref) {
+ delete this;
+ return 0;
+ }
+ return ref;
+}
+
+/*
+ Implements IUnknown::QueryInterface
+*/
+HRESULT WINAPI QAxScriptSite::QueryInterface(REFIID iid, void **ppvObject)
+{
+ *ppvObject = 0;
+ if (iid == IID_IUnknown)
+ *ppvObject = (IUnknown*)(IActiveScriptSite*)this;
+ else if (iid == IID_IActiveScriptSite)
+ *ppvObject = (IActiveScriptSite*)this;
+ else if (iid == IID_IActiveScriptSiteWindow)
+ *ppvObject = (IActiveScriptSiteWindow*)this;
+ else
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+}
+
+/*
+ Implements IActiveScriptSite::GetLCID
+
+ This method is not implemented. Use the system-defined locale.
+*/
+HRESULT WINAPI QAxScriptSite::GetLCID(LCID * /*plcid*/)
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Implements IActiveScriptSite::GetItemInfo
+
+ Tries to find the QAxBase for \a pstrName and returns the
+ relevant interfaces in \a item and \a type as requested through \a mask.
+*/
+HRESULT WINAPI QAxScriptSite::GetItemInfo(LPCOLESTR pstrName, DWORD mask, IUnknown **item, ITypeInfo **type)
+{
+ if (item)
+ *item = 0;
+ else if (mask & SCRIPTINFO_IUNKNOWN)
+ return E_POINTER;
+
+ if (type)
+ *type = 0;
+ else if (mask & SCRIPTINFO_ITYPEINFO)
+ return E_POINTER;
+
+ QAxBase *object = script->findObject(QString::fromUtf16((const ushort*)pstrName));
+ if (!object)
+ return TYPE_E_ELEMENTNOTFOUND;
+
+ if (mask & SCRIPTINFO_IUNKNOWN)
+ object->queryInterface(IID_IUnknown, (void**)item);
+ if (mask & SCRIPTINFO_ITYPEINFO) {
+ IProvideClassInfo *classInfo = 0;
+ object->queryInterface(IID_IProvideClassInfo, (void**)&classInfo);
+ if (classInfo) {
+ classInfo->GetClassInfo(type);
+ classInfo->Release();
+ }
+ }
+ return S_OK;
+}
+
+/*
+ Implements IActiveScriptSite::GetDocVersionString
+
+ This method is not implemented. The scripting engine should assume
+ that the script is in sync with the document.
+*/
+HRESULT WINAPI QAxScriptSite::GetDocVersionString(BSTR * /*version*/)
+{
+ return E_NOTIMPL;
+}
+
+/*
+ Implements IActiveScriptSite::OnScriptTerminate
+
+ This method is usually not called, but if it is it fires
+ QAxScript::finished().
+*/
+HRESULT WINAPI QAxScriptSite::OnScriptTerminate(const VARIANT *result, const EXCEPINFO *exception)
+{
+ emit script->finished();
+
+ if (result && result->vt != VT_EMPTY)
+ emit script->finished(VARIANTToQVariant(*result, 0));
+ if (exception)
+ emit script->finished(exception->wCode,
+ QString::fromUtf16((const ushort*)exception->bstrSource),
+ QString::fromUtf16((const ushort*)exception->bstrDescription),
+ QString::fromUtf16((const ushort*)exception->bstrHelpFile)
+ );
+ return S_OK;
+}
+
+/*
+ Implements IActiveScriptSite::OnEnterScript
+
+ Fires QAxScript::entered() to inform the host that the
+ scripting engine has begun executing the script code.
+*/
+HRESULT WINAPI QAxScriptSite::OnEnterScript()
+{
+ emit script->entered();
+ return S_OK;
+}
+
+/*
+ Implements IActiveScriptSite::OnLeaveScript
+
+ Fires QAxScript::finished() to inform the host that the
+ scripting engine has returned from executing the script code.
+*/
+HRESULT WINAPI QAxScriptSite::OnLeaveScript()
+{
+ emit script->finished();
+ return S_OK;
+}
+
+/*
+ Implements IActiveScriptSite::OnScriptError
+
+ Fires QAxScript::error() to inform the host that an
+ that an execution error occurred while the engine was running the script.
+*/
+HRESULT WINAPI QAxScriptSite::OnScriptError(IActiveScriptError *error)
+{
+ EXCEPINFO exception;
+ memset(&exception, 0, sizeof(exception));
+ DWORD context;
+ ULONG lineNumber;
+ LONG charPos;
+ BSTR bstrLineText;
+ QString lineText;
+
+ error->GetExceptionInfo(&exception);
+ error->GetSourcePosition(&context, &lineNumber, &charPos);
+ HRESULT hres = error->GetSourceLineText(&bstrLineText);
+ if (hres == S_OK) {
+ lineText = QString::fromUtf16((const ushort*)bstrLineText);
+ SysFreeString(bstrLineText);
+ }
+ SysFreeString(exception.bstrSource);
+ SysFreeString(exception.bstrDescription);
+ SysFreeString(exception.bstrHelpFile);
+
+ emit script->error(exception.wCode, QString::fromUtf16((const ushort*)exception.bstrDescription), lineNumber, lineText);
+
+ return S_OK;
+}
+
+/*
+ Implements IActiveScriptSite::OnStateChange
+
+ Fires QAxScript::stateChanged() to inform the
+ the host that the scripting engine has changed states.
+*/
+HRESULT WINAPI QAxScriptSite::OnStateChange(SCRIPTSTATE ssScriptState)
+{
+ emit script->stateChanged(ssScriptState);
+ return S_OK;
+}
+
+/*
+ \internal
+ Returns the toplevel widget parent of this script, or
+ the application' active window if there is no widget parent.
+*/
+QWidget *QAxScriptSite::window() const
+{
+ QWidget *w = 0;
+ QObject *p = script->parent();
+ while (!w && p) {
+ w = qobject_cast<QWidget*>(p);
+ p = p->parent();
+ }
+
+ if (w)
+ w = w->window();
+ if (!w && qApp)
+ w = qApp->activeWindow();
+
+ return w;
+}
+
+/*
+ Implements IActiveScriptSiteWindow::GetWindow
+
+ Retrieves the handle to a window that can act as the owner of a
+ pop-up window that the scripting engine must display.
+*/
+HRESULT WINAPI QAxScriptSite::GetWindow(HWND *phwnd)
+{
+ if (!phwnd)
+ return E_POINTER;
+
+ *phwnd = 0;
+ QWidget *w = window();
+ if (!w)
+ return E_FAIL;
+
+ *phwnd = w->winId();
+ return S_OK;
+}
+
+/*
+ Implements IActiveScriptSiteWindow::EnableModeless
+
+ Causes the host to enable or disable its main window
+ as well as any modeless dialog boxes.
+*/
+HRESULT WINAPI QAxScriptSite::EnableModeless(BOOL fEnable)
+{
+ QWidget *w = window();
+ if (!w)
+ return E_FAIL;
+
+ EnableWindow(w->winId(), fEnable);
+ return S_OK;
+}
+
+#endif //QT_NO_QAXSCRIPT
+
+
+/*!
+ \class QAxScriptEngine
+ \brief The QAxScriptEngine class provides a wrapper around a script engine.
+ \inmodule QAxContainer
+
+ Every instance of the QAxScriptEngine class represents an interpreter
+ for script code in a particular scripting language. The class is usually
+ not used directly. The QAxScript and QAxScriptManager classes provide
+ convenient functions to handle and call script code.
+
+ Direct access to the script engine is provided through
+ queryInterface().
+
+ \warning This class is not available with the bcc5.5 and MingW
+ compilers.
+
+ \sa QAxScript, QAxScriptManager, QAxBase, {ActiveQt Framework}
+*/
+
+/*!
+ \enum QAxScriptEngine::State
+
+ The State enumeration defines the different states a script
+ engine can be in.
+
+ \value Uninitialized The script has been created, but not yet initialized
+ \value Initialized The script has been initialized, but is not running
+ \value Started The script can execute code, but does not yet handle events
+ \value Connected The script can execute code and is connected so
+ that it can handle events
+ \value Disconnected The script is loaded, but is not connected to
+ event sources
+ \value Closed The script has been closed.
+*/
+
+/*!
+ Constructs a QAxScriptEngine object interpreting script code in \a language
+ provided by the code in \a script. This is usually done by the QAxScript
+ class when \link QAxScript::load() loading a script\endlink.
+
+ Instances of QAxScriptEngine should always have both a language and a
+ script.
+*/
+QAxScriptEngine::QAxScriptEngine(const QString &language, QAxScript *script)
+: QAxObject(script), script_code(script), engine(0), script_language(language)
+{
+#ifdef QT_CHECK_STATE
+ if (language.isEmpty())
+ qWarning("QAxScriptEngine: created without language");
+
+ if (!script_code)
+ qWarning("QAxScriptEngine: created without script");
+#endif
+ setObjectName(QLatin1String("QAxScriptEngine_") + language);
+ disableClassInfo();
+ disableEventSink();
+}
+
+/*!
+ Destroys the QAxScriptEngine object, releasing all allocated
+ resources.
+*/
+QAxScriptEngine::~QAxScriptEngine()
+{
+#ifndef QT_NO_QAXSCRIPT
+ if (engine) {
+ engine->SetScriptState(SCRIPTSTATE_DISCONNECTED);
+ engine->Close();
+ engine->Release();
+ }
+#endif
+}
+
+/*!
+ \fn QString QAxScriptEngine::scriptLanguage() const
+ Returns the scripting language, for example "VBScript",
+ or "JScript".
+*/
+
+/*!
+ \reimp
+*/
+bool QAxScriptEngine::initialize(IUnknown **ptr)
+{
+ *ptr = 0;
+
+#ifndef QT_NO_QAXSCRIPT
+ if (!script_code || script_language.isEmpty())
+ return false;
+
+ CLSID clsid;
+ HRESULT hres = CLSIDFromProgID((WCHAR*)script_language.utf16(), &clsid);
+ if(FAILED(hres))
+ return false;
+
+ CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, IID_IActiveScript, (void**)&engine);
+ if (!engine)
+ return false;
+
+ IActiveScriptParse *parser = 0;
+ engine->QueryInterface(IID_IActiveScriptParse, (void**)&parser);
+ if (!parser) {
+ engine->Release();
+ engine = 0;
+ return false;
+ }
+
+ if (engine->SetScriptSite(script_code->script_site) != S_OK) {
+ engine->Release();
+ engine = 0;
+ return false;
+ }
+ if (parser->InitNew() != S_OK) {
+ parser->Release();
+ engine->Release();
+ engine = 0;
+ return false;
+ }
+
+ BSTR bstrCode = QStringToBSTR(script_code->scriptCode());
+#ifdef Q_OS_WIN64
+ hres = parser->ParseScriptText(bstrCode, 0, 0, 0, DWORDLONG(this), 0, SCRIPTTEXT_ISVISIBLE, 0, 0);
+#else
+ hres = parser->ParseScriptText(bstrCode, 0, 0, 0, DWORD(this), 0, SCRIPTTEXT_ISVISIBLE, 0, 0);
+#endif
+ SysFreeString(bstrCode);
+
+ parser->Release();
+ parser = 0;
+
+ script_code->updateObjects();
+
+ if (engine->SetScriptState(SCRIPTSTATE_CONNECTED) != S_OK) {
+ engine = 0;
+ return false;
+ }
+
+ IDispatch *scriptDispatch = 0;
+ engine->GetScriptDispatch(0, &scriptDispatch);
+ if (scriptDispatch) {
+ scriptDispatch->QueryInterface(IID_IUnknown, (void**)ptr);
+ scriptDispatch->Release();
+ }
+#endif
+
+ return *ptr != 0;
+}
+
+/*!
+ \fn bool QAxScriptEngine::isValid() const
+
+ Returns true if the script engine has been initialized
+ correctly; otherwise returns false.
+*/
+
+/*!
+ Returns true if the script engine supports introspection;
+ otherwise returns false.
+*/
+bool QAxScriptEngine::hasIntrospection() const
+{
+ if (!isValid())
+ return false;
+
+ IDispatch *scriptDispatch = 0;
+ QAxBase::queryInterface(IID_IDispatch, (void**)&scriptDispatch);
+ if (!scriptDispatch)
+ return false;
+
+ UINT tic = 0;
+ HRESULT hres = scriptDispatch->GetTypeInfoCount(&tic);
+ scriptDispatch->Release();
+ return hres == S_OK && tic > 0;
+}
+
+/*!
+ Requests the interface \a uuid from the script engine object and
+ sets the value of \a iface to the provided interface, or to 0 if
+ the requested interface could not be provided.
+
+ Returns the result of the QueryInterface implementation of the COM
+ object.
+*/
+long QAxScriptEngine::queryInterface(const QUuid &uuid, void **iface) const
+{
+ *iface = 0;
+ if (!engine)
+ return E_NOTIMPL;
+
+#ifndef QT_NO_QAXSCRIPT
+ return engine->QueryInterface(uuid, iface);
+#else
+ return E_NOTIMPL;
+#endif
+}
+
+/*!
+ Returns the state of the script engine.
+*/
+QAxScriptEngine::State QAxScriptEngine::state() const
+{
+ if (!engine)
+ return Uninitialized;
+
+#ifndef QT_NO_QAXSCRIPT
+ SCRIPTSTATE state;
+ engine->GetScriptState(&state);
+ return (State)state;
+#else
+ return Uninitialized;
+#endif
+}
+
+/*!
+ Sets the state of the script engine to \a st.
+ Calling this function is usually not necessary.
+*/
+void QAxScriptEngine::setState(State st)
+{
+#ifndef QT_NO_QAXSCRIPT
+ if (!engine)
+ return;
+
+ engine->SetScriptState((SCRIPTSTATE)st);
+#endif
+}
+
+/*!
+ Registers an item with the script engine. Script code can
+ refer to this item using \a name.
+*/
+void QAxScriptEngine::addItem(const QString &name)
+{
+#ifndef QT_NO_QAXSCRIPT
+ if (!engine)
+ return;
+
+ engine->AddNamedItem((WCHAR*)name.utf16(), SCRIPTITEM_ISSOURCE|SCRIPTITEM_ISVISIBLE);
+#endif
+}
+
+/*!
+ \class QAxScript
+ \brief The QAxScript class provides a wrapper around script code.
+ \inmodule QAxContainer
+
+ Every instance of the QAxScript class represents a piece of
+ scripting code in a particular scripting language. The code is
+ loaded into the script engine using load(). Functions declared
+ in the code can be called using call().
+
+ The script provides scriptEngine() provides feedback to the
+ application through signals. The most important signal is the
+ error() signal. Direct access to the QAxScriptEngine is provided
+ through the scriptEngine() function.
+
+ \warning This class is not available with the bcc5.5 and MingW
+ compilers.
+
+ \sa QAxScriptEngine, QAxScriptManager, QAxBase, {ActiveQt Framework}
+*/
+
+/*!
+ \enum QAxScript::FunctionFlags
+
+ This FunctionFlags enum describes formatting for function introspection.
+
+ \value FunctionNames Only function names are returned.
+ \value FunctionSignatures Returns the functions with signatures.
+*/
+
+/*!
+ Constructs a QAxScript object called \a name and registers
+ it with the QAxScriptManager \a manager. This is usually done by the
+ QAxScriptManager class when \link QAxScriptManager::load() loading a
+ script\endlink.
+
+ A script should always have a name. A manager is necessary to allow
+ the script code to reference objects in the application. The \a manager
+ takes ownership of the object.
+*/
+QAxScript::QAxScript(const QString &name, QAxScriptManager *manager)
+: QObject(manager), script_name(name), script_manager(manager),
+script_engine(0)
+{
+ if (manager) {
+ manager->d->scriptDict.insert(name, this);
+ connect(this, SIGNAL(error(int,QString,int,QString)),
+ manager, SLOT(scriptError(int,QString,int,QString)));
+ }
+
+#ifndef QT_NO_QAXSCRIPT
+ script_site = new QAxScriptSite(this);
+#else
+ script_site = 0;
+#endif
+}
+
+/*!
+ Destroys the object, releasing all allocated resources.
+*/
+QAxScript::~QAxScript()
+{
+ delete script_engine;
+ script_engine = 0;
+
+#ifndef QT_NO_QAXSCRIPT
+ script_site->Release();
+#endif
+}
+
+/*!
+ Loads the script source \a code written in language \a language
+ into the script engine. Returns true if \a code was successfully
+ entered into the script engine; otherwise returns false.
+
+ If \a language is empty (the default) it will be determined
+ heuristically. If \a code contains the string \c {End Sub} it will
+ be interpreted as VBScript, otherwise as JScript. Additional
+ scripting languages can be registered using
+ QAxScript::registerEngine().
+
+ This function can only be called once for each QAxScript object,
+ which is done automatically when using QAxScriptManager::load().
+*/
+bool QAxScript::load(const QString &code, const QString &language)
+{
+ if (script_engine || code.isEmpty())
+ return false;
+
+ script_code = code;
+ QString lang = language;
+ if (lang.isEmpty()) {
+ if (code.contains(QLatin1String("End Sub"), Qt::CaseInsensitive))
+ lang = QLatin1String("VBScript");
+
+ QList<QAxEngineDescriptor>::ConstIterator it;
+ for (it = engines.begin(); it != engines.end(); ++it) {
+ QAxEngineDescriptor engine = *it;
+ if (engine.code.isEmpty())
+ continue;
+
+ if (code.contains(engine.code)) {
+ lang = engine.name;
+ break;
+ }
+ }
+ }
+ if (lang.isEmpty())
+ lang = QLatin1String("JScript");
+
+ script_engine = new QAxScriptEngine(lang, this);
+ // trigger call to initialize
+ script_engine->metaObject();
+
+ return script_engine->isValid();
+}
+
+/*!
+ Returns a list of all the functions in this script if the respective
+ script engine supports introspection; otherwise returns an empty list.
+ The functions are either provided with full prototypes or only as
+ names, depending on the value of \a flags.
+
+ \sa QAxScriptEngine::hasIntrospection()
+*/
+QStringList QAxScript::functions(FunctionFlags flags) const
+{
+ QStringList functions;
+
+ const QMetaObject *mo = script_engine->metaObject();
+ for (int i = mo->methodOffset(); i < mo->methodCount(); ++i) {
+ const QMetaMethod slot(mo->method(i));
+ if (slot.methodType() != QMetaMethod::Slot || slot.access() != QMetaMethod::Public)
+ continue;
+ QString slotname = QString::fromLatin1(slot.signature());
+ if (slotname.contains(QLatin1Char('_')))
+ continue;
+
+ if (flags == FunctionSignatures)
+ functions << slotname;
+ else
+ functions << slotname.left(slotname.indexOf(QLatin1Char('(')));
+ }
+
+ return functions;
+}
+
+/*!
+ Calls \a function, passing the parameters \a var1, \a var1,
+ \a var2, \a var3, \a var4, \a var5, \a var6, \a var7 and \a var8
+ as arguments and returns the value returned by the function, or an
+ invalid QVariant if the function does not return a value or when
+ the function call failed.
+
+ See QAxScriptManager::call() for more information about how to call
+ script functions.
+*/
+QVariant QAxScript::call(const QString &function, const QVariant &var1,
+ const QVariant &var2,
+ const QVariant &var3,
+ const QVariant &var4,
+ const QVariant &var5,
+ const QVariant &var6,
+ const QVariant &var7,
+ const QVariant &var8)
+{
+ if (!script_engine)
+ return QVariant();
+
+ return script_engine->dynamicCall(function.toLatin1(), var1, var2, var3, var4, var5, var6, var7, var8);
+}
+
+/*!
+ \overload
+
+ Calls \a function passing \a arguments as parameters, and returns
+ the result. Returns when the script's execution has finished.
+
+ See QAxScriptManager::call() for more information about how to call
+ script functions.
+*/
+QVariant QAxScript::call(const QString &function, QList<QVariant> &arguments)
+{
+ if (!script_engine)
+ return QVariant();
+
+ return script_engine->dynamicCall(function.toLatin1(), arguments);
+}
+
+/*! \internal
+ Registers all objects in the manager with the script engine.
+*/
+void QAxScript::updateObjects()
+{
+ if (!script_manager)
+ return;
+
+ script_manager->updateScript(this);
+}
+
+/*! \internal
+ Returns the object \a name registered with the manager.
+*/
+QAxBase *QAxScript::findObject(const QString &name)
+{
+ if (!script_manager)
+ return 0;
+
+ return script_manager->d->objectDict.value(name);
+}
+
+/*! \fn QString QAxScript::scriptName() const
+ Returns the name of the script.
+*/
+
+/*! \fn QString QAxScript::scriptCode() const
+ Returns the script's code, or the null-string if no
+ code has been loaded yet.
+
+ \sa load()
+*/
+
+/*! \fn QAxScriptEngine* QAxScript::scriptEngine() const
+ Returns a pointer to the script engine.
+
+ You can use the object returned to connect signals to the
+ script functions, or to access the script engine directly.
+*/
+
+/*! \fn void QAxScript::entered()
+
+ This signal is emitted when a script engine has started executing code.
+*/
+
+/*! \fn void QAxScript::finished()
+
+ This signal is emitted when a script engine has finished executing code.
+*/
+
+/*!
+ \fn void QAxScript::finished(const QVariant &result)
+ \overload
+
+ \a result contains the script's result. This will be an invalid
+ QVariant if the script has no return value.
+*/
+
+/*! \fn void QAxScript::finished(int code, const QString &source,
+ const QString &description, const QString &help)
+ \overload
+
+ \a code, \a source, \a description and \a help contain exception information
+ when the script terminated.
+*/
+
+/*! \fn void QAxScript::stateChanged(int state);
+
+ This signal is emitted when a script engine changes state.
+ \a state can be any value in the QAxScriptEngineState enumeration.
+*/
+
+/*!
+ \fn void QAxScript::error(int code, const QString &description,
+ int sourcePosition, const QString &sourceText)
+
+ This signal is emitted when an execution error occurred while
+ running a script.
+
+ \a code, \a description, \a sourcePosition and \a sourceText
+ contain information about the execution error.
+*/
+
+
+
+/*!
+ \class QAxScriptManager
+ \brief The QAxScriptManager class provides a bridge between application objects
+ and script code.
+ \inmodule QAxContainer
+
+ The QAxScriptManager acts as a bridge between the COM objects embedded
+ in the Qt application through QAxObject or QAxWidget, and the scripting
+ languages available through the Windows Script technologies, usually JScript
+ and VBScript.
+
+ Create one QAxScriptManager for each separate document in your
+ application, and add the COM objects the scripts need to access
+ using addObject(). Then load() the script sources and invoke the
+ functions using call().
+
+ \warning This class is not available with the bcc5.5 and MingW
+ compilers.
+
+ \sa QAxScript, QAxScriptEngine, QAxBase, {ActiveQt Framework}
+*/
+
+/*!
+ Creates a QAxScriptManager object. \a parent is passed on to the
+ QObject constructor.
+
+ It is usual to create one QAxScriptManager for each document in an
+ application.
+*/
+QAxScriptManager::QAxScriptManager(QObject *parent)
+: QObject(parent)
+{
+ d = new QAxScriptManagerPrivate;
+}
+
+/*!
+ Destroys the objects, releasing all allocated resources.
+*/
+QAxScriptManager::~QAxScriptManager()
+{
+ delete d;
+}
+
+/*!
+ Returns a list with all the functions that are available.
+ Functions provided by script engines that don't support
+ introspection are not included in the list.
+ The functions are either provided with full prototypes or
+ only as names, depending on the value of \a flags.
+*/
+QStringList QAxScriptManager::functions(QAxScript::FunctionFlags flags) const
+{
+ QStringList functions;
+
+ QHash<QString, QAxScript*>::ConstIterator scriptIt;
+ for (scriptIt = d->scriptDict.begin(); scriptIt != d->scriptDict.end(); ++scriptIt) {
+ QAxScript *script = scriptIt.value();
+ functions += script->functions(flags);
+ }
+
+ return functions;
+}
+
+/*!
+ Returns a list with the names of all the scripts.
+*/
+QStringList QAxScriptManager::scriptNames() const
+{
+ QStringList scripts;
+
+ QHash<QString, QAxScript*>::ConstIterator scriptIt;
+ for (scriptIt = d->scriptDict.begin(); scriptIt != d->scriptDict.end(); ++scriptIt) {
+ scripts << scriptIt.key();
+ }
+
+ return scripts;
+}
+
+/*!
+ Returns the script called \a name.
+
+ You can use the returned pointer to call functions directly
+ through QAxScript::call(), to access the script engine directly, or
+ to delete and thus unload the script.
+*/
+QAxScript *QAxScriptManager::script(const QString &name) const
+{
+ return d->scriptDict.value(name);
+}
+
+/*!
+ Adds \a object to the manager. Scripts handled by this manager
+ can access the object in the code using the object's
+ \l{QObject::objectName}{objectName} property.
+
+ You must add all the necessary objects before loading any scripts.
+*/
+void QAxScriptManager::addObject(QAxBase *object)
+{
+ QObject *obj = object->qObject();
+ QString name = obj->objectName();
+ if (d->objectDict.contains(name))
+ return;
+
+ d->objectDict.insert(name, object);
+ connect(obj, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*)));
+}
+
+/*! \fn void QAxScriptManager::addObject(QObject *object)
+ \overload
+
+ Adds a generic COM wrapper for \a object to the manager. \a object
+ must be exposed as a COM object using the functionality provided
+ by the QAxServer module. Applications
+ using this function you must link against the qaxserver library.
+*/
+
+/*!
+ Loads the script source \a code using the script engine for \a
+ language. The script can later be referred to using its \a name
+ which should not be empty.
+
+ The function returns a pointer to the script for the given
+ \a code if the \a code was loaded successfully; otherwise it
+ returns 0.
+
+ If \a language is empty it will be determined heuristically. If \a
+ code contains the string "End Sub" it will be interpreted as
+ VBScript, otherwise as JScript. Additional script engines can be
+ registered using registerEngine().
+
+ You must add all the objects necessary (using addObject()) \e
+ before loading any scripts. If \a code declares a function that is
+ already available (no matter in which language) the first function
+ is overloaded and can no longer be called via call(); but it will
+ still be available by calling its \link script() script \endlink
+ directly.
+
+ \sa addObject(), scriptNames(), functions()
+*/
+QAxScript *QAxScriptManager::load(const QString &code, const QString &name, const QString &language)
+{
+ QAxScript *script = new QAxScript(name, this);
+ if (script->load(code, language))
+ return script;
+
+ delete script;
+ return 0;
+}
+
+/*!
+ \overload
+
+ Loads the source code from the \a file. The script can later be
+ referred to using its \a name which should not be empty.
+
+ The function returns a pointer to the script engine for the code
+ in \a file if \a file was loaded successfully; otherwise it
+ returns 0.
+
+ The script engine used is determined from the file's extension. By
+ default ".js" files are interpreted as JScript files, and ".vbs"
+ and ".dsm" files are interpreted as VBScript. Additional script
+ engines can be registered using registerEngine().
+*/
+QAxScript *QAxScriptManager::load(const QString &file, const QString &name)
+{
+ QFile f(file);
+ if (!f.open(QIODevice::ReadOnly))
+ return 0;
+ QByteArray data = f.readAll();
+ QString contents = QString::fromLocal8Bit(data, data.size());
+ f.close();
+
+ if (contents.isEmpty())
+ return 0;
+
+ QString language;
+ if (file.endsWith(QLatin1String(".js"))) {
+ language = QLatin1String("JScript");
+ } else {
+ QList<QAxEngineDescriptor>::ConstIterator it;
+ for (it = engines.begin(); it != engines.end(); ++it) {
+ QAxEngineDescriptor engine = *it;
+ if (engine.extension.isEmpty())
+ continue;
+
+ if (file.endsWith(engine.extension)) {
+ language = engine.name;
+ break;
+ }
+ }
+ }
+
+ if (language.isEmpty())
+ language = QLatin1String("VBScript");
+
+ QAxScript *script = new QAxScript(name, this);
+ if (script->load(contents, language))
+ return script;
+
+ delete script;
+ return 0;
+}
+
+/*!
+ Calls \a function, passing the parameters \a var1, \a var1,
+ \a var2, \a var3, \a var4, \a var5, \a var6, \a var7 and \a var8
+ as arguments and returns the value returned by the function, or an
+ invalid QVariant if the function does not return a value or when
+ the function call failed. The call returns when the script's
+ execution has finished.
+
+ In most script engines the only supported parameter type is "const
+ QVariant&", for example, to call a JavaScript function
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxscript.cpp 0
+ use
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxscript.cpp 1
+ As with \link QAxBase::dynamicCall() dynamicCall \endlink the
+ parameters can directly be embedded in the function string.
+ \snippet doc/src/snippets/code/src_activeqt_container_qaxscript.cpp 2
+ However, this is slower.
+
+ Functions provided by script engines that don't support
+ introspection are not available and must be called directly
+ using QAxScript::call() on the respective \link script()
+ script \endlink object.
+
+ Note that calling this function can be significantely slower than
+ using call() on the respective QAxScript directly.
+*/
+QVariant QAxScriptManager::call(const QString &function, const QVariant &var1,
+ const QVariant &var2,
+ const QVariant &var3,
+ const QVariant &var4,
+ const QVariant &var5,
+ const QVariant &var6,
+ const QVariant &var7,
+ const QVariant &var8)
+{
+ QAxScript *s = script(function);
+ if (!s) {
+#ifdef QT_CHECK_STATE
+ qWarning("QAxScriptManager::call: No script provides function %s, or this function\n"
+ "\tis provided through an engine that does not support introspection", function.latin1());
+#endif
+ return QVariant();
+ }
+
+ return s->call(function, var1, var2, var3, var4, var5, var6, var7, var8);
+}
+
+/*! \overload
+
+ Calls \a function passing \a arguments as parameters, and returns
+ the result. Returns when the script's execution has finished.
+*/
+QVariant QAxScriptManager::call(const QString &function, QList<QVariant> &arguments)
+{
+ QAxScript *s = script(function);
+ if (!s) {
+#ifdef QT_CHECK_STATE
+ qWarning("QAxScriptManager::call: No script provides function %s, or this function\n"
+ "\tis provided through an engine that does not support introspection", function.latin1());
+#endif
+ return QVariant();
+ }
+
+ QList<QVariant> args(arguments);
+ return s->call(function, args);
+}
+
+/*!
+ Registers the script engine called \a name and returns true if the
+ engine was found; otherwise does nothing and returns false.
+
+ The script engine will be used when loading files with the given
+ \a extension, or when loading source code that contains the string
+ \a code.
+*/
+bool QAxScriptManager::registerEngine(const QString &name, const QString &extension, const QString &code)
+{
+ if (name.isEmpty())
+ return false;
+
+ CLSID clsid;
+ HRESULT hres = CLSIDFromProgID((WCHAR*)name.utf16(), &clsid);
+ if (hres != S_OK)
+ return false;
+
+ QAxEngineDescriptor engine;
+ engine.name = name;
+ engine.extension = extension;
+ engine.code = code;
+
+ engines.prepend(engine);
+ return true;
+}
+
+/*!
+ Returns a file filter listing all the supported script languages.
+ This filter string is convenient for use with QFileDialog.
+*/
+QString QAxScriptManager::scriptFileFilter()
+{
+ QString allFiles = QLatin1String("Script Files (*.js *.vbs *.dsm");
+ QString specialFiles = QLatin1String(";;VBScript Files (*.vbs *.dsm)"
+ ";;JavaScript Files (*.js)");
+
+ QList<QAxEngineDescriptor>::ConstIterator it;
+ for (it = engines.begin(); it != engines.end(); ++it) {
+ QAxEngineDescriptor engine = *it;
+ if (engine.extension.isEmpty())
+ continue;
+
+ allFiles += QLatin1String(" *") + engine.extension;
+ specialFiles += QLatin1String(";;") + engine.name + QLatin1String(" Files (*") + engine.extension + QLatin1String(")");
+ }
+ allFiles += QLatin1String(")");
+
+ return allFiles + specialFiles + QLatin1String(";;All Files (*.*)");
+}
+
+/*!
+ \fn void QAxScriptManager::error(QAxScript *script, int code, const QString &description,
+ int sourcePosition, const QString &sourceText)
+
+ This signal is emitted when an execution error occurred while
+ running \a script.
+
+ \a code, \a description, \a sourcePosition and \a sourceText
+ contain information about the execution error.
+
+ \warning Do not delete \a script in a slot connected to this signal. Use deleteLater()
+ instead.
+*/
+
+/*!
+ \internal
+
+ Returns a pointer to the first QAxScript that knows
+ about \a function, or 0 if this function is unknown.
+*/
+QAxScript *QAxScriptManager::scriptForFunction(const QString &function) const
+{
+ // check full prototypes if included
+ if (function.contains(QLatin1Char('('))) {
+ QHash<QString, QAxScript*>::ConstIterator scriptIt;
+ for (scriptIt = d->scriptDict.begin(); scriptIt != d->scriptDict.end(); ++scriptIt) {
+ QAxScript *script = scriptIt.value();
+
+ if (script->functions(QAxScript::FunctionSignatures).contains(function))
+ return script;
+ }
+ }
+
+ QString funcName = function;
+ funcName = funcName.left(funcName.indexOf(QLatin1Char('(')));
+ // second try, checking only names, not prototypes
+ QHash<QString, QAxScript*>::ConstIterator scriptIt;
+ for (scriptIt = d->scriptDict.begin(); scriptIt != d->scriptDict.end(); ++scriptIt) {
+ QAxScript *script = scriptIt.value();
+
+ if (script->functions(QAxScript::FunctionNames).contains(funcName))
+ return script;
+ }
+
+ return 0;
+}
+
+/*!
+ \internal
+*/
+void QAxScriptManager::updateScript(QAxScript *script)
+{
+ QHash<QString, QAxBase*>::ConstIterator objectIt;
+ for (objectIt = d->objectDict.constBegin(); objectIt != d->objectDict.constEnd(); ++objectIt) {
+ QString name = objectIt.key();
+
+ QAxScriptEngine *engine = script->scriptEngine();
+ if (engine)
+ engine->addItem(name);
+ }
+}
+
+/*!
+ \internal
+*/
+void QAxScriptManager::objectDestroyed(QObject *o)
+{
+ d->objectDict.take(o->objectName());
+}
+
+/*!
+ \internal
+*/
+void QAxScriptManager::scriptError(int code, const QString &desc, int spos, const QString &stext)
+{
+ QAxScript *source = qobject_cast<QAxScript*>(sender());
+ emit error(source, code, desc, spos, stext);
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_WIN_ACTIVEQT
diff --git a/src/activeqt/container/qaxscript.h b/src/activeqt/container/qaxscript.h
new file mode 100644
index 0000000..3332715
--- /dev/null
+++ b/src/activeqt/container/qaxscript.h
@@ -0,0 +1,248 @@
+/****************************************************************************
+**
+** 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 QAXSCRIPT_H
+#define QAXSCRIPT_H
+
+#include <ActiveQt/qaxobject.h>
+
+struct IActiveScript;
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(ActiveQt)
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+class QAxBase;
+class QAxScript;
+class QAxScriptSite;
+class QAxScriptEngine;
+class QAxScriptManager;
+class QAxScriptManagerPrivate;
+
+class QAxScriptEngine : public QAxObject
+{
+public:
+ enum State {
+ Uninitialized = 0,
+ Initialized = 5,
+ Started = 1,
+ Connected = 2,
+ Disconnected = 3,
+ Closed = 4
+ };
+
+ QAxScriptEngine(const QString &language, QAxScript *script);
+ ~QAxScriptEngine();
+
+ bool isValid() const;
+ bool hasIntrospection() const;
+
+ QString scriptLanguage() const;
+
+ State state() const;
+ void setState(State st);
+
+ void addItem(const QString &name);
+
+ long queryInterface(const QUuid &, void**) const;
+
+protected:
+ bool initialize(IUnknown** ptr);
+
+private:
+ QAxScript *script_code;
+ IActiveScript *engine;
+
+ QString script_language;
+};
+
+class QAxScript : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum FunctionFlags {
+ FunctionNames = 0,
+ FunctionSignatures
+ };
+
+ QAxScript(const QString &name, QAxScriptManager *manager);
+ ~QAxScript();
+
+ bool load(const QString &code, const QString &language = QString());
+
+ QStringList functions(FunctionFlags = FunctionNames) const;
+
+ QString scriptCode() const;
+ QString scriptName() const;
+ QAxScriptEngine *scriptEngine() const;
+
+ QVariant call(const QString &function, const QVariant &v1 = QVariant(),
+ const QVariant &v2 = QVariant(),
+ const QVariant &v3 = QVariant(),
+ const QVariant &v4 = QVariant(),
+ const QVariant &v5 = QVariant(),
+ const QVariant &v6 = QVariant(),
+ const QVariant &v7 = QVariant(),
+ const QVariant &v8 = QVariant());
+ QVariant call(const QString &function, QList<QVariant> &arguments);
+
+Q_SIGNALS:
+ void entered();
+ void finished();
+ void finished(const QVariant &result);
+ void finished(int code, const QString &source,const QString &description, const QString &help);
+ void stateChanged(int state);
+ void error(int code, const QString &description, int sourcePosition, const QString &sourceText);
+
+private:
+ friend class QAxScriptSite;
+ friend class QAxScriptEngine;
+
+ void updateObjects();
+ QAxBase *findObject(const QString &name);
+
+ QString script_name;
+ QString script_code;
+ QAxScriptManager *script_manager;
+ QAxScriptEngine *script_engine;
+ QAxScriptSite *script_site;
+};
+
+class QAxScriptManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ QAxScriptManager(QObject *parent = 0);
+ ~QAxScriptManager();
+
+ void addObject(QAxBase *object);
+ void addObject(QObject *object);
+
+ QStringList functions(QAxScript::FunctionFlags = QAxScript::FunctionNames) const;
+ QStringList scriptNames() const;
+ QAxScript *script(const QString &name) const;
+
+ QAxScript* load(const QString &code, const QString &name, const QString &language);
+ QAxScript* load(const QString &file, const QString &name);
+
+ QVariant call(const QString &function, const QVariant &v1 = QVariant(),
+ const QVariant &v2 = QVariant(),
+ const QVariant &v3 = QVariant(),
+ const QVariant &v4 = QVariant(),
+ const QVariant &v5 = QVariant(),
+ const QVariant &v6 = QVariant(),
+ const QVariant &v7 = QVariant(),
+ const QVariant &v8 = QVariant());
+ QVariant call(const QString &function, QList<QVariant> &arguments);
+
+ static bool registerEngine(const QString &name, const QString &extension, const QString &code = QString());
+ static QString scriptFileFilter();
+
+Q_SIGNALS:
+ void error(QAxScript *script, int code, const QString &description, int sourcePosition, const QString &sourceText);
+
+private Q_SLOTS:
+ void objectDestroyed(QObject *o);
+ void scriptError(int code, const QString &description, int sourcePosition, const QString &sourceText);
+
+private:
+ friend class QAxScript;
+ QAxScriptManagerPrivate *d;
+
+ void updateScript(QAxScript*);
+ QAxScript *scriptForFunction(const QString &function) const;
+};
+
+
+// QAxScript inlines
+
+inline QString QAxScript::scriptCode() const
+{
+ return script_code;
+}
+
+inline QString QAxScript::scriptName() const
+{
+ return script_name;
+}
+
+inline QAxScriptEngine *QAxScript::scriptEngine() const
+{
+ return script_engine;
+}
+
+// QAxScriptEngine inlines
+
+inline bool QAxScriptEngine::isValid() const
+{
+ return engine != 0;
+}
+
+inline QString QAxScriptEngine::scriptLanguage() const
+{
+ return script_language;
+}
+
+// QAxScriptManager inlines
+
+extern QAxBase *qax_create_object_wrapper(QObject*);
+
+inline void QAxScriptManager::addObject(QObject *object)
+{
+ QAxBase *wrapper = qax_create_object_wrapper(object);
+ if (!wrapper) {
+ qWarning("QAxScriptMananger::addObject: Class %s not exposed through the QAxFactory",
+ object->metaObject()->className());
+ Q_ASSERT(wrapper);
+ }
+ addObject(wrapper);
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_WIN_ACTIVEQT
+
+QT_END_HEADER
+
+#endif // QAXSCRIPT_H
diff --git a/src/activeqt/container/qaxscriptwrapper.cpp b/src/activeqt/container/qaxscriptwrapper.cpp
new file mode 100644
index 0000000..7515975
--- /dev/null
+++ b/src/activeqt/container/qaxscriptwrapper.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** 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 "qaxobject.h"
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+#include <ActiveQt/qaxfactory.h>
+
+#include <qt_windows.h>
+
+QT_BEGIN_NAMESPACE
+
+QAxBase *qax_create_object_wrapper(QObject *object)
+{
+ IDispatch *dispatch = 0;
+ QAxObject *wrapper = 0;
+ qAxFactory()->createObjectWrapper(object, &dispatch);
+ if (dispatch) {
+ wrapper = new QAxObject(dispatch, object);
+ wrapper->setObjectName(object->objectName());
+ dispatch->Release();
+ }
+ return wrapper;
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_WIN_ACTIVEQT
diff --git a/src/activeqt/container/qaxselect.cpp b/src/activeqt/container/qaxselect.cpp
new file mode 100644
index 0000000..7a47004
--- /dev/null
+++ b/src/activeqt/container/qaxselect.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** 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 "qaxselect.h"
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+#include <qt_windows.h>
+
+QT_BEGIN_NAMESPACE
+
+class ControlList : public QAbstractListModel
+{
+public:
+ ControlList(QObject *parent=0)
+ : QAbstractListModel(parent)
+ {
+ HKEY classes_key;
+ QT_WA_INLINE(
+ RegOpenKeyExW(HKEY_CLASSES_ROOT, L"CLSID", 0, KEY_READ, &classes_key),
+ RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &classes_key));
+ if (!classes_key)
+ return;
+
+ DWORD index = 0;
+ LONG result = 0;
+ TCHAR buffer[256];
+ DWORD szBuffer = sizeof(buffer);
+ FILETIME ft;
+ do {
+ result = QT_WA_INLINE(
+ RegEnumKeyExW(classes_key, index, (wchar_t*)&buffer, &szBuffer, 0, 0, 0, &ft),
+ RegEnumKeyExA(classes_key, index, (char*)&buffer, &szBuffer, 0, 0, 0, &ft));
+ szBuffer = sizeof(buffer);
+ if (result == ERROR_SUCCESS) {
+ HKEY sub_key;
+ QString clsid = QT_WA_INLINE(QString::fromUtf16((ushort*)buffer), QString::fromLocal8Bit((char*)buffer));
+ result = QT_WA_INLINE(
+ RegOpenKeyExW(classes_key, reinterpret_cast<const wchar_t *>(QString(clsid + "\\Control").utf16()), 0, KEY_READ, &sub_key),
+ RegOpenKeyA(classes_key, QString(clsid + QLatin1String("\\Control")).toLocal8Bit(), &sub_key));
+ if (result == ERROR_SUCCESS) {
+ RegCloseKey(sub_key);
+ QT_WA_INLINE(
+ RegistryQueryValueW(classes_key, buffer, (LPBYTE)buffer, &szBuffer),
+ RegQueryValueA(classes_key, (char*)buffer, (char*)buffer, (LONG*)&szBuffer));
+ QString name = QT_WA_INLINE(QString::fromUtf16((ushort*)buffer, szBuffer / sizeof(TCHAR)) , QString::fromLocal8Bit((char*)buffer, szBuffer));
+
+ controls << name;
+ clsids.insert(name, clsid);
+ }
+ result = ERROR_SUCCESS;
+ }
+ szBuffer = sizeof(buffer);
+ ++index;
+ } while (result == ERROR_SUCCESS);
+ RegCloseKey(classes_key);
+ controls.sort();
+ }
+
+ LONG RegistryQueryValueW(HKEY hKey, LPCWSTR lpSubKey, LPBYTE lpData, LPDWORD lpcbData)
+ {
+ LONG ret = ERROR_FILE_NOT_FOUND;
+ HKEY hSubKey = NULL;
+ RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ, &hSubKey);
+ if (hSubKey) {
+ ret = RegQueryValueExW(hSubKey, 0, 0, 0, lpData, lpcbData);
+ RegCloseKey(hSubKey);
+ }
+ return ret;
+ }
+
+ int rowCount(const QModelIndex & = QModelIndex()) const { return controls.count(); }
+ QVariant data(const QModelIndex &index, int role) const;
+
+private:
+ QStringList controls;
+ QMap<QString, QString> clsids;
+};
+
+QVariant ControlList::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (role == Qt::DisplayRole)
+ return controls.at(index.row());
+ if (role == Qt::UserRole)
+ return clsids.value(controls.at(index.row()));
+
+ return QVariant();
+}
+
+QAxSelect::QAxSelect(QWidget *parent, Qt::WindowFlags f)
+: QDialog(parent, f)
+{
+#ifndef QT_NO_CURSOR
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+#endif
+
+ setupUi(this);
+ ActiveXList->setModel(new ControlList(this));
+ connect(ActiveXList->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
+ this, SLOT(on_ActiveXList_clicked(QModelIndex)));
+#ifndef QT_NO_CURSOR
+ QApplication::restoreOverrideCursor();
+#endif
+ ActiveXList->setFocus();
+
+ connect(buttonOk, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(buttonCancel, SIGNAL(clicked()), this, SLOT(reject()));
+}
+
+void QAxSelect::on_ActiveXList_clicked(const QModelIndex &index)
+{
+ QVariant clsid = ActiveXList->model()->data(index, Qt::UserRole);
+ ActiveX->setText(clsid.toString());
+}
+
+void QAxSelect::on_ActiveXList_doubleClicked(const QModelIndex &index)
+{
+ QVariant clsid = ActiveXList->model()->data(index, Qt::UserRole);
+ ActiveX->setText(clsid.toString());
+
+ accept();
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_WIN_ACTIVEQT
diff --git a/src/activeqt/container/qaxselect.h b/src/activeqt/container/qaxselect.h
new file mode 100644
index 0000000..7e41b3f
--- /dev/null
+++ b/src/activeqt/container/qaxselect.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** 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 QAXSELECT_H
+#define QAXSELECT_H
+
+#include <QtGui/qdialog.h>
+
+#ifndef QT_NO_WIN_ACTIVEQT
+#include "ui_qaxselect.h"
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(ActiveQt)
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+class QAxSelect : public QDialog, private Ui::QAxSelect
+{
+ Q_OBJECT
+public:
+ QAxSelect(QWidget *parent = 0, Qt::WindowFlags f = 0);
+
+ QString clsid() const { return ActiveX->text(); }
+
+private Q_SLOTS:
+ void on_ActiveXList_clicked(const QModelIndex &index);
+ void on_ActiveXList_doubleClicked(const QModelIndex &index);
+};
+
+QT_END_NAMESPACE
+#endif // QT_NO_WIN_ACTIVEQT
+
+QT_END_HEADER
+
+#endif // QAXSELECT_H
diff --git a/src/activeqt/container/qaxselect.ui b/src/activeqt/container/qaxselect.ui
new file mode 100644
index 0000000..f9c8d2c
--- /dev/null
+++ b/src/activeqt/container/qaxselect.ui
@@ -0,0 +1,173 @@
+<ui version="4.0" stdsetdef="1" >
+ <class>QAxSelect</class>
+ <comment>*********************************************************************
+**
+** 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$
+**
+*********************************************************************</comment>
+ <widget class="QDialog" name="QAxSelect" >
+ <property name="objectName" >
+ <string notr="true" >QAxSelect</string>
+ </property>
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>439</width>
+ <height>326</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Select ActiveX Control</string>
+ </property>
+ <property name="sizeGripEnabled" >
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="objectName" >
+ <string notr="true" >unnamed</string>
+ </property>
+ <property name="margin" >
+ <number>11</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item rowspan="2" row="0" column="1" colspan="1" >
+ <layout class="QVBoxLayout" >
+ <property name="objectName" >
+ <string notr="true" >unnamed</string>
+ </property>
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonOk" >
+ <property name="objectName" >
+ <string notr="true" >buttonOk</string>
+ </property>
+ <property name="text" >
+ <string>OK</string>
+ </property>
+ <property name="autoDefault" >
+ <bool>true</bool>
+ </property>
+ <property name="default" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonCancel" >
+ <property name="objectName" >
+ <string notr="true" >buttonCancel</string>
+ </property>
+ <property name="text" >
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="autoDefault" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="Spacer2" >
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="sizeType" >
+ <enum>Expanding</enum>
+ </property>
+ <property name="orientation" >
+ <enum>Vertical</enum>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QListView" name="ActiveXList" >
+ <property name="objectName" >
+ <string notr="true" >ActiveXList</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <layout class="QHBoxLayout" >
+ <property name="objectName" >
+ <string notr="true" >unnamed</string>
+ </property>
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="TextLabel1" >
+ <property name="objectName" >
+ <string notr="true" >TextLabel1</string>
+ </property>
+ <property name="text" >
+ <string>COM &amp;Object:</string>
+ </property>
+ <property name="buddy" stdset="0" >
+ <cstring>ActiveX</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="ActiveX" >
+ <property name="objectName" >
+ <string notr="true" >ActiveX</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <includes>
+ <include location="local" >qaxwidget.h</include>
+ </includes>
+</ui>
diff --git a/src/activeqt/container/qaxwidget.cpp b/src/activeqt/container/qaxwidget.cpp
new file mode 100644
index 0000000..4e8473f
--- /dev/null
+++ b/src/activeqt/container/qaxwidget.cpp
@@ -0,0 +1,2228 @@
+/****************************************************************************
+**
+** 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 UNICODE
+#define UNICODE
+#endif
+
+
+#include "qaxwidget.h"
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+#include <ActiveQt/qaxaggregated.h>
+
+#include <qabstracteventdispatcher.h>
+#include <qapplication.h>
+#include <private/qapplication_p.h>
+#include <qdockwidget.h>
+#include <qevent.h>
+#include <qlayout.h>
+#include <qmainwindow.h>
+#include <qmenu.h>
+#include <qmenubar.h>
+#include <qmetaobject.h>
+#include <qpainter.h>
+#include <qpointer.h>
+#include <qregexp.h>
+#include <quuid.h>
+#include <qwhatsthis.h>
+
+#include <windowsx.h>
+#include <ocidl.h>
+#include <olectl.h>
+#include <docobj.h>
+
+// #define QAX_DEBUG
+
+#ifdef QAX_DEBUG
+#define AX_DEBUG(x) qDebug(#x);
+#else
+#define AX_DEBUG(x);
+#endif
+
+// #define QAX_SUPPORT_WINDOWLESS
+// #define QAX_SUPPORT_BORDERSPACE
+
+// missing interface from win32api
+#if defined(Q_CC_GNU)
+# if !defined(IOleInPlaceObjectWindowless)
+# undef INTERFACE
+# define INTERFACE IOleInPlaceObjectWindowless
+ DECLARE_INTERFACE_(IOleInPlaceObjectWindowless,IOleInPlaceObject)
+ {
+ STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
+ STDMETHOD_(ULONG,AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG,Release)(THIS) PURE;
+ STDMETHOD(GetWindow)(THIS_ HWND*) PURE;
+ STDMETHOD(ContextSensitiveHelp)(THIS_ BOOL) PURE;
+ STDMETHOD(InPlaceDeactivate)(THIS) PURE;
+ STDMETHOD(UIDeactivate)(THIS) PURE;
+ STDMETHOD(SetObjectRects)(THIS_ LPCRECT,LPCRECT) PURE;
+ STDMETHOD(ReactivateAndUndo)(THIS) PURE;
+ STDMETHOD(OnWindowMessage)(THIS_ UINT, WPARAM, LPARAM, LRESULT*) PURE;
+ STDMETHOD(GetDropTarget)(THIS_ IDropTarget**) PURE;
+ };
+# endif
+#endif
+
+#include "../shared/qaxtypes.h"
+
+QT_BEGIN_NAMESPACE
+
+/* \class QAxHostWidget
+ \brief The QAxHostWidget class is the actual container widget.
+
+ \internal
+*/
+class QAxHostWidget : public QWidget
+{
+ friend class QAxClientSite;
+public:
+ Q_OBJECT_CHECK
+ QAxHostWidget(QWidget *parent, QAxClientSite *ax);
+ ~QAxHostWidget();
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ int qt_metacall(QMetaObject::Call, int isignal, void **argv);
+ inline QAxClientSite *clientSite() const
+ {
+ return axhost;
+ }
+
+protected:
+ bool winEvent(MSG *msg, long *result);
+ bool event(QEvent *e);
+ bool eventFilter(QObject *o, QEvent *e);
+ void resizeEvent(QResizeEvent *e);
+ void focusInEvent(QFocusEvent *e);
+ void focusOutEvent(QFocusEvent *e);
+ void paintEvent(QPaintEvent *e);
+ void showEvent(QShowEvent *e);
+ QPaintEngine* paintEngine() const
+ {
+ return 0;
+ }
+
+private:
+ void resizeObject();
+
+ int setFocusTimer;
+ bool hasFocus;
+ QAxClientSite *axhost;
+};
+
+/* \class QAxClientSite
+ \brief The QAxClientSite class implements the client site interfaces.
+
+ \internal
+*/
+class QAxClientSite : public IDispatch,
+ public IOleClientSite,
+ public IOleControlSite,
+#ifdef QAX_SUPPORT_WINDOWLESS
+ public IOleInPlaceSiteWindowless,
+#else
+ public IOleInPlaceSite,
+#endif
+ public IOleInPlaceFrame,
+ public IOleDocumentSite,
+ public IAdviseSink
+{
+ friend class QAxHostWidget;
+public:
+ QAxClientSite(QAxWidget *c);
+ virtual ~QAxClientSite();
+
+ bool activateObject(bool initialized, const QByteArray &data);
+
+ void releaseAll();
+ void deactivate();
+ inline void reset(QWidget *p)
+ {
+ if (widget == p)
+ widget = 0;
+ else if (host == p)
+ host = 0;
+ }
+
+ inline IOleInPlaceActiveObject *inPlaceObject() const
+ {
+ return m_spInPlaceActiveObject;
+ }
+
+ inline HRESULT doVerb(LONG index)
+ {
+ if (!m_spOleObject)
+ return E_NOTIMPL;
+ if (!host)
+ return OLE_E_NOT_INPLACEACTIVE;
+
+ RECT rcPos = { host->x(), host->y(), host->x()+host->width(), host->y()+host->height() };
+ return m_spOleObject->DoVerb(index, 0, this, 0, host->winId(), &rcPos);
+ }
+
+ // IUnknown
+ unsigned long WINAPI AddRef();
+ unsigned long WINAPI Release();
+ STDMETHOD(QueryInterface)(REFIID iid, void **iface);
+
+ // IDispatch
+ HRESULT __stdcall GetTypeInfoCount(unsigned int *) { return E_NOTIMPL; }
+ HRESULT __stdcall GetTypeInfo(UINT, LCID, ITypeInfo **) { return E_NOTIMPL; }
+ HRESULT __stdcall GetIDsOfNames(const _GUID &, wchar_t **, unsigned int, unsigned long, long *) { return E_NOTIMPL; }
+ HRESULT __stdcall Invoke(DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS *pDispParams,
+ VARIANT *pVarResult,
+ EXCEPINFO *pExcepInfo,
+ UINT *puArgErr);
+ void emitAmbientPropertyChange(DISPID dispid);
+
+ // IOleClientSite
+ STDMETHOD(SaveObject)();
+ STDMETHOD(GetMoniker)(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk);
+ STDMETHOD(GetContainer)(LPOLECONTAINER FAR* ppContainer);
+ STDMETHOD(ShowObject)();
+ STDMETHOD(OnShowWindow)(BOOL fShow);
+ STDMETHOD(RequestNewObjectLayout)();
+
+ // IOleControlSite
+ STDMETHOD(OnControlInfoChanged)();
+ STDMETHOD(LockInPlaceActive)(BOOL fLock);
+ STDMETHOD(GetExtendedControl)(IDispatch** ppDisp);
+ STDMETHOD(TransformCoords)(POINTL* pPtlHimetric, POINTF* pPtfContainer, DWORD dwFlags);
+ STDMETHOD(TranslateAccelerator)(LPMSG lpMsg, DWORD grfModifiers);
+ STDMETHOD(OnFocus)(BOOL fGotFocus);
+ STDMETHOD(ShowPropertyFrame)();
+
+ // IOleWindow
+ STDMETHOD(GetWindow)(HWND *phwnd);
+ STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode);
+
+ // IOleInPlaceSite
+ STDMETHOD(CanInPlaceActivate)();
+ STDMETHOD(OnInPlaceActivate)();
+ STDMETHOD(OnUIActivate)();
+ STDMETHOD(GetWindowContext)(IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo);
+ STDMETHOD(Scroll)(SIZE scrollExtant);
+ STDMETHOD(OnUIDeactivate)(BOOL fUndoable);
+ STDMETHOD(OnInPlaceDeactivate)();
+ STDMETHOD(DiscardUndoState)();
+ STDMETHOD(DeactivateAndUndo)();
+ STDMETHOD(OnPosRectChange)(LPCRECT lprcPosRect);
+
+#ifdef QAX_SUPPORT_WINDOWLESS
+// IOleInPlaceSiteEx ###
+ STDMETHOD(OnInPlaceActivateEx)(BOOL* /*pfNoRedraw*/, DWORD /*dwFlags*/)
+ {
+ return S_OK;
+ }
+ STDMETHOD(OnInPlaceDeactivateEx)(BOOL /*fNoRedraw*/)
+ {
+ return S_OK;
+ }
+ STDMETHOD(RequestUIActivate)()
+ {
+ return S_OK;
+ }
+
+// IOleInPlaceSiteWindowless ###
+ STDMETHOD(CanWindowlessActivate)()
+ {
+ return S_OK;
+ }
+ STDMETHOD(GetCapture)()
+ {
+ return S_FALSE;
+ }
+ STDMETHOD(SetCapture)(BOOL /*fCapture*/)
+ {
+ return S_FALSE;
+ }
+ STDMETHOD(GetFocus)()
+ {
+ return S_FALSE;
+ }
+ STDMETHOD(SetFocus)(BOOL /*fCapture*/)
+ {
+ return S_FALSE;
+ }
+ STDMETHOD(GetDC)(LPCRECT /*pRect*/, DWORD /*grfFlags*/, HDC *phDC)
+ {
+ *phDC = 0;
+ return S_OK;
+ }
+ STDMETHOD(ReleaseDC)(HDC hDC)
+ {
+ ::ReleaseDC(widget->winId(), hDC);
+ return S_OK;
+ }
+ STDMETHOD(InvalidateRect)(LPCRECT pRect, BOOL fErase)
+ {
+ ::InvalidateRect(host->winId(), pRect, fErase);
+ return S_OK;
+ }
+ STDMETHOD(InvalidateRgn)(HRGN hRGN, BOOL fErase)
+ {
+ ::InvalidateRgn(host->winId(), hRGN, fErase);
+ return S_OK;
+ }
+ STDMETHOD(ScrollRect)(int /*dx*/, int /*dy*/, LPCRECT /*pRectScroll*/, LPCRECT /*pRectClip*/)
+ {
+ return S_OK;
+ }
+ STDMETHOD(AdjustRect)(LPRECT /*prc*/)
+ {
+ return S_OK;
+ }
+#ifdef Q_CC_GNU // signature incorrect in win32api
+ STDMETHOD(AdjustRect)(LPCRECT /*prc*/)
+ {
+ RECT rect;
+ return AdjustRect(&rect);
+ }
+#endif
+
+ STDMETHOD(OnDefWindowMessage)(UINT /*msg*/, WPARAM /*wPara*/, LPARAM /*lParam*/, LRESULT* /*plResult*/)
+ {
+ return S_FALSE;
+ }
+#endif
+
+ // IOleInPlaceFrame
+ STDMETHOD(InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths));
+ STDMETHOD(SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject));
+ STDMETHOD(RemoveMenus(HMENU hmenuShared));
+ STDMETHOD(SetStatusText(LPCOLESTR pszStatusText));
+ STDMETHOD(EnableModeless(BOOL fEnable));
+ STDMETHOD(TranslateAccelerator(LPMSG lpMsg, WORD grfModifiers));
+
+ // IOleInPlaceUIWindow
+ STDMETHOD(GetBorder(LPRECT lprectBorder));
+ STDMETHOD(RequestBorderSpace(LPCBORDERWIDTHS pborderwidths));
+ STDMETHOD(SetBorderSpace(LPCBORDERWIDTHS pborderwidths));
+ STDMETHOD(SetActiveObject(IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName));
+
+ // IOleDocumentSite
+ STDMETHOD(ActivateMe(IOleDocumentView *pViewToActivate));
+
+ // IAdviseSink
+ STDMETHOD_(void, OnDataChange)(FORMATETC* /*pFormatetc*/, STGMEDIUM* /*pStgmed*/)
+ {
+ AX_DEBUG(QAxClientSite::OnDataChange);
+ }
+ STDMETHOD_(void, OnViewChange)(DWORD /*dwAspect*/, LONG /*lindex*/)
+ {
+ AX_DEBUG(QAxClientSite::OnViewChange);
+ }
+ STDMETHOD_(void, OnRename)(IMoniker* /*pmk*/)
+ {
+ }
+ STDMETHOD_(void, OnSave)()
+ {
+ }
+ STDMETHOD_(void, OnClose)()
+ {
+ }
+
+ QSize sizeHint() const { return sizehint; }
+ QSize minimumSizeHint() const;
+ inline void resize(QSize sz) { if (host) host->resize(sz); }
+
+ bool translateKeyEvent(int message, int keycode) const
+ {
+ if (!widget)
+ return false;
+ return widget->translateKeyEvent(message, keycode);
+ }
+
+ int qt_metacall(QMetaObject::Call, int isignal, void **argv);
+ void windowActivationChange();
+
+ bool eventTranslated : 1;
+
+private:
+#if !defined(Q_OS_WINCE)
+ struct OleMenuItem {
+ OleMenuItem(HMENU hm = 0, int ID = 0, QMenu *menu = 0)
+ : hMenu(hm), id(ID), subMenu(menu)
+ {}
+ HMENU hMenu;
+ int id;
+ QMenu *subMenu;
+ };
+ QMenu *generatePopup(HMENU subMenu, QWidget *parent);
+#endif
+
+ IOleObject *m_spOleObject;
+ IOleControl *m_spOleControl;
+ IOleInPlaceObjectWindowless *m_spInPlaceObject;
+ IOleInPlaceActiveObject *m_spInPlaceActiveObject;
+ IOleDocumentView *m_spActiveView;
+
+ QAxAggregated *aggregatedObject;
+
+ bool inPlaceObjectWindowless :1;
+ bool inPlaceModelessEnabled :1;
+ bool canHostDocument : 1;
+
+ DWORD m_dwOleObject;
+#if !defined(Q_OS_WINCE)
+ HWND m_menuOwner;
+#endif
+ CONTROLINFO control_info;
+
+ QSize sizehint;
+ unsigned long ref;
+ QAxWidget *widget;
+ QAxHostWidget *host;
+#if !defined(Q_OS_WINCE)
+ QPointer<QMenuBar> menuBar;
+ QMap<QAction*,OleMenuItem> menuItemMap;
+#endif
+};
+
+static const ushort mouseTbl[] = {
+ WM_MOUSEMOVE, QEvent::MouseMove, 0,
+ WM_LBUTTONDOWN, QEvent::MouseButtonPress, Qt::LeftButton,
+ WM_LBUTTONUP, QEvent::MouseButtonRelease, Qt::LeftButton,
+ WM_LBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::LeftButton,
+ WM_RBUTTONDOWN, QEvent::MouseButtonPress, Qt::RightButton,
+ WM_RBUTTONUP, QEvent::MouseButtonRelease, Qt::RightButton,
+ WM_RBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::RightButton,
+ WM_MBUTTONDOWN, QEvent::MouseButtonPress, Qt::MidButton,
+ WM_MBUTTONUP, QEvent::MouseButtonRelease, Qt::MidButton,
+ WM_MBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::MidButton,
+ 0, 0, 0
+};
+
+static Qt::MouseButtons translateMouseButtonState(int s)
+{
+ Qt::MouseButtons bst = 0;
+ if (s & MK_LBUTTON)
+ bst |= Qt::LeftButton;
+ if (s & MK_MBUTTON)
+ bst |= Qt::MidButton;
+ if (s & MK_RBUTTON)
+ bst |= Qt::RightButton;
+
+ return bst;
+}
+
+static Qt::KeyboardModifiers translateModifierState(int s)
+{
+ Qt::KeyboardModifiers bst = 0;
+ if (s & MK_SHIFT)
+ bst |= Qt::ShiftModifier;
+ if (s & MK_CONTROL)
+ bst |= Qt::ControlModifier;
+ if (GetKeyState(VK_MENU) < 0)
+ bst |= Qt::AltModifier;
+
+ return bst;
+}
+
+static QAbstractEventDispatcher::EventFilter previous_filter = 0;
+#if QT_VERSION >= 0x050000
+#error "Fix QAbstractEventDispatcher::setEventFilter"
+#endif
+#if defined(Q_OS_WINCE)
+static int filter_ref = 0;
+#else
+static const char *qaxatom = "QAxContainer4_Atom";
+#endif
+
+// The filter procedure listening to user interaction on the control
+bool axc_FilterProc(void *m)
+{
+ MSG *msg = (MSG*)m;
+ const uint message = msg->message;
+ if ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) || (message >= WM_KEYFIRST && message <= WM_KEYLAST)) {
+ HWND hwnd = msg->hwnd;
+ QAxWidget *ax = 0;
+ QAxHostWidget *host = 0;
+ while (!host && hwnd) {
+ host = qobject_cast<QAxHostWidget*>(QWidget::find(hwnd));
+ hwnd = ::GetParent(hwnd);
+ }
+ if (host)
+ ax = qobject_cast<QAxWidget*>(host->parentWidget());
+ if (ax && msg->hwnd != host->winId()) {
+ if (message >= WM_KEYFIRST && message <= WM_KEYLAST) {
+ QAxClientSite *site = host->clientSite();
+ site->eventTranslated = true; // reset in QAxClientSite::TranslateAccelerator
+ HRESULT hres = S_FALSE;
+ if (site && site->inPlaceObject() && site->translateKeyEvent(msg->message, msg->wParam))
+ hres = site->inPlaceObject()->TranslateAccelerator(msg);
+ // if the object calls our TranslateAccelerator implementation, then continue with normal event processing
+ // otherwise the object has translated the accelerator, and the event should be stopped
+ if (site->eventTranslated && hres == S_OK)
+ return true;
+ } else {
+ int i;
+ for (i = 0; (UINT)mouseTbl[i] != message && mouseTbl[i]; i += 3)
+ ;
+
+ if (mouseTbl[i]) {
+ QEvent::Type type = (QEvent::Type)mouseTbl[++i];
+ int button = mouseTbl[++i];
+ if (type != QEvent::MouseMove || ax->hasMouseTracking() || button) {
+ if (type == QEvent::MouseMove)
+ button = 0;
+
+ DWORD ol_pos = GetMessagePos();
+ QPoint gpos(GET_X_LPARAM(ol_pos), GET_Y_LPARAM(ol_pos));
+ QPoint pos = ax->mapFromGlobal(gpos);
+
+ QMouseEvent e(type, pos, gpos, (Qt::MouseButton)button,
+ translateMouseButtonState(msg->wParam),
+ translateModifierState(msg->wParam));
+ QApplication::sendEvent(ax, &e);
+ }
+ }
+ }
+ }
+ }
+
+ if (previous_filter)
+ return previous_filter(m);
+
+ return false;
+}
+
+QAxClientSite::QAxClientSite(QAxWidget *c)
+: ref(1), widget(c), host(0), eventTranslated(true)
+{
+ aggregatedObject = widget->createAggregate();
+ if (aggregatedObject) {
+ aggregatedObject->controlling_unknown = (IUnknown*)(IDispatch*)this;
+ aggregatedObject->the_object = c;
+ }
+
+ m_spOleObject = 0;
+ m_spOleControl = 0;
+ m_spInPlaceObject = 0;
+ m_spInPlaceActiveObject = 0;
+ m_spActiveView = 0;
+
+ inPlaceObjectWindowless = false;
+ inPlaceModelessEnabled = true;
+ canHostDocument = false;
+
+ m_dwOleObject = 0;
+#if !defined(Q_OS_WINCE)
+ m_menuOwner = 0;
+ menuBar = 0;
+#endif
+ memset(&control_info, 0, sizeof(control_info));
+}
+
+bool QAxClientSite::activateObject(bool initialized, const QByteArray &data)
+{
+ if (!host)
+ host = new QAxHostWidget(widget, this);
+
+ bool showHost = false;
+ HRESULT hr = S_OK;
+ if (!m_spOleObject)
+ widget->queryInterface(IID_IOleObject, (void**)&m_spOleObject);
+ if (m_spOleObject) {
+ DWORD dwMiscStatus = 0;
+ m_spOleObject->GetMiscStatus(DVASPECT_CONTENT, &dwMiscStatus);
+
+#if !defined(Q_OS_WINCE)
+ IOleDocument *document = 0;
+ m_spOleObject->QueryInterface(IID_IOleDocument, (void**)&document);
+ if (document) {
+ IPersistStorage *persistStorage = 0;
+ document->QueryInterface(IID_IPersistStorage, (void**)&persistStorage);
+ if (persistStorage) {
+ // try to activate as document server
+ IStorage *storage = 0;
+ ILockBytes * bytes = 0;
+ HRESULT hres = ::CreateILockBytesOnHGlobal(0, TRUE, &bytes);
+ hres = ::StgCreateDocfileOnILockBytes(bytes, STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &storage);
+
+ persistStorage->InitNew(storage);
+ persistStorage->Release();
+ canHostDocument = true;
+ storage->Release();
+ bytes->Release();
+
+ m_spOleObject->SetClientSite(this);
+ OleRun(m_spOleObject);
+ }
+ document->Release();
+ }
+#endif
+
+ if (!canHostDocument) {
+ // activate as control
+ if(dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)
+ m_spOleObject->SetClientSite(this);
+
+ if (!initialized) {
+ IPersistStreamInit *spPSI = 0;
+ m_spOleObject->QueryInterface(IID_IPersistStreamInit, (void**)&spPSI);
+ if (spPSI) {
+ if (data.length()) {
+ IStream *pStream = 0;
+ HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, data.length());
+ if (hGlobal) {
+ BYTE *pStByte = (BYTE *)GlobalLock(hGlobal);
+ if (pStByte)
+ memcpy(pStByte, data.data(), data.length());
+ GlobalUnlock(hGlobal);
+ if (SUCCEEDED(CreateStreamOnHGlobal(hGlobal, TRUE, &pStream))) {
+ spPSI->Load(pStream);
+ pStream->Release();
+ }
+ GlobalFree(hGlobal);
+ }
+ } else {
+ spPSI->InitNew();
+ }
+ spPSI->Release();
+ } else if (data.length()) { //try initializing using a IPersistStorage
+ IPersistStorage *spPS = 0;
+ m_spOleObject->QueryInterface( IID_IPersistStorage, (void**)&spPS );
+ if (spPS) {
+ HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, data.length());
+ if (hGlobal) {
+#if !defined(Q_OS_WINCE)
+ BYTE* pbData = (BYTE*)GlobalLock(hGlobal);
+ if (pbData)
+ memcpy(pbData, data.data(), data.length());
+ GlobalUnlock(hGlobal);
+ // open an IStorage on the data and pass it to Load
+ LPLOCKBYTES pLockBytes = 0;
+ if (SUCCEEDED(CreateILockBytesOnHGlobal(hGlobal, TRUE, &pLockBytes))) {
+ LPSTORAGE pStorage = 0;
+ if (SUCCEEDED(StgOpenStorageOnILockBytes(pLockBytes, 0,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStorage))) {
+ spPS->Load(pStorage);
+ pStorage->Release();
+ }
+ pLockBytes->Release();
+ }
+ GlobalFree(hGlobal);
+#endif
+ }
+ spPS->Release();
+ }
+ }
+ }
+
+ if(!(dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST))
+ m_spOleObject->SetClientSite(this);
+ }
+
+ IViewObject *spViewObject = 0;
+ m_spOleObject->QueryInterface(IID_IViewObject, (void**) &spViewObject);
+
+ m_spOleObject->Advise(this, &m_dwOleObject);
+ IAdviseSink *spAdviseSink = 0;
+ QueryInterface(IID_IAdviseSink, (void**)&spAdviseSink);
+ if (spAdviseSink && spViewObject) {
+ if (spViewObject)
+ spViewObject->SetAdvise(DVASPECT_CONTENT, 0, spAdviseSink);
+ spAdviseSink->Release();
+ }
+ if (spViewObject)
+ spViewObject->Release();
+
+ m_spOleObject->SetHostNames(OLESTR("AXWIN"), 0);
+
+ if (!(dwMiscStatus & OLEMISC_INVISIBLEATRUNTIME)) {
+ SIZEL hmSize;
+ hmSize.cx = MAP_PIX_TO_LOGHIM(250, widget->logicalDpiX());
+ hmSize.cy = MAP_PIX_TO_LOGHIM(250, widget->logicalDpiY());
+
+ m_spOleObject->SetExtent(DVASPECT_CONTENT, &hmSize);
+ m_spOleObject->GetExtent(DVASPECT_CONTENT, &hmSize);
+
+ sizehint.setWidth(MAP_LOGHIM_TO_PIX(hmSize.cx, widget->logicalDpiX()));
+ sizehint.setHeight(MAP_LOGHIM_TO_PIX(hmSize.cy, widget->logicalDpiY()));
+ showHost = true;
+ } else {
+ sizehint = QSize(0, 0);
+ host->hide();
+ }
+ if (!(dwMiscStatus & OLEMISC_NOUIACTIVATE)) {
+ host->setFocusPolicy(Qt::StrongFocus);
+ } else {
+ host->setFocusPolicy(Qt::NoFocus);
+ }
+
+ RECT rcPos = { host->x(), host->y(), host->x()+sizehint.width(), host->y()+sizehint.height() };
+
+ hr = m_spOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, 0, (IOleClientSite*)this, 0, host->winId(), &rcPos);
+
+ if (!m_spOleControl)
+ m_spOleObject->QueryInterface(IID_IOleControl, (void**)&m_spOleControl);
+ if (m_spOleControl) {
+ m_spOleControl->OnAmbientPropertyChange(DISPID_AMBIENT_BACKCOLOR);
+ m_spOleControl->OnAmbientPropertyChange(DISPID_AMBIENT_FORECOLOR);
+ m_spOleControl->OnAmbientPropertyChange(DISPID_AMBIENT_FONT);
+ m_spOleControl->OnAmbientPropertyChange(DISPID_AMBIENT_USERMODE);
+
+ control_info.cb = sizeof(control_info);
+ m_spOleControl->GetControlInfo(&control_info);
+ }
+
+ BSTR userType;
+ HRESULT result = m_spOleObject->GetUserType(USERCLASSTYPE_SHORT, &userType);
+ if (result == S_OK) {
+ widget->setWindowTitle(QString::fromUtf16((const ushort *)userType));
+ CoTaskMemFree(userType);
+ }
+ } else {
+ IObjectWithSite *spSite = 0;
+ widget->queryInterface(IID_IObjectWithSite, (void**)&spSite);
+ if (spSite) {
+ spSite->SetSite((IUnknown*)(IDispatch*)this);
+ spSite->Release();
+ }
+ }
+
+ host->resize(widget->size());
+ if (showHost)
+ host->show();
+
+ if (host->focusPolicy() != Qt::NoFocus) {
+ widget->setFocusProxy(host);
+ widget->setFocusPolicy(host->focusPolicy());
+ }
+
+ return true;
+}
+
+QAxClientSite::~QAxClientSite()
+{
+ if (host) {
+ host->axhost = 0;
+ }
+
+ if (aggregatedObject)
+ aggregatedObject->the_object = 0;
+ delete aggregatedObject;
+ delete host;
+}
+
+void QAxClientSite::releaseAll()
+{
+ if (m_spOleObject) {
+ m_spOleObject->SetClientSite(0);
+ m_spOleObject->Unadvise(m_dwOleObject);
+ m_spOleObject->Release();
+ }
+ m_spOleObject = 0;
+ if (m_spOleControl) m_spOleControl->Release();
+ m_spOleControl = 0;
+ if (m_spInPlaceObject) m_spInPlaceObject->Release();
+ m_spInPlaceObject = 0;
+ if (m_spInPlaceActiveObject) m_spInPlaceActiveObject->Release();
+ m_spInPlaceActiveObject = 0;
+
+ inPlaceObjectWindowless = false;
+}
+
+void QAxClientSite::deactivate()
+{
+ if (m_spInPlaceObject) m_spInPlaceObject->InPlaceDeactivate();
+ // if this assertion fails the control didn't call OnInPlaceDeactivate
+ Q_ASSERT(m_spInPlaceObject == 0);
+}
+
+//**** IUnknown
+unsigned long WINAPI QAxClientSite::AddRef()
+{
+ return ++ref;
+}
+
+unsigned long WINAPI QAxClientSite::Release()
+{
+ if (!--ref) {
+ delete this;
+ return 0;
+ }
+ return ref;
+}
+
+HRESULT WINAPI QAxClientSite::QueryInterface(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 == IID_IDispatch)
+ *iface = (IDispatch*)this;
+ else if (iid == IID_IOleClientSite)
+ *iface = (IOleClientSite*)this;
+ else if (iid == IID_IOleControlSite)
+ *iface = (IOleControlSite*)this;
+ else if (iid == IID_IOleWindow)
+ *iface = (IOleWindow*)(IOleInPlaceSite*)this;
+ else if (iid == IID_IOleInPlaceSite)
+ *iface = (IOleInPlaceSite*)this;
+#ifdef QAX_SUPPORT_WINDOWLESS
+ else if (iid == IID_IOleInPlaceSiteEx)
+ *iface = (IOleInPlaceSiteEx*)this;
+ else if (iid == IID_IOleInPlaceSiteWindowless)
+ *iface = (IOleInPlaceSiteWindowless*)this;
+#endif
+ else if (iid == IID_IOleInPlaceFrame)
+ *iface = (IOleInPlaceFrame*)this;
+ else if (iid == IID_IOleInPlaceUIWindow)
+ *iface = (IOleInPlaceUIWindow*)this;
+ else if (iid == IID_IOleDocumentSite && canHostDocument)
+ *iface = (IOleDocumentSite*)this;
+ else if (iid == IID_IAdviseSink)
+ *iface = (IAdviseSink*)this;
+ }
+ if (!*iface)
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+}
+
+bool qax_runsInDesignMode = false;
+
+//**** IDispatch
+HRESULT WINAPI QAxClientSite::Invoke(DISPID dispIdMember,
+ REFIID /*riid*/,
+ LCID /*lcid*/,
+ WORD /*wFlags*/,
+ DISPPARAMS * /*pDispParams*/,
+ VARIANT *pVarResult,
+ EXCEPINFO * /*pExcepInfo*/,
+ UINT * /*puArgErr*/)
+{
+ if (!pVarResult)
+ return E_POINTER;
+ if (!widget || !host)
+ return E_UNEXPECTED;
+
+ switch(dispIdMember) {
+ case DISPID_AMBIENT_USERMODE:
+ pVarResult->vt = VT_BOOL;
+ pVarResult->boolVal = !qax_runsInDesignMode;
+ return S_OK;
+
+ case DISPID_AMBIENT_AUTOCLIP:
+ case DISPID_AMBIENT_SUPPORTSMNEMONICS:
+ pVarResult->vt = VT_BOOL;
+ pVarResult->boolVal = true;
+ return S_OK;
+
+ case DISPID_AMBIENT_SHOWHATCHING:
+ case DISPID_AMBIENT_SHOWGRABHANDLES:
+ case DISPID_AMBIENT_DISPLAYASDEFAULT:
+ case DISPID_AMBIENT_MESSAGEREFLECT:
+ pVarResult->vt = VT_BOOL;
+ pVarResult->boolVal = false;
+ return S_OK;
+
+ case DISPID_AMBIENT_DISPLAYNAME:
+ pVarResult->vt = VT_BSTR;
+ pVarResult->bstrVal = QStringToBSTR(widget->windowTitle());
+ return S_OK;
+
+ case DISPID_AMBIENT_FONT:
+ QVariantToVARIANT(widget->font(), *pVarResult);
+ return S_OK;
+
+ case DISPID_AMBIENT_BACKCOLOR:
+ pVarResult->vt = VT_UI4;
+ pVarResult->lVal = QColorToOLEColor(widget->palette().color(widget->backgroundRole()));
+ return S_OK;
+
+ case DISPID_AMBIENT_FORECOLOR:
+ pVarResult->vt = VT_UI4;
+ pVarResult->lVal = QColorToOLEColor(widget->palette().color(widget->foregroundRole()));
+ return S_OK;
+
+ case DISPID_AMBIENT_UIDEAD:
+ pVarResult->vt = VT_BOOL;
+ pVarResult->boolVal = !widget->isEnabled();
+ return S_OK;
+
+ default:
+ break;
+ }
+
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+void QAxClientSite::emitAmbientPropertyChange(DISPID dispid)
+{
+ if (m_spOleControl)
+ m_spOleControl->OnAmbientPropertyChange(dispid);
+}
+
+//**** IOleClientSite
+HRESULT WINAPI QAxClientSite::SaveObject()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI QAxClientSite::GetMoniker(DWORD, DWORD, IMoniker **ppmk)
+{
+ if (!ppmk)
+ return E_POINTER;
+
+ *ppmk = 0;
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI QAxClientSite::GetContainer(LPOLECONTAINER *ppContainer)
+{
+ if (!ppContainer)
+ return E_POINTER;
+
+ *ppContainer = 0;
+ return E_NOINTERFACE;
+}
+
+HRESULT WINAPI QAxClientSite::ShowObject()
+{
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::OnShowWindow(BOOL /*fShow*/)
+{
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::RequestNewObjectLayout()
+{
+ return E_NOTIMPL;
+}
+
+//**** IOleControlSite
+HRESULT WINAPI QAxClientSite::OnControlInfoChanged()
+{
+ if (m_spOleControl)
+ m_spOleControl->GetControlInfo(&control_info);
+
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::LockInPlaceActive(BOOL /*fLock*/)
+{
+ AX_DEBUG(QAxClientSite::LockInPlaceActive);
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::GetExtendedControl(IDispatch** ppDisp)
+{
+ if (!ppDisp)
+ return E_POINTER;
+
+ *ppDisp = 0;
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI QAxClientSite::TransformCoords(POINTL* /*pPtlHimetric*/, POINTF* /*pPtfContainer*/, DWORD /*dwFlags*/)
+{
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::TranslateAccelerator(LPMSG lpMsg, DWORD /*grfModifiers*/)
+{
+ eventTranslated = false;
+ if (lpMsg->message == WM_KEYDOWN && !lpMsg->wParam)
+ return S_OK;
+ QT_WA_INLINE(
+ SendMessage(host->winId(), lpMsg->message, lpMsg->wParam, lpMsg->lParam),
+ SendMessageA(host->winId(), lpMsg->message, lpMsg->wParam, lpMsg->lParam)
+ );
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::OnFocus(BOOL bGotFocus)
+{
+ AX_DEBUG(QAxClientSite::OnFocus);
+ if (host) {
+ host->hasFocus = bGotFocus;
+ qApp->removeEventFilter(host);
+ if (bGotFocus)
+ qApp->installEventFilter(host);
+ }
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::ShowPropertyFrame()
+{
+ return E_NOTIMPL;
+}
+
+//**** IOleWindow
+HRESULT WINAPI QAxClientSite::GetWindow(HWND *phwnd)
+{
+ if (!phwnd)
+ return E_POINTER;
+
+ *phwnd = host->winId();
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::ContextSensitiveHelp(BOOL fEnterMode)
+{
+ if (fEnterMode)
+ QWhatsThis::enterWhatsThisMode();
+ else
+ QWhatsThis::leaveWhatsThisMode();
+
+ return S_OK;
+}
+
+//**** IOleInPlaceSite
+HRESULT WINAPI QAxClientSite::CanInPlaceActivate()
+{
+ AX_DEBUG(QAxClientSite::CanInPlaceActivate);
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::OnInPlaceActivate()
+{
+ AX_DEBUG(QAxClientSite::OnInPlaceActivate);
+#if !defined(Q_OS_WINCE)
+ OleLockRunning(m_spOleObject, true, false);
+#endif
+ if (!m_spInPlaceObject) {
+/* ### disabled for now
+ m_spOleObject->QueryInterface(IID_IOleInPlaceObjectWindowless, (void**) &m_spInPlaceObject);
+*/
+ if (m_spInPlaceObject) {
+ inPlaceObjectWindowless = true;
+ } else {
+ inPlaceObjectWindowless = false;
+ m_spOleObject->QueryInterface(IID_IOleInPlaceObject, (void**) &m_spInPlaceObject);
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::OnUIActivate()
+{
+ AX_DEBUG(QAxClientSite::OnUIActivate);
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::GetWindowContext(IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo)
+{
+ if (!ppFrame || !ppDoc || !lprcPosRect || !lprcClipRect || !lpFrameInfo)
+ return E_POINTER;
+
+ QueryInterface(IID_IOleInPlaceFrame, (void**)ppFrame);
+ QueryInterface(IID_IOleInPlaceUIWindow, (void**)ppDoc);
+
+ ::GetClientRect(host->winId(), lprcPosRect);
+ ::GetClientRect(host->winId(), lprcClipRect);
+
+ lpFrameInfo->cb = sizeof(OLEINPLACEFRAMEINFO);
+ lpFrameInfo->fMDIApp = false;
+ lpFrameInfo->haccel = 0;
+ lpFrameInfo->cAccelEntries = 0;
+ lpFrameInfo->hwndFrame = widget ? widget->window()->winId() : 0;
+
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::Scroll(SIZE /*scrollExtant*/)
+{
+ return S_FALSE;
+}
+
+HRESULT WINAPI QAxClientSite::OnUIDeactivate(BOOL)
+{
+ AX_DEBUG(QAxClientSite::OnUIDeactivate);
+ if (host && host->hasFocus) {
+ qApp->removeEventFilter(host);
+ host->hasFocus = false;
+ }
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::OnInPlaceDeactivate()
+{
+ AX_DEBUG(QAxClientSite::OnInPlaceDeactivate);
+ if (m_spInPlaceObject)
+ m_spInPlaceObject->Release();
+ m_spInPlaceObject = 0;
+ inPlaceObjectWindowless = false;
+#if !defined(Q_OS_WINCE)
+ OleLockRunning(m_spOleObject, false, false);
+#endif
+
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::DiscardUndoState()
+{
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::DeactivateAndUndo()
+{
+ if (m_spInPlaceObject)
+ m_spInPlaceObject->UIDeactivate();
+
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::OnPosRectChange(LPCRECT /*lprcPosRect*/)
+{
+ AX_DEBUG(QAxClientSite::OnPosRectChange);
+ // ###
+ return S_OK;
+}
+
+//**** IOleInPlaceFrame
+#if defined(Q_OS_WINCE)
+HRESULT WINAPI QAxClientSite::InsertMenus(HMENU /*hmenuShared*/, LPOLEMENUGROUPWIDTHS /*lpMenuWidths*/)
+{
+ return E_NOTIMPL;
+#else
+HRESULT WINAPI QAxClientSite::InsertMenus(HMENU /*hmenuShared*/, LPOLEMENUGROUPWIDTHS lpMenuWidths)
+{
+ AX_DEBUG(QAxClientSite::InsertMenus);
+ QMenuBar *mb = menuBar;
+ if (!mb)
+ mb = qFindChild<QMenuBar*>(widget->window());
+ if (!mb)
+ return E_NOTIMPL;
+ menuBar = mb;
+
+ QMenu *fileMenu = 0;
+ QMenu *viewMenu = 0;
+ QMenu *windowMenu = 0;
+ QList<QAction*> actions = menuBar->actions();
+ for (int i = 0; i < actions.count(); ++i) {
+ QAction *action = actions.at(i);
+ QString text = action->text().remove(QLatin1Char('&'));
+ if (text == QLatin1String("File")) {
+ fileMenu = action->menu();
+ } else if (text == QLatin1String("View")) {
+ viewMenu = action->menu();
+ } else if (text == QLatin1String("Window")) {
+ windowMenu = action->menu();
+ }
+ }
+ if (fileMenu)
+ lpMenuWidths->width[0] = fileMenu->actions().count();
+ if (viewMenu)
+ lpMenuWidths->width[2] = viewMenu->actions().count();
+ if (windowMenu)
+ lpMenuWidths->width[4] = windowMenu->actions().count();
+
+ return S_OK;
+#endif
+}
+
+static int menuItemEntry(HMENU menu, int index, MENUITEMINFOA item, QString &text, QPixmap &/*icon*/)
+{
+ if (item.fType == MFT_STRING && item.cch) {
+ char *titlebuf = new char[item.cch+1];
+ item.dwTypeData = titlebuf;
+ item.cch++;
+ ::GetMenuItemInfoA(menu, index, true, &item);
+ text = QString::fromLocal8Bit(titlebuf);
+ delete []titlebuf;
+ return MFT_STRING;
+ }
+#if 0
+ else if (item.fType == MFT_BITMAP) {
+ HBITMAP hbm = (HBITMAP)LOWORD(item.hbmpItem);
+ SIZE bmsize;
+ GetBitmapDimensionEx(hbm, &bmsize);
+ QPixmap pixmap(1,1);
+ QSize sz(MAP_LOGHIM_TO_PIX(bmsize.cx, pixmap.logicalDpiX()),
+ MAP_LOGHIM_TO_PIX(bmsize.cy, pixmap.logicalDpiY()));
+
+ pixmap.resize(bmsize.cx, bmsize.cy);
+ if (!pixmap.isNull()) {
+ HDC hdc = ::CreateCompatibleDC(pixmap.handle());
+ ::SelectObject(hdc, hbm);
+ BOOL res = ::BitBlt(pixmap.handle(), 0, 0, pixmap.width(), pixmap.height(), hdc, 0, 0, SRCCOPY);
+ ::DeleteObject(hdc);
+ }
+
+ icon = pixmap;
+ }
+#endif
+ return -1;
+}
+
+#if !defined(Q_OS_WINCE)
+QMenu *QAxClientSite::generatePopup(HMENU subMenu, QWidget *parent)
+{
+ QMenu *popup = 0;
+ int count = GetMenuItemCount(subMenu);
+ if (count)
+ popup = new QMenu(parent);
+ for (int i = 0; i < count; ++i) {
+ MENUITEMINFOA item;
+ memset(&item, 0, sizeof(MENUITEMINFOA));
+ item.cbSize = sizeof(MENUITEMINFOA);
+ item.fMask = MIIM_ID | MIIM_TYPE | MIIM_SUBMENU;
+ ::GetMenuItemInfoA(subMenu, i, true, &item);
+
+ QAction *action = 0;
+ QMenu *popupMenu = 0;
+ if (item.fType == MFT_SEPARATOR) {
+ action = popup->addSeparator();
+ } else {
+ QString text;
+ QPixmap icon;
+ QKeySequence accel;
+ popupMenu = item.hSubMenu ? generatePopup(item.hSubMenu, popup) : 0;
+ int res = menuItemEntry(subMenu, i, item, text, icon);
+
+ int lastSep = text.lastIndexOf(QRegExp(QLatin1String("[\\s]")));
+ if (lastSep != -1) {
+ QString keyString = text.right(text.length() - lastSep);
+ accel = keyString;
+ if ((int)accel)
+ text = text.left(lastSep);
+ }
+
+ if (popupMenu)
+ popupMenu->setTitle(text);
+
+ switch (res) {
+ case MFT_STRING:
+ if (popupMenu)
+ action = popup->addMenu(popupMenu);
+ else
+ action = popup->addAction(text);
+ break;
+ case MFT_BITMAP:
+ if (popupMenu)
+ action = popup->addMenu(popupMenu);
+ else
+ action = popup->addAction(icon, text);
+ break;
+ }
+
+ if (action) {
+ if (int(accel))
+ action->setShortcut(accel);
+ if (!icon.isNull())
+ action->setIcon(icon);
+ }
+ }
+
+ if (action) {
+ OleMenuItem oleItem(subMenu, item.wID, popupMenu);
+ menuItemMap.insert(action, oleItem);
+ }
+ }
+ return popup;
+}
+#endif
+
+#if defined(Q_OS_WINCE)
+HRESULT WINAPI QAxClientSite::SetMenu(HMENU /*hmenuShared*/, HOLEMENU /*holemenu*/, HWND /*hwndActiveObject*/)
+{
+ return E_NOTIMPL;
+#else
+HRESULT WINAPI QAxClientSite::SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject)
+{
+ AX_DEBUG(QAxClientSite::SetMenu);
+
+ if (hmenuShared) {
+ m_menuOwner = hwndActiveObject;
+ QMenuBar *mb = menuBar;
+ if (!mb)
+ mb = qFindChild<QMenuBar*>(widget->window());
+ if (!mb)
+ return E_NOTIMPL;
+ menuBar = mb;
+
+ int count = GetMenuItemCount(hmenuShared);
+ for (int i = 0; i < count; ++i) {
+ MENUITEMINFOA item;
+ memset(&item, 0, sizeof(MENUITEMINFOA));
+ item.cbSize = sizeof(MENUITEMINFOA);
+ item.fMask = MIIM_ID | MIIM_TYPE | MIIM_SUBMENU;
+ ::GetMenuItemInfoA(hmenuShared, i, true, &item);
+
+ QAction *action = 0;
+ QMenu *popupMenu = 0;
+ if (item.fType == MFT_SEPARATOR) {
+ action = menuBar->addSeparator();
+ } else {
+ QString text;
+ QPixmap icon;
+ popupMenu = item.hSubMenu ? generatePopup(item.hSubMenu, menuBar) : 0;
+ int res = menuItemEntry(hmenuShared, i, item, text, icon);
+
+ if (popupMenu)
+ popupMenu->setTitle(text);
+
+ switch(res) {
+ case MFT_STRING:
+ if (popupMenu)
+ action = menuBar->addMenu(popupMenu);
+ else
+ action = menuBar->addAction(text);
+ break;
+ case MFT_BITMAP:
+ if (popupMenu)
+ action = menuBar->addMenu(popupMenu);
+ else
+ action = menuBar->addAction(text);
+ break;
+ default:
+ break;
+ }
+ if (action && !icon.isNull())
+ action->setIcon(icon);
+ }
+
+ if (action) {
+ OleMenuItem oleItem(hmenuShared, item.wID, popupMenu);
+ menuItemMap.insert(action, oleItem);
+ }
+ }
+ if (count) {
+ const QMetaObject *mbmo = menuBar->metaObject();
+ int index = mbmo->indexOfSignal("triggered(QAction*)");
+ Q_ASSERT(index != -1);
+ menuBar->disconnect(SIGNAL(triggered(QAction*)), host);
+ QMetaObject::connect(menuBar, index, host, index);
+ }
+ } else if (menuBar) {
+ m_menuOwner = 0;
+ QMap<QAction*, OleMenuItem>::Iterator it;
+ for (it = menuItemMap.begin(); it != menuItemMap.end(); ++it) {
+ QAction *action = it.key();
+ delete action;
+ }
+ menuItemMap.clear();
+ }
+
+ OleSetMenuDescriptor(holemenu, widget ? widget->window()->winId() : 0, m_menuOwner, this, m_spInPlaceActiveObject);
+ return S_OK;
+#endif
+}
+
+#if defined(Q_OS_WINCE)
+int QAxClientSite::qt_metacall(QMetaObject::Call /*call*/, int isignal, void ** /*argv*/)
+{
+ return isignal;
+#else
+int QAxClientSite::qt_metacall(QMetaObject::Call call, int isignal, void **argv)
+{
+ if (!m_spOleObject || call != QMetaObject::InvokeMetaMethod || !menuBar)
+ return isignal;
+
+ if (isignal != menuBar->metaObject()->indexOfSignal("triggered(QAction*)"))
+ return isignal;
+
+ QAction *action = *(QAction**)argv[1];
+ // ###
+
+ OleMenuItem oleItem = menuItemMap.value(action);
+ if (oleItem.hMenu)
+ ::PostMessageA(m_menuOwner, WM_COMMAND, oleItem.id, 0);
+ return -1;
+#endif
+}
+
+
+HRESULT WINAPI QAxClientSite::RemoveMenus(HMENU /*hmenuShared*/)
+{
+#if defined(Q_OS_WINCE)
+ return E_NOTIMPL;
+#else
+ AX_DEBUG(QAxClientSite::RemoveMenus);
+ QMap<QAction*, OleMenuItem>::Iterator it;
+ for (it = menuItemMap.begin(); it != menuItemMap.end(); ++it) {
+ QAction *action = it.key();
+ action->setVisible(false);
+ delete action;
+ }
+ menuItemMap.clear();
+ return S_OK;
+#endif
+}
+
+HRESULT WINAPI QAxClientSite::SetStatusText(LPCOLESTR pszStatusText)
+{
+ QStatusTipEvent tip(QString::fromUtf16((const ushort *)(BSTR)pszStatusText));
+ QApplication::sendEvent(widget, &tip);
+ return S_OK;
+}
+
+extern Q_GUI_EXPORT bool qt_win_ignoreNextMouseReleaseEvent;
+
+HRESULT WINAPI QAxClientSite::EnableModeless(BOOL fEnable)
+{
+ EnableWindow(host->window()->winId(), fEnable);
+
+ if (!fEnable) {
+ if (!QApplicationPrivate::isBlockedByModal(host))
+ QApplicationPrivate::enterModal(host);
+ } else {
+ if (QApplicationPrivate::isBlockedByModal(host))
+ QApplicationPrivate::leaveModal(host);
+ }
+ qt_win_ignoreNextMouseReleaseEvent = false;
+
+ return S_OK;
+}
+
+HRESULT WINAPI QAxClientSite::TranslateAccelerator(LPMSG lpMsg, WORD grfModifiers)
+{
+ return TranslateAccelerator(lpMsg, (DWORD)grfModifiers);
+}
+
+//**** IOleInPlaceUIWindow
+HRESULT WINAPI QAxClientSite::GetBorder(LPRECT lprectBorder)
+{
+#ifndef QAX_SUPPORT_BORDERSPACE
+ Q_UNUSED(lprectBorder);
+ return INPLACE_E_NOTOOLSPACE;
+#else
+ AX_DEBUG(QAxClientSite::GetBorder);
+
+ QMainWindow *mw = qobject_cast<QMainWindow*>(widget->window());
+ if (!mw)
+ return INPLACE_E_NOTOOLSPACE;
+
+ RECT border = { 0,0, 300, 200 };
+ *lprectBorder = border;
+ return S_OK;
+#endif
+}
+
+HRESULT WINAPI QAxClientSite::RequestBorderSpace(LPCBORDERWIDTHS /*pborderwidths*/)
+{
+#ifndef QAX_SUPPORT_BORDERSPACE
+ return INPLACE_E_NOTOOLSPACE;
+#else
+ AX_DEBUG(QAxClientSite::RequestBorderSpace);
+
+ QMainWindow *mw = qobject_cast<QMainWindow*>(widget->window());
+ if (!mw)
+ return INPLACE_E_NOTOOLSPACE;
+
+ return S_OK;
+#endif
+}
+
+HRESULT WINAPI QAxClientSite::SetBorderSpace(LPCBORDERWIDTHS pborderwidths)
+{
+#ifndef QAX_SUPPORT_BORDERSPACE
+ Q_UNUSED(pborderwidths);
+ return OLE_E_INVALIDRECT;
+#else
+ AX_DEBUG(QAxClientSite::SetBorderSpace);
+
+ // object has no toolbars and wants container toolbars to remain
+ if (!pborderwidths)
+ return S_OK;
+
+ QMainWindow *mw = qobject_cast<QMainWindow*>(widget->window());
+ if (!mw)
+ return OLE_E_INVALIDRECT;
+
+ bool removeToolBars = !(pborderwidths->left || pborderwidths->top || pborderwidths->right || pborderwidths->bottom);
+
+ // object has toolbars, and wants container to remove toolbars
+ if (removeToolBars) {
+ if (mw) {
+ //### remove our toolbars
+ }
+ }
+
+ if (pborderwidths->left) {
+ QDockWidget *left = new QDockWidget(mw);
+ left->setFixedWidth(pborderwidths->left);
+ mw->addDockWidget(Qt::LeftDockWidgetArea, left);
+ left->show();
+ }
+ if (pborderwidths->top) {
+ QDockWidget *top = new QDockWidget(mw);
+ top->setFixedHeight(pborderwidths->top);
+ mw->addDockWidget(Qt::TopDockWidgetArea, top);
+ top->show();
+ }
+
+ return S_OK;
+#endif
+}
+
+HRESULT WINAPI QAxClientSite::SetActiveObject(IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName)
+{
+ AX_DEBUG(QAxClientSite::SetActiveObject);
+
+ if (pszObjName && widget)
+ widget->setWindowTitle(QString::fromUtf16((const ushort *)(BSTR)pszObjName));
+
+ if (m_spInPlaceActiveObject) {
+ if (!inPlaceModelessEnabled)
+ m_spInPlaceActiveObject->EnableModeless(true);
+ inPlaceModelessEnabled = true;
+ m_spInPlaceActiveObject->Release();
+ }
+
+ m_spInPlaceActiveObject = pActiveObject;
+ if (m_spInPlaceActiveObject)
+ m_spInPlaceActiveObject->AddRef();
+
+ return S_OK;
+}
+
+//**** IOleDocumentSite
+HRESULT WINAPI QAxClientSite::ActivateMe(IOleDocumentView *pViewToActivate)
+{
+ AX_DEBUG(QAxClientSite::ActivateMe);
+
+ if (m_spActiveView)
+ m_spActiveView->Release();
+ m_spActiveView = 0;
+
+ if (!pViewToActivate) {
+ IOleDocument *document = 0;
+ m_spOleObject->QueryInterface(IID_IOleDocument, (void**)&document);
+ if (!document)
+ return E_FAIL;
+
+ document->CreateView(this, 0, 0, &pViewToActivate);
+
+ document->Release();
+ if (!pViewToActivate)
+ return E_OUTOFMEMORY;
+ } else {
+ pViewToActivate->SetInPlaceSite(this);
+ }
+
+ m_spActiveView = pViewToActivate;
+ m_spActiveView->AddRef();
+
+ m_spActiveView->UIActivate(TRUE);
+
+ RECT rect;
+ GetClientRect(widget->winId(), &rect);
+ m_spActiveView->SetRect(&rect);
+ m_spActiveView->Show(TRUE);
+
+ return S_OK;
+}
+
+QSize QAxClientSite::minimumSizeHint() const
+{
+ if (!m_spOleObject)
+ return QSize();
+
+ SIZE sz = { 0, 0 };
+ m_spOleObject->SetExtent(DVASPECT_CONTENT, &sz);
+ HRESULT res = m_spOleObject->GetExtent(DVASPECT_CONTENT, &sz);
+ if (SUCCEEDED(res)) {
+ return QSize(MAP_LOGHIM_TO_PIX(sz.cx, widget->logicalDpiX()),
+ MAP_LOGHIM_TO_PIX(sz.cy, widget->logicalDpiY()));
+ }
+ return QSize();
+}
+
+void QAxClientSite::windowActivationChange()
+{
+ AX_DEBUG(QAxClientSite::windowActivationChange);
+
+ if (m_spInPlaceActiveObject && widget) {
+ QWidget *modal = QApplication::activeModalWidget();
+ if (modal && inPlaceModelessEnabled) {
+ m_spInPlaceActiveObject->EnableModeless(false);
+ inPlaceModelessEnabled = false;
+ } else if (!inPlaceModelessEnabled) {
+ m_spInPlaceActiveObject->EnableModeless(true);
+ inPlaceModelessEnabled = true;
+ }
+ m_spInPlaceActiveObject->OnFrameWindowActivate(widget->isActiveWindow());
+ }
+}
+
+
+//**** QWidget
+
+QAxHostWidget::QAxHostWidget(QWidget *parent, QAxClientSite *ax)
+: QWidget(parent), setFocusTimer(0), hasFocus(false), axhost(ax)
+{
+ setAttribute(Qt::WA_NoBackground);
+ setAttribute(Qt::WA_NoSystemBackground);
+ setAttribute(Qt::WA_OpaquePaintEvent);
+ setAttribute(Qt::WA_PaintOnScreen);
+
+ setObjectName(parent->objectName() + QLatin1String(" - QAxHostWidget"));
+}
+
+QAxHostWidget::~QAxHostWidget()
+{
+ if (axhost)
+ axhost->reset(this);
+}
+
+int QAxHostWidget::qt_metacall(QMetaObject::Call call, int isignal, void **argv)
+{
+ if (axhost)
+ return axhost->qt_metacall(call, isignal, argv);
+ return -1;
+}
+
+QSize QAxHostWidget::sizeHint() const
+{
+ return axhost ? axhost->sizeHint() : QWidget::sizeHint();
+}
+
+QSize QAxHostWidget::minimumSizeHint() const
+{
+ QSize size;
+ if (axhost)
+ size = axhost->minimumSizeHint();
+ if (size.isValid())
+ return size;
+ return QWidget::minimumSizeHint();
+}
+
+void QAxHostWidget::resizeObject()
+{
+ if (!axhost)
+ return;
+
+ // document server - talk to view?
+ if (axhost->m_spActiveView) {
+ RECT rect;
+ GetClientRect(winId(), &rect);
+ axhost->m_spActiveView->SetRect(&rect);
+
+ return;
+ }
+
+ SIZEL hmSize;
+ hmSize.cx = MAP_PIX_TO_LOGHIM(width(), logicalDpiX());
+ hmSize.cy = MAP_PIX_TO_LOGHIM(height(), logicalDpiY());
+
+ if (axhost->m_spOleObject)
+ axhost->m_spOleObject->SetExtent(DVASPECT_CONTENT, &hmSize);
+ if (axhost->m_spInPlaceObject) {
+ RECT rcPos = { x(), y(), x()+width(), y()+height() };
+ axhost->m_spInPlaceObject->SetObjectRects(&rcPos, &rcPos);
+ }
+}
+
+void QAxHostWidget::resizeEvent(QResizeEvent *)
+{
+ resizeObject();
+}
+
+void QAxHostWidget::showEvent(QShowEvent *)
+{
+ resizeObject();
+}
+
+bool QAxHostWidget::winEvent(MSG *msg, long *result)
+{
+ if (axhost && axhost->inPlaceObjectWindowless) {
+ Q_ASSERT(axhost->m_spInPlaceObject);
+ IOleInPlaceObjectWindowless *windowless = (IOleInPlaceObjectWindowless*)axhost->m_spInPlaceObject;
+ Q_ASSERT(windowless);
+ LRESULT lres;
+ HRESULT hres = windowless->OnWindowMessage(msg->message, msg->wParam, msg->lParam, &lres);
+ if (hres == S_OK)
+ return true;
+ }
+ return QWidget::winEvent(msg, result);
+}
+
+bool QAxHostWidget::event(QEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::Timer:
+ if (axhost && ((QTimerEvent*)e)->timerId() == setFocusTimer) {
+ killTimer(setFocusTimer);
+ setFocusTimer = 0;
+ RECT rcPos = { x(), y(), x()+size().width(), y()+size().height() };
+ axhost->m_spOleObject->DoVerb(OLEIVERB_UIACTIVATE, 0, (IOleClientSite*)axhost, 0, winId(), &rcPos);
+ if (axhost->m_spActiveView)
+ axhost->m_spActiveView->UIActivate(TRUE);
+ }
+ break;
+ case QEvent::WindowBlocked:
+ if (IsWindowEnabled(winId())) {
+ EnableWindow(winId(), false);
+ if (axhost && axhost->m_spInPlaceActiveObject) {
+ axhost->inPlaceModelessEnabled = false;
+ axhost->m_spInPlaceActiveObject->EnableModeless(false);
+ }
+ }
+ break;
+ case QEvent::WindowUnblocked:
+ if (!IsWindowEnabled(winId())) {
+ EnableWindow(winId(), true);
+ if (axhost && axhost->m_spInPlaceActiveObject) {
+ axhost->inPlaceModelessEnabled = true;
+ axhost->m_spInPlaceActiveObject->EnableModeless(true);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return QWidget::event(e);
+}
+
+bool QAxHostWidget::eventFilter(QObject *o, QEvent *e)
+{
+ // focus goes to Qt while ActiveX still has it - deactivate
+ QWidget *newFocus = qobject_cast<QWidget*>(o);
+ if (e->type() == QEvent::FocusIn && hasFocus
+ && newFocus && newFocus->window() == window()) {
+ if (axhost && axhost->m_spInPlaceActiveObject && axhost->m_spInPlaceObject)
+ axhost->m_spInPlaceObject->UIDeactivate();
+ qApp->removeEventFilter(this);
+ }
+
+ return QWidget::eventFilter(o, e);
+}
+
+void QAxHostWidget::focusInEvent(QFocusEvent *e)
+{
+ QWidget::focusInEvent(e);
+
+ if (!axhost || !axhost->m_spOleObject)
+ return;
+
+ // this is called by QWidget::setFocus which calls ::SetFocus on "this",
+ // so we have to UIActivate the control after all that had happend.
+ AX_DEBUG(Setting focus on in-place object);
+ setFocusTimer = startTimer(0);
+}
+
+void QAxHostWidget::focusOutEvent(QFocusEvent *e)
+{
+ QWidget::focusOutEvent(e);
+ if (setFocusTimer) {
+ killTimer(setFocusTimer);
+ setFocusTimer = 0;
+ }
+ if (e->reason() == Qt::PopupFocusReason || e->reason() == Qt::MenuBarFocusReason)
+ return;
+
+ if (!axhost || !axhost->m_spInPlaceActiveObject || !axhost->m_spInPlaceObject)
+ return;
+
+ AX_DEBUG(Deactivating in-place object);
+ axhost->m_spInPlaceObject->UIDeactivate();
+}
+
+
+void QAxHostWidget::paintEvent(QPaintEvent*)
+{
+ if (!QPainter::redirected(this))
+ return;
+
+ IViewObject *view = 0;
+ if (axhost)
+ axhost->widget->queryInterface(IID_IViewObject, (void**)&view);
+ if (!view)
+ return;
+
+ // somebody tries to grab us!
+ QPixmap pm(size());
+ pm.fill();
+
+ HBITMAP hBmp = pm.toWinHBITMAP();
+ HDC hBmp_hdc = CreateCompatibleDC(qt_win_display_dc());
+ HGDIOBJ old_hBmp = SelectObject(hBmp_hdc, hBmp);
+
+ RECTL bounds;
+ bounds.left = 0;
+ bounds.right = pm.width();
+ bounds.top = 0;
+ bounds.bottom = pm.height();
+
+ view->Draw(DVASPECT_CONTENT, -1, 0, 0, 0, hBmp_hdc, &bounds, 0, 0 /*fptr*/, 0);
+ view->Release();
+
+ QPainter painter(this);
+ painter.drawPixmap(0, 0, QPixmap::fromWinHBITMAP(hBmp));
+
+ SelectObject(hBmp_hdc, old_hBmp);
+ DeleteObject(hBmp);
+ DeleteDC(hBmp_hdc);
+}
+
+/*!
+ \class QAxWidget
+ \brief The QAxWidget class is a QWidget that wraps an ActiveX control.
+
+ \inmodule QAxContainer
+
+ A QAxWidget can be instantiated as an empty object, with the name
+ of the ActiveX control it should wrap, or with an existing
+ interface pointer to the ActiveX control. The ActiveX control's
+ properties, methods and events which only use QAxBase
+ supported data types, become available as Qt properties,
+ slots and signals. The base class QAxBase provides an API to
+ access the ActiveX directly through the \c IUnknown pointer.
+
+ QAxWidget is a QWidget and can mostly be used as such, e.g. it can be
+ organized in a widget hierarchy and layouts or act as an event filter.
+ Standard widget properties, e.g. \link QWidget::enabled
+ enabled \endlink are supported, but it depends on the ActiveX
+ control to implement support for ambient properties like e.g.
+ palette or font. QAxWidget tries to provide the necessary hints.
+
+ However, you cannot reimplement Qt-specific event handlers like
+ mousePressEvent or keyPressEvent and expect them to be called reliably.
+ The embedded control covers the QAxWidget completely, and usually
+ handles the user interface itself. Use control-specific APIs (i.e. listen
+ to the signals of the control), or use standard COM techniques like
+ window procedure subclassing.
+
+ QAxWidget also inherits most of its ActiveX-related functionality
+ from QAxBase, notably dynamicCall() and querySubObject().
+
+ \warning
+ You can subclass QAxWidget, but you cannot use the \c Q_OBJECT macro
+ in the subclass (the generated moc-file will not compile), so you
+ cannot add further signals, slots or properties. This limitation
+ is due to the metaobject information generated in runtime. To work
+ around this problem, aggregate the QAxWidget as a member of the
+ QObject subclass.
+
+ \sa QAxBase, QAxObject, QAxScript, {ActiveQt Framework}
+*/
+
+/*!
+ Creates an empty QAxWidget widget and propagates \a parent
+ and \a f to the QWidget constructor. To initialize a control,
+ call setControl().
+*/
+QAxWidget::QAxWidget(QWidget *parent, Qt::WindowFlags f)
+: QWidget(parent, f), container(0)
+{
+}
+
+/*!
+ Creates an QAxWidget widget and initializes the ActiveX control \a c.
+ \a parent and \a f are propagated to the QWidget contructor.
+
+ \sa setControl()
+*/
+QAxWidget::QAxWidget(const QString &c, QWidget *parent, Qt::WindowFlags f)
+: QWidget(parent, f), container(0)
+{
+ setControl(c);
+}
+
+/*!
+ Creates a QAxWidget that wraps the COM object referenced by \a iface.
+ \a parent and \a f are propagated to the QWidget contructor.
+*/
+QAxWidget::QAxWidget(IUnknown *iface, QWidget *parent, Qt::WindowFlags f)
+: QWidget(parent, f), QAxBase(iface), container(0)
+{
+}
+
+/*!
+ Shuts down the ActiveX control and destroys the QAxWidget widget,
+ cleaning up all allocated resources.
+
+ \sa clear()
+*/
+QAxWidget::~QAxWidget()
+{
+ if (container)
+ container->reset(this);
+ clear();
+}
+
+/*!
+ \since 4.2
+
+ Calls QAxBase::initialize(\a ptr), and embeds the control in this
+ widget by calling createHostWindow(false) if successful.
+
+ To initialize the control before it is activated, reimplement this
+ function and add your initialization code before you call
+ createHostWindow(true).
+*/
+bool QAxWidget::initialize(IUnknown **ptr)
+{
+ if (!QAxBase::initialize(ptr))
+ return false;
+
+ return createHostWindow(false); // assume that control is not initialized
+}
+
+/*!
+ Creates the client site for the ActiveX control, and returns true if
+ the control could be embedded successfully, otherwise returns false.
+ If \a initialized is true the control has already been initialized.
+
+ This function is called by initialize(). If you reimplement initialize
+ to customize the actual control instantiation, call this function in your
+ reimplementation to have the control embedded by the default client side.
+ Creates the client site for the ActiveX control, and returns true if
+ the control could be embedded successfully, otherwise returns false.
+*/
+bool QAxWidget::createHostWindow(bool initialized)
+{
+ return createHostWindow(initialized, QByteArray());
+}
+
+/*!
+ \since 4.4
+
+ Creates the client site for the ActiveX control, and returns true if
+ the control could be embedded successfully, otherwise returns false.
+ If \a initialized is false the control will be initialized using the
+ \a data. The control will be initialized through either IPersistStreamInit
+ or IPersistStorage interface.
+
+ If the control needs to be initialized using custom data, call this function
+ in your reimplementation of initialize(). This function is not called by
+ the default implementation of initialize().
+*/
+bool QAxWidget::createHostWindow(bool initialized, const QByteArray &data)
+{
+#ifdef QT3_SUPPORT
+ QApplication::sendPostedEvents(0, QEvent::ChildInserted);
+#endif
+
+ container = new QAxClientSite(this);
+ container->activateObject(initialized, data);
+
+#if !defined(Q_OS_WINCE)
+ ATOM filter_ref = FindAtomA(qaxatom);
+#endif
+ if (!filter_ref)
+ previous_filter = QAbstractEventDispatcher::instance()->setEventFilter(axc_FilterProc);
+#if !defined(Q_OS_WINCE)
+ AddAtomA(qaxatom);
+#else
+ ++filter_ref;
+#endif
+
+ if (parentWidget())
+ QApplication::postEvent(parentWidget(), new QEvent(QEvent::LayoutRequest));
+
+ return true;
+}
+
+/*!
+ Reimplement this function when you want to implement additional
+ COM interfaces for the client site of 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 *QAxWidget::createAggregate()
+{
+ return 0;
+}
+
+/*!
+ \reimp
+
+ Shuts down the ActiveX control.
+*/
+void QAxWidget::clear()
+{
+ if (isNull())
+ return;
+ if (!control().isEmpty()) {
+#if !defined(Q_OS_WINCE)
+ ATOM filter_ref = FindAtomA(qaxatom);
+ if (filter_ref)
+ DeleteAtom(filter_ref);
+ filter_ref = FindAtomA(qaxatom);
+ if (!filter_ref) {
+#else
+ if (!filter_ref && !--filter_ref) {
+#endif
+ QAbstractEventDispatcher::instance()->setEventFilter(previous_filter);
+ previous_filter = 0;
+ }
+ }
+
+ if (container)
+ container->deactivate();
+
+ QAxBase::clear();
+ setFocusPolicy(Qt::NoFocus);
+
+ if (container) {
+ container->releaseAll();
+ container->Release();
+ }
+ container = 0;
+}
+
+/*!
+ \since 4.1
+
+ Requests the ActiveX control to perform the action \a verb. The
+ possible verbs are returned by verbs().
+
+ The function returns true if the object could perform the action, otherwise returns false.
+*/
+bool QAxWidget::doVerb(const QString &verb)
+{
+ if (!verbs().contains(verb))
+ return false;
+
+ HRESULT hres = container->doVerb(indexOfVerb(verb));
+
+ return hres == S_OK;
+}
+
+ /*!
+ \fn QObject *QAxWidget::qObject() const
+ \internal
+*/
+
+/*!
+ \reimp
+*/
+const QMetaObject *QAxWidget::metaObject() const
+{
+ return QAxBase::metaObject();
+}
+
+/*!
+ \reimp
+*/
+const QMetaObject *QAxWidget::parentMetaObject() const
+{
+ return &QWidget::staticMetaObject;
+}
+
+/*!
+ \internal
+*/
+void *QAxWidget::qt_metacast(const char *cname)
+{
+ if (!qstrcmp(cname, "QAxWidget")) return (void*)this;
+ if (!qstrcmp(cname, "QAxBase")) return (QAxBase*)this;
+ return QWidget::qt_metacast(cname);
+}
+
+/*!
+ \reimp
+*/
+const char *QAxWidget::className() const
+{
+ return "QAxWidget";
+}
+
+/*!
+ \reimp
+*/
+int QAxWidget::qt_metacall(QMetaObject::Call call, int id, void **v)
+{
+ id = QWidget::qt_metacall(call, id, v);
+ if (id < 0)
+ return id;
+ return QAxBase::qt_metacall(call, id, v);
+}
+
+/*!
+ \reimp
+*/
+QSize QAxWidget::sizeHint() const
+{
+ if (container) {
+ QSize sh = container->sizeHint();
+ if (sh.isValid())
+ return sh;
+ }
+
+ return QWidget::sizeHint();
+}
+
+/*!
+ \reimp
+*/
+QSize QAxWidget::minimumSizeHint() const
+{
+ if (container) {
+ QSize sh = container->minimumSizeHint();
+ if (sh.isValid())
+ return sh;
+ }
+
+ return QWidget::minimumSizeHint();
+}
+
+/*!
+ \reimp
+*/
+void QAxWidget::changeEvent(QEvent *e)
+{
+ if (isNull())
+ return;
+
+ switch (e->type()) {
+ case QEvent::EnabledChange:
+ container->emitAmbientPropertyChange(DISPID_AMBIENT_UIDEAD);
+ break;
+ case QEvent::FontChange:
+ container->emitAmbientPropertyChange(DISPID_AMBIENT_FONT);
+ break;
+ case QEvent::PaletteChange:
+ container->emitAmbientPropertyChange(DISPID_AMBIENT_BACKCOLOR);
+ container->emitAmbientPropertyChange(DISPID_AMBIENT_FORECOLOR);
+ break;
+ case QEvent::ActivationChange:
+ container->windowActivationChange();
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ \reimp
+*/
+void QAxWidget::resizeEvent(QResizeEvent *)
+{
+ if (container)
+ container->resize(size());
+}
+
+/*!
+ \reimp
+*/
+void QAxWidget::connectNotify(const char *)
+{
+ QAxBase::connectNotify();
+}
+
+
+/*!
+ Reimplement this function to pass certain key events to the
+ ActiveX control. \a message is the Window message identifier
+ specifying the message type (ie. WM_KEYDOWN), and \a keycode is
+ the virtual keycode (ie. VK_TAB).
+
+ If the function returns true the key event is passed on to the
+ ActiveX control, which then either processes the event or passes
+ the event on to Qt.
+
+ If the function returns false the processing of the key event is
+ ignored by ActiveQt, ie. the ActiveX control might handle it or
+ not.
+
+ The default implementation returns true for the following cases:
+
+ \table
+ \header
+ \i WM_SYSKEYDOWN
+ \i WM_SYSKEYUP
+ \i WM_KEYDOWN
+ \row
+ \i All keycodes
+ \i VK_MENU
+ \i VK_TAB, VK_DELETE and all non-arrow-keys in combination with VK_SHIFT,
+ VK_CONTROL or VK_MENU
+ \endtable
+
+ This table is the result of experimenting with popular ActiveX controls,
+ ie. Internet Explorer and Microsoft Office applications, but for some
+ controls it might require modification.
+*/
+bool QAxWidget::translateKeyEvent(int message, int keycode) const
+{
+ bool translate = false;
+
+ switch (message) {
+ case WM_SYSKEYDOWN:
+ translate = true;
+ break;
+ case WM_KEYDOWN:
+ translate = keycode == VK_TAB
+ || keycode == VK_DELETE;
+ if (!translate) {
+ int state = 0;
+ if (GetKeyState(VK_SHIFT) < 0)
+ state |= 0x01;
+ if (GetKeyState(VK_CONTROL) < 0)
+ state |= 0x02;
+ if (GetKeyState(VK_MENU) < 0)
+ state |= 0x04;
+ if (state) {
+ state = keycode < VK_LEFT || keycode > VK_DOWN;
+ }
+ translate = state;
+ }
+ break;
+ case WM_SYSKEYUP:
+ translate = keycode == VK_MENU;
+ break;
+ }
+
+ return translate;
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_WIN_ACTIVEQT
diff --git a/src/activeqt/container/qaxwidget.h b/src/activeqt/container/qaxwidget.h
new file mode 100644
index 0000000..e07caad
--- /dev/null
+++ b/src/activeqt/container/qaxwidget.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** 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 QAXWIDGET_H
+#define QAXWIDGET_H
+
+#include <ActiveQt/qaxbase.h>
+#include <QtGui/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(ActiveQt)
+
+#ifndef QT_NO_WIN_ACTIVEQT
+
+class QAxHostWindow;
+class QAxAggregated;
+
+class QAxClientSite;
+
+class QAxWidget : public QWidget, public QAxBase
+{
+public:
+ const QMetaObject *metaObject() const;
+ void* qt_metacast(const char*);
+ int qt_metacall(QMetaObject::Call, int, void **);
+ QObject* qObject() const { return (QWidget*)this; }
+ const char *className() const;
+
+ QAxWidget(QWidget* parent = 0, Qt::WindowFlags f = 0);
+ QAxWidget(const QString &c, QWidget *parent = 0, Qt::WindowFlags f = 0);
+ QAxWidget(IUnknown *iface, QWidget *parent = 0, Qt::WindowFlags f = 0);
+ ~QAxWidget();
+
+ void clear();
+ bool doVerb(const QString &verb);
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ virtual QAxAggregated *createAggregate();
+
+protected:
+ bool initialize(IUnknown**);
+ virtual bool createHostWindow(bool);
+ bool createHostWindow(bool, const QByteArray&);
+
+ void changeEvent(QEvent *e);
+ void resizeEvent(QResizeEvent *);
+
+ virtual bool translateKeyEvent(int message, int keycode) const;
+
+ void connectNotify(const char *signal);
+private:
+ friend class QAxClientSite;
+ QAxClientSite *container;
+
+ const QMetaObject *parentMetaObject() const;
+ static QMetaObject staticMetaObject;
+};
+
+#if defined Q_CC_MSVC && _MSC_VER < 1300
+template <> inline QAxWidget *qobject_cast_helper<QAxWidget*>(const QObject *o, QAxWidget *)
+#else
+template <> inline QAxWidget *qobject_cast<QAxWidget*>(const QObject *o)
+#endif
+{
+ void *result = o ? const_cast<QObject *>(o)->qt_metacast("QAxWidget") : 0;
+ return (QAxWidget*)(result);
+}
+
+#if defined Q_CC_MSVC && _MSC_VER < 1300
+template <> inline QAxWidget *qobject_cast_helper<QAxWidget*>(QObject *o, QAxWidget *)
+#else
+template <> inline QAxWidget *qobject_cast<QAxWidget*>(QObject *o)
+#endif
+{
+ void *result = o ? o->qt_metacast("QAxWidget") : 0;
+ return (QAxWidget*)(result);
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_WIN_ACTIVEQT
+
+QT_END_HEADER
+
+#endif // QAXWIDGET_H