1
/****************************************************************************
3
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
7
** This file is part of the ActiveQt framework of the Qt Toolkit.
9
** $QT_BEGIN_LICENSE:BSD$
10
** You may use this file under the terms of the BSD license as follows:
12
** "Redistribution and use in source and binary forms, with or without
13
** modification, are permitted provided that the following conditions are
15
** * Redistributions of source code must retain the above copyright
16
** notice, this list of conditions and the following disclaimer.
17
** * Redistributions in binary form must reproduce the above copyright
18
** notice, this list of conditions and the following disclaimer in
19
** the documentation and/or other materials provided with the
21
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
22
** the names of its contributors may be used to endorse or promote
23
** products derived from this software without specific prior written
26
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
39
****************************************************************************/
41
//#define QAX_NO_CLASSINFO
43
#define QT_CHECK_STATE
45
#include "qaxobject.h"
47
#ifndef QT_NO_WIN_ACTIVEQT
56
#include <qmetaobject.h>
57
#include <qsettings.h>
63
#include <qt_windows.h>
67
#include "../shared/qaxtypes.h"
75
\brief The QAxMetaObject class stores extended information
77
struct QAxMetaObject : public QMetaObject
86
delete [] (int*)d.data;
87
delete [] (char*)d.stringdata;
90
int numParameter(const QByteArray &prototype);
91
QByteArray paramType(const QByteArray &signature, int index, bool *out = 0);
92
QByteArray propertyType(const QByteArray &propertyName);
93
void parsePrototype(const QByteArray &prototype);
94
DISPID dispIDofName(const QByteArray &name, IDispatch *disp);
97
friend class MetaObjectGenerator;
98
// save information about QAxEventSink connections, and connect when found in cache
99
QList<QUuid> connectionInterfaces;
100
// DISPID -> signal name
101
QMap< QUuid, QMap<DISPID, QByteArray> > sigs;
102
// DISPID -> property changed signal name
103
QMap< QUuid, QMap<DISPID, QByteArray> > propsigs;
104
// DISPID -> property name
105
QMap< QUuid, QMap<DISPID, QByteArray> > props;
107
// Prototype -> member info
108
QHash<QByteArray, QList<QByteArray> > memberInfo;
109
QMap<QByteArray, QByteArray> realPrototype;
112
QHash<QByteArray, DISPID> dispIDs;
115
void QAxMetaObject::parsePrototype(const QByteArray &prototype)
117
QByteArray realProto = realPrototype.value(prototype, prototype);
118
QByteArray parameters = realProto.mid(realProto.indexOf('(') + 1);
119
parameters.truncate(parameters.length() - 1);
121
if (parameters.isEmpty()) {
122
memberInfo.insert(prototype, QList<QByteArray>());
124
QList<QByteArray> plist = parameters.split(',');
125
memberInfo.insert(prototype, plist);
129
inline QByteArray QAxMetaObject::propertyType(const QByteArray &propertyName)
131
return realPrototype.value(propertyName);
134
int QAxMetaObject::numParameter(const QByteArray &prototype)
136
if (!memberInfo.contains(prototype))
137
parsePrototype(prototype);
139
return memberInfo.value(prototype).count();
142
QByteArray QAxMetaObject::paramType(const QByteArray &prototype, int index, bool *out)
144
if (!memberInfo.contains(prototype))
145
parsePrototype(prototype);
150
QList<QByteArray> plist = memberInfo.value(prototype);
151
if (index > plist.count() - 1)
154
QByteArray param(plist.at(index));
158
bool byRef = param.endsWith('&') || param.endsWith("**");
160
param.truncate(param.length() - 1);
168
inline DISPID QAxMetaObject::dispIDofName(const QByteArray &name, IDispatch *disp)
170
DISPID dispid = dispIDs.value(name, DISPID_UNKNOWN);
171
if (dispid == DISPID_UNKNOWN) {
172
// get the Dispatch ID from the object
173
QString unicodeName = QLatin1String(name);
174
OLECHAR *names = (wchar_t*)unicodeName.utf16();
175
disp->GetIDsOfNames(IID_NULL, &names, 1, LOCALE_USER_DEFAULT, &dispid);
176
if (dispid != DISPID_UNKNOWN)
177
dispIDs.insert(name, dispid);
183
static QHash<QString, QAxMetaObject*> mo_cache;
184
static QHash<QUuid, QMap<QByteArray, QList<QPair<QByteArray, int> > > > enum_cache;
185
static int mo_cache_ref = 0;
186
static QMutex cache_mutex;
189
static const char *const type_conversion[][2] =
191
{ "float", "double"},
194
{ "QList<int>", "QVariantList" },
195
{ "QList<uint>", "QVariantList" },
196
{ "QList<double>", "QVariantList" },
197
{ "QList<bool>", "QVariantList" },
198
{ "QList<QDateTime>", "QVariantList" },
199
{ "QList<qlonglong>", "QVariantList" },
207
\brief The QAxEventSink class implements the event sink for all
208
IConnectionPoints implemented in the COM object.
211
class QAxEventSink : public IDispatch, public IPropertyNotifySink
214
QAxEventSink(QAxBase *com)
215
: cpoint(0), ciid(IID_NULL), combase(com), ref(1)
217
virtual ~QAxEventSink()
222
QUuid connectionInterface() const
226
QMap<DISPID, QByteArray> signalMap() const
230
QMap<DISPID, QByteArray> propertyMap() const
234
QMap<DISPID, QByteArray> propSignalMap() const
240
void advise(IConnectionPoint *cp, IID iid)
245
cpoint->Advise((IUnknown*)(IDispatch*)this, &cookie);
248
// disconnect from all connection points
253
cpoint->Unadvise(cookie);
259
void addSignal(DISPID memid, const char *name)
261
QByteArray signalname = name;
262
int pi = signalname.indexOf('(');
264
while (type_conversion[i][0]) {
266
int len = int(strlen(type_conversion[i][0]));
267
while ((ti = signalname.indexOf(type_conversion[i][0], ti)) != -1)
268
signalname.replace(ti, len, type_conversion[i][1]);
272
sigs.insert(memid, signalname);
273
QMap<DISPID,QByteArray>::ConstIterator it;
275
for (it = propsigs.constBegin(); it!= propsigs.constEnd(); ++it) {
276
if (it.value() == signalname) {
284
void addProperty(DISPID propid, const char *name, const char *signal)
286
props.insert(propid, name);
287
propsigs.insert(propid, signal);
291
unsigned long __stdcall AddRef()
295
unsigned long __stdcall Release()
303
HRESULT __stdcall QueryInterface(REFIID riid, void **ppvObject)
306
if (riid == IID_IUnknown)
307
*ppvObject = (IUnknown*)(IDispatch*)this;
308
else if (riid == IID_IDispatch)
309
*ppvObject = (IDispatch*)this;
310
else if (riid == IID_IPropertyNotifySink)
311
*ppvObject = (IPropertyNotifySink*)this;
312
else if (ciid == riid)
313
*ppvObject = (IDispatch*)this;
315
return E_NOINTERFACE;
322
HRESULT __stdcall GetTypeInfoCount(unsigned int *) { return E_NOTIMPL; }
323
HRESULT __stdcall GetTypeInfo(UINT, LCID, ITypeInfo **) { return E_NOTIMPL; }
324
HRESULT __stdcall GetIDsOfNames(const _GUID &, wchar_t **, unsigned int, unsigned long, long *) { return E_NOTIMPL; }
326
HRESULT __stdcall Invoke(DISPID dispIdMember,
330
DISPPARAMS *pDispParams,
336
if (riid != IID_NULL)
337
return DISP_E_UNKNOWNINTERFACE;
338
if (!(wFlags & DISPATCH_METHOD))
339
return DISP_E_MEMBERNOTFOUND;
343
QByteArray signame = sigs.value(dispIdMember);
344
if (signame.isEmpty())
345
return DISP_E_MEMBERNOTFOUND;
347
QObject *qobject = combase->qObject();
348
if (qobject->signalsBlocked())
351
QAxMetaObject *axmeta = combase->internalMetaObject();
352
const QMetaObject *meta = combase->metaObject();
355
// emit the generic signal "as is"
356
if (signalHasReceivers(qobject, "signal(QString,int,void*)")) {
357
index = meta->indexOfSignal("signal(QString,int,void*)");
358
Q_ASSERT(index != -1);
360
QString nameString = QLatin1String(signame);
361
void *argv[] = {0, &nameString, &pDispParams->cArgs, &pDispParams->rgvarg};
362
combase->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv);
367
// get the signal information from the metaobject
369
if (signalHasReceivers(qobject, signame)) {
370
index = meta->indexOfSignal(signame);
371
Q_ASSERT(index != -1);
372
const QMetaMethod signal = meta->method(index);
373
Q_ASSERT(signal.methodType() == QMetaMethod::Signal);
374
Q_ASSERT(signame == signal.signature());
375
// verify parameter count
376
int pcount = axmeta->numParameter(signame);
377
int argcount = pDispParams->cArgs;
378
if (pcount > argcount)
379
return DISP_E_PARAMNOTOPTIONAL;
380
else if (pcount < argcount)
381
return DISP_E_BADPARAMCOUNT;
383
// setup parameters (no return values in signals)
385
void *static_argv[QAX_NUM_PARAMS + 1];
386
void *static_argv_pointer[QAX_NUM_PARAMS + 1];
387
QVariant static_varp[QAX_NUM_PARAMS + 1];
390
void **argv_pointer = 0; // in case we need an additional level of indirection
394
if (pcount <= QAX_NUM_PARAMS) {
396
argv_pointer = static_argv_pointer;
399
argv = new void*[pcount + 1];
400
argv_pointer = new void*[pcount + 1];
401
varp = new QVariant[pcount + 1];
409
for (p = 0; p < pcount && ok; ++p) {
410
// map the VARIANT to the void*
411
QByteArray ptype = axmeta->paramType(signame, p);
412
varp[p + 1] = VARIANTToQVariant(pDispParams->rgvarg[pcount - p - 1], ptype);
413
argv_pointer[p + 1] = 0;
414
if (varp[p + 1].isValid()) {
415
if (varp[p + 1].type() == QVariant::UserType) {
416
argv[p + 1] = varp[p + 1].data();
417
} else if (ptype == "QVariant") {
418
argv[p + 1] = varp + p + 1;
420
argv[p + 1] = const_cast<void*>(varp[p + 1].constData());
421
if (ptype.endsWith('*')) {
422
argv_pointer[p + 1] = argv[p + 1];
423
argv[p + 1] = argv_pointer + p + 1;
426
} else if (ptype == "QVariant") {
427
argv[p + 1] = varp + p + 1;
434
// emit the generated signal if everything went well
435
combase->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv);
436
// update the VARIANT for references and free memory
437
for (p = 0; p < pcount; ++p) {
439
QByteArray ptype = axmeta->paramType(signame, p, &out);
441
if (!QVariantToVARIANT(varp[p + 1], pDispParams->rgvarg[pcount - p - 1], ptype, out))
447
if (argv != static_argv) {
449
delete [] argv_pointer;
452
hres = ok ? S_OK : (ok ? DISP_E_MEMBERNOTFOUND : DISP_E_TYPEMISMATCH);
458
QByteArray findProperty(DISPID dispID);
460
// IPropertyNotifySink
461
HRESULT __stdcall OnChanged(DISPID dispID)
464
if (dispID == DISPID_UNKNOWN || !combase)
467
const QMetaObject *meta = combase->metaObject();
471
QByteArray propname(findProperty(dispID));
472
if (propname.isEmpty())
475
QObject *qobject = combase->qObject();
476
if (qobject->signalsBlocked())
479
// emit the generic signal
480
int index = meta->indexOfSignal("propertyChanged(QString)");
482
QString propnameString = QString::fromLatin1(propname);
483
void *argv[] = {0, &propnameString};
484
combase->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv);
487
QByteArray signame = propsigs.value(dispID);
488
if (signame.isEmpty())
491
index = meta->indexOfSignal(signame);
492
if (index == -1) // bindable but not marked as bindable in typelib
495
// get the signal information from the metaobject
496
if (signalHasReceivers(qobject, signame)) {
497
index = meta->indexOfSignal(signame);
498
Q_ASSERT(index != -1);
500
QVariant var = qobject->property(propname);
504
const QMetaProperty metaProp = meta->property(meta->indexOfProperty(propname));
505
void *argv[] = {0, var.data()};
506
if (metaProp.type() == QVariant::LastType)
509
// emit the "changed" signal
510
combase->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv);
514
HRESULT __stdcall OnRequestEdit(DISPID dispID)
516
if (dispID == DISPID_UNKNOWN || !combase)
519
QByteArray propname(findProperty(dispID));
520
if (propname.isEmpty())
523
return combase->propertyWritable(propname) ? S_OK : S_FALSE;
526
static bool signalHasReceivers(QObject *qobject, const char *signalName)
529
return ((QAxObject*)qobject)->receivers(QByteArray::number(QSIGNAL_CODE) + signalName);
532
IConnectionPoint *cpoint;
536
QMap<DISPID, QByteArray> sigs;
537
QMap<DISPID, QByteArray> propsigs;
538
QMap<DISPID, QByteArray> props;
546
\class QAxBasePrivate
553
: useEventSink(true), useMetaObject(true), useClassInfo(true),
554
cachedMetaObject(false), initialized(false), tryCache(false),
555
ptr(0), disp(0), metaobj(0)
557
// protect initialization
558
QMutexLocker locker(&cache_mutex);
561
qRegisterMetaType<IUnknown*>("IUnknown*", &ptr);
562
qRegisterMetaType<IDispatch*>("IDispatch*", &disp);
571
QMutexLocker locker(&cache_mutex);
572
if (!--mo_cache_ref) {
573
qDeleteAll(mo_cache);
577
CoFreeUnusedLibraries();
580
inline IDispatch *dispatch() const
586
ptr->QueryInterface(IID_IDispatch, (void**)&disp);
592
QHash<QUuid, QAxEventSink*> eventSink;
593
uint useEventSink :1;
594
uint useMetaObject :1;
595
uint useClassInfo :1;
596
uint cachedMetaObject :1;
601
mutable IDispatch *disp;
603
QMap<QByteArray, bool> propWritable;
605
inline QAxMetaObject *metaObject()
608
metaobj = new QAxMetaObject;
612
mutable QMap<QString, LONG> verbs;
614
QAxMetaObject *metaobj;
618
QByteArray QAxEventSink::findProperty(DISPID dispID)
620
// look up in cache, and fall back to
621
// type info for precompiled metaobjects
622
QByteArray propname(props.value(dispID));
624
if (!propname.isEmpty())
627
IDispatch *dispatch = combase->d->dispatch();
628
ITypeInfo *typeinfo = 0;
630
dispatch->GetTypeInfo(0, LOCALE_USER_DEFAULT, &typeinfo);
636
typeinfo->GetNames(dispID, &names, 1, &cNames);
638
propname = QString::fromWCharArray(names).toLatin1();
639
SysFreeString(names);
643
QByteArray propsignal(propname + "Changed(");
644
const QMetaObject *mo = combase->metaObject();
645
int index = mo->indexOfProperty(propname);
646
const QMetaProperty prop = mo->property(index);
647
propsignal += prop.typeName();
649
addProperty(dispID, propname, propsignal);
656
\brief The QAxBase class is an abstract class that provides an API
657
to initialize and access a COM object.
659
\inmodule QAxContainer
661
QAxBase is an abstract class that cannot be used directly, and is
662
instantiated through the subclasses QAxObject and QAxWidget. This
663
class provides the API to access the COM object directly
664
through its IUnknown implementation. If the COM object implements
665
the IDispatch interface, the properties and methods of that object
666
become available as Qt properties and slots.
668
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 0
670
Properties exposed by the object's IDispatch implementation can
671
be read and written through the property system provided by the
672
Qt Object Model (both subclasses are QObjects, so you can use
673
QObject::setProperty() and QObject::property()). Properties with
674
multiple parameters are not supported.
676
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 1
678
Write-functions for properties and other methods exposed by the
679
object's IDispatch implementation can be called directly using
680
dynamicCall(), or indirectly as slots connected to a signal.
682
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 2
684
Outgoing events supported by the COM object are emitted as
687
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 3
689
QAxBase transparently converts between COM data types and the
690
equivalent Qt data types. Some COM types have no equivalent Qt data structure.
692
Supported COM datatypes are listed in the first column of following table.
693
The second column is the Qt type that can be used with the QObject property
694
functions. The third column is the Qt type that is used in the prototype of
695
generated signals and slots for in-parameters, and the last column is the Qt
696
type that is used in the prototype of signals and slots for out-parameters.
714
\i char, short, int, long
719
\i uchar, ushort, uint, ulong
744
\i SAFEARRAY(VARIANT)
746
\i const QList\<QVariant\>&
747
\i QList\<QVariant\>&
749
\i SAFEARRAY(int), SAFEARRAY(double), SAFEARRAY(Date)
751
\i const QList\<QVariant\>&
752
\i QList\<QVariant\>&
761
\i const QStringList&
781
\i \c QAxBase::asVariant()
782
\i QAxObject* (return value)
786
\i \c QAxBase::asVariant()
787
\i QAxObject* (return value)
794
\i VARIANT* (Since Qt 4.5)
800
Supported are also enumerations, and typedefs to supported types.
802
To call the methods of a COM interface described by the following IDL
804
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 4
806
use the QAxBase API like this:
808
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 5
810
Note that the QList the object should fill has to be provided as an
811
element in the parameter list of \l{QVariant}s.
813
If you need to access properties or pass parameters of
814
unsupported datatypes you must access the COM object directly
815
through its \c IDispatch implementation or other interfaces.
816
Those interfaces can be retrieved through queryInterface().
818
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 6
820
To get the definition of the COM interfaces you will have to use the header
821
files provided with the component you want to use. Some compilers can also
822
import type libraries using the #import compiler directive. See the component
823
documentation to find out which type libraries you have to import, and how to use
826
If you need to react to events that pass parameters of unsupported
827
datatypes you can use the generic signal that delivers the event
828
data as provided by the COM event.
830
\sa QAxObject, QAxWidget, QAxScript, {ActiveQt Framework}
834
\typedef QAxBase::PropertyBag
836
A QMap<QString,QVariant> that can store properties as name:value pairs.
840
Creates a QAxBase object that wraps the COM object \a iface. If \a
841
iface is 0 (the default), use setControl() to instantiate a COM
844
QAxBase::QAxBase(IUnknown *iface)
846
d = new QAxBasePrivate();
850
d->initialized = true;
852
#if defined(Q_OS_WINCE)
853
CoInitializeEx(0, COINIT_MULTITHREADED);
858
Shuts down the COM object and destroys the QAxBase object.
864
#if defined(Q_OS_WINCE)
877
Used by subclasses generated with dumpcpp to balance reference count.
879
void QAxBase::internalRelease()
888
Used by subclasses generated with dumpcpp to implement cast-operators.
890
void QAxBase::initializeFrom(QAxBase *that)
895
d->ptr = that->d->ptr;
898
d->initialized = true;
903
QAxMetaObject *QAxBase::internalMetaObject() const
905
return d->metaObject();
909
\property QAxBase::control
910
\brief the name of the COM object wrapped by this QAxBase object.
912
Setting this property initilializes the COM object. Any COM object
913
previously set is shut down.
915
The most efficient way to set this property is by using the
916
registered component's UUID, e.g.
918
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 7
920
The second fastest way is to use the registered control's class
921
name (with or without version number), e.g.
923
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 8
925
The slowest, but easiest way to use is to use the control's full
928
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 9
930
It is also possible to initialize the object from a file, e.g.
932
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 10
934
If the component's UUID is used the following patterns can be used
935
to initialize the control on a remote machine, to initialize a
936
licensed control or to connect to a running object:
938
\i To initialize the control on a different machine use the following
941
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 11
943
\i To initialize a licensed control use the following pattern:
945
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 12
947
\i To connect to an already running object use the following pattern:
949
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 13
952
The first two patterns can be combined, e.g. to initialize a licensed
953
control on a remote machine:
955
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 14
957
The control's read function always returns the control's UUID, if provided including the license
958
key, and the name of the server, but not including the username, the domain or the password.
960
bool QAxBase::setControl(const QString &c)
962
if (c.toLower() == d->ctrl.toLower())
963
return !d->ctrl.isEmpty();
966
// don't waste time for DCOM requests
967
int dcomIDIndex = search.indexOf(QLatin1String("/{"));
968
if ((dcomIDIndex == -1 || dcomIDIndex != search.length()-39) && !search.endsWith(QLatin1String("}&"))) {
972
HRESULT res = CLSIDFromProgID((wchar_t*)c.utf16(), &clsid);
974
search = QUuid(clsid).toString();
976
QSettings controls(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes\\"), QSettings::NativeFormat);
977
search = controls.value(c + QLatin1String("/CLSID/Default")).toString();
978
if (search.isEmpty()) {
979
controls.beginGroup(QLatin1String("/CLSID"));
980
QStringList clsids = controls.childGroups();
981
for (QStringList::Iterator it = clsids.begin(); it != clsids.end(); ++it) {
983
QString name = controls.value(clsid + QLatin1String("/Default")).toString();
993
if (search.isEmpty())
997
if (search.toLower() == d->ctrl.toLower())
998
return !d->ctrl.isEmpty();
1004
if (!initialize(&d->ptr))
1005
d->initialized = true;
1007
qWarning("QAxBase::setControl: requested control %s could not be instantiated", c.toLatin1().data());
1014
QString QAxBase::control() const
1020
Disables the event sink implementation for this ActiveX container.
1021
If you don't intend to listen to the ActiveX control's events use
1022
this function to speed up the meta object generation.
1024
Some ActiveX controls might be unstable when connected to an event
1025
sink. To get OLE events you must use standard COM methods to
1026
register your own event sink. Use queryInterface() to get access
1027
to the raw COM object.
1029
Note that this function should be called immediately after
1030
construction of the object.
1032
void QAxBase::disableEventSink()
1034
d->useEventSink = false;
1038
Disables the meta object generation for this ActiveX container.
1039
This also disables the event sink and class info generation. If
1040
you don't intend to use the Qt meta object implementation call
1041
this function to speed up instantiation of the control. You will
1042
still be able to call the object through \l dynamicCall(), but
1043
signals, slots and properties will not be available with QObject
1046
Some ActiveX controls might be unstable when used with OLE
1047
automation. Use standard COM methods to use those controls through
1048
the COM interfaces provided by queryInterface().
1050
Note that this function must be called immediately after
1051
construction of the object.
1053
void QAxBase::disableMetaObject()
1055
d->useMetaObject = false;
1056
d->useEventSink = false;
1057
d->useClassInfo = false;
1061
Disables the class info generation for this ActiveX container. If
1062
you don't require any class information about the ActiveX control
1063
use this function to speed up the meta object generation.
1065
Note that this function must be called immediately after
1066
construction of the object
1068
void QAxBase::disableClassInfo()
1070
d->useClassInfo = false;
1074
Disconnects and destroys the COM object.
1076
If you reimplement this function you must also reimplement the
1077
destructor to call clear(), and call this implementation at the
1078
end of your clear() function.
1080
void QAxBase::clear()
1082
QHash<QUuid, QAxEventSink*>::Iterator it = d->eventSink.begin();
1083
while (it != d->eventSink.end()) {
1084
QAxEventSink *eventSink = it.value();
1087
eventSink->unadvise();
1088
eventSink->Release();
1091
d->eventSink.clear();
1099
d->initialized = false;
1104
if (!d->cachedMetaObject)
1112
Returns the list of verbs that the COM object can execute. If
1113
the object does not implement IOleObject, or does not support
1114
any verbs, then this function returns an empty stringlist.
1116
Note that the OLE default verbs (OLEIVERB_SHOW etc) are not
1117
included in the list.
1119
QStringList QAxBase::verbs() const
1122
return QStringList();
1124
if (d->verbs.isEmpty()) {
1125
IOleObject *ole = 0;
1126
d->ptr->QueryInterface(IID_IOleObject, (void**)&ole);
1128
IEnumOLEVERB *enumVerbs = 0;
1129
ole->EnumVerbs(&enumVerbs);
1134
while (enumVerbs->Next(1, &verb, &c) == S_OK) {
1135
if (!verb.lpszVerbName)
1137
QString verbName = QString::fromWCharArray(verb.lpszVerbName);
1138
if (!verbName.isEmpty())
1139
d->verbs.insert(verbName, verb.lVerb);
1141
enumVerbs->Release();
1147
return d->verbs.keys();
1154
long QAxBase::indexOfVerb(const QString &verb) const
1156
return d->verbs.value(verb);
1160
This virtual function is called by setControl() and creates the
1161
requested COM object. \a ptr is set to the object's IUnknown
1162
implementation. The function returns true if the object
1163
initialization succeeded; otherwise the function returns false.
1165
The default implementation interprets the string returned by
1166
control(), and calls initializeRemote(), initializeLicensed()
1167
or initializeActive() if the string matches the respective
1168
patterns. If control() is the name of an existing file,
1169
initializeFromFile() is called. If no pattern is matched, or
1170
if remote or licensed initialization fails, CoCreateInstance
1171
is used directly to create the object.
1173
See the \l control property documentation for details about
1176
The interface returned in \a ptr must be referenced exactly once
1177
when this function returns. The interface provided by e.g.
1178
CoCreateInstance is already referenced, and there is no need to
1181
bool QAxBase::initialize(IUnknown **ptr)
1183
if (*ptr || control().isEmpty())
1190
const QString ctrl(d->ctrl);
1191
if (ctrl.contains(QLatin1String("/{"))) // DCOM request
1192
res = initializeRemote(ptr);
1193
else if (ctrl.contains(QLatin1String("}:"))) // licensed control
1194
res = initializeLicensed(ptr);
1195
else if (ctrl.contains(QLatin1String("}&"))) // running object
1196
res = initializeActive(ptr);
1197
else if (QFile::exists(ctrl)) // existing file
1198
res = initializeFromFile(ptr);
1200
if (!res) { // standard
1201
HRESULT hres = CoCreateInstance(QUuid(ctrl), 0, CLSCTX_SERVER, IID_IUnknown, (void**)ptr);
1205
qErrnoWarning(hres, "CoCreateInstance failure");
1213
Creates an instance of a licensed control, and returns the IUnknown interface
1214
to the object in \a ptr. This functions returns true if successful, otherwise
1217
This function is called by initialize() if the control string contains the
1218
substring "}:". The license key needs to follow this substring.
1222
bool QAxBase::initializeLicensed(IUnknown** ptr)
1224
int at = control().lastIndexOf(QLatin1String("}:"));
1226
QString clsid(control().left(at));
1227
QString key(control().mid(at+2));
1229
IClassFactory *factory = 0;
1230
CoGetClassObject(QUuid(clsid), CLSCTX_SERVER, 0, IID_IClassFactory, (void**)&factory);
1233
initializeLicensedHelper(factory, key, ptr);
1240
Called by initializeLicensed and initializedRemote to create an object
1243
bool QAxBase::initializeLicensedHelper(void *f, const QString &key, IUnknown **ptr)
1245
IClassFactory *factory = (IClassFactory*)f;
1246
IClassFactory2 *factory2 = 0;
1247
factory->QueryInterface(IID_IClassFactory2, (void**)&factory2);
1249
BSTR bkey = QStringToBSTR(key);
1250
HRESULT hres = factory2->CreateInstanceLic(0, 0, IID_IUnknown, bkey, (void**)ptr);
1251
SysFreeString(bkey);
1254
licinfo.cbLicInfo = sizeof(LICINFO);
1255
factory2->GetLicInfo(&licinfo);
1259
qErrnoWarning("CreateInstanceLic failed");
1260
if (!licinfo.fLicVerified) {
1261
qWarning("Wrong license key specified, and machine is not fully licensed.");
1262
} else if (licinfo.fRuntimeKeyAvail) {
1264
factory2->RequestLicKey(0, &licenseKey);
1265
QString qlicenseKey = QString::fromWCharArray(licenseKey);
1266
SysFreeString(licenseKey);
1267
qWarning("Use license key is '%s' to create object on unlicensed machine.",
1268
qlicenseKey.toLatin1().constData());
1270
} else if (licinfo.fLicVerified) {
1271
qWarning("Machine is fully licensed for '%s'", control().toLatin1().constData());
1272
if (licinfo.fRuntimeKeyAvail) {
1274
factory2->RequestLicKey(0, &licenseKey);
1275
QString qlicenseKey = QString::fromWCharArray(licenseKey);
1276
SysFreeString(licenseKey);
1278
if (qlicenseKey != key)
1279
qWarning("Runtime license key is '%s'", qlicenseKey.toLatin1().constData());
1285
factory2->Release();
1286
} else { // give it a shot without license
1287
factory->CreateInstance(0, IID_IUnknown, (void**)ptr);
1294
Connects to an active instance running on the current machine, and returns the
1295
IUnknown interface to the running object in \a ptr. This function returns true
1296
if successful, otherwise returns false.
1298
This function is called by initialize() if the control string contains the
1303
bool QAxBase::initializeActive(IUnknown** ptr)
1305
#if defined(Q_OS_WINCE)
1309
int at = control().lastIndexOf(QLatin1String("}&"));
1310
QString clsid(control().left(at));
1312
GetActiveObject(QUuid(clsid), 0, ptr);
1319
# ifndef OLEPENDER_NONE
1320
# define OLERENDER_NONE 0
1325
Creates the COM object handling the filename in the control property, and
1326
returns the IUnknown interface to the object in \a ptr. This function returns
1327
true if successful, otherwise returns false.
1329
This function is called by initialize() if the control string is the name of
1334
bool QAxBase::initializeFromFile(IUnknown** ptr)
1336
#if defined(Q_OS_WINCE)
1340
IStorage *storage = 0;
1341
ILockBytes * bytes = 0;
1342
HRESULT hres = ::CreateILockBytesOnHGlobal(0, TRUE, &bytes);
1343
hres = ::StgCreateDocfileOnILockBytes(bytes, STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &storage);
1345
hres = OleCreateFromFile(CLSID_NULL, reinterpret_cast<const wchar_t*>(control().utf16()), IID_IUnknown, OLERENDER_NONE, 0, 0, storage, (void**)ptr);
1350
return hres == S_OK;
1355
// There seams to be a naming problem in mingw headers
1357
#ifndef COAUTHIDENTITY
1358
#define COAUTHIDENTITY AUTH_IDENTITY
1364
Creates the instance on a remote server, and returns the IUnknown interface
1365
to the object in \a ptr. This function returns true if successful, otherwise
1368
This function is called by initialize() if the control string contains the
1369
substring "/{". The information about the remote machine needs to be provided
1370
in front of the substring.
1374
bool QAxBase::initializeRemote(IUnknown** ptr)
1376
int at = control().lastIndexOf(QLatin1String("/{"));
1378
QString server(control().left(at));
1379
QString clsid(control().mid(at+1));
1386
at = server.indexOf(QChar::fromLatin1('@'));
1388
user = server.left(at);
1389
server = server.mid(at+1);
1391
at = user.indexOf(QChar::fromLatin1(':'));
1393
passwd = user.mid(at+1);
1394
user = user.left(at);
1396
at = user.indexOf(QChar::fromLatin1('/'));
1398
domain = user.left(at);
1399
user = user.mid(at+1);
1403
at = clsid.lastIndexOf(QLatin1String("}:"));
1405
key = clsid.mid(at+2);
1406
clsid = clsid.left(at);
1409
d->ctrl = server + QChar::fromLatin1('/') + clsid;
1411
d->ctrl = d->ctrl + QChar::fromLatin1(':') + key;
1413
COAUTHIDENTITY authIdentity;
1414
authIdentity.UserLength = user.length();
1415
authIdentity.User = authIdentity.UserLength ? (ushort*)user.utf16() : 0;
1416
authIdentity.DomainLength = domain.length();
1417
authIdentity.Domain = authIdentity.DomainLength ? (ushort*)domain.utf16() : 0;
1418
authIdentity.PasswordLength = passwd.length();
1419
authIdentity.Password = authIdentity.PasswordLength ? (ushort*)passwd.utf16() : 0;
1420
authIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
1422
COAUTHINFO authInfo;
1423
authInfo.dwAuthnSvc = RPC_C_AUTHN_WINNT;
1424
authInfo.dwAuthzSvc = RPC_C_AUTHZ_NONE;
1425
authInfo.pwszServerPrincName = 0;
1426
authInfo.dwAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT;
1427
authInfo.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
1428
authInfo.pAuthIdentityData = &authIdentity;
1429
authInfo.dwCapabilities = 0;
1431
COSERVERINFO serverInfo;
1432
serverInfo.dwReserved1 = 0;
1433
serverInfo.dwReserved2 = 0;
1434
serverInfo.pAuthInfo = &authInfo;
1435
serverInfo.pwszName = (wchar_t*)server.utf16();
1437
IClassFactory *factory = 0;
1438
HRESULT res = CoGetClassObject(QUuid(clsid), CLSCTX_REMOTE_SERVER, &serverInfo, IID_IClassFactory, (void**)&factory);
1441
initializeLicensedHelper(factory, key, ptr);
1443
res = factory->CreateInstance(0, IID_IUnknown, (void**)ptr);
1448
qErrnoWarning(res, "initializeRemote Failed");
1455
Requests the interface \a uuid from the COM object and sets the
1456
value of \a iface to the provided interface, or to 0 if the
1457
requested interface could not be provided.
1459
Returns the result of the QueryInterface implementation of the COM object.
1463
long QAxBase::queryInterface(const QUuid &uuid, void **iface) const
1467
((QAxBase*)this)->initialize(&d->ptr);
1468
d->initialized = true;
1471
if (d->ptr && !uuid.isNull())
1472
return d->ptr->QueryInterface(uuid, iface);
1477
class MetaObjectGenerator
1480
MetaObjectGenerator(QAxBase *ax, QAxBasePrivate *dptr);
1481
MetaObjectGenerator(ITypeLib *typelib, ITypeInfo *typeinfo);
1482
~MetaObjectGenerator();
1484
QMetaObject *metaObject(const QMetaObject *parentObject, const QByteArray &className = QByteArray());
1486
void readClassInfo();
1487
void readEnumInfo();
1488
void readInterfaceInfo();
1489
void readFuncsInfo(ITypeInfo *typeinfo, ushort nFuncs);
1490
void readVarsInfo(ITypeInfo *typeinfo, ushort nVars);
1491
void readEventInfo();
1492
void readEventInterface(ITypeInfo *eventinfo, IConnectionPoint *cpoint);
1494
inline void addClassInfo(const char *key, const char *value)
1496
classinfo_list.insert(key, value);
1503
QMetaObject *tryCache();
1505
QByteArray createPrototype(FUNCDESC *funcdesc, ITypeInfo *typeinfo, const QList<QByteArray> &names,
1506
QByteArray &type, QList<QByteArray> ¶meters);
1508
QByteArray usertypeToString(const TYPEDESC &tdesc, ITypeInfo *info, const QByteArray &function);
1509
QByteArray guessTypes(const TYPEDESC &tdesc, ITypeInfo *info, const QByteArray &function);
1511
// ### from qmetaobject.cpp
1513
Invalid = 0x00000000,
1514
Readable = 0x00000001,
1515
Writable = 0x00000002,
1516
Resettable = 0x00000004,
1517
EnumOrFlag = 0x00000008,
1518
StdCppSet = 0x00000100,
1519
// Override = 0x00000200,
1520
Designable = 0x00001000,
1521
ResolveDesignable = 0x00002000,
1522
Scriptable = 0x00004000,
1523
ResolveScriptable = 0x00008000,
1524
Stored = 0x00010000,
1525
ResolveStored = 0x00020000,
1526
Editable = 0x00040000,
1527
ResolveEditable = 0x00080000,
1529
ResolveUser = 0x00200000,
1530
// And our own - don't use the upper byte, as it's used for the property type
1531
RequestingEdit = 0x00400000,
1532
Bindable = 0x00800000
1535
AccessPrivate = 0x00,
1536
AccessProtected = 0x01,
1537
AccessPublic = 0x02,
1538
MemberMethod = 0x00,
1539
MemberSignal = 0x04,
1541
MemberCompatibility = 0x10,
1542
MemberCloned = 0x20,
1543
MemberScriptable = 0x40,
1546
inline QList<QByteArray> paramList(const QByteArray &proto)
1548
QByteArray prototype(proto);
1549
QByteArray parameters = prototype.mid(prototype.indexOf('(') + 1);
1550
parameters.truncate(parameters.length() - 1);
1552
QList<QByteArray> plist = parameters.split(',');
1556
inline QByteArray replaceType(const QByteArray &type)
1559
while (type_conversion[i][0]) {
1560
int len = int(strlen(type_conversion[i][0]));
1562
if ((ti = type.indexOf(type_conversion[i][0])) != -1) {
1563
QByteArray rtype(type);
1564
rtype.replace(ti, len, type_conversion[i][1]);
1572
QByteArray replacePrototype(const QByteArray &prototype)
1574
QByteArray proto(prototype);
1576
QList<QByteArray> plist = paramList(prototype);
1577
for (int p = 0; p < plist.count(); ++p) {
1578
QByteArray param(plist.at(p));
1579
if (param != replaceType(param)) {
1581
while (type_conversion[type][0]) {
1582
int paren = proto.indexOf('(');
1583
while ((paren = proto.indexOf(type_conversion[type][0])) != -1) {
1584
proto.replace(paren, qstrlen(type_conversion[type][0]), type_conversion[type][1]);
1595
QMap<QByteArray, QByteArray> classinfo_list;
1597
inline bool hasClassInfo(const char *key)
1599
return classinfo_list.contains(key);
1606
QByteArray parameters;
1608
QByteArray realPrototype;
1610
QMap<QByteArray, Method> signal_list;
1611
inline void addSignal(const QByteArray &prototype, const QByteArray ¶meters)
1613
QByteArray proto(replacePrototype(prototype));
1615
Method &signal = signal_list[proto];
1617
signal.parameters = parameters;
1618
signal.flags = QMetaMethod::Public | MemberSignal;
1619
if (proto != prototype)
1620
signal.realPrototype = prototype;
1623
void addChangedSignal(const QByteArray &function, const QByteArray &type, int memid);
1625
inline bool hasSignal(const QByteArray &prototype)
1627
return signal_list.contains(prototype);
1630
QMap<QByteArray, Method> slot_list;
1631
inline void addSlot(const QByteArray &type, const QByteArray &prototype, const QByteArray ¶meters, int flags = QMetaMethod::Public)
1633
QByteArray proto = replacePrototype(prototype);
1635
Method &slot = slot_list[proto];
1636
slot.type = replaceType(type);
1637
slot.parameters = parameters;
1638
slot.flags = flags | MemberSlot;
1639
if (proto != prototype)
1640
slot.realPrototype = prototype;
1643
void addSetterSlot(const QByteArray &property);
1645
inline bool hasSlot(const QByteArray &prototype)
1647
return slot_list.contains(prototype);
1651
Property() : typeId(0)
1655
QByteArray realType;
1657
QMap<QByteArray, Property> property_list;
1658
void addProperty(const QByteArray &type, const QByteArray &name, uint flags)
1660
QByteArray propertyType(type);
1661
if (propertyType.endsWith('&'))
1662
propertyType.chop(1);
1664
Property &prop = property_list[name];
1665
if (!propertyType.isEmpty() && propertyType != "HRESULT") {
1666
prop.type = replaceType(propertyType);
1667
if (prop.type != propertyType)
1668
prop.realType = propertyType;
1670
if (flags & Writable)
1672
prop.typeId |= flags;
1673
QVariant::Type vartype = QVariant::nameToType(prop.type);
1675
case QVariant::Invalid:
1676
if (prop.type == "QVariant") {
1677
prop.typeId |= 0xff << 24;
1681
case QVariant::UserType:
1682
if (QMetaType::type(prop.type) == -1)
1683
qWarning("QAxBase: Unsupported property type: %s", prop.type.data());
1686
prop.typeId |= vartype << 24;
1691
inline bool hasProperty(const QByteArray &name)
1693
return property_list.contains(name);
1696
inline QByteArray propertyType(const QByteArray &name)
1698
return property_list.value(name).type;
1701
QMap<QByteArray, QList<QPair<QByteArray, int> > > enum_list;
1702
inline void addEnumValue(const QByteArray &enumname, const QByteArray &key, int value)
1704
enum_list[enumname].append(QPair<QByteArray, int>(key, value));
1707
inline bool hasEnum(const QByteArray &enumname)
1709
return enum_list.contains(enumname);
1716
ITypeInfo *dispInfo;
1717
ITypeInfo *classInfo;
1719
QByteArray current_typelib;
1723
QByteArray debugInfo;
1725
QUuid iid_propNotifySink;
1727
friend QMetaObject *qax_readClassInfo(ITypeLib *typeLib, ITypeInfo *classInfo, const QMetaObject *parentObject);
1730
QMetaObject *qax_readEnumInfo(ITypeLib *typeLib, const QMetaObject *parentObject)
1732
MetaObjectGenerator generator(typeLib, 0);
1734
generator.readEnumInfo();
1735
return generator.metaObject(parentObject, "EnumInfo");
1738
QMetaObject *qax_readInterfaceInfo(ITypeLib *typeLib, ITypeInfo *typeInfo, const QMetaObject *parentObject)
1740
MetaObjectGenerator generator(typeLib, typeInfo);
1744
if (S_OK != typeInfo->GetDocumentation(-1, &bstr, 0, 0, 0))
1747
className = QString::fromWCharArray(bstr);
1748
SysFreeString(bstr);
1750
generator.readEnumInfo();
1751
generator.readFuncsInfo(typeInfo, 0);
1752
generator.readVarsInfo(typeInfo, 0);
1754
return generator.metaObject(parentObject, className.toLatin1());
1757
QMetaObject *qax_readClassInfo(ITypeLib *typeLib, ITypeInfo *classInfo, const QMetaObject *parentObject)
1759
MetaObjectGenerator generator(typeLib, 0);
1760
generator.addSignal("exception(int,QString,QString,QString)", "code,source,disc,help");
1761
generator.addSignal("propertyChanged(QString)", "name");
1765
if (S_OK != classInfo->GetDocumentation(-1, &bstr, 0, 0, 0))
1768
className = QString::fromWCharArray(bstr);
1769
SysFreeString(bstr);
1771
generator.readEnumInfo();
1774
classInfo->GetTypeAttr(&typeattr);
1776
int nInterfaces = typeattr->cImplTypes;
1777
classInfo->ReleaseTypeAttr(typeattr);
1779
for (int index = 0; index < nInterfaces; ++index) {
1781
if (S_OK != classInfo->GetRefTypeOfImplType(index, &refType))
1785
classInfo->GetImplTypeFlags(index, &flags);
1786
if (flags & IMPLTYPEFLAG_FRESTRICTED)
1789
ITypeInfo *interfaceInfo = 0;
1790
classInfo->GetRefTypeInfo(refType, &interfaceInfo);
1794
interfaceInfo->GetDocumentation(-1, &bstr, 0, 0, 0);
1795
QString interfaceName = QString::fromWCharArray(bstr);
1796
SysFreeString(bstr);
1799
TYPEATTR *typeattr = 0;
1800
interfaceInfo->GetTypeAttr(&typeattr);
1802
if (flags & IMPLTYPEFLAG_FSOURCE) {
1803
if (typeattr && !(typeattr->wTypeFlags & TYPEFLAG_FHIDDEN))
1804
key = "Event Interface " + QByteArray::number(index);
1805
generator.readEventInterface(interfaceInfo, 0);
1807
if (typeattr && !(typeattr->wTypeFlags & TYPEFLAG_FHIDDEN))
1808
key = "Interface " + QByteArray::number(index);
1809
generator.readFuncsInfo(interfaceInfo, 0);
1810
generator.readVarsInfo(interfaceInfo, 0);
1813
generator.addClassInfo(key.data(), interfaceName.toLatin1());
1816
interfaceInfo->ReleaseTypeAttr(typeattr);
1817
interfaceInfo->Release();
1821
return generator.metaObject(parentObject, className.toLatin1());
1824
MetaObjectGenerator::MetaObjectGenerator(QAxBase *ax, QAxBasePrivate *dptr)
1825
: that(ax), d(dptr), disp(0), dispInfo(0), classInfo(0), typelib(0),
1826
iidnames(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes"), QSettings::NativeFormat)
1831
MetaObjectGenerator::MetaObjectGenerator(ITypeLib *tlib, ITypeInfo *tinfo)
1832
: that(0), d(0), disp(0), dispInfo(tinfo), classInfo(0), typelib(tlib),
1833
iidnames(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes"), QSettings::NativeFormat)
1842
typelib->GetDocumentation(-1, &bstr, 0, 0, 0);
1843
current_typelib = QString::fromWCharArray(bstr).toLatin1();
1844
SysFreeString(bstr);
1849
void MetaObjectGenerator::init()
1852
disp = d->dispatch();
1854
iid_propNotifySink = IID_IPropertyNotifySink;
1856
addSignal("signal(QString,int,void*)", "name,argc,argv");
1857
addSignal("exception(int,QString,QString,QString)", "code,source,disc,help");
1858
addSignal("propertyChanged(QString)", "name");
1859
if (d || dispInfo) {
1860
addProperty("QString", "control", Readable|Writable|Designable|Scriptable|Stored|Editable|StdCppSet);
1864
MetaObjectGenerator::~MetaObjectGenerator()
1866
if (dispInfo) dispInfo->Release();
1867
if (classInfo) classInfo->Release();
1868
if (typelib) typelib->Release();
1871
bool qax_dispatchEqualsIDispatch = true;
1872
QList<QByteArray> qax_qualified_usertypes;
1874
QByteArray MetaObjectGenerator::usertypeToString(const TYPEDESC &tdesc, ITypeInfo *info, const QByteArray &function)
1876
HREFTYPE usertype = tdesc.hreftype;
1877
if (tdesc.vt != VT_USERDEFINED)
1880
QByteArray typeName;
1881
ITypeInfo *usertypeinfo = 0;
1882
info->GetRefTypeInfo(usertype, &usertypeinfo);
1884
ITypeLib *usertypelib = 0;
1886
usertypeinfo->GetContainingTypeLib(&usertypelib, &index);
1888
// get type library name
1889
BSTR typelibname = 0;
1890
usertypelib->GetDocumentation(-1, &typelibname, 0, 0, 0);
1891
QByteArray typeLibName = QString::fromWCharArray(typelibname).toLatin1();
1892
SysFreeString(typelibname);
1895
BSTR usertypename = 0;
1896
usertypelib->GetDocumentation(index, &usertypename, 0, 0, 0);
1897
QByteArray userTypeName = QString::fromWCharArray(usertypename).toLatin1();
1898
SysFreeString(usertypename);
1900
if (hasEnum(userTypeName)) // known enum?
1901
typeName = userTypeName;
1902
else if (userTypeName == "OLE_COLOR" || userTypeName == "VB_OLE_COLOR")
1903
typeName = "QColor";
1904
else if (userTypeName == "IFontDisp" || userTypeName == "IFontDisp*" || userTypeName == "IFont" || userTypeName == "IFont*")
1906
else if (userTypeName == "Picture" || userTypeName == "Picture*")
1907
typeName = "QPixmap";
1909
if (typeName.isEmpty()) {
1910
TYPEATTR *typeattr = 0;
1911
usertypeinfo->GetTypeAttr(&typeattr);
1913
switch(typeattr->typekind) {
1915
userTypeName = guessTypes(typeattr->tdescAlias, usertypeinfo, function);
1917
case TKIND_DISPATCH:
1919
if (qax_dispatchEqualsIDispatch) {
1920
userTypeName = "IDispatch";
1922
if (typeLibName != current_typelib)
1923
userTypeName = typeLibName + "::" + userTypeName;
1924
if (!qax_qualified_usertypes.contains(userTypeName))
1925
qax_qualified_usertypes << userTypeName;
1929
if (typeLibName != current_typelib)
1930
userTypeName = typeLibName + "::" + userTypeName;
1931
if (!qax_qualified_usertypes.contains("enum " + userTypeName))
1932
qax_qualified_usertypes << "enum " + userTypeName;
1934
case TKIND_INTERFACE:
1935
if (typeLibName != current_typelib)
1936
userTypeName = typeLibName + "::" + userTypeName;
1937
if (!qax_qualified_usertypes.contains(userTypeName))
1938
qax_qualified_usertypes << userTypeName;
1941
if (!qax_qualified_usertypes.contains("struct " + userTypeName))
1942
qax_qualified_usertypes << "struct "+ userTypeName;
1949
usertypeinfo->ReleaseTypeAttr(typeattr);
1950
typeName = userTypeName;
1952
usertypelib->Release();
1954
usertypeinfo->Release();
1960
#define VT_UNHANDLED(x) case VT_##x: qWarning("QAxBase: Unhandled type %s", #x); str = #x; break;
1962
QByteArray MetaObjectGenerator::guessTypes(const TYPEDESC &tdesc, ITypeInfo *info, const QByteArray &function)
2025
str = guessTypes(*tdesc.lptdesc, info, function);
2026
switch(tdesc.lptdesc->vt) {
2049
if (str == "QFont" || str == "QPixmap") {
2052
} else if (str == "void*") {
2058
if (str == "QColor")
2060
else if (str == "QDateTime")
2062
else if (str == "QVariantList")
2064
else if (str == "QByteArray")
2066
else if (str == "QStringList")
2068
else if (!str.isEmpty() && hasEnum(str))
2070
else if (!str.isEmpty() && str != "QFont" && str != "QPixmap" && str != "QVariant")
2075
switch(tdesc.lpadesc->tdescElem.vt) {
2076
// some shortcuts, and generic support for lists of QVariant-supported types
2081
str = "QStringList";
2084
str = "QVariantList";
2087
str = guessTypes(tdesc.lpadesc->tdescElem, info, function);
2089
str = "QList<" + str + '>';
2094
str = guessTypes(tdesc.lpadesc->tdescElem, info, function);
2095
if (!str.isEmpty()) {
2096
for (int index = 0; index < tdesc.lpadesc->cDims; ++index)
2097
str += '[' + QByteArray::number((int)tdesc.lpadesc->rgbounds[index].cElements) + ']';
2100
case VT_USERDEFINED:
2101
str = usertypeToString(tdesc, info, function);
2104
VT_UNHANDLED(FILETIME);
2106
VT_UNHANDLED(ERROR);
2107
VT_UNHANDLED(DECIMAL);
2108
VT_UNHANDLED(LPSTR);
2113
if (tdesc.vt & VT_BYREF)
2116
str.replace("&*", "**");
2120
void MetaObjectGenerator::readClassInfo()
2122
// Read class information
2123
IProvideClassInfo *provideClassInfo = 0;
2125
d->ptr->QueryInterface(IID_IProvideClassInfo, (void**)&provideClassInfo);
2126
if (provideClassInfo) {
2127
provideClassInfo->GetClassInfo(&classInfo);
2128
TYPEATTR *typeattr = 0;
2130
classInfo->GetTypeAttr(&typeattr);
2134
QUuid clsid(typeattr->guid);
2135
coClassID = clsid.toString().toUpper();
2136
#ifndef QAX_NO_CLASSINFO
2138
if (d->useClassInfo && !hasClassInfo("CoClass")) {
2139
QString coClassIDstr = iidnames.value(QLatin1String("/CLSID/") + coClassID + QLatin1String("/Default"), coClassID).toString();
2140
addClassInfo("CoClass", coClassIDstr.isEmpty() ? coClassID.toLatin1() : coClassIDstr.toLatin1());
2141
QByteArray version = QByteArray::number(typeattr->wMajorVerNum) + '.' + QByteArray::number(typeattr->wMinorVerNum);
2142
if (version != "0.0")
2143
addClassInfo("Version", version);
2146
classInfo->ReleaseTypeAttr(typeattr);
2148
provideClassInfo->Release();
2149
provideClassInfo = 0;
2151
if (d->tryCache && !coClassID.isEmpty())
2152
cacheKey = QString::fromLatin1("%1$%2$%3$%4").arg(coClassID)
2153
.arg((int)d->useEventSink).arg((int)d->useClassInfo).arg((int)qax_dispatchEqualsIDispatch);
2157
if (disp && !dispInfo)
2158
disp->GetTypeInfo(index, LOCALE_USER_DEFAULT, &dispInfo);
2160
if (dispInfo && !typelib)
2161
dispInfo->GetContainingTypeLib(&typelib, &index);
2164
QSettings controls(QLatin1String("HKEY_LOCAL_MACHINE\\Software"), QSettings::NativeFormat);
2165
QString tlid = controls.value(QLatin1String("/Classes/CLSID/") + that->control() + QLatin1String("/TypeLib/.")).toString();
2167
if (!tlid.isEmpty()) {
2168
controls.beginGroup(QLatin1String("/Classes/TypeLib/") + tlid);
2169
QStringList versions = controls.childGroups();
2170
QStringList::Iterator vit = versions.begin();
2171
while (tlfile.isEmpty() && vit != versions.end()) {
2172
QString version = *vit;
2174
tlfile = controls.value(QLatin1Char('/') + version + QLatin1String("/0/win32/.")).toString();
2176
controls.endGroup();
2178
tlfile = controls.value(QLatin1String("/Classes/CLSID/") + that->control() + QLatin1String("/InprocServer32/.")).toString();
2179
if (tlfile.isEmpty())
2180
tlfile = controls.value(QLatin1String("/Classes/CLSID/") + that->control() + QLatin1String("/LocalServer32/.")).toString();
2182
if (!tlfile.isEmpty()) {
2183
LoadTypeLib((OLECHAR*)tlfile.utf16(), &typelib);
2185
tlfile = tlfile.left(tlfile.lastIndexOf(QLatin1Char('.'))) + QLatin1String(".tlb");
2186
LoadTypeLib((OLECHAR*)tlfile.utf16(), &typelib);
2189
tlfile = tlfile.left(tlfile.lastIndexOf(QLatin1Char('.'))) + QLatin1String(".olb");
2190
LoadTypeLib((OLECHAR*)tlfile.utf16(), &typelib);
2195
if (!classInfo && typelib && that)
2196
typelib->GetTypeInfoOfGuid(QUuid(that->control()), &classInfo);
2198
if (classInfo && !dispInfo) {
2199
TYPEATTR *classAttr;
2200
classInfo->GetTypeAttr(&classAttr);
2202
for (int i = 0; i < classAttr->cImplTypes; ++i) {
2204
classInfo->GetImplTypeFlags(i, &typeFlags);
2205
if (typeFlags & IMPLTYPEFLAG_FSOURCE)
2209
if (S_OK == classInfo->GetRefTypeOfImplType(i, &hrefType))
2210
classInfo->GetRefTypeInfo(hrefType, &dispInfo);
2212
TYPEATTR *ifaceAttr;
2213
dispInfo->GetTypeAttr(&ifaceAttr);
2214
WORD typekind = ifaceAttr->typekind;
2215
dispInfo->ReleaseTypeAttr(ifaceAttr);
2217
if (typekind & TKIND_DISPATCH) {
2220
dispInfo->Release();
2225
classInfo->ReleaseTypeAttr(classAttr);
2229
if (!d || !dispInfo || !cacheKey.isEmpty() || !d->tryCache)
2232
TYPEATTR *typeattr = 0;
2233
dispInfo->GetTypeAttr(&typeattr);
2235
QString interfaceID;
2237
QUuid iid(typeattr->guid);
2238
interfaceID = iid.toString().toUpper();
2240
dispInfo->ReleaseTypeAttr(typeattr);
2241
// ### event interfaces!!
2242
if (!interfaceID.isEmpty())
2243
cacheKey = QString::fromLatin1("%1$%2$%3$%4").arg(interfaceID)
2244
.arg((int)d->useEventSink).arg((int)d->useClassInfo).arg((int)qax_dispatchEqualsIDispatch);
2248
void MetaObjectGenerator::readEnumInfo()
2255
if (d && d->tryCache) {
2256
TLIBATTR *libAttr = 0;
2257
typelib->GetLibAttr(&libAttr);
2259
libUuid = QUuid(libAttr->guid);
2260
typelib->ReleaseTLibAttr(libAttr);
2261
enum_list = enum_cache.value(libUuid);
2262
if (!enum_list.isEmpty())
2268
QSet<QString> clashCheck;
2271
int enum_serial = 0;
2272
UINT index = typelib->GetTypeInfoCount();
2273
for (UINT i = 0; i < index; ++i) {
2275
typelib->GetTypeInfoType(i, &typekind);
2276
if (typekind == TKIND_ENUM) {
2277
// Get the type information for the enum
2278
ITypeInfo *enuminfo = 0;
2279
typelib->GetTypeInfo(i, &enuminfo);
2283
// Get the name of the enumeration
2285
QByteArray enumName;
2286
if (typelib->GetDocumentation(i, &enumname, 0, 0, 0) == S_OK) {
2287
enumName = QString::fromWCharArray(enumname).toLatin1();
2288
SysFreeString(enumname);
2290
enumName = "enum" + QByteArray::number(++enum_serial);
2293
// Get the attributes of the enum type
2294
TYPEATTR *typeattr = 0;
2295
enuminfo->GetTypeAttr(&typeattr);
2297
// Get all values of the enumeration
2298
for (UINT vd = 0; vd < (UINT)typeattr->cVars; ++vd) {
2299
VARDESC *vardesc = 0;
2300
enuminfo->GetVarDesc(vd, &vardesc);
2301
if (vardesc && vardesc->varkind == VAR_CONST) {
2302
int value = vardesc->lpvarValue->lVal;
2303
int memid = vardesc->memid;
2304
// Get the name of the value
2306
QByteArray valueName;
2308
enuminfo->GetNames(memid, &valuename, 1, &maxNamesOut);
2310
valueName = QString::fromWCharArray(valuename).toLatin1();
2311
SysFreeString(valuename);
2313
valueName = "value" + QByteArray::number(valueindex++);
2316
if (clashCheck.contains(QString::fromLatin1(valueName)))
2317
valueName += QByteArray::number(++clashIndex);
2319
clashCheck.insert(QString::fromLatin1(valueName));
2320
addEnumValue(enumName, valueName, value);
2322
enuminfo->ReleaseVarDesc(vardesc);
2325
enuminfo->ReleaseTypeAttr(typeattr);
2326
enuminfo->Release();
2330
if (!libUuid.isNull())
2331
enum_cache.insert(libUuid, enum_list);
2334
void MetaObjectGenerator::addChangedSignal(const QByteArray &function, const QByteArray &type, int memid)
2336
QAxEventSink *eventSink = 0;
2338
eventSink = d->eventSink.value(iid_propNotifySink);
2339
if (!eventSink && d->useEventSink) {
2340
eventSink = new QAxEventSink(that);
2341
d->eventSink.insert(iid_propNotifySink, eventSink);
2344
// generate changed signal
2345
QByteArray signalName(function);
2346
signalName += "Changed";
2347
QByteArray signalProto = signalName + '(' + replaceType(type) + ')';
2348
if (!hasSignal(signalProto))
2349
addSignal(signalProto, function);
2351
eventSink->addProperty(memid, function, signalProto);
2354
void MetaObjectGenerator::addSetterSlot(const QByteArray &property)
2357
QByteArray prototype(property);
2358
if (isupper(prototype.at(0))) {
2362
prototype[0] = toupper(prototype[0]);
2364
prototype = set + prototype + '(' + propertyType(property) + ')';
2365
if (!hasSlot(prototype))
2366
addSlot(0, prototype, property);
2369
QByteArray MetaObjectGenerator::createPrototype(FUNCDESC *funcdesc, ITypeInfo *typeinfo, const QList<QByteArray> &names,
2370
QByteArray &type, QList<QByteArray> ¶meters)
2372
QByteArray prototype;
2373
QByteArray function(names.at(0));
2374
const QByteArray hresult("HRESULT");
2375
// get function prototype
2376
type = guessTypes(funcdesc->elemdescFunc.tdesc, typeinfo, function);
2377
if ((type.isEmpty() || type == hresult) && funcdesc->invkind == INVOKE_PROPERTYPUT && funcdesc->lprgelemdescParam) {
2378
type = guessTypes(funcdesc->lprgelemdescParam->tdesc, typeinfo, function);
2381
prototype = function + '(';
2382
if (funcdesc->invkind == INVOKE_FUNC && type == hresult)
2386
for (p = 1; p < names.count(); ++p) {
2388
QByteArray paramName = names.at(p);
2389
bool optional = p > (funcdesc->cParams - funcdesc->cParamsOpt);
2390
TYPEDESC tdesc = funcdesc->lprgelemdescParam[p-1].tdesc;
2391
PARAMDESC pdesc = funcdesc->lprgelemdescParam[p-1].paramdesc;
2393
QByteArray ptype = guessTypes(tdesc, typeinfo, function);
2394
if (pdesc.wParamFlags & PARAMFLAG_FRETVAL) {
2395
if (ptype.endsWith('&')) {
2396
ptype.truncate(ptype.length() - 1);
2397
} else if (ptype.endsWith("**")) {
2398
ptype.truncate(ptype.length() - 1);
2403
if (pdesc.wParamFlags & PARAMFLAG_FOUT && !ptype.endsWith('&') && !ptype.endsWith("**"))
2405
if (optional || pdesc.wParamFlags & PARAMFLAG_FOPT)
2407
else if (pdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) {
2408
// ### get the value from pdesc.pparamdescex
2411
parameters << paramName;
2413
if (p < funcdesc->cParams && !(pdesc.wParamFlags & PARAMFLAG_FRETVAL))
2417
if (!prototype.isEmpty()) {
2418
if (prototype.endsWith(',')) {
2419
if (funcdesc->invkind == INVOKE_PROPERTYPUT && p == funcdesc->cParams) {
2420
TYPEDESC tdesc = funcdesc->lprgelemdescParam[p-1].tdesc;
2421
QByteArray ptype = guessTypes(tdesc, typeinfo, function);
2424
parameters << "rhs";
2426
prototype[prototype.length()-1] = ')';
2436
void MetaObjectGenerator::readFuncsInfo(ITypeInfo *typeinfo, ushort nFuncs)
2439
TYPEATTR *typeattr = 0;
2440
typeinfo->GetTypeAttr(&typeattr);
2442
nFuncs = typeattr->cFuncs;
2443
typeinfo->ReleaseTypeAttr(typeattr);
2447
// get information about all functions
2448
for (ushort fd = 0; fd < nFuncs ; ++fd) {
2449
FUNCDESC *funcdesc = 0;
2450
typeinfo->GetFuncDesc(fd, &funcdesc);
2454
QByteArray function;
2456
QByteArray prototype;
2457
QList<QByteArray> parameters;
2459
// parse function description
2460
BSTR bstrNames[256];
2461
UINT maxNames = 255;
2463
typeinfo->GetNames(funcdesc->memid, (BSTR*)&bstrNames, maxNames, &maxNamesOut);
2464
QList<QByteArray> names;
2466
for (p = 0; p < (int)maxNamesOut; ++p) {
2467
names << QString::fromWCharArray(bstrNames[p]).toLatin1();
2468
SysFreeString(bstrNames[p]);
2472
function = names.at(0);
2473
if ((maxNamesOut == 3 && function == "QueryInterface") ||
2474
(maxNamesOut == 1 && function == "AddRef") ||
2475
(maxNamesOut == 1 && function == "Release") ||
2476
(maxNamesOut == 9 && function == "Invoke") ||
2477
(maxNamesOut == 6 && function == "GetIDsOfNames") ||
2478
(maxNamesOut == 2 && function == "GetTypeInfoCount") ||
2479
(maxNamesOut == 4 && function == "GetTypeInfo")) {
2480
typeinfo->ReleaseFuncDesc(funcdesc);
2484
prototype = createPrototype(/*in*/ funcdesc, typeinfo, names, /*out*/type, parameters);
2486
// get type of function
2487
switch(funcdesc->invkind) {
2488
case INVOKE_PROPERTYGET: // property
2489
case INVOKE_PROPERTYPUT:
2490
if (funcdesc->cParams - funcdesc->cParamsOpt <= 1) {
2491
bool dontBreak = false;
2492
// getter with non-default-parameters -> fall through to function handling
2493
if (funcdesc->invkind == INVOKE_PROPERTYGET && parameters.count() && funcdesc->cParams - funcdesc->cParamsOpt) {
2496
uint flags = Readable;
2497
if (funcdesc->invkind != INVOKE_PROPERTYGET)
2499
if (!(funcdesc->wFuncFlags & (FUNCFLAG_FNONBROWSABLE | FUNCFLAG_FHIDDEN)))
2500
flags |= Designable;
2501
if (!(funcdesc->wFuncFlags & FUNCFLAG_FRESTRICTED))
2502
flags |= Scriptable;
2503
if (funcdesc->wFuncFlags & FUNCFLAG_FREQUESTEDIT)
2504
flags |= RequestingEdit;
2506
flags |= EnumOrFlag;
2508
if (funcdesc->wFuncFlags & FUNCFLAG_FBINDABLE && funcdesc->invkind == INVOKE_PROPERTYGET) {
2509
addChangedSignal(function, type, funcdesc->memid);
2512
// Don't generate code for properties without type
2515
addProperty(type, function, flags);
2517
// more parameters -> function handling
2518
if (funcdesc->invkind == INVOKE_PROPERTYGET && funcdesc->cParams)
2522
if (!funcdesc->cParams) {
2523
// don't generate slots for incomplete properties
2528
if (funcdesc->invkind == INVOKE_PROPERTYGET)
2531
// generate setter slot
2532
if (funcdesc->invkind == INVOKE_PROPERTYPUT && hasProperty(function)) {
2533
addSetterSlot(function);
2536
} else if (funcdesc->invkind == INVOKE_PROPERTYPUT && hasProperty(function)) {
2537
addSetterSlot(function);
2538
// more parameters -> function handling
2539
if (funcdesc->cParams > 1)
2545
if (funcdesc->invkind == INVOKE_PROPERTYPUT) {
2547
if (isupper(prototype.at(0))) {
2551
prototype[0] = toupper(prototype[0]);
2554
prototype = set + prototype;
2556
// FALL THROUGH to support multi-variat properties
2557
case INVOKE_FUNC: // method
2559
bool cloned = false;
2563
for (p = 0; p < parameters.count(); ++p) {
2564
pnames += parameters.at(p);
2565
if (p < parameters.count() - 1)
2568
defargs = pnames.contains("=0");
2569
int flags = QMetaMethod::Public;
2571
flags |= QMetaMethod::Cloned << 4;
2573
addSlot(type, prototype, pnames.replace("=0", ""), flags);
2576
parameters.takeLast();
2577
int lastParam = prototype.lastIndexOf(',');
2578
if (lastParam == -1)
2579
lastParam = prototype.indexOf('(') + 1;
2580
prototype.truncate(lastParam);
2590
#if 0 // documentation in metaobject would be cool?
2591
// get function documentation
2593
info->GetDocumentation(funcdesc->memid, 0, &bstrDocu, 0, 0);
2594
QString strDocu = QString::fromWCharArray(bstrDocu);
2595
SysFreeString(bstrDocu);
2597
desc += '[' + strDocu + ']';
2600
typeinfo->ReleaseFuncDesc(funcdesc);
2604
void MetaObjectGenerator::readVarsInfo(ITypeInfo *typeinfo, ushort nVars)
2607
TYPEATTR *typeattr = 0;
2608
typeinfo->GetTypeAttr(&typeattr);
2610
nVars = typeattr->cVars;
2611
typeinfo->ReleaseTypeAttr(typeattr);
2615
// get information about all variables
2616
for (ushort vd = 0; vd < nVars; ++vd) {
2618
typeinfo->GetVarDesc(vd, &vardesc);
2622
// no use if it's not a dispatched variable
2623
if (vardesc->varkind != VAR_DISPATCH) {
2624
typeinfo->ReleaseVarDesc(vardesc);
2628
// get variable name
2632
typeinfo->GetNames(vardesc->memid, &bstrName, maxNames, &maxNamesOut);
2633
if (maxNamesOut != 1 || !bstrName) {
2634
typeinfo->ReleaseVarDesc(vardesc);
2637
QByteArray variableType;
2638
QByteArray variableName;
2641
variableName = QString::fromWCharArray(bstrName).toLatin1();
2642
SysFreeString(bstrName);
2644
// get variable type
2645
TYPEDESC typedesc = vardesc->elemdescVar.tdesc;
2646
variableType = guessTypes(typedesc, typeinfo, variableName);
2648
// generate meta property
2649
if (!hasProperty(variableName)) {
2651
if (!(vardesc->wVarFlags & VARFLAG_FREADONLY))
2653
if (!(vardesc->wVarFlags & (VARFLAG_FNONBROWSABLE | VARFLAG_FHIDDEN)))
2654
flags |= Designable;
2655
if (!(vardesc->wVarFlags & VARFLAG_FRESTRICTED))
2656
flags |= Scriptable;
2657
if (vardesc->wVarFlags & VARFLAG_FREQUESTEDIT)
2658
flags |= RequestingEdit;
2659
if (hasEnum(variableType))
2660
flags |= EnumOrFlag;
2662
if (vardesc->wVarFlags & VARFLAG_FBINDABLE) {
2663
addChangedSignal(variableName, variableType, vardesc->memid);
2666
addProperty(variableType, variableName, flags);
2669
// generate a set slot
2670
if (!(vardesc->wVarFlags & VARFLAG_FREADONLY))
2671
addSetterSlot(variableName);
2673
#if 0 // documentation in metaobject would be cool?
2674
// get function documentation
2676
info->GetDocumentation(vardesc->memid, 0, &bstrDocu, 0, 0);
2677
QString strDocu = QString::fromWCharArray(bstrDocu);
2678
SysFreeString(bstrDocu);
2680
desc += '[' + strDocu + ']';
2683
typeinfo->ReleaseVarDesc(vardesc);
2687
void MetaObjectGenerator::readInterfaceInfo()
2689
ITypeInfo *typeinfo = dispInfo;
2693
int interface_serial = 0;
2698
// get information about type
2700
typeinfo->GetTypeAttr(&typeattr);
2701
bool interesting = true;
2703
// get number of functions, variables, and implemented interfaces
2704
nFuncs = typeattr->cFuncs;
2705
nVars = typeattr->cVars;
2706
nImpl = typeattr->cImplTypes;
2708
if ((typeattr->typekind == TKIND_DISPATCH || typeattr->typekind == TKIND_INTERFACE) &&
2709
(typeattr->guid != IID_IDispatch && typeattr->guid != IID_IUnknown)) {
2710
#ifndef QAX_NO_CLASSINFO
2711
if (d && d->useClassInfo) {
2713
QUuid uuid(typeattr->guid);
2714
QString uuidstr = uuid.toString().toUpper();
2715
uuidstr = iidnames.value(QLatin1String("/Interface/") + uuidstr + QLatin1String("/Default"), uuidstr).toString();
2716
addClassInfo("Interface " + QByteArray::number(++interface_serial), uuidstr.toLatin1());
2719
typeinfo->ReleaseTypeAttr(typeattr);
2721
interesting = false;
2722
typeinfo->ReleaseTypeAttr(typeattr);
2727
readFuncsInfo(typeinfo, nFuncs);
2728
readVarsInfo(typeinfo, nVars);
2732
typeinfo->Release();
2737
// go up one base class
2739
typeinfo->GetRefTypeOfImplType(0, &pRefType);
2740
ITypeInfo *baseInfo = 0;
2741
typeinfo->GetRefTypeInfo(pRefType, &baseInfo);
2742
typeinfo->Release();
2743
if (typeinfo == baseInfo) { // IUnknown inherits IUnknown ???
2744
baseInfo->Release();
2748
typeinfo = baseInfo;
2752
void MetaObjectGenerator::readEventInterface(ITypeInfo *eventinfo, IConnectionPoint *cpoint)
2754
TYPEATTR *eventattr;
2755
eventinfo->GetTypeAttr(&eventattr);
2758
if (eventattr->typekind != TKIND_DISPATCH) {
2759
eventinfo->ReleaseTypeAttr(eventattr);
2763
QAxEventSink *eventSink = 0;
2766
cpoint->GetConnectionInterface(&conniid);
2767
eventSink = d->eventSink.value(QUuid(conniid));
2769
eventSink = new QAxEventSink(that);
2770
d->eventSink.insert(QUuid(conniid), eventSink);
2771
eventSink->advise(cpoint, conniid);
2775
// get information about all event functions
2776
for (UINT fd = 0; fd < (UINT)eventattr->cFuncs; ++fd) {
2778
eventinfo->GetFuncDesc(fd, &funcdesc);
2781
if (funcdesc->invkind != INVOKE_FUNC ||
2782
funcdesc->funckind != FUNC_DISPATCH) {
2783
eventinfo->ReleaseTypeAttr(eventattr);
2784
eventinfo->ReleaseFuncDesc(funcdesc);
2788
QByteArray function;
2789
QByteArray prototype;
2790
QList<QByteArray> parameters;
2792
// parse event function description
2793
BSTR bstrNames[256];
2794
UINT maxNames = 255;
2796
eventinfo->GetNames(funcdesc->memid, (BSTR*)&bstrNames, maxNames, &maxNamesOut);
2797
QList<QByteArray> names;
2799
for (p = 0; p < (int)maxNamesOut; ++p) {
2800
names << QString::fromWCharArray(bstrNames[p]).toLatin1();
2801
SysFreeString(bstrNames[p]);
2804
// get event function prototype
2805
function = names.at(0);
2806
QByteArray type; // dummy - we don't care about return values for signals
2807
prototype = createPrototype(/*in*/ funcdesc, eventinfo, names, /*out*/type, parameters);
2808
if (!hasSignal(prototype)) {
2810
for (p = 0; p < parameters.count(); ++p) {
2811
pnames += parameters.at(p);
2812
if (p < parameters.count() - 1)
2815
addSignal(prototype, pnames);
2818
eventSink->addSignal(funcdesc->memid, prototype);
2820
#if 0 // documentation in metaobject would be cool?
2821
// get function documentation
2823
eventinfo->GetDocumentation(funcdesc->memid, 0, &bstrDocu, 0, 0);
2824
QString strDocu = QString::fromWCharArray(bstrDocu);
2825
SysFreeString(bstrDocu);
2827
desc += '[' + strDocu + ']';
2830
eventinfo->ReleaseFuncDesc(funcdesc);
2832
eventinfo->ReleaseTypeAttr(eventattr);
2835
void MetaObjectGenerator::readEventInfo()
2837
int event_serial = 0;
2838
IConnectionPointContainer *cpoints = 0;
2839
if (d && d->useEventSink)
2840
d->ptr->QueryInterface(IID_IConnectionPointContainer, (void**)&cpoints);
2842
// Get connection point enumerator
2843
IEnumConnectionPoints *epoints = 0;
2844
cpoints->EnumConnectionPoints(&epoints);
2847
IConnectionPoint *cpoint = 0;
2849
QList<QUuid> cpointlist;
2851
if (cpoint) cpoint->Release();
2853
HRESULT hr = epoints->Next(c, &cpoint, &c);
2854
if (!c || hr != S_OK)
2858
cpoint->GetConnectionInterface(&conniid);
2859
// workaround for typelibrary bug of Word.Application
2860
QUuid connuuid(conniid);
2861
if (cpointlist.contains(connuuid))
2864
#ifndef QAX_NO_CLASSINFO
2865
if (d->useClassInfo) {
2866
QString uuidstr = connuuid.toString().toUpper();
2867
uuidstr = iidnames.value(QLatin1String("/Interface/") + uuidstr + QLatin1String("/Default"), uuidstr).toString();
2868
addClassInfo("Event Interface " + QByteArray::number(++event_serial), uuidstr.toLatin1());
2872
// get information about type
2873
if (conniid == IID_IPropertyNotifySink) {
2874
// test whether property notify sink has been created already, and advise on it
2875
QAxEventSink *eventSink = d->eventSink.value(iid_propNotifySink);
2877
eventSink->advise(cpoint, conniid);
2881
ITypeInfo *eventinfo = 0;
2883
typelib->GetTypeInfoOfGuid(conniid, &eventinfo);
2886
// avoid recursion (see workaround above)
2887
cpointlist.append(connuuid);
2889
readEventInterface(eventinfo, cpoint);
2890
eventinfo->Release();
2893
if (cpoint) cpoint->Release();
2895
} else if (classInfo) { // no enumeration - search source interfaces and ask for those
2896
TYPEATTR *typeattr = 0;
2897
classInfo->GetTypeAttr(&typeattr);
2899
for (int i = 0; i < typeattr->cImplTypes; ++i) {
2901
classInfo->GetImplTypeFlags(i, &flags);
2902
if (!(flags & IMPLTYPEFLAG_FSOURCE))
2905
if (S_OK != classInfo->GetRefTypeOfImplType(i, &reference))
2907
ITypeInfo *eventInfo = 0;
2908
classInfo->GetRefTypeInfo(reference, &eventInfo);
2911
TYPEATTR *eventattr = 0;
2912
eventInfo->GetTypeAttr(&eventattr);
2914
IConnectionPoint *cpoint = 0;
2915
cpoints->FindConnectionPoint(eventattr->guid, &cpoint);
2917
if (eventattr->guid == IID_IPropertyNotifySink) {
2918
// test whether property notify sink has been created already, and advise on it
2919
QAxEventSink *eventSink = d->eventSink.value(iid_propNotifySink);
2921
eventSink->advise(cpoint, eventattr->guid);
2925
readEventInterface(eventInfo, cpoint);
2928
eventInfo->ReleaseTypeAttr(eventattr);
2930
eventInfo->Release();
2932
classInfo->ReleaseTypeAttr(typeattr);
2939
QMetaObject *MetaObjectGenerator::tryCache()
2941
if (!cacheKey.isEmpty()) {
2942
d->metaobj = mo_cache.value(cacheKey);
2944
d->cachedMetaObject = true;
2946
IConnectionPointContainer *cpoints = 0;
2947
d->ptr->QueryInterface(IID_IConnectionPointContainer, (void**)&cpoints);
2949
QList<QUuid>::ConstIterator it = d->metaobj->connectionInterfaces.begin();
2950
while (it != d->metaobj->connectionInterfaces.end()) {
2954
IConnectionPoint *cpoint = 0;
2955
cpoints->FindConnectionPoint(iid, &cpoint);
2957
QAxEventSink *sink = new QAxEventSink(that);
2958
sink->advise(cpoint, iid);
2959
d->eventSink.insert(iid, sink);
2960
sink->sigs = d->metaobj->sigs.value(iid);
2961
sink->props = d->metaobj->props.value(iid);
2962
sink->propsigs = d->metaobj->propsigs.value(iid);
2975
QMetaObject *MetaObjectGenerator::metaObject(const QMetaObject *parentObject, const QByteArray &className)
2981
typelib->GetDocumentation(-1, &bstr, 0, 0, 0);
2982
current_typelib = QString::fromWCharArray(bstr).toLatin1();
2983
SysFreeString(bstr);
2985
if (d->tryCache && tryCache())
2988
readInterfaceInfo();
2992
current_typelib = QByteArray();
2994
#ifndef QAX_NO_CLASSINFO
2995
if (!debugInfo.isEmpty() && d->useClassInfo)
2996
addClassInfo("debugInfo", debugInfo);
2999
QAxMetaObject *metaobj = new QAxMetaObject;
3001
// revision + classname + table + zero terminator
3002
uint int_data_size = 1+1+2+2+2+2+1;
3004
int_data_size += classinfo_list.count() * 2;
3005
int_data_size += signal_list.count() * 5;
3006
int_data_size += slot_list.count() * 5;
3007
int_data_size += property_list.count() * 3;
3008
int_data_size += enum_list.count() * 4;
3009
for (QMap<QByteArray, QList<QPair<QByteArray, int> > >::ConstIterator it = enum_list.begin();
3010
it != enum_list.end(); ++it) {
3011
int_data_size += (*it).count() * 2;
3014
uint *int_data = new uint[int_data_size];
3015
int_data[0] = 1; // revision number
3016
int_data[1] = 0; // classname index
3017
int_data[2] = classinfo_list.count(); // num_classinfo
3018
int_data[3] = 10; // idx_classinfo
3019
int_data[4] = signal_list.count() + slot_list.count(); // num_methods
3020
int_data[5] = int_data[3] + int_data[2] * 2; // idx_signals
3021
int_data[6] = property_list.count(); // num_properties
3022
int_data[7] = int_data[5] + int_data[4] * 5; // idx_properties
3023
int_data[8] = enum_list.count(); // num_enums
3024
int_data[9] = int_data[7] + int_data[6] * 3; // idx_enums
3025
int_data[int_data_size - 1] = 0; // eod;
3028
// data + zero-terminator
3029
QByteArray stringdata = that ? QByteArray(that->className()) : className;
3031
stringdata.reserve(8192);
3033
uint offset = int_data[3]; //idx_classinfo
3035
// each class info in form key\0value\0
3036
for (QMap<QByteArray, QByteArray>::ConstIterator it = classinfo_list.begin(); it != classinfo_list.end(); ++it) {
3037
QByteArray key(it.key());
3038
QByteArray value(it.value());
3039
int_data[offset++] = stringdata.length();
3042
int_data[offset++] = stringdata.length();
3043
stringdata += value;
3046
Q_ASSERT(offset == int_data[5]);
3048
// each signal in form prototype\0parameters\0type\0tag\0
3049
for (QMap<QByteArray, Method>::ConstIterator it = signal_list.begin(); it != signal_list.end(); ++it) {
3050
QByteArray prototype(QMetaObject::normalizedSignature(it.key()));
3051
QByteArray type(it.value().type);
3052
QByteArray parameters(it.value().parameters);
3053
if (!it.value().realPrototype.isEmpty())
3054
metaobj->realPrototype.insert(prototype, it.value().realPrototype);
3056
int flags = it.value().flags;
3058
int_data[offset++] = stringdata.length();
3059
stringdata += prototype;
3061
int_data[offset++] = stringdata.length();
3062
stringdata += parameters;
3064
int_data[offset++] = stringdata.length();
3067
int_data[offset++] = stringdata.length();
3070
int_data[offset++] = flags;
3073
// each slot in form prototype\0parameters\0type\0tag\0
3074
for (QMap<QByteArray, Method>::ConstIterator it = slot_list.begin(); it != slot_list.end(); ++it) {
3075
QByteArray prototype(QMetaObject::normalizedSignature(it.key()));
3076
QByteArray type(it.value().type);
3077
QByteArray parameters(it.value().parameters);
3078
if (!it.value().realPrototype.isEmpty())
3079
metaobj->realPrototype.insert(prototype, it.value().realPrototype);
3081
int flags = it.value().flags;
3083
int_data[offset++] = stringdata.length();
3084
stringdata += prototype;
3086
int_data[offset++] = stringdata.length();
3087
stringdata += parameters;
3089
int_data[offset++] = stringdata.length();
3092
int_data[offset++] = stringdata.length();
3095
int_data[offset++] = flags;
3097
Q_ASSERT(offset == int_data[7]);
3099
// each property in form name\0type\0
3100
for (QMap<QByteArray, Property>::ConstIterator it = property_list.begin(); it != property_list.end(); ++it) {
3101
QByteArray name(it.key());
3102
QByteArray type(it.value().type);
3103
QByteArray realType(it.value().realType);
3104
if (!realType.isEmpty() && realType != type)
3105
metaobj->realPrototype.insert(name, realType);
3106
uint flags = it.value().typeId;
3108
int_data[offset++] = stringdata.length();
3111
int_data[offset++] = stringdata.length();
3114
int_data[offset++] = flags;
3116
Q_ASSERT(offset == int_data[9]);
3118
int value_offset = offset + enum_list.count() * 4;
3119
// each enum in form name\0
3120
for (QMap<QByteArray, QList<QPair<QByteArray, int> > >::ConstIterator it = enum_list.begin(); it != enum_list.end(); ++it) {
3121
QByteArray name(it.key());
3122
int flags = 0x0; // 0x1 for flag?
3123
int count = it.value().count();
3125
int_data[offset++] = stringdata.length();
3128
int_data[offset++] = flags;
3129
int_data[offset++] = count;
3130
int_data[offset++] = value_offset;
3131
value_offset += count * 2;
3133
Q_ASSERT(offset == int_data[9] + enum_list.count() * 4);
3135
// each enum value in form key\0
3136
for (QMap<QByteArray, QList<QPair<QByteArray, int> > >::ConstIterator it = enum_list.begin(); it != enum_list.end(); ++it) {
3137
for (QList<QPair<QByteArray,int> >::ConstIterator it2 = it.value().begin(); it2 != it.value().end(); ++it2) {
3138
QByteArray key((*it2).first);
3139
int value = (*it2).second;
3140
int_data[offset++] = stringdata.length();
3143
int_data[offset++] = value;
3146
Q_ASSERT(offset == int_data_size-1);
3148
char *string_data = new char[stringdata.length()];
3149
memset(string_data, 0, sizeof(string_data));
3150
memcpy(string_data, stringdata, stringdata.length());
3152
// put the metaobject together
3153
metaobj->d.data = int_data;
3154
metaobj->d.extradata = 0;
3155
metaobj->d.stringdata = string_data;
3156
metaobj->d.superdata = parentObject;
3159
d->metaobj = metaobj;
3161
if (!cacheKey.isEmpty()) {
3162
mo_cache.insert(cacheKey, d->metaobj);
3163
d->cachedMetaObject = true;
3164
for (QHash<QUuid, QAxEventSink*>::Iterator it = d->eventSink.begin(); it != d->eventSink.end(); ++it) {
3165
QAxEventSink *sink = it.value();
3167
QUuid ciid = sink->connectionInterface();
3169
d->metaobj->connectionInterfaces.append(ciid);
3170
d->metaobj->sigs.insert(ciid, sink->signalMap());
3171
d->metaobj->props.insert(ciid, sink->propertyMap());
3172
d->metaobj->propsigs.insert(ciid, sink->propSignalMap());
3180
static const uint qt_meta_data_QAxBase[] = {
3187
1, 25, // properties
3190
// signals: signature, parameters, type, tag, flags
3193
102, 80, 8, 8, 0x05,
3195
// properties: name, type, flags
3196
149, 141, 0x0a095103,
3201
static const char qt_meta_stringdata_QAxBase[] = {
3202
"QAxBase\0\0name,argc,argv\0signal(QString,int,void*)\0name\0"
3203
"propertyChanged(QString)\0code,source,desc,help\0"
3204
"exception(int,QString,QString,QString)\0QString\0control\0"
3207
static QMetaObject qaxobject_staticMetaObject = {
3208
{ &QObject::staticMetaObject, qt_meta_stringdata_QAxBase,
3209
qt_meta_data_QAxBase, 0 }
3211
static QMetaObject qaxwidget_staticMetaObject = {
3212
{ &QWidget::staticMetaObject, qt_meta_stringdata_QAxBase,
3213
qt_meta_data_QAxBase, 0 }
3219
The metaobject is generated on the fly from the information
3220
provided by the IDispatch and ITypeInfo interface implementations
3223
const QMetaObject *QAxBase::metaObject() const
3227
const QMetaObject* parentObject = parentMetaObject();
3229
if (!d->ptr && !d->initialized) {
3230
((QAxBase*)this)->initialize(&d->ptr);
3231
d->initialized = true;
3234
#ifndef QT_NO_THREAD
3235
// only one thread at a time can generate meta objects
3236
QMutexLocker locker(&cache_mutex);
3239
// return the default meta object if not yet initialized
3240
if (!d->ptr || !d->useMetaObject) {
3241
if (qObject()->isWidgetType())
3242
return &qaxwidget_staticMetaObject;
3243
return &qaxobject_staticMetaObject;
3245
MetaObjectGenerator generator((QAxBase*)this, d);
3246
return generator.metaObject(parentObject);
3252
Connects to all event interfaces of the object.
3254
Called by the subclasses' connectNotify() reimplementations, so
3255
at this point the connection as actually been created already.
3257
void QAxBase::connectNotify()
3259
if (d->eventSink.count()) // already listening
3262
IEnumConnectionPoints *epoints = 0;
3263
if (d->ptr && d->useEventSink) {
3264
IConnectionPointContainer *cpoints = 0;
3265
d->ptr->QueryInterface(IID_IConnectionPointContainer, (void**)&cpoints);
3269
cpoints->EnumConnectionPoints(&epoints);
3277
IDispatch *disp = d->dispatch();
3278
ITypeInfo *typeinfo = 0;
3279
ITypeLib *typelib = 0;
3281
disp->GetTypeInfo(0, LOCALE_USER_DEFAULT, &typeinfo);
3283
typeinfo->GetContainingTypeLib(&typelib, &index);
3290
MetaObjectGenerator generator(this, d);
3291
bool haveEnumInfo = false;
3294
IConnectionPoint *cpoint = 0;
3297
if (cpoint) cpoint->Release();
3299
epoints->Next(c, &cpoint, &c);
3304
cpoint->GetConnectionInterface(&conniid);
3305
// workaround for typelibrary bug of Word.Application
3306
QString connuuid(QUuid(conniid).toString());
3307
if (d->eventSink.contains(connuuid))
3310
// Get ITypeInfo for source-interface, and skip if not supporting IDispatch
3311
ITypeInfo *eventinfo = 0;
3312
typelib->GetTypeInfoOfGuid(conniid, &eventinfo);
3314
TYPEATTR *eventAttr;
3315
eventinfo->GetTypeAttr(&eventAttr);
3317
eventinfo->Release();
3321
TYPEKIND eventKind = eventAttr->typekind;
3322
eventinfo->ReleaseTypeAttr(eventAttr);
3323
if (eventKind != TKIND_DISPATCH) {
3324
eventinfo->Release();
3329
// always into the cache to avoid recoursion
3330
QAxEventSink *eventSink = eventinfo ? new QAxEventSink(this) : 0;
3331
d->eventSink.insert(connuuid, eventSink);
3336
// have to get type info to support signals with enum parameters
3337
if (!haveEnumInfo) {
3338
bool wasTryCache = d->tryCache;
3340
generator.readClassInfo();
3341
generator.readEnumInfo();
3342
d->tryCache = wasTryCache;
3343
haveEnumInfo = true;
3345
generator.readEventInterface(eventinfo, cpoint);
3346
eventSink->advise(cpoint, conniid);
3348
eventinfo->Release();
3350
if (cpoint) cpoint->Release();
3355
// make sure we don't try again
3356
if (!d->eventSink.count())
3357
d->eventSink.insert(QString(), 0);
3361
\fn QString QAxBase::generateDocumentation()
3363
Returns a rich text string with documentation for the
3364
wrapped COM object. Dump the string to an HTML-file,
3365
or use it in e.g. a QTextBrowser widget.
3368
static bool checkHRESULT(HRESULT hres, EXCEPINFO *exc, QAxBase *that, const QString &name, uint argerr)
3373
case DISP_E_BADPARAMCOUNT:
3374
qWarning("QAxBase: Error calling IDispatch member %s: Bad parameter count", name.toLatin1().data());
3376
case DISP_E_BADVARTYPE:
3377
qWarning("QAxBase: Error calling IDispatch member %s: Bad variant type", name.toLatin1().data());
3379
case DISP_E_EXCEPTION:
3381
bool printWarning = true;
3382
unsigned short code = -1;
3383
QString source, desc, help;
3384
const QMetaObject *mo = that->metaObject();
3385
int exceptionSignal = mo->indexOfSignal("exception(int,QString,QString,QString)");
3386
if (exceptionSignal >= 0) {
3387
if (exc->pfnDeferredFillIn)
3388
exc->pfnDeferredFillIn(exc);
3390
code = exc->wCode ? exc->wCode : exc->scode;
3391
source = QString::fromWCharArray(exc->bstrSource);
3392
desc = QString::fromWCharArray(exc->bstrDescription);
3393
help = QString::fromWCharArray(exc->bstrHelpFile);
3394
uint helpContext = exc->dwHelpContext;
3396
if (helpContext && !help.isEmpty())
3397
help += QString::fromLatin1(" [%1]").arg(helpContext);
3399
if (QAxEventSink::signalHasReceivers(that->qObject(), "exception(int,QString,QString,QString)")) {
3400
void *argv[] = {0, &code, &source, &desc, &help};
3401
that->qt_metacall(QMetaObject::InvokeMetaMethod, exceptionSignal, argv);
3402
printWarning = false;
3406
qWarning("QAxBase: Error calling IDispatch member %s: Exception thrown by server", name.toLatin1().data());
3407
qWarning(" Code : %d", code);
3408
qWarning(" Source : %s", source.toLatin1().data());
3409
qWarning(" Description: %s", desc.toLatin1().data());
3410
qWarning(" Help : %s", help.toLatin1().data());
3411
qWarning(" Connect to the exception(int,QString,QString,QString) signal to catch this exception");
3415
case DISP_E_MEMBERNOTFOUND:
3416
qWarning("QAxBase: Error calling IDispatch member %s: Member not found", name.toLatin1().data());
3418
case DISP_E_NONAMEDARGS:
3419
qWarning("QAxBase: Error calling IDispatch member %s: No named arguments", name.toLatin1().data());
3421
case DISP_E_OVERFLOW:
3422
qWarning("QAxBase: Error calling IDispatch member %s: Overflow", name.toLatin1().data());
3424
case DISP_E_PARAMNOTFOUND:
3425
qWarning("QAxBase: Error calling IDispatch member %s: Parameter %d not found", name.toLatin1().data(), argerr);
3427
case DISP_E_TYPEMISMATCH:
3428
qWarning("QAxBase: Error calling IDispatch member %s: Type mismatch in parameter %d", name.toLatin1().data(), argerr);
3430
case DISP_E_UNKNOWNINTERFACE:
3431
qWarning("QAxBase: Error calling IDispatch member %s: Unknown interface", name.toLatin1().data());
3433
case DISP_E_UNKNOWNLCID:
3434
qWarning("QAxBase: Error calling IDispatch member %s: Unknown locale ID", name.toLatin1().data());
3436
case DISP_E_PARAMNOTOPTIONAL:
3437
qWarning("QAxBase: Error calling IDispatch member %s: Non-optional parameter missing", name.toLatin1().data());
3440
qWarning("QAxBase: Error calling IDispatch member %s: Unknown error", name.toLatin1().data());
3448
int QAxBase::internalProperty(QMetaObject::Call call, int index, void **v)
3450
const QMetaObject *mo = metaObject();
3451
const QMetaProperty prop = mo->property(index + mo->propertyOffset());
3452
QByteArray propname = prop.name();
3454
// hardcoded control property
3455
if (propname == "control") {
3457
case QMetaObject::ReadProperty:
3458
*(QString*)*v = control();
3460
case QMetaObject::WriteProperty:
3461
setControl(*(QString*)*v);
3463
case QMetaObject::ResetProperty:
3469
return index - mo->propertyCount();
3472
// get the IDispatch
3473
if (!d->ptr || !prop.isValid())
3475
IDispatch *disp = d->dispatch();
3479
DISPID dispid = d->metaObject()->dispIDofName(propname, disp);
3480
if (dispid == DISPID_UNKNOWN)
3483
Q_ASSERT(d->metaobj);
3484
// property found, so everthing that goes wrong now should not bother the caller
3485
index -= mo->propertyCount();
3490
EXCEPINFO excepinfo;
3491
memset(&excepinfo, 0, sizeof(excepinfo));
3493
HRESULT hres = E_FAIL;
3495
QByteArray proptype(prop.typeName());
3497
case QMetaObject::ReadProperty:
3500
params.cNamedArgs = 0;
3501
params.rgdispidNamedArgs = 0;
3504
hres = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, ¶ms, &arg, &excepinfo, 0);
3506
// map result VARIANTARG to void*
3507
uint type = QVariant::Int;
3508
if (!prop.isEnumType())
3510
QVariantToVoidStar(VARIANTToQVariant(arg, proptype, type), *v, proptype, type);
3511
if ((arg.vt != VT_DISPATCH && arg.vt != VT_UNKNOWN) || type == QVariant::Pixmap || type == QVariant::Font)
3516
case QMetaObject::WriteProperty:
3518
QVariant::Type t = (QVariant::Type)prop.type();
3520
DISPID dispidNamed = DISPID_PROPERTYPUT;
3522
params.cNamedArgs = 1;
3523
params.rgdispidNamedArgs = &dispidNamed;
3524
params.rgvarg = &arg;
3527
arg.scode = DISP_E_TYPEMISMATCH;
3529
// map void* to VARIANTARG via QVariant
3531
if (prop.isEnumType()) {
3535
if (t == QVariant::LastType) {
3536
qvar = *(QVariant*)v[0];
3538
} else if (t == QVariant::UserType) {
3539
qvar = QVariant(qRegisterMetaType<void*>(prop.typeName()), (void**)v[0]);
3540
// qVariantSetValue(qvar, *(void**)v[0], prop.typeName());
3542
proptype = d->metaObject()->propertyType(propname);
3543
qvar = QVariant(t, v[0]);
3547
QVariantToVARIANT(qvar, arg, proptype);
3548
if (arg.vt == VT_EMPTY || arg.vt == VT_ERROR) {
3549
qWarning("QAxBase::setProperty: Unhandled property type %s", prop.typeName());
3553
hres = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms, 0, &excepinfo, &argerr);
3561
checkHRESULT(hres, &excepinfo, this, QLatin1String(propname), argerr);
3565
int QAxBase::internalInvoke(QMetaObject::Call call, int index, void **v)
3567
Q_ASSERT(call == QMetaObject::InvokeMetaMethod);
3570
// get the IDispatch
3571
IDispatch *disp = d->dispatch();
3575
const QMetaObject *mo = metaObject();
3576
// get the slot information
3577
const QMetaMethod slot = mo->method(index + mo->methodOffset());
3578
Q_ASSERT(slot.methodType() == QMetaMethod::Slot);
3580
QByteArray signature(slot.signature());
3581
QByteArray slotname(signature);
3582
slotname.truncate(slotname.indexOf('('));
3584
// Get the Dispatch ID of the method to be called
3585
bool isProperty = false;
3586
DISPID dispid = d->metaObject()->dispIDofName(slotname, disp);
3588
Q_ASSERT(d->metaobj);
3590
if (dispid == DISPID_UNKNOWN && slotname.toLower().startsWith("set")) {
3591
// see if we are calling a property set function as a slot
3592
slotname = slotname.right(slotname.length() - 3);
3593
dispid = d->metaobj->dispIDofName(slotname, disp);
3596
if (dispid == DISPID_UNKNOWN)
3599
// slot found, so everthing that goes wrong now should not bother the caller
3600
index -= mo->methodCount();
3602
// setup the parameters
3604
DISPID dispidNamed = DISPID_PROPERTYPUT;
3605
params.cArgs = d->metaobj->numParameter(signature);
3606
params.cNamedArgs = isProperty ? 1 : 0;
3607
params.rgdispidNamedArgs = isProperty ? &dispidNamed : 0;
3609
VARIANTARG static_rgvarg[QAX_NUM_PARAMS];
3611
if (params.cArgs <= QAX_NUM_PARAMS)
3612
params.rgvarg = static_rgvarg;
3614
params.rgvarg = new VARIANTARG[params.cArgs];
3618
for (p = 0; p < (int)params.cArgs; ++p) {
3620
QByteArray type = d->metaobj->paramType(signature, p, &out);
3621
QVariant::Type vt = QVariant::nameToType(type);
3623
if (vt != QVariant::UserType)
3624
qvar = QVariant(vt, v[p + 1]);
3626
if (!qvar.isValid()) {
3627
if (type == "IDispatch*")
3628
qVariantSetValue(qvar, *(IDispatch**)v[p+1]);
3629
else if (type == "IUnknown*")
3630
qVariantSetValue(qvar, *(IUnknown**)v[p+1]);
3631
else if (type == "QVariant")
3632
qvar = *(QVariant*)v[p + 1];
3633
else if (mo->indexOfEnumerator(type) != -1)
3634
qvar = *(int*)v[p + 1];
3636
qvar = QVariant(QMetaType::type(type), v[p + 1]);
3639
QVariantToVARIANT(qvar, params.rgvarg[params.cArgs - p - 1], type, out);
3646
HRESULT hres = E_FAIL;
3647
EXCEPINFO excepinfo;
3648
memset(&excepinfo, 0, sizeof(excepinfo));
3650
WORD wFlags = isProperty ? DISPATCH_PROPERTYPUT : DISPATCH_METHOD | DISPATCH_PROPERTYGET;
3651
hres = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, wFlags, ¶ms, &ret, &excepinfo, &argerr);
3654
if (hres == S_OK && ret.vt != VT_EMPTY)
3655
QVariantToVoidStar(VARIANTToQVariant(ret, slot.typeName()), v[0], slot.typeName());
3657
// update out parameters
3658
for (p = 0; p < (int)params.cArgs; ++p) {
3660
QByteArray ptype = d->metaobj->paramType(signature, p, &out);
3662
QVariantToVoidStar(VARIANTToQVariant(params.rgvarg[params.cArgs - p - 1], ptype), v[p+1], ptype);
3665
for (p = 0; p < (int)params.cArgs; ++p)
3666
clearVARIANT(params.rgvarg+p);
3667
if (params.rgvarg != static_rgvarg)
3668
delete [] params.rgvarg;
3670
checkHRESULT(hres, &excepinfo, this, QString::fromLatin1(slotname), params.cArgs-argerr-1);
3677
int QAxBase::qt_metacall(QMetaObject::Call call, int id, void **v)
3679
const QMetaObject *mo = metaObject();
3680
if (isNull() && mo->property(id + mo->propertyOffset()).name() != QByteArray("control")) {
3681
qWarning("QAxBase::qt_metacall: Object is not initialized, or initialization failed");
3686
case QMetaObject::InvokeMetaMethod:
3687
switch (mo->method(id + mo->methodOffset()).methodType()) {
3688
case QMetaMethod::Signal:
3689
QMetaObject::activate(qObject(), mo, id, v);
3690
id -= mo->methodCount();
3692
case QMetaMethod::Method:
3693
case QMetaMethod::Slot:
3694
id = internalInvoke(call, id, v);
3700
case QMetaObject::ReadProperty:
3701
case QMetaObject::WriteProperty:
3702
case QMetaObject::ResetProperty:
3703
id = internalProperty(call, id, v);
3705
case QMetaObject::QueryPropertyScriptable:
3706
case QMetaObject::QueryPropertyDesignable:
3707
case QMetaObject::QueryPropertyStored:
3708
case QMetaObject::QueryPropertyEditable:
3709
case QMetaObject::QueryPropertyUser:
3710
id -= mo->propertyCount();
3719
#ifdef QT_CHECK_STATE
3720
static void qax_noSuchFunction(int disptype, const QByteArray &name, const QByteArray &function, const QAxBase *that)
3722
const QMetaObject *metaObject = that->metaObject();
3723
const char *coclass = metaObject->classInfo(metaObject->indexOfClassInfo("CoClass")).value();
3725
if (disptype == DISPATCH_METHOD) {
3726
qWarning("QAxBase::dynamicCallHelper: %s: No such method in %s [%s]", name.data(), that->control().toLatin1().data(), coclass ? coclass: "unknown");
3727
qWarning("\tCandidates are:");
3728
for (int i = 0; i < metaObject->methodCount(); ++i) {
3729
const QMetaMethod slot(metaObject->method(i));
3730
if (slot.methodType() != QMetaMethod::Slot)
3732
QByteArray signature = slot.signature();
3733
if (signature.toLower().startsWith(function.toLower()))
3734
qWarning("\t\t%s", signature.data());
3737
qWarning("QAxBase::dynamicCallHelper: %s: No such property in %s [%s]", name.data(), that->control().toLatin1().data(), coclass ? coclass: "unknown");
3738
if (!function.isEmpty()) {
3739
qWarning("\tCandidates are:");
3740
char f0 = function.toLower().at(0);
3741
for (int i = metaObject->propertyOffset(); i < metaObject->propertyCount(); ++i) {
3742
QByteArray signature(metaObject->property(i).name());
3743
if (!signature.isEmpty() && signature.toLower().at(0) == f0)
3744
qWarning("\t\t%s", signature.data());
3754
\a name is already normalized?
3756
bool QAxBase::dynamicCallHelper(const char *name, void *inout, QList<QVariant> &vars, QByteArray &type)
3759
qWarning("QAxBase::dynamicCallHelper: Object is not initialized, or initialization failed");
3763
IDispatch *disp = d->dispatch();
3765
qWarning("QAxBase::dynamicCallHelper: Object does not support automation");
3769
const QMetaObject *mo = metaObject();
3771
Q_ASSERT(d->metaobj);
3773
int varc = vars.count();
3775
QByteArray normFunction = QMetaObject::normalizedSignature(name);
3776
QByteArray function(normFunction);
3777
VARIANT staticarg[QAX_NUM_PARAMS];
3779
VARIANTARG *res = (VARIANTARG*)inout;
3781
unsigned short disptype;
3786
if (function.contains('(')) {
3787
disptype = DISPATCH_METHOD | DISPATCH_PROPERTYGET;
3788
if (d->useMetaObject)
3789
id = mo->indexOfSlot(function);
3791
const QMetaMethod slot = mo->method(id);
3792
Q_ASSERT(slot.methodType() == QMetaMethod::Slot);
3793
function = slot.signature();
3794
type = slot.typeName();
3796
function.truncate(function.indexOf('('));
3797
parse = !varc && normFunction.length() > function.length() + 2;
3799
QString args = QLatin1String(normFunction);
3800
args = args.mid(function.length() + 1);
3801
// parse argument string int list of arguments
3803
const QChar *c = args.unicode();
3805
bool inString = false;
3806
bool inEscape = false;
3807
while (index < (int)args.length()) {
3811
switch(cc.toLatin1()) {
3814
cc = QLatin1Char('\n');
3818
cc = QLatin1Char('\r');
3822
cc = QLatin1Char('\t');
3825
if (!inEscape && inString) {
3832
inString = !inString;
3838
if (!inString && curArg.isEmpty())
3845
curArg = curArg.trimmed();
3846
if (curArg.at(0) == QLatin1Char('\"') && curArg.at(curArg.length()-1) == QLatin1Char('\"')) {
3847
vars << curArg.mid(1, curArg.length() - 2);
3849
bool isNumber = false;
3850
bool isDouble = false;
3851
int number = curArg.toInt(&isNumber);
3852
double dbl = curArg.toDouble(&isDouble);
3855
} else if (isDouble) {
3858
bool isEnum = false;
3859
for (int enumIndex = 0; enumIndex < mo->enumeratorCount(); ++enumIndex) {
3860
QMetaEnum metaEnum =mo->enumerator(enumIndex);
3861
int value = metaEnum.keyToValue(curArg.toLatin1());
3862
if (value != -1 && !QByteArray(metaEnum.valueToKey(value)).isEmpty()) {
3881
varc = vars.count();
3884
if (d->useMetaObject)
3885
id = mo->indexOfProperty(normFunction);
3888
const QMetaProperty prop =mo->property(id);
3889
type = prop.typeName();
3893
disptype = DISPATCH_PROPERTYPUT;
3895
disptype = DISPATCH_PROPERTYGET;
3899
varc = qMin(varc, d->metaobj->numParameter(normFunction));
3900
arg = varc <= QAX_NUM_PARAMS ? staticarg : new VARIANT[varc];
3901
for (int i = 0; i < varc; ++i) {
3902
QVariant var(vars.at(i));
3903
VariantInit(arg + (varc - i - 1));
3905
QByteArray paramType;
3906
if (disptype == DISPATCH_PROPERTYPUT)
3908
else if (parse || disptype == DISPATCH_PROPERTYGET)
3911
paramType = d->metaobj->paramType(normFunction, i, &out);
3913
if ((!parse && d->useMetaObject && var.type() == QVariant::String) || var.type() == QVariant::ByteArray) {
3914
int enumIndex =mo->indexOfEnumerator(paramType);
3915
if (enumIndex != -1) {
3916
QMetaEnum metaEnum =mo->enumerator(enumIndex);
3917
QVariantToVARIANT(metaEnum.keyToValue(var.toByteArray()), arg[varc - i - 1], "int", out);
3921
if (arg[varc - i - 1].vt == VT_EMPTY)
3922
QVariantToVARIANT(var, arg[varc - i - 1], paramType, out);
3926
DISPID dispid = d->metaobj->dispIDofName(function, disp);
3927
if (dispid == DISPID_UNKNOWN && function.toLower().startsWith("set")) {
3928
function = function.mid(3);
3929
dispid = d->metaobj->dispIDofName(function, disp);
3930
disptype = DISPATCH_PROPERTYPUT;
3933
if (dispid == DISPID_UNKNOWN) {
3934
#ifdef QT_CHECK_STATE
3935
qax_noSuchFunction(disptype, normFunction, function, this);
3941
DISPID dispidNamed = DISPID_PROPERTYPUT;
3943
params.cArgs = varc;
3944
params.cNamedArgs = (disptype == DISPATCH_PROPERTYPUT) ? 1 : 0;
3945
params.rgdispidNamedArgs = (disptype == DISPATCH_PROPERTYPUT) ? &dispidNamed : 0;
3946
params.rgvarg = arg;
3947
EXCEPINFO excepinfo;
3948
memset(&excepinfo, 0, sizeof(excepinfo));
3951
HRESULT hres = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, disptype, ¶ms, res, &excepinfo, &argerr);
3953
if (disptype == (DISPATCH_METHOD|DISPATCH_PROPERTYGET) && hres == S_OK && varc) {
3954
for (int i = 0; i < varc; ++i)
3955
if (arg[varc-i-1].vt & VT_BYREF) // update out-parameters
3956
vars[i] = VARIANTToQVariant(arg[varc-i-1], vars.at(i).typeName());
3960
for (int i = 0; i < varc; ++i)
3961
clearVARIANT(params.rgvarg+i);
3962
if (arg && arg != staticarg)
3965
return checkHRESULT(hres, &excepinfo, this, QLatin1String(function), varc-argerr-1);
3970
Calls the COM object's method \a function, passing the
3971
parameters \a var1, \a var1, \a var2, \a var3, \a var4, \a var5,
3972
\a var6, \a var7 and \a var8, and returns the value returned by
3973
the method, or an invalid QVariant if the method does not return
3974
a value or when the function call failed.
3976
If \a function is a method of the object the string must be provided
3977
as the full prototype, for example as it would be written in a
3978
QObject::connect() call.
3980
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 15
3982
Alternatively a function can be called passing the parameters embedded
3983
in the string, e.g. above function can also be invoked using
3985
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 16
3987
All parameters are passed as strings; it depends on the control whether
3988
they are interpreted correctly, and is slower than using the prototype
3989
with correctly typed parameters.
3991
If \a function is a property the string has to be the name of the
3992
property. The property setter is called when \a var1 is a valid QVariant,
3993
otherwise the getter is called.
3995
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 17
3997
Note that it is faster to get and set properties using
3998
QObject::property() and QObject::setProperty().
4000
dynamicCall() can also be used to call objects with a
4001
\l{QAxBase::disableMetaObject()}{disabled metaobject} wrapper,
4002
which can improve performance significantely, esp. when calling many
4003
different objects of different types during an automation process.
4004
ActiveQt will then however not validate parameters.
4006
It is only possible to call functions through dynamicCall() that
4007
have parameters or return values of datatypes supported by
4008
QVariant. See the QAxBase class documentation for a list of
4009
supported and unsupported datatypes. If you want to call functions
4010
that have unsupported datatypes in the parameter list, use
4011
queryInterface() to retrieve the appropriate COM interface, and
4012
use the function directly.
4014
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 18
4016
This is also more efficient.
4018
QVariant QAxBase::dynamicCall(const char *function,
4019
const QVariant &var1,
4020
const QVariant &var2,
4021
const QVariant &var3,
4022
const QVariant &var4,
4023
const QVariant &var5,
4024
const QVariant &var6,
4025
const QVariant &var7,
4026
const QVariant &var8)
4028
QList<QVariant> vars;
4029
QVariant var = var1;
4031
while(var.isValid()) {
4034
case 2: var = var2; break;
4035
case 3: var = var3; break;
4036
case 4: var = var4; break;
4037
case 5: var = var5; break;
4038
case 6: var = var6; break;
4039
case 7: var = var7; break;
4040
case 8: var = var8; break;
4041
default:var = QVariant(); break;
4045
return dynamicCall(function, vars);
4051
Calls the COM object's method \a function, passing the
4052
parameters in \a vars, and returns the value returned by
4053
the method. If the method does not return a value or when
4054
the function call failed this function returns an invalid
4057
The QVariant objects in \a vars are updated when the method has
4060
QVariant QAxBase::dynamicCall(const char *function, QList<QVariant> &vars)
4066
if (!dynamicCallHelper(function, &res, vars, rettype))
4069
QVariant qvar = VARIANTToQVariant(res, rettype);
4070
if ((res.vt != VT_DISPATCH && res.vt != VT_UNKNOWN) || qvar.type() == QVariant::Pixmap || qvar.type() == QVariant::Font)
4077
Returns a pointer to a QAxObject wrapping the COM object provided
4078
by the method or property \a name, passing passing the parameters
4079
\a var1, \a var1, \a var2, \a var3, \a var4, \a var5, \a var6,
4080
\a var7 and \a var8.
4082
If \a name is provided by a method the string must include the
4083
full function prototype.
4085
If \a name is a property the string must be the name of the property,
4086
and \a var1, ... \a var8 are ignored.
4088
The returned QAxObject is a child of this object (which is either of
4089
type QAxObject or QAxWidget), and is deleted when this object is
4090
deleted. It is however safe to delete the returned object yourself,
4091
and you should do so when you iterate over lists of subobjects.
4093
COM enabled applications usually have an object model publishing
4094
certain elements of the application as dispatch interfaces. Use
4095
this method to navigate the hierarchy of the object model, e.g.
4097
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 19
4099
QAxObject *QAxBase::querySubObject(const char *name,
4100
const QVariant &var1,
4101
const QVariant &var2,
4102
const QVariant &var3,
4103
const QVariant &var4,
4104
const QVariant &var5,
4105
const QVariant &var6,
4106
const QVariant &var7,
4107
const QVariant &var8)
4109
QList<QVariant> vars;
4110
QVariant var = var1;
4112
while(var.isValid()) {
4115
case 2: var = var2; break;
4116
case 3: var = var3; break;
4117
case 4: var = var4; break;
4118
case 5: var = var5; break;
4119
case 6: var = var6; break;
4120
case 7: var = var7; break;
4121
case 8: var = var8; break;
4122
default:var = QVariant(); break;
4126
return querySubObject(name, vars);
4132
The QVariant objects in \a vars are updated when the method has
4135
QAxObject *QAxBase::querySubObject(const char *name, QList<QVariant> &vars)
4137
QAxObject *object = 0;
4142
if (!dynamicCallHelper(name, &res, vars, rettype))
4148
if (rettype.isEmpty() || rettype == "IDispatch*" || rettype == "QVariant") {
4149
object = new QAxObject(res.pdispVal, qObject());
4150
} else if (QMetaType::type(rettype)) {
4151
QVariant qvar = VARIANTToQVariant(res, rettype, 0);
4152
object = *(QAxObject**)qvar.constData();
4153
// qVariantGet(qvar, object, rettype);
4154
res.pdispVal->AddRef();
4157
((QAxBase*)object)->d->tryCache = true;
4162
if (rettype.isEmpty() || rettype == "IUnknown*") {
4163
object = new QAxObject(res.punkVal, qObject());
4164
} else if (QMetaType::type(rettype)) {
4165
QVariant qvar = VARIANTToQVariant(res, rettype, 0);
4166
object = *(QAxObject**)qvar.constData();
4167
// qVariantGet(qvar, object, rettype);
4168
res.punkVal->AddRef();
4171
((QAxBase*)object)->d->tryCache = true;
4175
#ifdef QT_CHECK_STATE
4177
const char *coclass = metaObject()->classInfo(metaObject()->indexOfClassInfo("CoClass")).value();
4178
qWarning("QAxBase::querySubObject: %s: Error calling function or property in %s (%s)"
4179
, name, control().toLatin1().data(), coclass ? coclass: "unknown");
4184
#ifdef QT_CHECK_STATE
4186
const char *coclass = metaObject()->classInfo(metaObject()->indexOfClassInfo("CoClass")).value();
4187
qWarning("QAxBase::querySubObject: %s: Method or property is not of interface type in %s (%s)"
4188
, name, control().toLatin1().data(), coclass ? coclass: "unknown");
4198
class QtPropertyBag : public IPropertyBag
4201
QtPropertyBag() :ref(0) {}
4202
virtual ~QtPropertyBag() {}
4204
HRESULT __stdcall QueryInterface(REFIID iid, LPVOID *iface)
4207
if (iid == IID_IUnknown)
4209
else if (iid == IID_IPropertyBag)
4212
return E_NOINTERFACE;
4217
unsigned long __stdcall AddRef() { return ++ref; }
4218
unsigned long __stdcall Release()
4227
HRESULT __stdcall Read(LPCOLESTR name, VARIANT *var, IErrorLog *)
4232
QString property = QString::fromWCharArray(name);
4233
QVariant qvar = map.value(property);
4234
QVariantToVARIANT(qvar, *var);
4237
HRESULT __stdcall Write(LPCOLESTR name, VARIANT *var)
4241
QString property = QString::fromWCharArray(name);
4242
QVariant qvar = VARIANTToQVariant(*var, 0);
4243
map[property] = qvar;
4248
QAxBase::PropertyBag map;
4255
Returns a name:value map of all the properties exposed by the COM
4258
This is more efficient than getting multiple properties
4259
individually if the COM object supports property bags.
4261
\warning It is not guaranteed that the property bag implementation
4262
of the COM object returns all properties, or that the properties
4263
returned are the same as those available through the IDispatch
4266
QAxBase::PropertyBag QAxBase::propertyBag() const
4270
if (!d->ptr && !d->initialized) {
4271
((QAxBase*)this)->initialize(&d->ptr);
4272
d->initialized = true;
4277
IPersistPropertyBag *persist = 0;
4278
d->ptr->QueryInterface(IID_IPersistPropertyBag, (void**)&persist);
4280
QtPropertyBag *pbag = new QtPropertyBag();
4282
persist->Save(pbag, false, true);
4288
const QMetaObject *mo = metaObject();
4289
for (int p = mo->propertyOffset(); p < mo->propertyCount(); ++p) {
4290
const QMetaProperty property = mo->property(p);
4291
QVariant var = qObject()->property(property.name());
4292
result.insert(QLatin1String(property.name()), var);
4299
Sets the properties of the COM object to the corresponding values
4303
You should only set property bags that have been returned by the
4304
propertyBag function, as it cannot be guaranteed that the property
4305
bag implementation of the COM object supports the same properties
4306
that are available through the IDispatch interface.
4310
void QAxBase::setPropertyBag(const PropertyBag &bag)
4312
if (!d->ptr && !d->initialized) {
4313
initialize(&d->ptr);
4314
d->initialized = true;
4319
IPersistPropertyBag *persist = 0;
4320
d->ptr->QueryInterface(IID_IPersistPropertyBag, (void**)&persist);
4322
QtPropertyBag *pbag = new QtPropertyBag();
4325
persist->Load(pbag, 0);
4329
const QMetaObject *mo = metaObject();
4330
for (int p = mo->propertyOffset(); p < mo->propertyCount(); ++p) {
4331
const QMetaProperty property = mo->property(p);
4332
QVariant var = bag.value(QLatin1String(property.name()));
4333
qObject()->setProperty(property.name(), var);
4339
Returns true if the property \a prop is writable; otherwise
4340
returns false. By default, all properties are writable.
4343
Depending on the control implementation this setting might be
4344
ignored for some properties.
4346
\sa setPropertyWritable(), propertyChanged()
4348
bool QAxBase::propertyWritable(const char *prop) const
4350
return d->propWritable.value(prop, true);
4354
Sets the property \a prop to writable if \a ok is true, otherwise
4355
sets \a prop to be read-only. By default, all properties are
4359
Depending on the control implementation this setting might be
4360
ignored for some properties.
4362
\sa propertyWritable(), propertyChanged()
4364
void QAxBase::setPropertyWritable(const char *prop, bool ok)
4366
d->propWritable[prop] = ok;
4370
Returns true if there is no COM object loaded by this wrapper;
4371
otherwise return false.
4375
bool QAxBase::isNull() const
4381
Returns a QVariant that wraps the COM object. The variant can
4382
then be used as a parameter in e.g. dynamicCall().
4384
QVariant QAxBase::asVariant() const
4386
if (!d->ptr && !d->initialized) {
4387
((QAxBase*)this)->initialize(&d->ptr);
4388
d->initialized = true;
4392
QByteArray cn(className());
4393
if (cn == "QAxObject" || cn == "QAxWidget" || cn == "QAxBase") {
4395
qVariantSetValue(qvar, d->dispatch());
4397
qVariantSetValue(qvar, d->ptr);
4399
cn = cn.mid(cn.lastIndexOf(':') + 1);
4400
QObject *object = qObject();
4401
if (QMetaType::type(cn))
4402
qvar = QVariant(qRegisterMetaType<QObject*>(cn + '*'), &object);
4403
// qVariantSetValue(qvar, qObject(), cn + '*');
4409
// internal function that creates a QAxObject from an iface
4410
// used by type-conversion code (types.cpp)
4411
void *qax_createObjectWrapper(int metaType, IUnknown *iface)
4416
QAxObject *object = (QAxObject*)QMetaType::construct(metaType, 0);
4417
QAxBasePrivate *d = object->d;
4420
d->initialized = true;
4422
// no release, since no addref
4428
\fn void QAxBase::signal(const QString &name, int argc, void *argv)
4430
This generic signal gets emitted when the COM object issues the
4431
event \a name. \a argc is the number of parameters provided by the
4432
event (DISPPARAMS.cArgs), and \a argv is the pointer to the
4433
parameter values (DISPPARAMS.rgvarg). Note that the order of parameter
4434
values is turned around, ie. the last element of the array is the first
4435
parameter in the function.
4437
\snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 20
4439
Use this signal if the event has parameters of unsupported data
4440
types. Otherwise, connect directly to the signal \a name.
4444
\fn void QAxBase::propertyChanged(const QString &name)
4446
If the COM object supports property notification, this signal gets
4447
emitted when the property called \a name is changed.
4451
\fn void QAxBase::exception(int code, const QString &source, const QString &desc, const QString &help)
4453
This signal is emitted when the COM object throws an exception while called using the OLE automation
4454
interface IDispatch. \a code, \a source, \a desc and \a help provide information about the exception as
4455
provided by the COM server and can be used to provide useful feedback to the end user. \a help includes
4456
the help file, and the help context ID in brackets, e.g. "filename [id]".
4460
\fn QObject *QAxBase::qObject() const
4465
\fn const char *QAxBase::className() const
4470
#endif //QT_NO_WIN_ACTIVEQT