~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/activeqt/container/qaxbase.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
 
4
** All rights reserved.
 
5
** Contact: Nokia Corporation (qt-info@nokia.com)
 
6
**
 
7
** This file is part of the ActiveQt framework of the Qt Toolkit.
 
8
**
 
9
** $QT_BEGIN_LICENSE:BSD$
 
10
** You may use this file under the terms of the BSD license as follows:
 
11
**
 
12
** "Redistribution and use in source and binary forms, with or without
 
13
** modification, are permitted provided that the following conditions are
 
14
** met:
 
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
 
20
**     distribution.
 
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
 
24
**     permission.
 
25
**
 
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."
 
37
** $QT_END_LICENSE$
 
38
**
 
39
****************************************************************************/
 
40
 
 
41
//#define QAX_NO_CLASSINFO
 
42
 
 
43
#define QT_CHECK_STATE
 
44
 
 
45
#include "qaxobject.h"
 
46
 
 
47
#ifndef QT_NO_WIN_ACTIVEQT
 
48
 
 
49
#include <qfile.h>
 
50
#include <qwidget.h>
 
51
 
 
52
#include <quuid.h>
 
53
#include <qhash.h>
 
54
#include <qset.h>
 
55
#include <qpair.h>
 
56
#include <qmetaobject.h>
 
57
#include <qsettings.h>
 
58
 
 
59
#ifndef QT_NO_THREAD
 
60
#   include <qmutex.h>
 
61
#endif
 
62
 
 
63
#include <qt_windows.h>
 
64
#include <ocidl.h>
 
65
#include <ctype.h>
 
66
 
 
67
#include "../shared/qaxtypes.h"
 
68
 
 
69
QT_BEGIN_NAMESPACE
 
70
 
 
71
/*
 
72
    \internal
 
73
    \class QAxMetaObject
 
74
 
 
75
    \brief The QAxMetaObject class stores extended information
 
76
*/
 
77
struct QAxMetaObject : public QMetaObject
 
78
{
 
79
    QAxMetaObject()
 
80
    {
 
81
        d.data = 0;
 
82
        d.stringdata = 0;
 
83
    }
 
84
    ~QAxMetaObject()
 
85
    {
 
86
        delete [] (int*)d.data;
 
87
        delete [] (char*)d.stringdata;
 
88
    }
 
89
 
 
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);
 
95
 
 
96
private:
 
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;
 
106
 
 
107
    // Prototype -> member info
 
108
    QHash<QByteArray, QList<QByteArray> > memberInfo;
 
109
    QMap<QByteArray, QByteArray> realPrototype;
 
110
 
 
111
    // DISPID cache
 
112
    QHash<QByteArray, DISPID> dispIDs;
 
113
};
 
114
 
 
115
void QAxMetaObject::parsePrototype(const QByteArray &prototype)
 
116
{
 
117
    QByteArray realProto = realPrototype.value(prototype, prototype);
 
118
    QByteArray parameters = realProto.mid(realProto.indexOf('(') + 1);
 
119
    parameters.truncate(parameters.length() - 1);
 
120
 
 
121
    if (parameters.isEmpty()) {
 
122
        memberInfo.insert(prototype, QList<QByteArray>());
 
123
    } else {
 
124
        QList<QByteArray> plist = parameters.split(',');
 
125
        memberInfo.insert(prototype, plist);
 
126
    }
 
127
}
 
128
 
 
129
inline QByteArray QAxMetaObject::propertyType(const QByteArray &propertyName)
 
130
{
 
131
    return realPrototype.value(propertyName);
 
132
}
 
133
 
 
134
int QAxMetaObject::numParameter(const QByteArray &prototype)
 
135
{
 
136
    if (!memberInfo.contains(prototype))
 
137
        parsePrototype(prototype);
 
138
 
 
139
    return memberInfo.value(prototype).count();
 
140
}
 
141
 
 
142
QByteArray QAxMetaObject::paramType(const QByteArray &prototype, int index, bool *out)
 
143
{
 
144
    if (!memberInfo.contains(prototype))
 
145
        parsePrototype(prototype);
 
146
 
 
147
    if (out)
 
148
        *out = false;
 
149
 
 
150
    QList<QByteArray> plist = memberInfo.value(prototype);
 
151
    if (index > plist.count() - 1)
 
152
        return QByteArray();
 
153
 
 
154
    QByteArray param(plist.at(index));
 
155
    if (param.isEmpty())
 
156
        return QByteArray();
 
157
 
 
158
    bool byRef = param.endsWith('&') || param.endsWith("**");
 
159
    if (byRef) {
 
160
        param.truncate(param.length() - 1);
 
161
        if (out)
 
162
            *out = true;
 
163
    }
 
164
 
 
165
    return param;
 
166
}
 
167
 
 
168
inline DISPID QAxMetaObject::dispIDofName(const QByteArray &name, IDispatch *disp)
 
169
{
 
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);
 
178
    }
 
179
    return dispid;
 
180
}
 
181
 
 
182
 
 
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;
 
187
 
 
188
 
 
189
static const char *const type_conversion[][2] =
 
190
{
 
191
    { "float", "double"},
 
192
    { "short", "int"},
 
193
    { "char", "int"},
 
194
    { "QList<int>", "QVariantList" },
 
195
    { "QList<uint>", "QVariantList" },
 
196
    { "QList<double>", "QVariantList" },
 
197
    { "QList<bool>", "QVariantList" },
 
198
    { "QList<QDateTime>", "QVariantList" },
 
199
    { "QList<qlonglong>", "QVariantList" },
 
200
    { 0, 0 }
 
201
};
 
202
 
 
203
/*
 
204
    \internal
 
205
    \class QAxEventSink
 
206
 
 
207
    \brief The QAxEventSink class implements the event sink for all
 
208
           IConnectionPoints implemented in the COM object.
 
209
*/
 
210
 
 
211
class QAxEventSink : public IDispatch, public IPropertyNotifySink
 
212
{
 
213
public:
 
214
    QAxEventSink(QAxBase *com)
 
215
        : cpoint(0), ciid(IID_NULL), combase(com), ref(1)
 
216
    {}
 
217
    virtual ~QAxEventSink()
 
218
    {
 
219
        Q_ASSERT(!cpoint);
 
220
    }
 
221
 
 
222
    QUuid connectionInterface() const
 
223
    {
 
224
        return ciid;
 
225
    }
 
226
    QMap<DISPID, QByteArray> signalMap() const
 
227
    {
 
228
        return sigs;
 
229
    }
 
230
    QMap<DISPID, QByteArray> propertyMap() const
 
231
    {
 
232
        return props;
 
233
    }
 
234
    QMap<DISPID, QByteArray> propSignalMap() const
 
235
    {
 
236
        return propsigs;
 
237
    }
 
238
 
 
239
    // add a connection
 
240
    void advise(IConnectionPoint *cp, IID iid)
 
241
    {
 
242
        cpoint = cp;
 
243
        cpoint->AddRef();
 
244
        ciid = iid;
 
245
        cpoint->Advise((IUnknown*)(IDispatch*)this, &cookie);
 
246
    }
 
247
 
 
248
    // disconnect from all connection points
 
249
    void unadvise()
 
250
    {
 
251
        combase = 0;
 
252
        if (cpoint) {
 
253
            cpoint->Unadvise(cookie);
 
254
            cpoint->Release();
 
255
            cpoint = 0;
 
256
        }
 
257
    }
 
258
 
 
259
    void addSignal(DISPID memid, const char *name)
 
260
    {
 
261
        QByteArray signalname = name;
 
262
        int pi = signalname.indexOf('(');
 
263
        int i = 0;
 
264
        while (type_conversion[i][0]) {
 
265
            int ti = pi;
 
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]);
 
269
            ++i;
 
270
        }
 
271
 
 
272
        sigs.insert(memid, signalname);
 
273
        QMap<DISPID,QByteArray>::ConstIterator it;
 
274
        DISPID id = -1;
 
275
        for (it = propsigs.constBegin(); it!= propsigs.constEnd(); ++it) {
 
276
            if (it.value() == signalname) {
 
277
                id = it.key();
 
278
                break;
 
279
            }
 
280
        }
 
281
        if (id != -1)
 
282
            propsigs.remove(id);
 
283
    }
 
284
    void addProperty(DISPID propid, const char *name, const char *signal)
 
285
    {
 
286
        props.insert(propid, name);
 
287
        propsigs.insert(propid, signal);
 
288
    }
 
289
 
 
290
    // IUnknown
 
291
    unsigned long __stdcall AddRef()
 
292
    {
 
293
        return ref++;
 
294
    }
 
295
    unsigned long __stdcall Release()
 
296
    {
 
297
        if (!--ref) {
 
298
            delete this;
 
299
            return 0;
 
300
        }
 
301
        return ref;
 
302
    }
 
303
    HRESULT __stdcall QueryInterface(REFIID riid, void **ppvObject)
 
304
    {
 
305
        *ppvObject = 0;
 
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;
 
314
        else
 
315
            return E_NOINTERFACE;
 
316
 
 
317
        AddRef();
 
318
        return S_OK;
 
319
    }
 
320
 
 
321
    // IDispatch
 
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; }
 
325
 
 
326
    HRESULT __stdcall Invoke(DISPID dispIdMember,
 
327
                            REFIID riid,
 
328
                            LCID,
 
329
                            WORD wFlags,
 
330
                            DISPPARAMS *pDispParams,
 
331
                            VARIANT*,
 
332
                            EXCEPINFO*,
 
333
                            UINT*)
 
334
    {
 
335
        // verify input
 
336
        if (riid != IID_NULL)
 
337
            return DISP_E_UNKNOWNINTERFACE;
 
338
        if (!(wFlags & DISPATCH_METHOD))
 
339
            return DISP_E_MEMBERNOTFOUND;
 
340
        if (!combase)
 
341
            return E_UNEXPECTED;
 
342
 
 
343
        QByteArray signame = sigs.value(dispIdMember);
 
344
        if (signame.isEmpty())
 
345
            return DISP_E_MEMBERNOTFOUND;
 
346
 
 
347
        QObject *qobject = combase->qObject();
 
348
        if (qobject->signalsBlocked())
 
349
            return S_OK;
 
350
 
 
351
        QAxMetaObject *axmeta = combase->internalMetaObject();
 
352
        const QMetaObject *meta = combase->metaObject();
 
353
 
 
354
        int index = -1;
 
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);
 
359
 
 
360
            QString nameString = QLatin1String(signame);
 
361
            void *argv[] = {0, &nameString, &pDispParams->cArgs, &pDispParams->rgvarg};
 
362
            combase->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv);
 
363
        }
 
364
 
 
365
        HRESULT hres = S_OK;
 
366
 
 
367
        // get the signal information from the metaobject
 
368
        index = -1;
 
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;
 
382
 
 
383
            // setup parameters (no return values in signals)
 
384
            bool ok = true;
 
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];
 
388
 
 
389
            void **argv = 0;
 
390
            void **argv_pointer = 0; // in case we need an additional level of indirection
 
391
            QVariant *varp = 0;
 
392
 
 
393
            if (pcount) {
 
394
                if (pcount <= QAX_NUM_PARAMS) {
 
395
                    argv = static_argv;
 
396
                    argv_pointer = static_argv_pointer;
 
397
                    varp = static_varp;
 
398
                } else {
 
399
                    argv = new void*[pcount + 1];
 
400
                    argv_pointer = new void*[pcount + 1];
 
401
                    varp = new QVariant[pcount + 1];
 
402
                }
 
403
 
 
404
                argv[0] = 0;
 
405
                argv_pointer[0] = 0;
 
406
            }
 
407
 
 
408
            int p;
 
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;
 
419
                    } else {
 
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;
 
424
                        }
 
425
                    }
 
426
                } else if (ptype == "QVariant") {
 
427
                    argv[p + 1] = varp + p + 1;
 
428
                } else {
 
429
                    ok = false;
 
430
                }
 
431
            }
 
432
 
 
433
            if (ok) {
 
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) {
 
438
                    bool out;
 
439
                    QByteArray ptype = axmeta->paramType(signame, p, &out);
 
440
                    if (out) {
 
441
                        if (!QVariantToVARIANT(varp[p + 1], pDispParams->rgvarg[pcount - p - 1], ptype, out))
 
442
                            ok = false;
 
443
                    }
 
444
                }
 
445
            }
 
446
 
 
447
            if (argv != static_argv) {
 
448
                delete [] argv;
 
449
                delete [] argv_pointer;
 
450
                delete [] varp;
 
451
            }
 
452
            hres = ok ? S_OK : (ok ? DISP_E_MEMBERNOTFOUND : DISP_E_TYPEMISMATCH);
 
453
        }
 
454
 
 
455
        return hres;
 
456
    }
 
457
 
 
458
    QByteArray findProperty(DISPID dispID);
 
459
 
 
460
    // IPropertyNotifySink
 
461
    HRESULT __stdcall OnChanged(DISPID dispID)
 
462
    {
 
463
        // verify input
 
464
        if (dispID == DISPID_UNKNOWN || !combase)
 
465
            return S_OK;
 
466
 
 
467
        const QMetaObject *meta = combase->metaObject();
 
468
        if (!meta)
 
469
            return S_OK;
 
470
 
 
471
        QByteArray propname(findProperty(dispID));
 
472
        if (propname.isEmpty())
 
473
            return S_OK;
 
474
 
 
475
        QObject *qobject = combase->qObject();
 
476
        if (qobject->signalsBlocked())
 
477
            return S_OK;
 
478
 
 
479
        // emit the generic signal
 
480
        int index = meta->indexOfSignal("propertyChanged(QString)");
 
481
        if (index != -1) {
 
482
            QString propnameString = QString::fromLatin1(propname);
 
483
            void *argv[] = {0, &propnameString};
 
484
            combase->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv);
 
485
        }
 
486
 
 
487
        QByteArray signame = propsigs.value(dispID);
 
488
        if (signame.isEmpty())
 
489
            return S_OK;
 
490
 
 
491
        index = meta->indexOfSignal(signame);
 
492
        if (index == -1) // bindable but not marked as bindable in typelib
 
493
            return S_OK;
 
494
 
 
495
        // get the signal information from the metaobject
 
496
        if (signalHasReceivers(qobject, signame)) {
 
497
            index = meta->indexOfSignal(signame);
 
498
            Q_ASSERT(index != -1);
 
499
            // setup parameters
 
500
            QVariant var = qobject->property(propname);
 
501
            if (!var.isValid())
 
502
                return S_OK;
 
503
 
 
504
            const QMetaProperty metaProp = meta->property(meta->indexOfProperty(propname));
 
505
            void *argv[] = {0, var.data()};
 
506
            if (metaProp.type() == QVariant::LastType)
 
507
                argv[1] = &var;
 
508
 
 
509
            // emit the "changed" signal
 
510
            combase->qt_metacall(QMetaObject::InvokeMetaMethod, index, argv);
 
511
        }
 
512
        return S_OK;
 
513
    }
 
514
    HRESULT __stdcall OnRequestEdit(DISPID dispID)
 
515
    {
 
516
        if (dispID == DISPID_UNKNOWN || !combase)
 
517
            return S_OK;
 
518
 
 
519
        QByteArray propname(findProperty(dispID));
 
520
        if (propname.isEmpty())
 
521
            return S_OK;
 
522
 
 
523
        return combase->propertyWritable(propname) ? S_OK : S_FALSE;
 
524
    }
 
525
 
 
526
    static bool signalHasReceivers(QObject *qobject, const char *signalName)
 
527
    {
 
528
        Q_ASSERT(qobject);
 
529
        return ((QAxObject*)qobject)->receivers(QByteArray::number(QSIGNAL_CODE) + signalName);
 
530
    }
 
531
 
 
532
    IConnectionPoint *cpoint;
 
533
    IID ciid;
 
534
    ULONG cookie;
 
535
 
 
536
    QMap<DISPID, QByteArray> sigs;
 
537
    QMap<DISPID, QByteArray> propsigs;
 
538
    QMap<DISPID, QByteArray> props;
 
539
 
 
540
    QAxBase *combase;
 
541
    long ref;
 
542
};
 
543
 
 
544
/*
 
545
    \internal
 
546
    \class QAxBasePrivate
 
547
*/
 
548
 
 
549
class QAxBasePrivate
 
550
{
 
551
public:
 
552
    QAxBasePrivate()
 
553
        : useEventSink(true), useMetaObject(true), useClassInfo(true),
 
554
        cachedMetaObject(false), initialized(false), tryCache(false),
 
555
        ptr(0), disp(0), metaobj(0)
 
556
    {
 
557
        // protect initialization
 
558
        QMutexLocker locker(&cache_mutex);
 
559
        mo_cache_ref++;
 
560
 
 
561
        qRegisterMetaType<IUnknown*>("IUnknown*", &ptr);
 
562
        qRegisterMetaType<IDispatch*>("IDispatch*", &disp);
 
563
    }
 
564
 
 
565
    ~QAxBasePrivate()
 
566
    {
 
567
        Q_ASSERT(!ptr);
 
568
        Q_ASSERT(!disp);
 
569
 
 
570
        // protect cleanup
 
571
        QMutexLocker locker(&cache_mutex);
 
572
        if (!--mo_cache_ref) {
 
573
            qDeleteAll(mo_cache);
 
574
            mo_cache.clear();
 
575
        }
 
576
 
 
577
        CoFreeUnusedLibraries();
 
578
    }
 
579
 
 
580
    inline IDispatch *dispatch() const
 
581
    {
 
582
        if (disp)
 
583
            return disp;
 
584
 
 
585
        if (ptr)
 
586
            ptr->QueryInterface(IID_IDispatch, (void**)&disp);
 
587
        return disp;
 
588
    }
 
589
 
 
590
    QString ctrl;
 
591
 
 
592
    QHash<QUuid, QAxEventSink*> eventSink;
 
593
    uint useEventSink       :1;
 
594
    uint useMetaObject      :1;
 
595
    uint useClassInfo       :1;
 
596
    uint cachedMetaObject   :1;
 
597
    uint initialized        :1;
 
598
    uint tryCache           :1;
 
599
 
 
600
    IUnknown *ptr;
 
601
    mutable IDispatch *disp;
 
602
 
 
603
    QMap<QByteArray, bool> propWritable;
 
604
 
 
605
    inline QAxMetaObject *metaObject()
 
606
    {
 
607
        if (!metaobj)
 
608
            metaobj = new QAxMetaObject;
 
609
        return metaobj;
 
610
    }
 
611
 
 
612
    mutable QMap<QString, LONG> verbs;
 
613
 
 
614
    QAxMetaObject *metaobj;
 
615
};
 
616
 
 
617
 
 
618
QByteArray QAxEventSink::findProperty(DISPID dispID)
 
619
{
 
620
    // look up in cache, and fall back to
 
621
    // type info for precompiled metaobjects
 
622
    QByteArray propname(props.value(dispID));
 
623
 
 
624
    if (!propname.isEmpty())
 
625
        return propname;
 
626
 
 
627
    IDispatch *dispatch = combase->d->dispatch();
 
628
    ITypeInfo *typeinfo = 0;
 
629
    if (dispatch)
 
630
        dispatch->GetTypeInfo(0, LOCALE_USER_DEFAULT, &typeinfo);
 
631
    if (!typeinfo)
 
632
        return propname;
 
633
 
 
634
    BSTR names;
 
635
    UINT cNames;
 
636
    typeinfo->GetNames(dispID, &names, 1, &cNames);
 
637
    if (cNames) {
 
638
        propname = QString::fromWCharArray(names).toLatin1();
 
639
        SysFreeString(names);
 
640
    }
 
641
    typeinfo->Release();
 
642
 
 
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();
 
648
    propsignal += ')';
 
649
    addProperty(dispID, propname, propsignal);
 
650
 
 
651
    return propname;
 
652
}
 
653
 
 
654
/*!
 
655
    \class QAxBase
 
656
    \brief The QAxBase class is an abstract class that provides an API
 
657
    to initialize and access a COM object.
 
658
 
 
659
    \inmodule QAxContainer
 
660
 
 
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.
 
667
 
 
668
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 0
 
669
 
 
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.
 
675
 
 
676
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 1
 
677
 
 
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.
 
681
 
 
682
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 2
 
683
 
 
684
    Outgoing events supported by the COM object are emitted as
 
685
    standard Qt signals.
 
686
 
 
687
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 3
 
688
 
 
689
    QAxBase transparently converts between COM data types and the
 
690
    equivalent Qt data types. Some COM types have no equivalent Qt data structure.
 
691
 
 
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.
 
697
    \table
 
698
    \header
 
699
    \i COM type
 
700
    \i Qt property
 
701
    \i in-parameter
 
702
    \i out-parameter
 
703
    \row
 
704
    \i VARIANT_BOOL
 
705
    \i bool
 
706
    \i bool
 
707
    \i bool&
 
708
    \row
 
709
    \i BSTR
 
710
    \i QString
 
711
    \i const QString&
 
712
    \i QString&
 
713
    \row
 
714
    \i char, short, int, long
 
715
    \i int
 
716
    \i int
 
717
    \i int&
 
718
    \row
 
719
    \i uchar, ushort, uint, ulong
 
720
    \i uint
 
721
    \i uint
 
722
    \i uint&
 
723
    \row
 
724
    \i float, double
 
725
    \i double
 
726
    \i double
 
727
    \i double&
 
728
    \row
 
729
    \i DATE
 
730
    \i QDateTime
 
731
    \i const QDateTime&
 
732
    \i QDateTime&
 
733
    \row
 
734
    \i CY
 
735
    \i qlonglong
 
736
    \i qlonglong
 
737
    \i qlonglong&
 
738
    \row
 
739
    \i OLE_COLOR
 
740
    \i QColor
 
741
    \i const QColor&
 
742
    \i QColor&
 
743
    \row
 
744
    \i SAFEARRAY(VARIANT)
 
745
    \i QList\<QVariant\>
 
746
    \i const QList\<QVariant\>&
 
747
    \i QList\<QVariant\>&
 
748
    \row
 
749
    \i SAFEARRAY(int), SAFEARRAY(double), SAFEARRAY(Date)
 
750
    \i QList\<QVariant\>
 
751
    \i const QList\<QVariant\>&
 
752
    \i QList\<QVariant\>&
 
753
    \row
 
754
    \i SAFEARRAY(BYTE)
 
755
    \i QByteArray
 
756
    \i const QByteArray&
 
757
    \i QByteArray&
 
758
    \row
 
759
    \i SAFEARRAY(BSTR)
 
760
    \i QStringList
 
761
    \i const QStringList&
 
762
    \i QStringList&
 
763
    \row
 
764
    \i VARIANT
 
765
    \i type-dependent
 
766
    \i const QVariant&
 
767
    \i QVariant&
 
768
    \row
 
769
    \i IFontDisp*
 
770
    \i QFont
 
771
    \i const QFont&
 
772
    \i QFont&
 
773
    \row
 
774
    \i IPictureDisp*
 
775
    \i QPixmap
 
776
    \i const QPixmap&
 
777
    \i QPixmap&
 
778
    \row
 
779
    \i IDispatch*
 
780
    \i QAxObject*
 
781
    \i \c QAxBase::asVariant()
 
782
    \i QAxObject* (return value)
 
783
    \row
 
784
    \i IUnknown*
 
785
    \i QAxObject*
 
786
    \i \c QAxBase::asVariant()
 
787
    \i QAxObject* (return value)
 
788
    \row
 
789
    \i SCODE, DECIMAL
 
790
    \i \e unsupported
 
791
    \i \e unsupported
 
792
    \i \e unsupported
 
793
    \row
 
794
    \i VARIANT* (Since Qt 4.5)
 
795
    \i \e unsupported
 
796
    \i \e QVariant&
 
797
    \i \e QVariant&
 
798
    \endtable
 
799
 
 
800
    Supported are also enumerations, and typedefs to supported types.
 
801
 
 
802
    To call the methods of a COM interface described by the following IDL
 
803
 
 
804
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 4
 
805
 
 
806
    use the QAxBase API like this:
 
807
 
 
808
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 5
 
809
 
 
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.
 
812
 
 
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().
 
817
 
 
818
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 6
 
819
 
 
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
 
824
    them.
 
825
 
 
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.
 
829
 
 
830
    \sa QAxObject, QAxWidget, QAxScript, {ActiveQt Framework}
 
831
*/
 
832
 
 
833
/*!
 
834
    \typedef QAxBase::PropertyBag
 
835
 
 
836
    A QMap<QString,QVariant> that can store properties as name:value pairs.
 
837
*/
 
838
 
 
839
/*!
 
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
 
842
    object.
 
843
*/
 
844
QAxBase::QAxBase(IUnknown *iface)
 
845
{
 
846
    d = new QAxBasePrivate();
 
847
    d->ptr = iface;
 
848
    if (d->ptr) {
 
849
        d->ptr->AddRef();
 
850
        d->initialized = true;
 
851
    }
 
852
#if defined(Q_OS_WINCE)
 
853
    CoInitializeEx(0, COINIT_MULTITHREADED);
 
854
#endif
 
855
}
 
856
 
 
857
/*!
 
858
    Shuts down the COM object and destroys the QAxBase object.
 
859
 
 
860
    \sa clear()
 
861
*/
 
862
QAxBase::~QAxBase()
 
863
{
 
864
#if defined(Q_OS_WINCE)
 
865
    CoUninitialize();
 
866
#endif
 
867
 
 
868
    clear();
 
869
 
 
870
    delete d;
 
871
    d = 0;
 
872
}
 
873
 
 
874
/*!
 
875
    \internal
 
876
 
 
877
    Used by subclasses generated with dumpcpp to balance reference count.
 
878
*/
 
879
void QAxBase::internalRelease()
 
880
{
 
881
    if (d->ptr)
 
882
        d->ptr->Release();
 
883
}
 
884
 
 
885
/*!
 
886
    \internal
 
887
 
 
888
    Used by subclasses generated with dumpcpp to implement cast-operators.
 
889
*/
 
890
void QAxBase::initializeFrom(QAxBase *that)
 
891
{
 
892
    if (d->ptr)
 
893
        return;
 
894
 
 
895
    d->ptr = that->d->ptr;
 
896
    if (d->ptr) {
 
897
        d->ptr->AddRef();
 
898
        d->initialized = true;
 
899
    }
 
900
}
 
901
 
 
902
 
 
903
QAxMetaObject *QAxBase::internalMetaObject() const
 
904
{
 
905
    return d->metaObject();
 
906
}
 
907
 
 
908
/*!
 
909
    \property QAxBase::control
 
910
    \brief the name of the COM object wrapped by this QAxBase object.
 
911
 
 
912
    Setting this property initilializes the COM object. Any COM object
 
913
    previously set is shut down.
 
914
 
 
915
    The most efficient way to set this property is by using the
 
916
    registered component's UUID, e.g.
 
917
 
 
918
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 7
 
919
 
 
920
    The second fastest way is to use the registered control's class
 
921
    name (with or without version number), e.g.
 
922
 
 
923
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 8
 
924
 
 
925
    The slowest, but easiest way to use is to use the control's full
 
926
    name, e.g.
 
927
 
 
928
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 9
 
929
 
 
930
    It is also possible to initialize the object from a file, e.g.
 
931
 
 
932
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 10
 
933
 
 
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:
 
937
    \list
 
938
    \i To initialize the control on a different machine use the following
 
939
    pattern:
 
940
 
 
941
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 11
 
942
 
 
943
    \i To initialize a licensed control use the following pattern:
 
944
 
 
945
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 12
 
946
 
 
947
    \i To connect to an already running object use the following pattern:
 
948
 
 
949
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 13
 
950
 
 
951
    \endlist
 
952
    The first two patterns can be combined, e.g. to initialize a licensed
 
953
    control on a remote machine:
 
954
 
 
955
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 14
 
956
 
 
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.
 
959
*/
 
960
bool QAxBase::setControl(const QString &c)
 
961
{
 
962
    if (c.toLower() == d->ctrl.toLower())
 
963
        return !d->ctrl.isEmpty();
 
964
 
 
965
    QString search = c;
 
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("}&"))) {
 
969
        QUuid uuid(search);
 
970
        if (uuid.isNull()) {
 
971
            CLSID clsid;
 
972
            HRESULT res = CLSIDFromProgID((wchar_t*)c.utf16(), &clsid);
 
973
            if (res == S_OK)
 
974
                search = QUuid(clsid).toString();
 
975
            else {
 
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) {
 
982
                        QString clsid = *it;
 
983
                        QString name = controls.value(clsid + QLatin1String("/Default")).toString();
 
984
                        if (name == c) {
 
985
                            search = clsid;
 
986
                            break;
 
987
                        }
 
988
                    }
 
989
                    controls.endGroup();
 
990
                }
 
991
            }
 
992
        }
 
993
        if (search.isEmpty())
 
994
            search = c;
 
995
    }
 
996
 
 
997
    if (search.toLower() == d->ctrl.toLower())
 
998
        return !d->ctrl.isEmpty();
 
999
 
 
1000
    clear();
 
1001
    d->ctrl = search;
 
1002
 
 
1003
    d->tryCache = true;
 
1004
    if (!initialize(&d->ptr))
 
1005
        d->initialized = true;
 
1006
    if (isNull()) {
 
1007
        qWarning("QAxBase::setControl: requested control %s could not be instantiated", c.toLatin1().data());
 
1008
        clear();
 
1009
        return false;
 
1010
    }
 
1011
    return true;
 
1012
}
 
1013
 
 
1014
QString QAxBase::control() const
 
1015
{
 
1016
    return d->ctrl;
 
1017
}
 
1018
 
 
1019
/*!
 
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.
 
1023
 
 
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.
 
1028
 
 
1029
    Note that this function should be called immediately after
 
1030
    construction of the object.
 
1031
*/
 
1032
void QAxBase::disableEventSink()
 
1033
{
 
1034
    d->useEventSink = false;
 
1035
}
 
1036
 
 
1037
/*!
 
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
 
1044
    APIs.
 
1045
 
 
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().
 
1049
 
 
1050
    Note that this function must be called immediately after
 
1051
    construction of the object.
 
1052
*/
 
1053
void QAxBase::disableMetaObject()
 
1054
{
 
1055
    d->useMetaObject    = false;
 
1056
    d->useEventSink     = false;
 
1057
    d->useClassInfo     = false;
 
1058
}
 
1059
 
 
1060
/*!
 
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.
 
1064
 
 
1065
    Note that this function must be called immediately after
 
1066
    construction of the object
 
1067
*/
 
1068
void QAxBase::disableClassInfo()
 
1069
{
 
1070
    d->useClassInfo = false;
 
1071
}
 
1072
 
 
1073
/*!
 
1074
    Disconnects and destroys the COM object.
 
1075
 
 
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.
 
1079
*/
 
1080
void QAxBase::clear()
 
1081
{
 
1082
    QHash<QUuid, QAxEventSink*>::Iterator it =  d->eventSink.begin();
 
1083
    while (it != d->eventSink.end()) {
 
1084
        QAxEventSink *eventSink = it.value();
 
1085
        ++it;
 
1086
        if (eventSink) {
 
1087
            eventSink->unadvise();
 
1088
            eventSink->Release();
 
1089
        }
 
1090
    }
 
1091
    d->eventSink.clear();
 
1092
    if (d->disp) {
 
1093
        d->disp->Release();
 
1094
        d->disp = 0;
 
1095
    }
 
1096
    if (d->ptr) {
 
1097
        d->ptr->Release();
 
1098
        d->ptr = 0;
 
1099
        d->initialized = false;
 
1100
    }
 
1101
 
 
1102
    d->ctrl.clear();
 
1103
 
 
1104
    if (!d->cachedMetaObject)
 
1105
        delete d->metaobj;
 
1106
    d->metaobj = 0;
 
1107
}
 
1108
 
 
1109
/*!
 
1110
    \since 4.1
 
1111
 
 
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.
 
1115
 
 
1116
    Note that the OLE default verbs (OLEIVERB_SHOW etc) are not
 
1117
    included in the list.
 
1118
*/
 
1119
QStringList QAxBase::verbs() const
 
1120
{
 
1121
    if (!d->ptr)
 
1122
        return QStringList();
 
1123
 
 
1124
    if (d->verbs.isEmpty()) {
 
1125
        IOleObject *ole = 0;
 
1126
        d->ptr->QueryInterface(IID_IOleObject, (void**)&ole);
 
1127
        if (ole) {
 
1128
            IEnumOLEVERB *enumVerbs = 0;
 
1129
            ole->EnumVerbs(&enumVerbs);
 
1130
            if (enumVerbs) {
 
1131
                enumVerbs->Reset();
 
1132
                ULONG c;
 
1133
                OLEVERB verb;
 
1134
                while (enumVerbs->Next(1, &verb, &c) == S_OK) {
 
1135
                    if (!verb.lpszVerbName)
 
1136
                        continue;
 
1137
                    QString verbName = QString::fromWCharArray(verb.lpszVerbName);
 
1138
                    if (!verbName.isEmpty())
 
1139
                        d->verbs.insert(verbName, verb.lVerb);
 
1140
                }
 
1141
                enumVerbs->Release();
 
1142
            }
 
1143
            ole->Release();
 
1144
        }
 
1145
    }
 
1146
 
 
1147
    return d->verbs.keys();
 
1148
}
 
1149
 
 
1150
/*!
 
1151
    \internal
 
1152
*/
 
1153
 
 
1154
long QAxBase::indexOfVerb(const QString &verb) const
 
1155
{
 
1156
    return d->verbs.value(verb);
 
1157
}
 
1158
 
 
1159
/*!
 
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.
 
1164
 
 
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.
 
1172
 
 
1173
    See the \l control property documentation for details about
 
1174
    supported patterns.
 
1175
 
 
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
 
1179
    reference it again.
 
1180
*/
 
1181
bool QAxBase::initialize(IUnknown **ptr)
 
1182
{
 
1183
    if (*ptr || control().isEmpty())
 
1184
        return false;
 
1185
 
 
1186
    *ptr = 0;
 
1187
 
 
1188
    bool res = false;
 
1189
 
 
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);
 
1199
 
 
1200
    if (!res) { // standard
 
1201
        HRESULT hres = CoCreateInstance(QUuid(ctrl), 0, CLSCTX_SERVER, IID_IUnknown, (void**)ptr);
 
1202
        res = S_OK == hres;
 
1203
#ifndef QT_NO_DEBUG
 
1204
        if (!res)
 
1205
            qErrnoWarning(hres, "CoCreateInstance failure");
 
1206
#endif
 
1207
    }
 
1208
 
 
1209
    return *ptr != 0;
 
1210
}
 
1211
 
 
1212
/*!
 
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
 
1215
    returns false.
 
1216
 
 
1217
    This function is called by initialize() if the control string contains the
 
1218
    substring "}:". The license key needs to follow this substring.
 
1219
 
 
1220
    \sa initialize()
 
1221
*/
 
1222
bool QAxBase::initializeLicensed(IUnknown** ptr)
 
1223
{
 
1224
    int at = control().lastIndexOf(QLatin1String("}:"));
 
1225
 
 
1226
    QString clsid(control().left(at));
 
1227
    QString key(control().mid(at+2));
 
1228
 
 
1229
    IClassFactory *factory = 0;
 
1230
    CoGetClassObject(QUuid(clsid), CLSCTX_SERVER, 0, IID_IClassFactory, (void**)&factory);
 
1231
    if (!factory)
 
1232
        return false;
 
1233
    initializeLicensedHelper(factory, key, ptr);
 
1234
    factory->Release();
 
1235
 
 
1236
    return *ptr != 0;
 
1237
}
 
1238
 
 
1239
/* \internal
 
1240
    Called by initializeLicensed and initializedRemote to create an object
 
1241
    via IClassFactory2.
 
1242
*/
 
1243
bool QAxBase::initializeLicensedHelper(void *f, const QString &key, IUnknown **ptr)
 
1244
{
 
1245
    IClassFactory *factory = (IClassFactory*)f;
 
1246
    IClassFactory2 *factory2 = 0;
 
1247
    factory->QueryInterface(IID_IClassFactory2, (void**)&factory2);
 
1248
    if (factory2) {
 
1249
        BSTR bkey = QStringToBSTR(key);
 
1250
        HRESULT hres = factory2->CreateInstanceLic(0, 0, IID_IUnknown, bkey, (void**)ptr);
 
1251
        SysFreeString(bkey);
 
1252
#ifdef QT_DEBUG
 
1253
        LICINFO licinfo;
 
1254
        licinfo.cbLicInfo = sizeof(LICINFO);
 
1255
        factory2->GetLicInfo(&licinfo);
 
1256
 
 
1257
        if (hres != S_OK) {
 
1258
            SetLastError(hres);
 
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) {
 
1263
                BSTR licenseKey;
 
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());
 
1269
            }
 
1270
        } else if (licinfo.fLicVerified) {
 
1271
            qWarning("Machine is fully licensed for '%s'", control().toLatin1().constData());
 
1272
            if (licinfo.fRuntimeKeyAvail) {
 
1273
                BSTR licenseKey;
 
1274
                factory2->RequestLicKey(0, &licenseKey);
 
1275
                QString qlicenseKey = QString::fromWCharArray(licenseKey);
 
1276
                SysFreeString(licenseKey);
 
1277
 
 
1278
                if (qlicenseKey != key)
 
1279
                    qWarning("Runtime license key is '%s'", qlicenseKey.toLatin1().constData());
 
1280
            }
 
1281
        }
 
1282
#else
 
1283
        Q_UNUSED(hres);
 
1284
#endif
 
1285
        factory2->Release();
 
1286
    } else {  // give it a shot without license
 
1287
        factory->CreateInstance(0, IID_IUnknown, (void**)ptr);
 
1288
    }
 
1289
    return *ptr != 0;
 
1290
}
 
1291
 
 
1292
 
 
1293
/*!
 
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.
 
1297
 
 
1298
    This function is called by initialize() if the control string contains the
 
1299
    substring "}&".
 
1300
 
 
1301
    \sa initialize()
 
1302
*/
 
1303
bool QAxBase::initializeActive(IUnknown** ptr)
 
1304
{
 
1305
#if defined(Q_OS_WINCE)
 
1306
    Q_UNUSED(ptr);
 
1307
    return false;
 
1308
#else
 
1309
    int at = control().lastIndexOf(QLatin1String("}&"));
 
1310
    QString clsid(control().left(at));
 
1311
 
 
1312
    GetActiveObject(QUuid(clsid), 0, ptr);
 
1313
 
 
1314
    return *ptr != 0;
 
1315
#endif
 
1316
}
 
1317
 
 
1318
#ifdef Q_CC_GNU
 
1319
#   ifndef OLEPENDER_NONE
 
1320
#   define OLERENDER_NONE 0
 
1321
#   endif
 
1322
#endif
 
1323
 
 
1324
/*!
 
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.
 
1328
 
 
1329
    This function is called by initialize() if the control string is the name of
 
1330
    an existing file.
 
1331
 
 
1332
    \sa initialize()
 
1333
*/
 
1334
bool QAxBase::initializeFromFile(IUnknown** ptr)
 
1335
{
 
1336
#if defined(Q_OS_WINCE)
 
1337
    Q_UNUSED(ptr);
 
1338
    return false;
 
1339
#else
 
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);
 
1344
 
 
1345
    hres = OleCreateFromFile(CLSID_NULL, reinterpret_cast<const wchar_t*>(control().utf16()), IID_IUnknown, OLERENDER_NONE, 0, 0, storage, (void**)ptr);
 
1346
 
 
1347
    storage->Release();
 
1348
    bytes->Release();
 
1349
 
 
1350
    return hres == S_OK;
 
1351
#endif
 
1352
}
 
1353
 
 
1354
 
 
1355
// There seams to be a naming problem in mingw headers
 
1356
#ifdef Q_CC_GNU
 
1357
#ifndef COAUTHIDENTITY
 
1358
#define COAUTHIDENTITY AUTH_IDENTITY
 
1359
#endif
 
1360
#endif
 
1361
 
 
1362
 
 
1363
/*!
 
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
 
1366
    returns false.
 
1367
 
 
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.
 
1371
 
 
1372
    \sa initialize()
 
1373
*/
 
1374
bool QAxBase::initializeRemote(IUnknown** ptr)
 
1375
{
 
1376
    int at = control().lastIndexOf(QLatin1String("/{"));
 
1377
 
 
1378
    QString server(control().left(at));
 
1379
    QString clsid(control().mid(at+1));
 
1380
 
 
1381
    QString user;
 
1382
    QString domain;
 
1383
    QString passwd;
 
1384
    QString key;
 
1385
 
 
1386
    at = server.indexOf(QChar::fromLatin1('@'));
 
1387
    if (at != -1) {
 
1388
        user = server.left(at);
 
1389
        server = server.mid(at+1);
 
1390
 
 
1391
        at = user.indexOf(QChar::fromLatin1(':'));
 
1392
        if (at != -1) {
 
1393
            passwd = user.mid(at+1);
 
1394
            user = user.left(at);
 
1395
        }
 
1396
        at = user.indexOf(QChar::fromLatin1('/'));
 
1397
        if (at != -1) {
 
1398
            domain = user.left(at);
 
1399
            user = user.mid(at+1);
 
1400
        }
 
1401
    }
 
1402
 
 
1403
    at = clsid.lastIndexOf(QLatin1String("}:"));
 
1404
    if (at != -1) {
 
1405
        key = clsid.mid(at+2);
 
1406
        clsid = clsid.left(at);
 
1407
    }
 
1408
 
 
1409
    d->ctrl = server + QChar::fromLatin1('/') + clsid;
 
1410
    if (!key.isEmpty())
 
1411
        d->ctrl = d->ctrl + QChar::fromLatin1(':') + key;
 
1412
 
 
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;
 
1421
 
 
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;
 
1430
 
 
1431
    COSERVERINFO serverInfo;
 
1432
    serverInfo.dwReserved1 = 0;
 
1433
    serverInfo.dwReserved2 = 0;
 
1434
    serverInfo.pAuthInfo = &authInfo;
 
1435
    serverInfo.pwszName = (wchar_t*)server.utf16();
 
1436
 
 
1437
    IClassFactory *factory = 0;
 
1438
    HRESULT res = CoGetClassObject(QUuid(clsid), CLSCTX_REMOTE_SERVER, &serverInfo, IID_IClassFactory, (void**)&factory);
 
1439
    if (factory) {
 
1440
        if (!key.isEmpty())
 
1441
            initializeLicensedHelper(factory, key, ptr);
 
1442
        else
 
1443
            res = factory->CreateInstance(0, IID_IUnknown, (void**)ptr);
 
1444
        factory->Release();
 
1445
    }
 
1446
#ifndef QT_NO_DEBUG
 
1447
    if (res != S_OK)
 
1448
        qErrnoWarning(res, "initializeRemote Failed");
 
1449
#endif
 
1450
 
 
1451
    return res == S_OK;
 
1452
}
 
1453
 
 
1454
/*!
 
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.
 
1458
 
 
1459
    Returns the result of the QueryInterface implementation of the COM object.
 
1460
 
 
1461
    \sa control
 
1462
*/
 
1463
long QAxBase::queryInterface(const QUuid &uuid, void **iface) const
 
1464
{
 
1465
    *iface = 0;
 
1466
    if (!d->ptr) {
 
1467
        ((QAxBase*)this)->initialize(&d->ptr);
 
1468
        d->initialized = true;
 
1469
    }
 
1470
 
 
1471
    if (d->ptr && !uuid.isNull())
 
1472
        return d->ptr->QueryInterface(uuid, iface);
 
1473
 
 
1474
    return E_NOTIMPL;
 
1475
}
 
1476
 
 
1477
class MetaObjectGenerator
 
1478
{
 
1479
public:
 
1480
    MetaObjectGenerator(QAxBase *ax, QAxBasePrivate *dptr);
 
1481
    MetaObjectGenerator(ITypeLib *typelib, ITypeInfo *typeinfo);
 
1482
    ~MetaObjectGenerator();
 
1483
 
 
1484
    QMetaObject *metaObject(const QMetaObject *parentObject, const QByteArray &className = QByteArray());
 
1485
 
 
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);
 
1493
 
 
1494
    inline void addClassInfo(const char *key, const char *value)
 
1495
    {
 
1496
        classinfo_list.insert(key, value);
 
1497
    }
 
1498
 
 
1499
private:
 
1500
    void init();
 
1501
 
 
1502
 
 
1503
    QMetaObject *tryCache();
 
1504
 
 
1505
    QByteArray createPrototype(FUNCDESC *funcdesc, ITypeInfo *typeinfo, const QList<QByteArray> &names,
 
1506
        QByteArray &type, QList<QByteArray> &parameters);
 
1507
 
 
1508
    QByteArray usertypeToString(const TYPEDESC &tdesc, ITypeInfo *info, const QByteArray &function);
 
1509
    QByteArray guessTypes(const TYPEDESC &tdesc, ITypeInfo *info, const QByteArray &function);
 
1510
 
 
1511
    // ### from qmetaobject.cpp
 
1512
    enum ProperyFlags  {
 
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,
 
1528
        User                    = 0x00100000,
 
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
 
1533
    };
 
1534
    enum MemberFlags {
 
1535
        AccessPrivate = 0x00,
 
1536
        AccessProtected = 0x01,
 
1537
        AccessPublic = 0x02,
 
1538
        MemberMethod = 0x00,
 
1539
        MemberSignal = 0x04,
 
1540
        MemberSlot = 0x08,
 
1541
        MemberCompatibility = 0x10,
 
1542
        MemberCloned = 0x20,
 
1543
        MemberScriptable = 0x40,
 
1544
    };
 
1545
 
 
1546
    inline QList<QByteArray> paramList(const QByteArray &proto)
 
1547
    {
 
1548
        QByteArray prototype(proto);
 
1549
        QByteArray parameters = prototype.mid(prototype.indexOf('(') + 1);
 
1550
        parameters.truncate(parameters.length() - 1);
 
1551
 
 
1552
        QList<QByteArray> plist = parameters.split(',');
 
1553
        return plist;
 
1554
    }
 
1555
 
 
1556
    inline QByteArray replaceType(const QByteArray &type)
 
1557
    {
 
1558
        int i = 0;
 
1559
        while (type_conversion[i][0]) {
 
1560
            int len = int(strlen(type_conversion[i][0]));
 
1561
            int ti;
 
1562
            if ((ti = type.indexOf(type_conversion[i][0])) != -1) {
 
1563
                QByteArray rtype(type);
 
1564
                rtype.replace(ti, len, type_conversion[i][1]);
 
1565
                return rtype;
 
1566
            }
 
1567
            ++i;
 
1568
        }
 
1569
        return type;
 
1570
    }
 
1571
 
 
1572
    QByteArray replacePrototype(const QByteArray &prototype)
 
1573
    {
 
1574
        QByteArray proto(prototype);
 
1575
 
 
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)) {
 
1580
                int type = 0;
 
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]);
 
1585
                    }
 
1586
                    ++type;
 
1587
                }
 
1588
                break;
 
1589
            }
 
1590
        }
 
1591
 
 
1592
        return proto;
 
1593
    }
 
1594
 
 
1595
    QMap<QByteArray, QByteArray> classinfo_list;
 
1596
 
 
1597
    inline bool hasClassInfo(const char *key)
 
1598
    {
 
1599
        return classinfo_list.contains(key);
 
1600
    }
 
1601
 
 
1602
    struct Method {
 
1603
        Method() : flags(0) 
 
1604
        {}
 
1605
        QByteArray type;
 
1606
        QByteArray parameters;
 
1607
        int flags;
 
1608
        QByteArray realPrototype;
 
1609
    };
 
1610
    QMap<QByteArray, Method> signal_list;
 
1611
    inline void addSignal(const QByteArray &prototype, const QByteArray &parameters)
 
1612
    {
 
1613
        QByteArray proto(replacePrototype(prototype));
 
1614
 
 
1615
        Method &signal = signal_list[proto];
 
1616
        signal.type = 0;
 
1617
        signal.parameters = parameters;
 
1618
        signal.flags = QMetaMethod::Public | MemberSignal;
 
1619
        if (proto != prototype)
 
1620
            signal.realPrototype = prototype;
 
1621
    }
 
1622
 
 
1623
    void addChangedSignal(const QByteArray &function, const QByteArray &type, int memid);
 
1624
 
 
1625
    inline bool hasSignal(const QByteArray &prototype)
 
1626
    {
 
1627
        return signal_list.contains(prototype);
 
1628
    }
 
1629
 
 
1630
    QMap<QByteArray, Method> slot_list;
 
1631
    inline void addSlot(const QByteArray &type, const QByteArray &prototype, const QByteArray &parameters, int flags = QMetaMethod::Public)
 
1632
    {
 
1633
        QByteArray proto = replacePrototype(prototype);
 
1634
 
 
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;
 
1641
    }
 
1642
 
 
1643
    void addSetterSlot(const QByteArray &property);
 
1644
 
 
1645
    inline bool hasSlot(const QByteArray &prototype)
 
1646
    {
 
1647
        return slot_list.contains(prototype);
 
1648
    }
 
1649
 
 
1650
    struct Property {
 
1651
        Property() : typeId(0)
 
1652
        {}
 
1653
        QByteArray type;
 
1654
        uint typeId;
 
1655
        QByteArray realType;
 
1656
    };
 
1657
    QMap<QByteArray, Property> property_list;
 
1658
    void addProperty(const QByteArray &type, const QByteArray &name, uint flags)
 
1659
    {
 
1660
        QByteArray propertyType(type);
 
1661
        if (propertyType.endsWith('&'))
 
1662
            propertyType.chop(1);
 
1663
 
 
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;
 
1669
        }
 
1670
        if (flags & Writable)
 
1671
            flags |= Stored;
 
1672
        prop.typeId |= flags;
 
1673
        QVariant::Type vartype = QVariant::nameToType(prop.type);
 
1674
        switch(vartype) {
 
1675
        case QVariant::Invalid:
 
1676
            if (prop.type == "QVariant") {
 
1677
                prop.typeId |= 0xff << 24;
 
1678
                break;
 
1679
            }
 
1680
            // fall through
 
1681
        case QVariant::UserType:
 
1682
            if (QMetaType::type(prop.type) == -1)
 
1683
                qWarning("QAxBase: Unsupported property type: %s", prop.type.data());
 
1684
            break;
 
1685
        default:
 
1686
            prop.typeId |= vartype << 24;
 
1687
            break;
 
1688
        }
 
1689
    }
 
1690
 
 
1691
    inline bool hasProperty(const QByteArray &name)
 
1692
    {
 
1693
        return property_list.contains(name);
 
1694
    }
 
1695
 
 
1696
    inline QByteArray propertyType(const QByteArray &name)
 
1697
    {
 
1698
        return property_list.value(name).type;
 
1699
    }
 
1700
 
 
1701
    QMap<QByteArray, QList<QPair<QByteArray, int> > > enum_list;
 
1702
    inline void addEnumValue(const QByteArray &enumname, const QByteArray &key, int value)
 
1703
    {
 
1704
        enum_list[enumname].append(QPair<QByteArray, int>(key, value));
 
1705
    }
 
1706
 
 
1707
    inline bool hasEnum(const QByteArray &enumname)
 
1708
    {
 
1709
        return enum_list.contains(enumname);
 
1710
    }
 
1711
 
 
1712
    QAxBase *that;
 
1713
    QAxBasePrivate *d;
 
1714
 
 
1715
    IDispatch *disp;
 
1716
    ITypeInfo *dispInfo;
 
1717
    ITypeInfo *classInfo;
 
1718
    ITypeLib *typelib;
 
1719
    QByteArray current_typelib;
 
1720
 
 
1721
    QSettings iidnames;
 
1722
    QString cacheKey;
 
1723
    QByteArray debugInfo;
 
1724
 
 
1725
    QUuid iid_propNotifySink;
 
1726
 
 
1727
    friend QMetaObject *qax_readClassInfo(ITypeLib *typeLib, ITypeInfo *classInfo, const QMetaObject *parentObject);
 
1728
};
 
1729
 
 
1730
QMetaObject *qax_readEnumInfo(ITypeLib *typeLib, const QMetaObject *parentObject)
 
1731
{
 
1732
    MetaObjectGenerator generator(typeLib, 0);
 
1733
 
 
1734
    generator.readEnumInfo();
 
1735
    return generator.metaObject(parentObject, "EnumInfo");
 
1736
}
 
1737
 
 
1738
QMetaObject *qax_readInterfaceInfo(ITypeLib *typeLib, ITypeInfo *typeInfo, const QMetaObject *parentObject)
 
1739
{
 
1740
    MetaObjectGenerator generator(typeLib, typeInfo);
 
1741
 
 
1742
    QString className;
 
1743
    BSTR bstr;
 
1744
    if (S_OK != typeInfo->GetDocumentation(-1, &bstr, 0, 0, 0))
 
1745
        return 0;
 
1746
 
 
1747
    className = QString::fromWCharArray(bstr);
 
1748
    SysFreeString(bstr);
 
1749
 
 
1750
    generator.readEnumInfo();
 
1751
    generator.readFuncsInfo(typeInfo, 0);
 
1752
    generator.readVarsInfo(typeInfo, 0);
 
1753
 
 
1754
    return generator.metaObject(parentObject, className.toLatin1());
 
1755
}
 
1756
 
 
1757
QMetaObject *qax_readClassInfo(ITypeLib *typeLib, ITypeInfo *classInfo, const QMetaObject *parentObject)
 
1758
{
 
1759
    MetaObjectGenerator generator(typeLib, 0);
 
1760
    generator.addSignal("exception(int,QString,QString,QString)", "code,source,disc,help");
 
1761
    generator.addSignal("propertyChanged(QString)", "name");
 
1762
 
 
1763
    QString className;
 
1764
    BSTR bstr;
 
1765
    if (S_OK != classInfo->GetDocumentation(-1, &bstr, 0, 0, 0))
 
1766
        return 0;
 
1767
 
 
1768
    className = QString::fromWCharArray(bstr);
 
1769
    SysFreeString(bstr);
 
1770
 
 
1771
    generator.readEnumInfo();
 
1772
 
 
1773
    TYPEATTR *typeattr;
 
1774
    classInfo->GetTypeAttr(&typeattr);
 
1775
    if (typeattr) {
 
1776
        int nInterfaces = typeattr->cImplTypes;
 
1777
        classInfo->ReleaseTypeAttr(typeattr);
 
1778
 
 
1779
        for (int index = 0; index < nInterfaces; ++index) {
 
1780
            HREFTYPE refType;
 
1781
            if (S_OK != classInfo->GetRefTypeOfImplType(index, &refType))
 
1782
                continue;
 
1783
 
 
1784
            int flags = 0;
 
1785
            classInfo->GetImplTypeFlags(index, &flags);
 
1786
            if (flags & IMPLTYPEFLAG_FRESTRICTED)
 
1787
                continue;
 
1788
 
 
1789
            ITypeInfo *interfaceInfo = 0;
 
1790
            classInfo->GetRefTypeInfo(refType, &interfaceInfo);
 
1791
            if (!interfaceInfo)
 
1792
                continue;
 
1793
 
 
1794
            interfaceInfo->GetDocumentation(-1, &bstr, 0, 0, 0);
 
1795
            QString interfaceName = QString::fromWCharArray(bstr);
 
1796
            SysFreeString(bstr);
 
1797
            QByteArray key;
 
1798
 
 
1799
            TYPEATTR *typeattr = 0;
 
1800
            interfaceInfo->GetTypeAttr(&typeattr);
 
1801
 
 
1802
            if (flags & IMPLTYPEFLAG_FSOURCE) {
 
1803
                if (typeattr && !(typeattr->wTypeFlags & TYPEFLAG_FHIDDEN))
 
1804
                    key = "Event Interface " + QByteArray::number(index);
 
1805
                generator.readEventInterface(interfaceInfo, 0);
 
1806
            } else {
 
1807
                if (typeattr && !(typeattr->wTypeFlags & TYPEFLAG_FHIDDEN))
 
1808
                    key = "Interface " + QByteArray::number(index);
 
1809
                generator.readFuncsInfo(interfaceInfo, 0);
 
1810
                generator.readVarsInfo(interfaceInfo, 0);
 
1811
            }
 
1812
            if (!key.isEmpty())
 
1813
                generator.addClassInfo(key.data(), interfaceName.toLatin1());
 
1814
 
 
1815
            if (typeattr)
 
1816
                interfaceInfo->ReleaseTypeAttr(typeattr);
 
1817
            interfaceInfo->Release();
 
1818
        }
 
1819
    }
 
1820
 
 
1821
    return generator.metaObject(parentObject, className.toLatin1());
 
1822
}
 
1823
 
 
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)
 
1827
{
 
1828
    init();
 
1829
}
 
1830
 
 
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)
 
1834
{
 
1835
    init();
 
1836
 
 
1837
    if (dispInfo)
 
1838
        dispInfo->AddRef();
 
1839
    if (typelib) {
 
1840
        typelib->AddRef();
 
1841
        BSTR bstr;
 
1842
        typelib->GetDocumentation(-1, &bstr, 0, 0, 0);
 
1843
        current_typelib = QString::fromWCharArray(bstr).toLatin1();
 
1844
        SysFreeString(bstr);
 
1845
    }
 
1846
    readClassInfo();
 
1847
}
 
1848
 
 
1849
void MetaObjectGenerator::init()
 
1850
{
 
1851
    if (d)
 
1852
        disp = d->dispatch();
 
1853
 
 
1854
    iid_propNotifySink = IID_IPropertyNotifySink;
 
1855
 
 
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);
 
1861
    }
 
1862
}
 
1863
 
 
1864
MetaObjectGenerator::~MetaObjectGenerator()
 
1865
{
 
1866
    if (dispInfo) dispInfo->Release();
 
1867
    if (classInfo) classInfo->Release();
 
1868
    if (typelib) typelib->Release();
 
1869
}
 
1870
 
 
1871
bool qax_dispatchEqualsIDispatch = true;
 
1872
QList<QByteArray> qax_qualified_usertypes;
 
1873
 
 
1874
QByteArray MetaObjectGenerator::usertypeToString(const TYPEDESC &tdesc, ITypeInfo *info, const QByteArray &function)
 
1875
{
 
1876
    HREFTYPE usertype = tdesc.hreftype;
 
1877
    if (tdesc.vt != VT_USERDEFINED)
 
1878
        return 0;
 
1879
 
 
1880
    QByteArray typeName;
 
1881
    ITypeInfo *usertypeinfo = 0;
 
1882
    info->GetRefTypeInfo(usertype, &usertypeinfo);
 
1883
    if (usertypeinfo) {
 
1884
        ITypeLib *usertypelib = 0;
 
1885
        UINT index;
 
1886
        usertypeinfo->GetContainingTypeLib(&usertypelib, &index);
 
1887
        if (usertypelib) {
 
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);
 
1893
 
 
1894
            // get type name
 
1895
            BSTR usertypename = 0;
 
1896
            usertypelib->GetDocumentation(index, &usertypename, 0, 0, 0);
 
1897
            QByteArray userTypeName = QString::fromWCharArray(usertypename).toLatin1();
 
1898
            SysFreeString(usertypename);
 
1899
 
 
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*")
 
1905
                typeName = "QFont";
 
1906
            else if (userTypeName == "Picture" || userTypeName == "Picture*")
 
1907
                typeName = "QPixmap";
 
1908
 
 
1909
            if (typeName.isEmpty()) {
 
1910
                TYPEATTR *typeattr = 0;
 
1911
                usertypeinfo->GetTypeAttr(&typeattr);
 
1912
                if (typeattr) {
 
1913
                    switch(typeattr->typekind) {
 
1914
                    case TKIND_ALIAS:
 
1915
                        userTypeName = guessTypes(typeattr->tdescAlias, usertypeinfo, function);
 
1916
                        break;
 
1917
                    case TKIND_DISPATCH:
 
1918
                    case TKIND_COCLASS:
 
1919
                        if (qax_dispatchEqualsIDispatch) {
 
1920
                            userTypeName = "IDispatch";
 
1921
                        } else {
 
1922
                            if (typeLibName != current_typelib)
 
1923
                                userTypeName = typeLibName + "::" + userTypeName;
 
1924
                            if (!qax_qualified_usertypes.contains(userTypeName))
 
1925
                                qax_qualified_usertypes << userTypeName;
 
1926
                        }
 
1927
                        break;
 
1928
                    case TKIND_ENUM:
 
1929
                        if (typeLibName != current_typelib)
 
1930
                            userTypeName = typeLibName + "::" + userTypeName;
 
1931
                        if (!qax_qualified_usertypes.contains("enum " + userTypeName))
 
1932
                            qax_qualified_usertypes << "enum " + userTypeName;
 
1933
                        break;
 
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;
 
1939
                        break;
 
1940
                    case TKIND_RECORD:
 
1941
                        if (!qax_qualified_usertypes.contains("struct " + userTypeName))
 
1942
                            qax_qualified_usertypes << "struct "+ userTypeName;
 
1943
                        break;
 
1944
                    default:
 
1945
                        break;
 
1946
                    }
 
1947
                }
 
1948
 
 
1949
                usertypeinfo->ReleaseTypeAttr(typeattr);
 
1950
                typeName = userTypeName;
 
1951
            }
 
1952
            usertypelib->Release();
 
1953
        }
 
1954
        usertypeinfo->Release();
 
1955
    }
 
1956
 
 
1957
    return typeName;
 
1958
}
 
1959
 
 
1960
#define VT_UNHANDLED(x) case VT_##x: qWarning("QAxBase: Unhandled type %s", #x); str = #x; break;
 
1961
 
 
1962
QByteArray MetaObjectGenerator::guessTypes(const TYPEDESC &tdesc, ITypeInfo *info, const QByteArray &function)
 
1963
{
 
1964
    QByteArray str;
 
1965
    switch (tdesc.vt) {
 
1966
    case VT_EMPTY:
 
1967
    case VT_VOID:
 
1968
        break;
 
1969
    case VT_LPWSTR:
 
1970
        str = "wchar_t *";
 
1971
        break;
 
1972
    case VT_BSTR:
 
1973
        str = "QString";
 
1974
        break;
 
1975
    case VT_BOOL:
 
1976
        str = "bool";
 
1977
        break;
 
1978
    case VT_I1:
 
1979
        str = "char";
 
1980
        break;
 
1981
    case VT_I2:
 
1982
        str = "short";
 
1983
        break;
 
1984
    case VT_I4:
 
1985
    case VT_INT:
 
1986
        str = "int";
 
1987
        break;
 
1988
    case VT_I8:
 
1989
        str = "qlonglong";
 
1990
        break;
 
1991
    case VT_UI1:
 
1992
    case VT_UI2:
 
1993
    case VT_UI4:
 
1994
    case VT_UINT:
 
1995
        str = "uint";
 
1996
        break;
 
1997
    case VT_UI8:
 
1998
        str = "qulonglong";
 
1999
        break;
 
2000
    case VT_CY:
 
2001
        str = "qlonglong";
 
2002
        break;
 
2003
    case VT_R4:
 
2004
        str = "float";
 
2005
        break;
 
2006
    case VT_R8:
 
2007
        str = "double";
 
2008
        break;
 
2009
    case VT_DATE:
 
2010
        str = "QDateTime";
 
2011
        break;
 
2012
    case VT_DISPATCH:
 
2013
        str = "IDispatch*";
 
2014
        break;
 
2015
    case VT_VARIANT:
 
2016
        str = "QVariant";
 
2017
        break;
 
2018
    case VT_UNKNOWN:
 
2019
        str = "IUnknown*";
 
2020
        break;
 
2021
    case VT_HRESULT:
 
2022
        str = "HRESULT";
 
2023
        break;
 
2024
    case VT_PTR:
 
2025
        str = guessTypes(*tdesc.lptdesc, info, function);
 
2026
        switch(tdesc.lptdesc->vt) {
 
2027
        case VT_VOID:
 
2028
            str = "void*";
 
2029
            break;
 
2030
        case VT_VARIANT:
 
2031
        case VT_BSTR:
 
2032
        case VT_I1:
 
2033
        case VT_I2:
 
2034
        case VT_I4:
 
2035
        case VT_I8:
 
2036
        case VT_UI1:
 
2037
        case VT_UI2:
 
2038
        case VT_UI4:
 
2039
        case VT_UI8:
 
2040
        case VT_BOOL:
 
2041
        case VT_R4:
 
2042
        case VT_R8:
 
2043
        case VT_INT:
 
2044
        case VT_UINT:
 
2045
        case VT_CY:
 
2046
            str += '&';
 
2047
            break;
 
2048
        case VT_PTR:
 
2049
            if (str == "QFont" || str == "QPixmap") {
 
2050
                str += '&';
 
2051
                break;
 
2052
            } else if (str == "void*") {
 
2053
                str = "void **";
 
2054
                break;
 
2055
            }
 
2056
            // FALLTHROUGH
 
2057
        default:
 
2058
            if (str == "QColor")
 
2059
                str += '&';
 
2060
            else if (str == "QDateTime")
 
2061
                str += '&';
 
2062
            else if (str == "QVariantList")
 
2063
                str += '&';
 
2064
            else if (str == "QByteArray")
 
2065
                str += '&';
 
2066
            else if (str == "QStringList")
 
2067
                str += '&';
 
2068
            else if (!str.isEmpty() && hasEnum(str))
 
2069
                str += '&';
 
2070
            else if (!str.isEmpty() && str != "QFont" && str != "QPixmap" && str != "QVariant")
 
2071
                str += '*';
 
2072
        }
 
2073
        break;
 
2074
    case VT_SAFEARRAY:
 
2075
        switch(tdesc.lpadesc->tdescElem.vt) {
 
2076
        // some shortcuts, and generic support for lists of QVariant-supported types
 
2077
        case VT_UI1:
 
2078
            str = "QByteArray";
 
2079
            break;
 
2080
        case VT_BSTR:
 
2081
            str = "QStringList";
 
2082
            break;
 
2083
        case VT_VARIANT:
 
2084
            str = "QVariantList";
 
2085
            break;
 
2086
        default:
 
2087
            str = guessTypes(tdesc.lpadesc->tdescElem, info, function);
 
2088
            if (!str.isEmpty())
 
2089
                str = "QList<" + str + '>';
 
2090
            break;
 
2091
        }
 
2092
        break;
 
2093
    case VT_CARRAY:
 
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) + ']';
 
2098
        }
 
2099
        break;
 
2100
    case VT_USERDEFINED:
 
2101
        str = usertypeToString(tdesc, info, function);
 
2102
        break;
 
2103
 
 
2104
    VT_UNHANDLED(FILETIME);
 
2105
    VT_UNHANDLED(BLOB);
 
2106
    VT_UNHANDLED(ERROR);
 
2107
    VT_UNHANDLED(DECIMAL);
 
2108
    VT_UNHANDLED(LPSTR);
 
2109
    default:
 
2110
        break;
 
2111
    }
 
2112
 
 
2113
    if (tdesc.vt & VT_BYREF)
 
2114
        str += '&';
 
2115
 
 
2116
    str.replace("&*", "**");
 
2117
    return str;
 
2118
}
 
2119
 
 
2120
void MetaObjectGenerator::readClassInfo()
 
2121
{
 
2122
    // Read class information
 
2123
    IProvideClassInfo *provideClassInfo = 0;
 
2124
    if (d)
 
2125
        d->ptr->QueryInterface(IID_IProvideClassInfo, (void**)&provideClassInfo);
 
2126
    if (provideClassInfo) {
 
2127
        provideClassInfo->GetClassInfo(&classInfo);
 
2128
        TYPEATTR *typeattr = 0;
 
2129
        if (classInfo)
 
2130
            classInfo->GetTypeAttr(&typeattr);
 
2131
 
 
2132
        QString coClassID;
 
2133
        if (typeattr) {
 
2134
            QUuid clsid(typeattr->guid);
 
2135
            coClassID = clsid.toString().toUpper();
 
2136
#ifndef QAX_NO_CLASSINFO
 
2137
            // UUID
 
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);
 
2144
            }
 
2145
#endif
 
2146
            classInfo->ReleaseTypeAttr(typeattr);
 
2147
        }
 
2148
        provideClassInfo->Release();
 
2149
        provideClassInfo = 0;
 
2150
 
 
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);
 
2154
    }
 
2155
 
 
2156
    UINT index = 0;
 
2157
    if (disp && !dispInfo)
 
2158
        disp->GetTypeInfo(index, LOCALE_USER_DEFAULT, &dispInfo);
 
2159
 
 
2160
    if (dispInfo && !typelib)
 
2161
        dispInfo->GetContainingTypeLib(&typelib, &index);
 
2162
 
 
2163
    if (!typelib) {
 
2164
        QSettings controls(QLatin1String("HKEY_LOCAL_MACHINE\\Software"), QSettings::NativeFormat);
 
2165
        QString tlid = controls.value(QLatin1String("/Classes/CLSID/") + that->control() + QLatin1String("/TypeLib/.")).toString();
 
2166
        QString tlfile;
 
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;
 
2173
                ++vit;
 
2174
                tlfile = controls.value(QLatin1Char('/') + version + QLatin1String("/0/win32/.")).toString();
 
2175
            }
 
2176
            controls.endGroup();
 
2177
        } else {
 
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();
 
2181
        }
 
2182
        if (!tlfile.isEmpty()) {
 
2183
            LoadTypeLib((OLECHAR*)tlfile.utf16(), &typelib);
 
2184
            if (!typelib) {
 
2185
                tlfile = tlfile.left(tlfile.lastIndexOf(QLatin1Char('.'))) + QLatin1String(".tlb");
 
2186
                LoadTypeLib((OLECHAR*)tlfile.utf16(), &typelib);
 
2187
            }
 
2188
            if (!typelib) {
 
2189
                tlfile = tlfile.left(tlfile.lastIndexOf(QLatin1Char('.'))) + QLatin1String(".olb");
 
2190
                LoadTypeLib((OLECHAR*)tlfile.utf16(), &typelib);
 
2191
            }
 
2192
        }
 
2193
    }
 
2194
 
 
2195
    if (!classInfo && typelib && that)
 
2196
        typelib->GetTypeInfoOfGuid(QUuid(that->control()), &classInfo);
 
2197
 
 
2198
    if (classInfo && !dispInfo) {
 
2199
        TYPEATTR *classAttr;
 
2200
        classInfo->GetTypeAttr(&classAttr);
 
2201
        if (classAttr) {
 
2202
            for (int i = 0; i < classAttr->cImplTypes; ++i) {
 
2203
                int typeFlags = 0;
 
2204
                classInfo->GetImplTypeFlags(i, &typeFlags);
 
2205
                if (typeFlags & IMPLTYPEFLAG_FSOURCE)
 
2206
                    continue;
 
2207
                
 
2208
                HREFTYPE hrefType;
 
2209
                if (S_OK == classInfo->GetRefTypeOfImplType(i, &hrefType))
 
2210
                    classInfo->GetRefTypeInfo(hrefType, &dispInfo);
 
2211
                if (dispInfo) {
 
2212
                    TYPEATTR *ifaceAttr;
 
2213
                    dispInfo->GetTypeAttr(&ifaceAttr);
 
2214
                    WORD typekind = ifaceAttr->typekind;
 
2215
                    dispInfo->ReleaseTypeAttr(ifaceAttr);
 
2216
                    
 
2217
                    if (typekind & TKIND_DISPATCH) {
 
2218
                        break;
 
2219
                    } else {
 
2220
                        dispInfo->Release();
 
2221
                        dispInfo = 0;
 
2222
                    }
 
2223
                }
 
2224
            }
 
2225
            classInfo->ReleaseTypeAttr(classAttr);
 
2226
        }
 
2227
    }
 
2228
 
 
2229
    if (!d || !dispInfo || !cacheKey.isEmpty() || !d->tryCache)
 
2230
        return;
 
2231
 
 
2232
    TYPEATTR *typeattr = 0;
 
2233
    dispInfo->GetTypeAttr(&typeattr);
 
2234
 
 
2235
    QString interfaceID;
 
2236
    if (typeattr) {
 
2237
        QUuid iid(typeattr->guid);
 
2238
        interfaceID = iid.toString().toUpper();
 
2239
 
 
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);
 
2245
    }
 
2246
}
 
2247
 
 
2248
void MetaObjectGenerator::readEnumInfo()
 
2249
{
 
2250
    if (!typelib)
 
2251
        return;
 
2252
 
 
2253
    QUuid libUuid;
 
2254
 
 
2255
    if (d && d->tryCache) {
 
2256
        TLIBATTR *libAttr = 0;
 
2257
        typelib->GetLibAttr(&libAttr);
 
2258
        if (libAttr) {
 
2259
            libUuid = QUuid(libAttr->guid);
 
2260
            typelib->ReleaseTLibAttr(libAttr);
 
2261
            enum_list = enum_cache.value(libUuid);
 
2262
            if (!enum_list.isEmpty())
 
2263
                return;
 
2264
        }
 
2265
    }
 
2266
 
 
2267
    int valueindex = 0;
 
2268
    QSet<QString> clashCheck;
 
2269
    int clashIndex = 0;
 
2270
 
 
2271
    int enum_serial = 0;
 
2272
    UINT index = typelib->GetTypeInfoCount();
 
2273
    for (UINT i = 0; i < index; ++i) {
 
2274
        TYPEKIND typekind;
 
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);
 
2280
            if (!enuminfo)
 
2281
                continue;
 
2282
 
 
2283
            // Get the name of the enumeration
 
2284
            BSTR enumname;
 
2285
            QByteArray enumName;
 
2286
            if (typelib->GetDocumentation(i, &enumname, 0, 0, 0) == S_OK) {
 
2287
                enumName = QString::fromWCharArray(enumname).toLatin1();
 
2288
                SysFreeString(enumname);
 
2289
            } else {
 
2290
                enumName = "enum" + QByteArray::number(++enum_serial);
 
2291
            }
 
2292
 
 
2293
            // Get the attributes of the enum type
 
2294
            TYPEATTR *typeattr = 0;
 
2295
            enuminfo->GetTypeAttr(&typeattr);
 
2296
            if (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
 
2305
                        BSTR valuename;
 
2306
                        QByteArray valueName;
 
2307
                        UINT maxNamesOut;
 
2308
                        enuminfo->GetNames(memid, &valuename, 1, &maxNamesOut);
 
2309
                        if (maxNamesOut) {
 
2310
                            valueName = QString::fromWCharArray(valuename).toLatin1();
 
2311
                            SysFreeString(valuename);
 
2312
                        } else {
 
2313
                            valueName = "value" + QByteArray::number(valueindex++);
 
2314
                        }
 
2315
 
 
2316
                        if (clashCheck.contains(QString::fromLatin1(valueName)))
 
2317
                            valueName += QByteArray::number(++clashIndex);
 
2318
 
 
2319
                        clashCheck.insert(QString::fromLatin1(valueName));
 
2320
                        addEnumValue(enumName, valueName, value);
 
2321
                    }
 
2322
                    enuminfo->ReleaseVarDesc(vardesc);
 
2323
                }
 
2324
            }
 
2325
            enuminfo->ReleaseTypeAttr(typeattr);
 
2326
            enuminfo->Release();
 
2327
        }
 
2328
    }
 
2329
 
 
2330
    if (!libUuid.isNull())
 
2331
        enum_cache.insert(libUuid, enum_list);
 
2332
}
 
2333
 
 
2334
void MetaObjectGenerator::addChangedSignal(const QByteArray &function, const QByteArray &type, int memid)
 
2335
{
 
2336
    QAxEventSink *eventSink = 0;
 
2337
    if (d) {
 
2338
        eventSink = d->eventSink.value(iid_propNotifySink);
 
2339
        if (!eventSink && d->useEventSink) {
 
2340
            eventSink = new QAxEventSink(that);
 
2341
            d->eventSink.insert(iid_propNotifySink, eventSink);
 
2342
        }
 
2343
    }
 
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);
 
2350
    if (eventSink)
 
2351
        eventSink->addProperty(memid, function, signalProto);
 
2352
}
 
2353
 
 
2354
void MetaObjectGenerator::addSetterSlot(const QByteArray &property)
 
2355
{
 
2356
    QByteArray set;
 
2357
    QByteArray prototype(property);
 
2358
    if (isupper(prototype.at(0))) {
 
2359
        set = "Set";
 
2360
    } else {
 
2361
        set = "set";
 
2362
        prototype[0] = toupper(prototype[0]);
 
2363
    }
 
2364
    prototype = set + prototype + '(' + propertyType(property) + ')';
 
2365
    if (!hasSlot(prototype))
 
2366
        addSlot(0, prototype, property);
 
2367
}
 
2368
 
 
2369
QByteArray MetaObjectGenerator::createPrototype(FUNCDESC *funcdesc, ITypeInfo *typeinfo, const QList<QByteArray> &names,
 
2370
                                             QByteArray &type, QList<QByteArray> &parameters)
 
2371
{
 
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);
 
2379
    }
 
2380
 
 
2381
    prototype = function + '(';
 
2382
    if (funcdesc->invkind == INVOKE_FUNC && type == hresult)
 
2383
        type = 0;
 
2384
 
 
2385
    int p;
 
2386
    for (p = 1; p < names.count(); ++p) {
 
2387
        // parameter
 
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;
 
2392
 
 
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);
 
2399
            }
 
2400
            type = ptype;
 
2401
        } else {
 
2402
            prototype += ptype;
 
2403
            if (pdesc.wParamFlags & PARAMFLAG_FOUT && !ptype.endsWith('&') && !ptype.endsWith("**"))
 
2404
                prototype += '&';
 
2405
            if (optional || pdesc.wParamFlags & PARAMFLAG_FOPT)
 
2406
                paramName += "=0";
 
2407
            else if (pdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) {
 
2408
                // ### get the value from pdesc.pparamdescex
 
2409
                paramName += "=0";
 
2410
            }
 
2411
            parameters << paramName;
 
2412
        }
 
2413
        if (p < funcdesc->cParams && !(pdesc.wParamFlags & PARAMFLAG_FRETVAL))
 
2414
            prototype += ',';
 
2415
    }
 
2416
 
 
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);
 
2422
                prototype += ptype;
 
2423
                prototype += ')';
 
2424
                parameters << "rhs";
 
2425
            } else {
 
2426
                prototype[prototype.length()-1] = ')';
 
2427
            }
 
2428
        } else {
 
2429
            prototype += ')';
 
2430
        }
 
2431
    }
 
2432
 
 
2433
    return prototype;
 
2434
}
 
2435
 
 
2436
void MetaObjectGenerator::readFuncsInfo(ITypeInfo *typeinfo, ushort nFuncs)
 
2437
{
 
2438
    if (!nFuncs) {
 
2439
        TYPEATTR *typeattr = 0;
 
2440
        typeinfo->GetTypeAttr(&typeattr);
 
2441
        if (typeattr) {
 
2442
            nFuncs = typeattr->cFuncs;
 
2443
            typeinfo->ReleaseTypeAttr(typeattr);
 
2444
        }
 
2445
    }
 
2446
 
 
2447
    // get information about all functions
 
2448
    for (ushort fd = 0; fd < nFuncs ; ++fd) {
 
2449
        FUNCDESC *funcdesc = 0;
 
2450
        typeinfo->GetFuncDesc(fd, &funcdesc);
 
2451
        if (!funcdesc)
 
2452
            break;
 
2453
 
 
2454
        QByteArray function;
 
2455
        QByteArray type;
 
2456
        QByteArray prototype;
 
2457
        QList<QByteArray> parameters;
 
2458
 
 
2459
        // parse function description
 
2460
        BSTR bstrNames[256];
 
2461
        UINT maxNames = 255;
 
2462
        UINT maxNamesOut;
 
2463
        typeinfo->GetNames(funcdesc->memid, (BSTR*)&bstrNames, maxNames, &maxNamesOut);
 
2464
        QList<QByteArray> names;
 
2465
        int p;
 
2466
        for (p = 0; p < (int)maxNamesOut; ++p) {
 
2467
            names << QString::fromWCharArray(bstrNames[p]).toLatin1();
 
2468
            SysFreeString(bstrNames[p]);
 
2469
        }
 
2470
 
 
2471
        // function name
 
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);
 
2481
            continue;
 
2482
        }
 
2483
 
 
2484
        prototype = createPrototype(/*in*/ funcdesc, typeinfo, names, /*out*/type, parameters);
 
2485
 
 
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) {
 
2494
                    dontBreak = true;
 
2495
                } else {
 
2496
                    uint flags = Readable;
 
2497
                    if (funcdesc->invkind != INVOKE_PROPERTYGET)
 
2498
                        flags |= Writable;
 
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;
 
2505
                    if (hasEnum(type))
 
2506
                        flags |= EnumOrFlag;
 
2507
 
 
2508
                    if (funcdesc->wFuncFlags & FUNCFLAG_FBINDABLE && funcdesc->invkind == INVOKE_PROPERTYGET) {
 
2509
                        addChangedSignal(function, type, funcdesc->memid);
 
2510
                        flags |= Bindable;
 
2511
                    }
 
2512
                    // Don't generate code for properties without type
 
2513
                    if (type.isEmpty())
 
2514
                        break;
 
2515
                    addProperty(type, function, flags);
 
2516
 
 
2517
                    // more parameters -> function handling
 
2518
                    if (funcdesc->invkind == INVOKE_PROPERTYGET && funcdesc->cParams)
 
2519
                        dontBreak = true;
 
2520
                }
 
2521
 
 
2522
                if (!funcdesc->cParams) {
 
2523
                    // don't generate slots for incomplete properties
 
2524
                    if (type.isEmpty())
 
2525
                        break;
 
2526
 
 
2527
                    // Done for getters
 
2528
                    if (funcdesc->invkind == INVOKE_PROPERTYGET)
 
2529
                        break;
 
2530
 
 
2531
                    // generate setter slot
 
2532
                    if (funcdesc->invkind == INVOKE_PROPERTYPUT && hasProperty(function)) {
 
2533
                        addSetterSlot(function);
 
2534
                        break;
 
2535
                    }
 
2536
                } else if (funcdesc->invkind == INVOKE_PROPERTYPUT && hasProperty(function)) {
 
2537
                    addSetterSlot(function);
 
2538
                    // more parameters -> function handling
 
2539
                    if (funcdesc->cParams > 1)
 
2540
                        dontBreak = true;
 
2541
                }
 
2542
                if (!dontBreak)
 
2543
                    break;
 
2544
            }
 
2545
            if (funcdesc->invkind == INVOKE_PROPERTYPUT) {
 
2546
                QByteArray set;
 
2547
                if (isupper(prototype.at(0))) {
 
2548
                    set = "Set";
 
2549
                } else {
 
2550
                    set = "set";
 
2551
                    prototype[0] = toupper(prototype[0]);
 
2552
                }
 
2553
 
 
2554
                prototype = set + prototype;
 
2555
            }
 
2556
            // FALL THROUGH to support multi-variat properties
 
2557
        case INVOKE_FUNC: // method
 
2558
            {
 
2559
                bool cloned = false;
 
2560
                bool defargs;
 
2561
                do {
 
2562
                    QByteArray pnames;
 
2563
                    for (p = 0; p < parameters.count(); ++p) {
 
2564
                        pnames += parameters.at(p);
 
2565
                        if (p < parameters.count() - 1)
 
2566
                            pnames += ',';
 
2567
                    }
 
2568
                    defargs = pnames.contains("=0");
 
2569
                    int flags = QMetaMethod::Public;
 
2570
                    if (cloned)
 
2571
                        flags |= QMetaMethod::Cloned << 4;
 
2572
                    cloned |= defargs;
 
2573
                    addSlot(type, prototype, pnames.replace("=0", ""), flags);
 
2574
 
 
2575
                    if (defargs) {
 
2576
                        parameters.takeLast();
 
2577
                        int lastParam = prototype.lastIndexOf(',');
 
2578
                        if (lastParam == -1)
 
2579
                            lastParam = prototype.indexOf('(') + 1;
 
2580
                        prototype.truncate(lastParam);
 
2581
                        prototype += ')';
 
2582
                    }
 
2583
                } while (defargs);
 
2584
            }
 
2585
            break;
 
2586
 
 
2587
        default:
 
2588
            break;
 
2589
        }
 
2590
#if 0 // documentation in metaobject would be cool?
 
2591
        // get function documentation
 
2592
        BSTR bstrDocu;
 
2593
        info->GetDocumentation(funcdesc->memid, 0, &bstrDocu, 0, 0);
 
2594
        QString strDocu = QString::fromWCharArray(bstrDocu);
 
2595
        SysFreeString(bstrDocu);
 
2596
        if (!!strDocu)
 
2597
            desc += '[' + strDocu + ']';
 
2598
        desc += '\n';
 
2599
#endif
 
2600
        typeinfo->ReleaseFuncDesc(funcdesc);
 
2601
    }
 
2602
}
 
2603
 
 
2604
void MetaObjectGenerator::readVarsInfo(ITypeInfo *typeinfo, ushort nVars)
 
2605
{
 
2606
    if (!nVars) {
 
2607
        TYPEATTR *typeattr = 0;
 
2608
        typeinfo->GetTypeAttr(&typeattr);
 
2609
        if (typeattr) {
 
2610
            nVars = typeattr->cVars;
 
2611
            typeinfo->ReleaseTypeAttr(typeattr);
 
2612
        }
 
2613
    }
 
2614
 
 
2615
    // get information about all variables
 
2616
    for (ushort vd = 0; vd < nVars; ++vd) {
 
2617
        VARDESC *vardesc;
 
2618
        typeinfo->GetVarDesc(vd, &vardesc);
 
2619
        if (!vardesc)
 
2620
            break;
 
2621
 
 
2622
        // no use if it's not a dispatched variable
 
2623
        if (vardesc->varkind != VAR_DISPATCH) {
 
2624
            typeinfo->ReleaseVarDesc(vardesc);
 
2625
            continue;
 
2626
        }
 
2627
 
 
2628
        // get variable name
 
2629
        BSTR bstrName;
 
2630
        UINT maxNames = 1;
 
2631
        UINT maxNamesOut;
 
2632
        typeinfo->GetNames(vardesc->memid, &bstrName, maxNames, &maxNamesOut);
 
2633
        if (maxNamesOut != 1 || !bstrName) {
 
2634
            typeinfo->ReleaseVarDesc(vardesc);
 
2635
            continue;
 
2636
        }
 
2637
        QByteArray variableType;
 
2638
        QByteArray variableName;
 
2639
        uint flags = 0;
 
2640
 
 
2641
        variableName = QString::fromWCharArray(bstrName).toLatin1();
 
2642
        SysFreeString(bstrName);
 
2643
 
 
2644
        // get variable type
 
2645
        TYPEDESC typedesc = vardesc->elemdescVar.tdesc;
 
2646
        variableType = guessTypes(typedesc, typeinfo, variableName);
 
2647
 
 
2648
        // generate meta property
 
2649
        if (!hasProperty(variableName)) {
 
2650
            flags = Readable;
 
2651
            if (!(vardesc->wVarFlags & VARFLAG_FREADONLY))
 
2652
                flags |= Writable;
 
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;
 
2661
 
 
2662
            if (vardesc->wVarFlags & VARFLAG_FBINDABLE) {
 
2663
                addChangedSignal(variableName, variableType, vardesc->memid);
 
2664
                flags |= Bindable;
 
2665
            }
 
2666
            addProperty(variableType, variableName, flags);
 
2667
        }
 
2668
 
 
2669
        // generate a set slot
 
2670
        if (!(vardesc->wVarFlags & VARFLAG_FREADONLY))
 
2671
            addSetterSlot(variableName);
 
2672
 
 
2673
#if 0 // documentation in metaobject would be cool?
 
2674
        // get function documentation
 
2675
        BSTR bstrDocu;
 
2676
        info->GetDocumentation(vardesc->memid, 0, &bstrDocu, 0, 0);
 
2677
        QString strDocu = QString::fromWCharArray(bstrDocu);
 
2678
        SysFreeString(bstrDocu);
 
2679
        if (!!strDocu)
 
2680
            desc += '[' + strDocu + ']';
 
2681
        desc += '\n';
 
2682
#endif
 
2683
        typeinfo->ReleaseVarDesc(vardesc);
 
2684
    }
 
2685
}
 
2686
 
 
2687
void MetaObjectGenerator::readInterfaceInfo()
 
2688
{
 
2689
    ITypeInfo *typeinfo = dispInfo;
 
2690
    if (!typeinfo)
 
2691
        return;
 
2692
    typeinfo->AddRef();
 
2693
    int interface_serial = 0;
 
2694
    while (typeinfo) {
 
2695
        ushort nFuncs = 0;
 
2696
        ushort nVars = 0;
 
2697
        ushort nImpl = 0;
 
2698
        // get information about type
 
2699
        TYPEATTR *typeattr;
 
2700
        typeinfo->GetTypeAttr(&typeattr);
 
2701
        bool interesting = true;
 
2702
        if (typeattr) {
 
2703
            // get number of functions, variables, and implemented interfaces
 
2704
            nFuncs = typeattr->cFuncs;
 
2705
            nVars = typeattr->cVars;
 
2706
            nImpl = typeattr->cImplTypes;
 
2707
 
 
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) {
 
2712
                    // UUID
 
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());
 
2717
                }
 
2718
#endif
 
2719
                typeinfo->ReleaseTypeAttr(typeattr);
 
2720
            } else {
 
2721
                interesting = false;
 
2722
                typeinfo->ReleaseTypeAttr(typeattr);
 
2723
            }
 
2724
        }
 
2725
 
 
2726
        if (interesting) {
 
2727
            readFuncsInfo(typeinfo, nFuncs);
 
2728
            readVarsInfo(typeinfo, nVars);
 
2729
        }
 
2730
 
 
2731
        if (!nImpl) {
 
2732
            typeinfo->Release();
 
2733
            typeinfo = 0;
 
2734
            break;
 
2735
        }
 
2736
 
 
2737
        // go up one base class
 
2738
        HREFTYPE pRefType;
 
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();
 
2745
            typeinfo = 0;
 
2746
            break;
 
2747
        }
 
2748
        typeinfo = baseInfo;
 
2749
    }
 
2750
}
 
2751
 
 
2752
void MetaObjectGenerator::readEventInterface(ITypeInfo *eventinfo, IConnectionPoint *cpoint)
 
2753
{
 
2754
    TYPEATTR *eventattr;
 
2755
    eventinfo->GetTypeAttr(&eventattr);
 
2756
    if (!eventattr)
 
2757
        return;
 
2758
    if (eventattr->typekind != TKIND_DISPATCH) {
 
2759
        eventinfo->ReleaseTypeAttr(eventattr);
 
2760
        return;
 
2761
    }
 
2762
 
 
2763
    QAxEventSink *eventSink = 0;
 
2764
    if (d) {
 
2765
        IID conniid;
 
2766
        cpoint->GetConnectionInterface(&conniid);
 
2767
        eventSink = d->eventSink.value(QUuid(conniid));
 
2768
        if (!eventSink) {
 
2769
            eventSink = new QAxEventSink(that);
 
2770
            d->eventSink.insert(QUuid(conniid), eventSink);
 
2771
            eventSink->advise(cpoint, conniid);
 
2772
        }
 
2773
    }
 
2774
 
 
2775
    // get information about all event functions
 
2776
    for (UINT fd = 0; fd < (UINT)eventattr->cFuncs; ++fd) {
 
2777
        FUNCDESC *funcdesc;
 
2778
        eventinfo->GetFuncDesc(fd, &funcdesc);
 
2779
        if (!funcdesc)
 
2780
            break;
 
2781
        if (funcdesc->invkind != INVOKE_FUNC ||
 
2782
            funcdesc->funckind != FUNC_DISPATCH) {
 
2783
            eventinfo->ReleaseTypeAttr(eventattr);
 
2784
            eventinfo->ReleaseFuncDesc(funcdesc);
 
2785
            continue;
 
2786
        }
 
2787
 
 
2788
        QByteArray function;
 
2789
        QByteArray prototype;
 
2790
        QList<QByteArray> parameters;
 
2791
 
 
2792
        // parse event function description
 
2793
        BSTR bstrNames[256];
 
2794
        UINT maxNames = 255;
 
2795
        UINT maxNamesOut;
 
2796
        eventinfo->GetNames(funcdesc->memid, (BSTR*)&bstrNames, maxNames, &maxNamesOut);
 
2797
        QList<QByteArray> names;
 
2798
        int p;
 
2799
        for (p = 0; p < (int)maxNamesOut; ++p) {
 
2800
            names << QString::fromWCharArray(bstrNames[p]).toLatin1();
 
2801
            SysFreeString(bstrNames[p]);
 
2802
        }
 
2803
 
 
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)) {
 
2809
            QByteArray pnames;
 
2810
            for (p = 0; p < parameters.count(); ++p) {
 
2811
                pnames += parameters.at(p);
 
2812
                if (p < parameters.count() - 1)
 
2813
                    pnames += ',';
 
2814
            }
 
2815
            addSignal(prototype, pnames);
 
2816
        }
 
2817
        if (eventSink)
 
2818
            eventSink->addSignal(funcdesc->memid, prototype);
 
2819
 
 
2820
#if 0 // documentation in metaobject would be cool?
 
2821
        // get function documentation
 
2822
        BSTR bstrDocu;
 
2823
        eventinfo->GetDocumentation(funcdesc->memid, 0, &bstrDocu, 0, 0);
 
2824
        QString strDocu = QString::fromWCharArray(bstrDocu);
 
2825
        SysFreeString(bstrDocu);
 
2826
        if (!!strDocu)
 
2827
            desc += '[' + strDocu + ']';
 
2828
        desc += '\n';
 
2829
#endif
 
2830
        eventinfo->ReleaseFuncDesc(funcdesc);
 
2831
    }
 
2832
    eventinfo->ReleaseTypeAttr(eventattr);
 
2833
}
 
2834
 
 
2835
void MetaObjectGenerator::readEventInfo()
 
2836
{
 
2837
    int event_serial = 0;
 
2838
    IConnectionPointContainer *cpoints = 0;
 
2839
    if (d && d->useEventSink)
 
2840
        d->ptr->QueryInterface(IID_IConnectionPointContainer, (void**)&cpoints);
 
2841
    if (cpoints) {
 
2842
        // Get connection point enumerator
 
2843
        IEnumConnectionPoints *epoints = 0;
 
2844
        cpoints->EnumConnectionPoints(&epoints);
 
2845
        if (epoints) {
 
2846
            ULONG c = 1;
 
2847
            IConnectionPoint *cpoint = 0;
 
2848
            epoints->Reset();
 
2849
            QList<QUuid> cpointlist;
 
2850
            do {
 
2851
                if (cpoint) cpoint->Release();
 
2852
                cpoint = 0;
 
2853
                HRESULT hr = epoints->Next(c, &cpoint, &c);
 
2854
                if (!c || hr != S_OK)
 
2855
                    break;
 
2856
 
 
2857
                IID conniid;
 
2858
                cpoint->GetConnectionInterface(&conniid);
 
2859
                // workaround for typelibrary bug of Word.Application
 
2860
                QUuid connuuid(conniid);
 
2861
                if (cpointlist.contains(connuuid))
 
2862
                    break;
 
2863
 
 
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());
 
2869
                }
 
2870
#endif
 
2871
 
 
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);
 
2876
                    if (eventSink)
 
2877
                        eventSink->advise(cpoint, conniid);
 
2878
                    continue;
 
2879
                }
 
2880
 
 
2881
                ITypeInfo *eventinfo = 0;
 
2882
                if (typelib)
 
2883
                    typelib->GetTypeInfoOfGuid(conniid, &eventinfo);
 
2884
 
 
2885
                if (eventinfo) {
 
2886
                    // avoid recursion (see workaround above)
 
2887
                    cpointlist.append(connuuid);
 
2888
 
 
2889
                    readEventInterface(eventinfo, cpoint);
 
2890
                    eventinfo->Release();
 
2891
                }
 
2892
            } while (c);
 
2893
            if (cpoint) cpoint->Release();
 
2894
            epoints->Release();
 
2895
        } else if (classInfo) { // no enumeration - search source interfaces and ask for those
 
2896
            TYPEATTR *typeattr = 0;
 
2897
            classInfo->GetTypeAttr(&typeattr);
 
2898
            if (typeattr) {
 
2899
                for (int i = 0; i < typeattr->cImplTypes; ++i) {
 
2900
                    int flags = 0;
 
2901
                    classInfo->GetImplTypeFlags(i, &flags);
 
2902
                    if (!(flags & IMPLTYPEFLAG_FSOURCE))
 
2903
                        continue;
 
2904
                    HREFTYPE reference;
 
2905
                    if (S_OK != classInfo->GetRefTypeOfImplType(i, &reference))
 
2906
                        continue;
 
2907
                    ITypeInfo *eventInfo = 0;
 
2908
                    classInfo->GetRefTypeInfo(reference, &eventInfo);
 
2909
                    if (!eventInfo)
 
2910
                        continue;
 
2911
                    TYPEATTR *eventattr = 0;
 
2912
                    eventInfo->GetTypeAttr(&eventattr);
 
2913
                    if (eventattr) {
 
2914
                        IConnectionPoint *cpoint = 0;
 
2915
                        cpoints->FindConnectionPoint(eventattr->guid, &cpoint);
 
2916
                        if (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);
 
2920
                                if (eventSink)
 
2921
                                    eventSink->advise(cpoint, eventattr->guid);
 
2922
                                continue;
 
2923
                            }
 
2924
 
 
2925
                            readEventInterface(eventInfo, cpoint);
 
2926
                            cpoint->Release();
 
2927
                        }
 
2928
                        eventInfo->ReleaseTypeAttr(eventattr);
 
2929
                    }
 
2930
                    eventInfo->Release();
 
2931
                }
 
2932
                classInfo->ReleaseTypeAttr(typeattr);
 
2933
            }
 
2934
        }
 
2935
        cpoints->Release();
 
2936
    }
 
2937
}
 
2938
 
 
2939
QMetaObject *MetaObjectGenerator::tryCache()
 
2940
{
 
2941
    if (!cacheKey.isEmpty()) {
 
2942
        d->metaobj = mo_cache.value(cacheKey);
 
2943
        if (d->metaobj) {
 
2944
            d->cachedMetaObject = true;
 
2945
 
 
2946
            IConnectionPointContainer *cpoints = 0;
 
2947
            d->ptr->QueryInterface(IID_IConnectionPointContainer, (void**)&cpoints);
 
2948
            if (cpoints) {
 
2949
                QList<QUuid>::ConstIterator it = d->metaobj->connectionInterfaces.begin();
 
2950
                while (it != d->metaobj->connectionInterfaces.end()) {
 
2951
                    QUuid iid = *it;
 
2952
                    ++it;
 
2953
 
 
2954
                    IConnectionPoint *cpoint = 0;
 
2955
                    cpoints->FindConnectionPoint(iid, &cpoint);
 
2956
                    if (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);
 
2963
                        cpoint->Release();
 
2964
                    }
 
2965
                }
 
2966
                cpoints->Release();
 
2967
            }
 
2968
 
 
2969
            return d->metaobj;
 
2970
        }
 
2971
    }
 
2972
    return 0;
 
2973
}
 
2974
 
 
2975
QMetaObject *MetaObjectGenerator::metaObject(const QMetaObject *parentObject, const QByteArray &className)
 
2976
{
 
2977
    if (that) {
 
2978
        readClassInfo();
 
2979
        if (typelib) {
 
2980
            BSTR bstr;
 
2981
            typelib->GetDocumentation(-1, &bstr, 0, 0, 0);
 
2982
            current_typelib = QString::fromWCharArray(bstr).toLatin1();
 
2983
            SysFreeString(bstr);
 
2984
        }
 
2985
        if (d->tryCache && tryCache())
 
2986
            return d->metaobj;
 
2987
        readEnumInfo();
 
2988
        readInterfaceInfo();
 
2989
        readEventInfo();
 
2990
    }
 
2991
 
 
2992
    current_typelib = QByteArray();
 
2993
 
 
2994
#ifndef QAX_NO_CLASSINFO
 
2995
    if (!debugInfo.isEmpty() && d->useClassInfo)
 
2996
        addClassInfo("debugInfo", debugInfo);
 
2997
#endif
 
2998
 
 
2999
    QAxMetaObject *metaobj = new QAxMetaObject;
 
3000
 
 
3001
    // revision + classname + table + zero terminator
 
3002
    uint int_data_size = 1+1+2+2+2+2+1;
 
3003
 
 
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;
 
3012
    }
 
3013
 
 
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;
 
3026
 
 
3027
    char null('\0');
 
3028
    // data + zero-terminator
 
3029
    QByteArray stringdata = that ? QByteArray(that->className()) : className;
 
3030
    stringdata += null;
 
3031
    stringdata.reserve(8192);
 
3032
 
 
3033
    uint offset = int_data[3]; //idx_classinfo
 
3034
 
 
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();
 
3040
        stringdata += key;
 
3041
        stringdata += null;
 
3042
        int_data[offset++] = stringdata.length();
 
3043
        stringdata += value;
 
3044
        stringdata += null;
 
3045
    }
 
3046
    Q_ASSERT(offset == int_data[5]);
 
3047
 
 
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);
 
3055
        QByteArray tag;
 
3056
        int flags = it.value().flags;
 
3057
 
 
3058
        int_data[offset++] = stringdata.length();
 
3059
        stringdata += prototype;
 
3060
        stringdata += null;
 
3061
        int_data[offset++] = stringdata.length();
 
3062
        stringdata += parameters;
 
3063
        stringdata += null;
 
3064
        int_data[offset++] = stringdata.length();
 
3065
        stringdata += type;
 
3066
        stringdata += null;
 
3067
        int_data[offset++] = stringdata.length();
 
3068
        stringdata += tag;
 
3069
        stringdata += null;
 
3070
        int_data[offset++] = flags;
 
3071
    }
 
3072
 
 
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);
 
3080
        QByteArray tag;
 
3081
        int flags = it.value().flags;
 
3082
 
 
3083
        int_data[offset++] = stringdata.length();
 
3084
        stringdata += prototype;
 
3085
        stringdata += null;
 
3086
        int_data[offset++] = stringdata.length();
 
3087
        stringdata += parameters;
 
3088
        stringdata += null;
 
3089
        int_data[offset++] = stringdata.length();
 
3090
        stringdata += type;
 
3091
        stringdata += null;
 
3092
        int_data[offset++] = stringdata.length();
 
3093
        stringdata += tag;
 
3094
        stringdata += null;
 
3095
        int_data[offset++] = flags;
 
3096
    }
 
3097
    Q_ASSERT(offset == int_data[7]);
 
3098
 
 
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;
 
3107
 
 
3108
        int_data[offset++] = stringdata.length();
 
3109
        stringdata += name;
 
3110
        stringdata += null;
 
3111
        int_data[offset++] = stringdata.length();
 
3112
        stringdata += type;
 
3113
        stringdata += null;
 
3114
        int_data[offset++] = flags;
 
3115
    }
 
3116
    Q_ASSERT(offset == int_data[9]);
 
3117
 
 
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();
 
3124
 
 
3125
        int_data[offset++] = stringdata.length();
 
3126
        stringdata += name;
 
3127
        stringdata += null;
 
3128
        int_data[offset++] = flags;
 
3129
        int_data[offset++] = count;
 
3130
        int_data[offset++] = value_offset;
 
3131
        value_offset += count * 2;
 
3132
    }
 
3133
    Q_ASSERT(offset == int_data[9] + enum_list.count() * 4);
 
3134
 
 
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();
 
3141
            stringdata += key;
 
3142
            stringdata += null;
 
3143
            int_data[offset++] = value;
 
3144
        }
 
3145
    }
 
3146
    Q_ASSERT(offset == int_data_size-1);
 
3147
 
 
3148
    char *string_data = new char[stringdata.length()];
 
3149
    memset(string_data, 0, sizeof(string_data));
 
3150
    memcpy(string_data, stringdata, stringdata.length());
 
3151
 
 
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;
 
3157
 
 
3158
    if (d)
 
3159
        d->metaobj = metaobj;
 
3160
 
 
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();
 
3166
            if (sink) {
 
3167
                QUuid ciid = sink->connectionInterface();
 
3168
 
 
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());
 
3173
            }
 
3174
        }
 
3175
    }
 
3176
 
 
3177
    return metaobj;
 
3178
}
 
3179
 
 
3180
static const uint qt_meta_data_QAxBase[] = {
 
3181
 
 
3182
 // content:
 
3183
       1,       // revision
 
3184
       0,       // classname
 
3185
       0,    0, // classinfo
 
3186
       3,   10, // methods
 
3187
       1,   25, // properties
 
3188
       0,    0, // enums/sets
 
3189
 
 
3190
 // signals: signature, parameters, type, tag, flags
 
3191
      24,    9,    8,    8, 0x05,
 
3192
      55,   50,    8,    8, 0x05,
 
3193
     102,   80,    8,    8, 0x05,
 
3194
 
 
3195
 // properties: name, type, flags
 
3196
     149,  141, 0x0a095103,
 
3197
 
 
3198
       0        // eod
 
3199
};
 
3200
 
 
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"
 
3205
};
 
3206
 
 
3207
static QMetaObject qaxobject_staticMetaObject = {
 
3208
    { &QObject::staticMetaObject, qt_meta_stringdata_QAxBase,
 
3209
        qt_meta_data_QAxBase, 0 }
 
3210
};
 
3211
static QMetaObject qaxwidget_staticMetaObject = {
 
3212
    { &QWidget::staticMetaObject, qt_meta_stringdata_QAxBase,
 
3213
        qt_meta_data_QAxBase, 0 }
 
3214
};
 
3215
 
 
3216
/*!
 
3217
    \internal
 
3218
 
 
3219
    The metaobject is generated on the fly from the information
 
3220
    provided by the IDispatch and ITypeInfo interface implementations
 
3221
    in the COM object.
 
3222
*/
 
3223
const QMetaObject *QAxBase::metaObject() const
 
3224
{
 
3225
    if (d->metaobj)
 
3226
        return d->metaobj;
 
3227
    const QMetaObject* parentObject = parentMetaObject();
 
3228
 
 
3229
    if (!d->ptr && !d->initialized) {
 
3230
        ((QAxBase*)this)->initialize(&d->ptr);
 
3231
        d->initialized = true;
 
3232
    }
 
3233
 
 
3234
#ifndef QT_NO_THREAD
 
3235
    // only one thread at a time can generate meta objects
 
3236
    QMutexLocker locker(&cache_mutex);
 
3237
#endif
 
3238
 
 
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;
 
3244
    }
 
3245
    MetaObjectGenerator generator((QAxBase*)this, d);
 
3246
    return generator.metaObject(parentObject);
 
3247
}
 
3248
 
 
3249
/*!
 
3250
    \internal
 
3251
 
 
3252
    Connects to all event interfaces of the object.
 
3253
 
 
3254
    Called by the subclasses' connectNotify() reimplementations, so
 
3255
    at this point the connection as actually been created already.
 
3256
*/
 
3257
void QAxBase::connectNotify()
 
3258
{
 
3259
    if (d->eventSink.count()) // already listening
 
3260
        return;
 
3261
 
 
3262
    IEnumConnectionPoints *epoints = 0;
 
3263
    if (d->ptr && d->useEventSink) {
 
3264
        IConnectionPointContainer *cpoints = 0;
 
3265
        d->ptr->QueryInterface(IID_IConnectionPointContainer, (void**)&cpoints);
 
3266
        if (!cpoints)
 
3267
            return;
 
3268
 
 
3269
        cpoints->EnumConnectionPoints(&epoints);
 
3270
        cpoints->Release();
 
3271
    }
 
3272
 
 
3273
    if (!epoints)
 
3274
        return;
 
3275
 
 
3276
    UINT index;
 
3277
    IDispatch *disp = d->dispatch();
 
3278
    ITypeInfo *typeinfo = 0;
 
3279
    ITypeLib  *typelib = 0;
 
3280
    if (disp)
 
3281
        disp->GetTypeInfo(0, LOCALE_USER_DEFAULT, &typeinfo);
 
3282
    if (typeinfo)
 
3283
        typeinfo->GetContainingTypeLib(&typelib, &index);
 
3284
 
 
3285
    if (!typelib) {
 
3286
        epoints->Release();
 
3287
        return;
 
3288
    }
 
3289
 
 
3290
    MetaObjectGenerator generator(this, d);
 
3291
    bool haveEnumInfo = false;
 
3292
 
 
3293
    ULONG c = 1;
 
3294
    IConnectionPoint *cpoint = 0;
 
3295
    epoints->Reset();
 
3296
    do {
 
3297
        if (cpoint) cpoint->Release();
 
3298
        cpoint = 0;
 
3299
        epoints->Next(c, &cpoint, &c);
 
3300
        if (!c || !cpoint)
 
3301
            break;
 
3302
 
 
3303
        IID conniid;
 
3304
        cpoint->GetConnectionInterface(&conniid);
 
3305
        // workaround for typelibrary bug of Word.Application
 
3306
        QString connuuid(QUuid(conniid).toString());
 
3307
        if (d->eventSink.contains(connuuid))
 
3308
            break;
 
3309
 
 
3310
        // Get ITypeInfo for source-interface, and skip if not supporting IDispatch
 
3311
        ITypeInfo *eventinfo = 0;
 
3312
        typelib->GetTypeInfoOfGuid(conniid, &eventinfo);
 
3313
        if (eventinfo) {
 
3314
            TYPEATTR *eventAttr;
 
3315
            eventinfo->GetTypeAttr(&eventAttr);
 
3316
            if (!eventAttr) {
 
3317
                eventinfo->Release();
 
3318
                break;
 
3319
            }
 
3320
 
 
3321
            TYPEKIND eventKind = eventAttr->typekind;
 
3322
            eventinfo->ReleaseTypeAttr(eventAttr);
 
3323
            if (eventKind != TKIND_DISPATCH) {
 
3324
                eventinfo->Release();
 
3325
                break;
 
3326
            }
 
3327
        }
 
3328
 
 
3329
        // always into the cache to avoid recoursion
 
3330
        QAxEventSink *eventSink = eventinfo ? new QAxEventSink(this) : 0;
 
3331
        d->eventSink.insert(connuuid, eventSink);
 
3332
 
 
3333
        if (!eventinfo)
 
3334
            continue;
 
3335
 
 
3336
        // have to get type info to support signals with enum parameters
 
3337
        if (!haveEnumInfo) {
 
3338
            bool wasTryCache = d->tryCache;
 
3339
            d->tryCache = true;
 
3340
            generator.readClassInfo();
 
3341
            generator.readEnumInfo();
 
3342
            d->tryCache = wasTryCache;
 
3343
            haveEnumInfo = true;
 
3344
        }
 
3345
        generator.readEventInterface(eventinfo, cpoint);
 
3346
        eventSink->advise(cpoint, conniid);
 
3347
 
 
3348
        eventinfo->Release();
 
3349
    } while (c);
 
3350
    if (cpoint) cpoint->Release();
 
3351
    epoints->Release();
 
3352
 
 
3353
    typelib->Release();
 
3354
 
 
3355
    // make sure we don't try again
 
3356
    if (!d->eventSink.count())
 
3357
        d->eventSink.insert(QString(), 0);
 
3358
}
 
3359
 
 
3360
/*!
 
3361
    \fn QString QAxBase::generateDocumentation()
 
3362
 
 
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.
 
3366
*/
 
3367
 
 
3368
static bool checkHRESULT(HRESULT hres, EXCEPINFO *exc, QAxBase *that, const QString &name, uint argerr)
 
3369
{
 
3370
    switch(hres) {
 
3371
    case S_OK:
 
3372
        return true;
 
3373
    case DISP_E_BADPARAMCOUNT:
 
3374
        qWarning("QAxBase: Error calling IDispatch member %s: Bad parameter count", name.toLatin1().data());
 
3375
        return false;
 
3376
    case DISP_E_BADVARTYPE:
 
3377
        qWarning("QAxBase: Error calling IDispatch member %s: Bad variant type", name.toLatin1().data());
 
3378
        return false;
 
3379
    case DISP_E_EXCEPTION:
 
3380
        {
 
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);
 
3389
 
 
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;
 
3395
 
 
3396
                if (helpContext && !help.isEmpty())
 
3397
                    help += QString::fromLatin1(" [%1]").arg(helpContext);
 
3398
 
 
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;
 
3403
                }
 
3404
            }
 
3405
            if (printWarning) {
 
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");
 
3412
            }
 
3413
        }       
 
3414
        return false;
 
3415
    case DISP_E_MEMBERNOTFOUND:
 
3416
        qWarning("QAxBase: Error calling IDispatch member %s: Member not found", name.toLatin1().data());
 
3417
        return false;
 
3418
    case DISP_E_NONAMEDARGS:
 
3419
        qWarning("QAxBase: Error calling IDispatch member %s: No named arguments", name.toLatin1().data());
 
3420
        return false;
 
3421
    case DISP_E_OVERFLOW:
 
3422
        qWarning("QAxBase: Error calling IDispatch member %s: Overflow", name.toLatin1().data());
 
3423
        return false;
 
3424
    case DISP_E_PARAMNOTFOUND:
 
3425
        qWarning("QAxBase: Error calling IDispatch member %s: Parameter %d not found", name.toLatin1().data(), argerr);
 
3426
        return false;
 
3427
    case DISP_E_TYPEMISMATCH:
 
3428
        qWarning("QAxBase: Error calling IDispatch member %s: Type mismatch in parameter %d", name.toLatin1().data(), argerr);
 
3429
        return false;
 
3430
    case DISP_E_UNKNOWNINTERFACE:
 
3431
        qWarning("QAxBase: Error calling IDispatch member %s: Unknown interface", name.toLatin1().data());
 
3432
        return false;
 
3433
    case DISP_E_UNKNOWNLCID:
 
3434
        qWarning("QAxBase: Error calling IDispatch member %s: Unknown locale ID", name.toLatin1().data());
 
3435
        return false;
 
3436
    case DISP_E_PARAMNOTOPTIONAL:
 
3437
        qWarning("QAxBase: Error calling IDispatch member %s: Non-optional parameter missing", name.toLatin1().data());
 
3438
        return false;
 
3439
    default:
 
3440
        qWarning("QAxBase: Error calling IDispatch member %s: Unknown error", name.toLatin1().data());
 
3441
        return false;
 
3442
    }
 
3443
}
 
3444
 
 
3445
/*!
 
3446
    \internal
 
3447
*/
 
3448
int QAxBase::internalProperty(QMetaObject::Call call, int index, void **v)
 
3449
{
 
3450
    const QMetaObject *mo = metaObject();
 
3451
    const QMetaProperty prop = mo->property(index + mo->propertyOffset());
 
3452
    QByteArray propname = prop.name();
 
3453
 
 
3454
    // hardcoded control property
 
3455
    if (propname == "control") {
 
3456
        switch(call) {
 
3457
        case QMetaObject::ReadProperty:
 
3458
            *(QString*)*v = control();
 
3459
            break;
 
3460
        case QMetaObject::WriteProperty:
 
3461
            setControl(*(QString*)*v);
 
3462
            break;
 
3463
        case QMetaObject::ResetProperty:
 
3464
            clear();
 
3465
            break;
 
3466
        default:
 
3467
            break;
 
3468
        }
 
3469
        return index - mo->propertyCount();
 
3470
    }
 
3471
 
 
3472
    // get the IDispatch
 
3473
    if (!d->ptr || !prop.isValid())
 
3474
        return index;
 
3475
    IDispatch *disp = d->dispatch();
 
3476
    if (!disp)
 
3477
        return index;
 
3478
 
 
3479
    DISPID dispid = d->metaObject()->dispIDofName(propname, disp);
 
3480
    if (dispid == DISPID_UNKNOWN)
 
3481
        return index;
 
3482
 
 
3483
    Q_ASSERT(d->metaobj);
 
3484
    // property found, so everthing that goes wrong now should not bother the caller
 
3485
    index -= mo->propertyCount();
 
3486
 
 
3487
    VARIANTARG arg;
 
3488
    VariantInit(&arg);
 
3489
    DISPPARAMS params;
 
3490
    EXCEPINFO excepinfo;
 
3491
    memset(&excepinfo, 0, sizeof(excepinfo));
 
3492
    UINT argerr = 0;
 
3493
    HRESULT hres = E_FAIL;
 
3494
 
 
3495
    QByteArray proptype(prop.typeName());
 
3496
    switch (call) {
 
3497
    case QMetaObject::ReadProperty:
 
3498
        {
 
3499
            params.cArgs = 0;
 
3500
            params.cNamedArgs = 0;
 
3501
            params.rgdispidNamedArgs = 0;
 
3502
            params.rgvarg = 0;
 
3503
 
 
3504
            hres = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &params, &arg, &excepinfo, 0);
 
3505
 
 
3506
            // map result VARIANTARG to void*
 
3507
            uint type = QVariant::Int;
 
3508
            if (!prop.isEnumType())
 
3509
                type = prop.type();
 
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)
 
3512
                clearVARIANT(&arg);
 
3513
        }
 
3514
        break;
 
3515
 
 
3516
    case QMetaObject::WriteProperty:
 
3517
        {
 
3518
            QVariant::Type t = (QVariant::Type)prop.type();
 
3519
 
 
3520
            DISPID dispidNamed = DISPID_PROPERTYPUT;
 
3521
            params.cArgs = 1;
 
3522
            params.cNamedArgs = 1;
 
3523
            params.rgdispidNamedArgs = &dispidNamed;
 
3524
            params.rgvarg = &arg;
 
3525
 
 
3526
            arg.vt = VT_ERROR;
 
3527
            arg.scode = DISP_E_TYPEMISMATCH;
 
3528
 
 
3529
            // map void* to VARIANTARG via QVariant
 
3530
            QVariant qvar;
 
3531
            if (prop.isEnumType()) {
 
3532
                qvar = *(int*)v[0];
 
3533
                proptype = 0;
 
3534
            } else {
 
3535
                if (t == QVariant::LastType) {
 
3536
                    qvar = *(QVariant*)v[0];
 
3537
                    proptype = 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());
 
3541
                } else {
 
3542
                    proptype = d->metaObject()->propertyType(propname);
 
3543
                    qvar = QVariant(t, v[0]);
 
3544
                }
 
3545
            }
 
3546
 
 
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());
 
3550
                break;
 
3551
            }
 
3552
        }
 
3553
        hres = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, &params, 0, &excepinfo, &argerr);
 
3554
        clearVARIANT(&arg);
 
3555
        break;
 
3556
 
 
3557
    default:
 
3558
        break;
 
3559
    }
 
3560
 
 
3561
    checkHRESULT(hres, &excepinfo, this, QLatin1String(propname), argerr);
 
3562
    return index;
 
3563
}
 
3564
 
 
3565
int QAxBase::internalInvoke(QMetaObject::Call call, int index, void **v)
 
3566
{
 
3567
    Q_ASSERT(call == QMetaObject::InvokeMetaMethod);
 
3568
    Q_UNUSED(call);
 
3569
 
 
3570
    // get the IDispatch
 
3571
    IDispatch *disp = d->dispatch();
 
3572
    if (!disp)
 
3573
        return index;
 
3574
 
 
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);
 
3579
 
 
3580
    QByteArray signature(slot.signature());
 
3581
    QByteArray slotname(signature);
 
3582
    slotname.truncate(slotname.indexOf('('));
 
3583
 
 
3584
    // Get the Dispatch ID of the method to be called
 
3585
    bool isProperty = false;
 
3586
    DISPID dispid = d->metaObject()->dispIDofName(slotname, disp);
 
3587
 
 
3588
    Q_ASSERT(d->metaobj);
 
3589
 
 
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);
 
3594
        isProperty = true;
 
3595
    }
 
3596
    if (dispid == DISPID_UNKNOWN)
 
3597
        return index;
 
3598
 
 
3599
    // slot found, so everthing that goes wrong now should not bother the caller
 
3600
    index -= mo->methodCount();
 
3601
 
 
3602
    // setup the parameters
 
3603
    DISPPARAMS params;
 
3604
    DISPID dispidNamed = DISPID_PROPERTYPUT;
 
3605
    params.cArgs = d->metaobj->numParameter(signature);
 
3606
    params.cNamedArgs = isProperty ? 1 : 0;
 
3607
    params.rgdispidNamedArgs = isProperty ? &dispidNamed : 0;
 
3608
    params.rgvarg = 0;
 
3609
    VARIANTARG static_rgvarg[QAX_NUM_PARAMS];
 
3610
    if (params.cArgs) {
 
3611
        if (params.cArgs <= QAX_NUM_PARAMS)
 
3612
            params.rgvarg = static_rgvarg;
 
3613
        else
 
3614
            params.rgvarg = new VARIANTARG[params.cArgs];
 
3615
    }
 
3616
 
 
3617
    int p;
 
3618
    for (p = 0; p < (int)params.cArgs; ++p) {
 
3619
        bool out;
 
3620
        QByteArray type = d->metaobj->paramType(signature, p, &out);
 
3621
        QVariant::Type vt = QVariant::nameToType(type);
 
3622
        QVariant qvar;
 
3623
        if (vt != QVariant::UserType)
 
3624
            qvar = QVariant(vt, v[p + 1]);
 
3625
 
 
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];
 
3635
            else
 
3636
                qvar = QVariant(QMetaType::type(type), v[p + 1]);
 
3637
        }
 
3638
 
 
3639
        QVariantToVARIANT(qvar, params.rgvarg[params.cArgs - p - 1], type, out);
 
3640
    }
 
3641
 
 
3642
    // call the method
 
3643
    VARIANT ret;
 
3644
    VariantInit(&ret);
 
3645
    UINT argerr = 0;
 
3646
    HRESULT hres = E_FAIL;
 
3647
    EXCEPINFO excepinfo;
 
3648
    memset(&excepinfo, 0, sizeof(excepinfo));
 
3649
 
 
3650
    WORD wFlags = isProperty ? DISPATCH_PROPERTYPUT : DISPATCH_METHOD | DISPATCH_PROPERTYGET;
 
3651
    hres = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, wFlags, &params, &ret, &excepinfo, &argerr);
 
3652
 
 
3653
    // get return value
 
3654
    if (hres == S_OK && ret.vt != VT_EMPTY)
 
3655
        QVariantToVoidStar(VARIANTToQVariant(ret, slot.typeName()), v[0], slot.typeName());
 
3656
 
 
3657
    // update out parameters
 
3658
    for (p = 0; p < (int)params.cArgs; ++p) {
 
3659
        bool out;
 
3660
        QByteArray ptype = d->metaobj->paramType(signature, p, &out);
 
3661
        if (out)
 
3662
            QVariantToVoidStar(VARIANTToQVariant(params.rgvarg[params.cArgs - p - 1], ptype), v[p+1], ptype);
 
3663
    }
 
3664
    // clean up
 
3665
    for (p = 0; p < (int)params.cArgs; ++p)
 
3666
        clearVARIANT(params.rgvarg+p);
 
3667
    if (params.rgvarg != static_rgvarg)
 
3668
        delete [] params.rgvarg;
 
3669
 
 
3670
    checkHRESULT(hres, &excepinfo, this, QString::fromLatin1(slotname), params.cArgs-argerr-1);
 
3671
    return index;
 
3672
}
 
3673
 
 
3674
/*!
 
3675
    \internal
 
3676
*/
 
3677
int QAxBase::qt_metacall(QMetaObject::Call call, int id, void **v)
 
3678
{
 
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");
 
3682
        return id;
 
3683
    }
 
3684
 
 
3685
    switch(call) {
 
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();
 
3691
            break;
 
3692
        case QMetaMethod::Method:
 
3693
        case QMetaMethod::Slot:
 
3694
            id = internalInvoke(call, id, v);
 
3695
            break;
 
3696
        default:
 
3697
            break;
 
3698
        }
 
3699
        break;
 
3700
    case QMetaObject::ReadProperty:
 
3701
    case QMetaObject::WriteProperty:
 
3702
    case QMetaObject::ResetProperty:
 
3703
        id = internalProperty(call, id, v);
 
3704
        break;
 
3705
    case QMetaObject::QueryPropertyScriptable:
 
3706
    case QMetaObject::QueryPropertyDesignable:
 
3707
    case QMetaObject::QueryPropertyStored:
 
3708
    case QMetaObject::QueryPropertyEditable:
 
3709
    case QMetaObject::QueryPropertyUser:
 
3710
        id -= mo->propertyCount();
 
3711
        break;
 
3712
    default:
 
3713
        break;
 
3714
    }
 
3715
    Q_ASSERT(id < 0);
 
3716
    return id;
 
3717
}
 
3718
 
 
3719
#ifdef QT_CHECK_STATE
 
3720
static void qax_noSuchFunction(int disptype, const QByteArray &name, const QByteArray &function, const QAxBase *that)
 
3721
{
 
3722
    const QMetaObject *metaObject = that->metaObject();
 
3723
    const char *coclass = metaObject->classInfo(metaObject->indexOfClassInfo("CoClass")).value();
 
3724
 
 
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)
 
3731
                continue;
 
3732
            QByteArray signature = slot.signature();
 
3733
            if (signature.toLower().startsWith(function.toLower()))
 
3734
                qWarning("\t\t%s", signature.data());
 
3735
        }
 
3736
    } else {
 
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());
 
3745
            }
 
3746
        }
 
3747
    }
 
3748
}
 
3749
#endif
 
3750
 
 
3751
/*!
 
3752
    \internal
 
3753
 
 
3754
    \a name is already normalized?
 
3755
*/
 
3756
bool QAxBase::dynamicCallHelper(const char *name, void *inout, QList<QVariant> &vars, QByteArray &type)
 
3757
{
 
3758
    if (isNull()) {
 
3759
        qWarning("QAxBase::dynamicCallHelper: Object is not initialized, or initialization failed");
 
3760
        return false;
 
3761
    }
 
3762
 
 
3763
    IDispatch *disp = d->dispatch();
 
3764
    if (!disp) {
 
3765
        qWarning("QAxBase::dynamicCallHelper: Object does not support automation");
 
3766
        return false;
 
3767
    }
 
3768
 
 
3769
    const QMetaObject *mo = metaObject();
 
3770
    d->metaObject();
 
3771
    Q_ASSERT(d->metaobj);
 
3772
 
 
3773
    int varc = vars.count();
 
3774
 
 
3775
    QByteArray normFunction = QMetaObject::normalizedSignature(name);
 
3776
    QByteArray function(normFunction);
 
3777
    VARIANT staticarg[QAX_NUM_PARAMS];
 
3778
    VARIANT *arg = 0;
 
3779
    VARIANTARG *res = (VARIANTARG*)inout;
 
3780
 
 
3781
    unsigned short disptype;
 
3782
 
 
3783
    int id = -1;
 
3784
    bool parse = false;
 
3785
 
 
3786
    if (function.contains('(')) {
 
3787
        disptype = DISPATCH_METHOD | DISPATCH_PROPERTYGET;
 
3788
        if (d->useMetaObject)
 
3789
            id = mo->indexOfSlot(function);
 
3790
        if (id >= 0) {
 
3791
            const QMetaMethod slot = mo->method(id);
 
3792
            Q_ASSERT(slot.methodType() == QMetaMethod::Slot);
 
3793
            function = slot.signature();
 
3794
            type = slot.typeName();
 
3795
        }
 
3796
        function.truncate(function.indexOf('('));
 
3797
        parse = !varc && normFunction.length() > function.length() + 2;
 
3798
        if (parse) {
 
3799
            QString args = QLatin1String(normFunction);
 
3800
            args = args.mid(function.length() + 1);
 
3801
            // parse argument string int list of arguments
 
3802
            QString curArg;
 
3803
            const QChar *c = args.unicode();
 
3804
            int index = 0;
 
3805
            bool inString = false;
 
3806
            bool inEscape = false;
 
3807
            while (index < (int)args.length()) {
 
3808
                QChar cc = *c;
 
3809
                ++c;
 
3810
                ++index;
 
3811
                switch(cc.toLatin1()) {
 
3812
                case 'n':
 
3813
                    if (inEscape)
 
3814
                        cc = QLatin1Char('\n');
 
3815
                    break;
 
3816
                case 'r':
 
3817
                    if (inEscape)
 
3818
                        cc = QLatin1Char('\r');
 
3819
                    break;
 
3820
                case 't':
 
3821
                    if (inEscape)
 
3822
                        cc = QLatin1Char('\t');
 
3823
                    break;
 
3824
                case '\\':
 
3825
                    if (!inEscape && inString) {
 
3826
                        inEscape = true;
 
3827
                        continue;
 
3828
                    }
 
3829
                    break;
 
3830
                case '"':
 
3831
                    if (!inEscape) {
 
3832
                        inString = !inString;
 
3833
                        curArg += cc;
 
3834
                        continue;
 
3835
                    }
 
3836
                    break;
 
3837
                case ' ':
 
3838
                    if (!inString && curArg.isEmpty())
 
3839
                        continue;
 
3840
                    break;
 
3841
                case ',':
 
3842
                case ')':
 
3843
                    if (inString)
 
3844
                        break;
 
3845
                    curArg = curArg.trimmed();
 
3846
                    if (curArg.at(0) == QLatin1Char('\"') && curArg.at(curArg.length()-1) == QLatin1Char('\"')) {
 
3847
                        vars << curArg.mid(1, curArg.length() - 2);
 
3848
                    } else {
 
3849
                        bool isNumber = false;
 
3850
                        bool isDouble = false;
 
3851
                        int number = curArg.toInt(&isNumber);
 
3852
                        double dbl = curArg.toDouble(&isDouble);
 
3853
                        if (isNumber) {
 
3854
                            vars << number;
 
3855
                        } else if (isDouble) {
 
3856
                            vars << dbl;
 
3857
                        } else {
 
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()) {
 
3863
                                    vars << value;
 
3864
                                    isEnum = true;
 
3865
                                    break;
 
3866
                                }
 
3867
                            }
 
3868
                            if (!isEnum)
 
3869
                                vars << curArg;
 
3870
                        }
 
3871
                    }
 
3872
                    curArg.clear();
 
3873
                    continue;
 
3874
                default:
 
3875
                    break;
 
3876
                }
 
3877
                inEscape = false;
 
3878
                curArg += cc;
 
3879
            }
 
3880
 
 
3881
            varc = vars.count();
 
3882
        }
 
3883
    } else {
 
3884
        if (d->useMetaObject)
 
3885
            id = mo->indexOfProperty(normFunction);
 
3886
 
 
3887
        if (id >= 0) {
 
3888
            const QMetaProperty prop =mo->property(id);
 
3889
            type = prop.typeName();
 
3890
        }
 
3891
        if (varc == 1) {
 
3892
            res = 0;
 
3893
            disptype = DISPATCH_PROPERTYPUT;
 
3894
        } else {
 
3895
            disptype = DISPATCH_PROPERTYGET;
 
3896
        }
 
3897
    }
 
3898
    if (varc) {
 
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));
 
3904
            bool out = false;
 
3905
            QByteArray paramType;
 
3906
            if (disptype == DISPATCH_PROPERTYPUT)
 
3907
                paramType = type;
 
3908
            else if (parse || disptype == DISPATCH_PROPERTYGET)
 
3909
                paramType = 0;
 
3910
            else
 
3911
                paramType = d->metaobj->paramType(normFunction, i, &out);
 
3912
 
 
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);
 
3918
                }
 
3919
            }
 
3920
 
 
3921
            if (arg[varc - i - 1].vt == VT_EMPTY)
 
3922
                QVariantToVARIANT(var, arg[varc - i - 1], paramType, out);
 
3923
        }
 
3924
    }
 
3925
 
 
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;
 
3931
    }
 
3932
 
 
3933
    if (dispid == DISPID_UNKNOWN) {
 
3934
#ifdef QT_CHECK_STATE
 
3935
        qax_noSuchFunction(disptype, normFunction, function, this);
 
3936
#endif
 
3937
        return false;
 
3938
    }
 
3939
 
 
3940
    DISPPARAMS params;
 
3941
    DISPID dispidNamed = DISPID_PROPERTYPUT;
 
3942
 
 
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));
 
3949
    UINT argerr = 0;
 
3950
 
 
3951
    HRESULT hres = disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, disptype, &params, res, &excepinfo, &argerr);
 
3952
 
 
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());
 
3957
    }
 
3958
 
 
3959
    // clean up
 
3960
    for (int i = 0; i < varc; ++i)
 
3961
        clearVARIANT(params.rgvarg+i);
 
3962
    if (arg && arg != staticarg)
 
3963
        delete[] arg;
 
3964
 
 
3965
    return checkHRESULT(hres, &excepinfo, this, QLatin1String(function), varc-argerr-1);
 
3966
}
 
3967
 
 
3968
 
 
3969
/*!
 
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.
 
3975
 
 
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.
 
3979
 
 
3980
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 15
 
3981
 
 
3982
    Alternatively a function can be called passing the parameters embedded
 
3983
    in the string, e.g. above function can also be invoked using
 
3984
 
 
3985
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 16
 
3986
 
 
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.
 
3990
 
 
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.
 
3994
 
 
3995
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 17
 
3996
 
 
3997
    Note that it is faster to get and set properties using
 
3998
    QObject::property() and QObject::setProperty().
 
3999
 
 
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.
 
4005
 
 
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.
 
4013
 
 
4014
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 18
 
4015
 
 
4016
    This is also more efficient.
 
4017
*/
 
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)
 
4027
{
 
4028
    QList<QVariant> vars;
 
4029
    QVariant var = var1;
 
4030
    int argc = 1;
 
4031
    while(var.isValid()) {
 
4032
        vars << var;
 
4033
        switch(++argc) {
 
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;
 
4042
        }
 
4043
    }
 
4044
 
 
4045
    return dynamicCall(function, vars);
 
4046
}
 
4047
 
 
4048
/*!
 
4049
    \overload
 
4050
 
 
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
 
4055
    QVariant object.
 
4056
 
 
4057
    The QVariant objects in \a vars are updated when the method has
 
4058
    out-parameters.
 
4059
*/
 
4060
QVariant QAxBase::dynamicCall(const char *function, QList<QVariant> &vars)
 
4061
{
 
4062
    VARIANTARG res;
 
4063
    VariantInit(&res);
 
4064
 
 
4065
    QByteArray rettype;
 
4066
    if (!dynamicCallHelper(function, &res, vars, rettype))
 
4067
        return QVariant();
 
4068
 
 
4069
    QVariant qvar = VARIANTToQVariant(res, rettype);
 
4070
    if ((res.vt != VT_DISPATCH && res.vt != VT_UNKNOWN) || qvar.type() == QVariant::Pixmap || qvar.type() == QVariant::Font)
 
4071
        clearVARIANT(&res);
 
4072
 
 
4073
    return qvar;
 
4074
}
 
4075
 
 
4076
/*!
 
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.
 
4081
 
 
4082
    If \a name is provided by a method the string must include the
 
4083
    full function prototype.
 
4084
 
 
4085
    If \a name is a property the string must be the name of the property,
 
4086
    and \a var1, ... \a var8 are ignored.
 
4087
 
 
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.
 
4092
 
 
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.
 
4096
 
 
4097
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 19
 
4098
*/
 
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)
 
4108
{
 
4109
    QList<QVariant> vars;
 
4110
    QVariant var = var1;
 
4111
    int argc = 1;
 
4112
    while(var.isValid()) {
 
4113
        vars << var;
 
4114
        switch(++argc) {
 
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;
 
4123
        }
 
4124
    }
 
4125
 
 
4126
    return querySubObject(name, vars);
 
4127
}
 
4128
 
 
4129
/*!
 
4130
    \overload
 
4131
 
 
4132
    The QVariant objects in \a vars are updated when the method has
 
4133
    out-parameters.
 
4134
*/
 
4135
QAxObject *QAxBase::querySubObject(const char *name, QList<QVariant> &vars)
 
4136
{
 
4137
    QAxObject *object = 0;
 
4138
    VARIANTARG res;
 
4139
    VariantInit(&res);
 
4140
 
 
4141
    QByteArray rettype;
 
4142
    if (!dynamicCallHelper(name, &res, vars, rettype))
 
4143
        return 0;
 
4144
 
 
4145
    switch (res.vt) {
 
4146
    case VT_DISPATCH:
 
4147
        if (res.pdispVal) {
 
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();
 
4155
            }
 
4156
            if (object)
 
4157
                ((QAxBase*)object)->d->tryCache = true;
 
4158
        }
 
4159
        break;
 
4160
    case VT_UNKNOWN:
 
4161
        if (res.punkVal) {
 
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();
 
4169
            }
 
4170
            if (object)
 
4171
                ((QAxBase*)object)->d->tryCache = true;
 
4172
        }
 
4173
        break;
 
4174
    case VT_EMPTY:
 
4175
#ifdef QT_CHECK_STATE
 
4176
        {
 
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");
 
4180
        }
 
4181
#endif
 
4182
        break;
 
4183
    default:
 
4184
#ifdef QT_CHECK_STATE
 
4185
        {
 
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");
 
4189
        }
 
4190
#endif
 
4191
        break;
 
4192
    }
 
4193
 
 
4194
    clearVARIANT(&res);
 
4195
    return object;
 
4196
}
 
4197
 
 
4198
class QtPropertyBag : public IPropertyBag
 
4199
{
 
4200
public:
 
4201
    QtPropertyBag() :ref(0) {}
 
4202
    virtual ~QtPropertyBag() {}
 
4203
 
 
4204
    HRESULT __stdcall QueryInterface(REFIID iid, LPVOID *iface)
 
4205
    {
 
4206
        *iface = 0;
 
4207
        if (iid == IID_IUnknown)
 
4208
            *iface = this;
 
4209
        else if (iid == IID_IPropertyBag)
 
4210
            *iface = this;
 
4211
        else
 
4212
            return E_NOINTERFACE;
 
4213
 
 
4214
        AddRef();
 
4215
        return S_OK;
 
4216
    }
 
4217
    unsigned long __stdcall AddRef() { return ++ref; }
 
4218
    unsigned long __stdcall Release()
 
4219
    {
 
4220
        if (!--ref) {
 
4221
            delete this;
 
4222
            return 0;
 
4223
        }
 
4224
        return ref;
 
4225
    }
 
4226
 
 
4227
    HRESULT __stdcall Read(LPCOLESTR name, VARIANT *var, IErrorLog *)
 
4228
    {
 
4229
        if (!var)
 
4230
            return E_POINTER;
 
4231
 
 
4232
        QString property = QString::fromWCharArray(name);
 
4233
        QVariant qvar = map.value(property);
 
4234
        QVariantToVARIANT(qvar, *var);
 
4235
        return S_OK;
 
4236
    }
 
4237
    HRESULT __stdcall Write(LPCOLESTR name, VARIANT *var)
 
4238
    {
 
4239
        if (!var)
 
4240
            return E_POINTER;
 
4241
        QString property = QString::fromWCharArray(name);
 
4242
        QVariant qvar = VARIANTToQVariant(*var, 0);
 
4243
        map[property] = qvar;
 
4244
 
 
4245
        return S_OK;
 
4246
    }
 
4247
 
 
4248
    QAxBase::PropertyBag map;
 
4249
 
 
4250
private:
 
4251
    unsigned long ref;
 
4252
};
 
4253
 
 
4254
/*!
 
4255
    Returns a name:value map of all the properties exposed by the COM
 
4256
    object.
 
4257
 
 
4258
    This is more efficient than getting multiple properties
 
4259
    individually if the COM object supports property bags.
 
4260
 
 
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
 
4264
    interface.
 
4265
*/
 
4266
QAxBase::PropertyBag QAxBase::propertyBag() const
 
4267
{
 
4268
    PropertyBag result;
 
4269
 
 
4270
    if (!d->ptr && !d->initialized) {
 
4271
        ((QAxBase*)this)->initialize(&d->ptr);
 
4272
        d->initialized = true;
 
4273
    }
 
4274
 
 
4275
    if (isNull())
 
4276
        return result;
 
4277
    IPersistPropertyBag *persist = 0;
 
4278
    d->ptr->QueryInterface(IID_IPersistPropertyBag, (void**)&persist);
 
4279
    if (persist) {
 
4280
        QtPropertyBag *pbag = new QtPropertyBag();
 
4281
        pbag->AddRef();
 
4282
        persist->Save(pbag, false, true);
 
4283
        result = pbag->map;
 
4284
        pbag->Release();
 
4285
        persist->Release();
 
4286
        return result;
 
4287
    } else {
 
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);
 
4293
        }
 
4294
    }
 
4295
    return result;
 
4296
}
 
4297
 
 
4298
/*!
 
4299
    Sets the properties of the COM object to the corresponding values
 
4300
    in \a bag.
 
4301
 
 
4302
    \warning
 
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.
 
4307
 
 
4308
    \sa propertyBag()
 
4309
*/
 
4310
void QAxBase::setPropertyBag(const PropertyBag &bag)
 
4311
{
 
4312
    if (!d->ptr && !d->initialized) {
 
4313
        initialize(&d->ptr);
 
4314
        d->initialized = true;
 
4315
    }
 
4316
 
 
4317
    if (isNull())
 
4318
        return;
 
4319
    IPersistPropertyBag *persist = 0;
 
4320
    d->ptr->QueryInterface(IID_IPersistPropertyBag, (void**)&persist);
 
4321
    if (persist) {
 
4322
        QtPropertyBag *pbag = new QtPropertyBag();
 
4323
        pbag->map = bag;
 
4324
        pbag->AddRef();
 
4325
        persist->Load(pbag, 0);
 
4326
        pbag->Release();
 
4327
        persist->Release();
 
4328
    } else {
 
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);
 
4334
        }
 
4335
    }
 
4336
}
 
4337
 
 
4338
/*!
 
4339
    Returns true if the property \a prop is writable; otherwise
 
4340
    returns false. By default, all properties are writable.
 
4341
 
 
4342
    \warning
 
4343
    Depending on the control implementation this setting might be
 
4344
    ignored for some properties.
 
4345
 
 
4346
    \sa setPropertyWritable(), propertyChanged()
 
4347
*/
 
4348
bool QAxBase::propertyWritable(const char *prop) const
 
4349
{
 
4350
    return d->propWritable.value(prop, true);
 
4351
}
 
4352
 
 
4353
/*!
 
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
 
4356
    writable.
 
4357
 
 
4358
    \warning
 
4359
    Depending on the control implementation this setting might be
 
4360
    ignored for some properties.
 
4361
 
 
4362
    \sa propertyWritable(), propertyChanged()
 
4363
*/
 
4364
void QAxBase::setPropertyWritable(const char *prop, bool ok)
 
4365
{
 
4366
    d->propWritable[prop] = ok;
 
4367
}
 
4368
 
 
4369
/*!
 
4370
    Returns true if there is no COM object loaded by this wrapper;
 
4371
    otherwise return false.
 
4372
 
 
4373
    \sa control
 
4374
*/
 
4375
bool QAxBase::isNull() const
 
4376
{
 
4377
    return !d->ptr;
 
4378
}
 
4379
 
 
4380
/*!
 
4381
    Returns a QVariant that wraps the COM object. The variant can
 
4382
    then be used as a parameter in e.g. dynamicCall().
 
4383
*/
 
4384
QVariant QAxBase::asVariant() const
 
4385
{
 
4386
    if (!d->ptr && !d->initialized) {
 
4387
        ((QAxBase*)this)->initialize(&d->ptr);
 
4388
        d->initialized = true;
 
4389
    }
 
4390
 
 
4391
    QVariant qvar;
 
4392
    QByteArray cn(className());
 
4393
    if (cn == "QAxObject" || cn == "QAxWidget" || cn == "QAxBase") {
 
4394
        if (d->dispatch())
 
4395
            qVariantSetValue(qvar, d->dispatch());
 
4396
        else if (d->ptr)
 
4397
            qVariantSetValue(qvar, d->ptr);
 
4398
    } else {
 
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 + '*');
 
4404
    }
 
4405
 
 
4406
    return qvar;
 
4407
}
 
4408
 
 
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)
 
4412
{
 
4413
    if (!iface)
 
4414
        return 0;
 
4415
 
 
4416
    QAxObject *object = (QAxObject*)QMetaType::construct(metaType, 0);
 
4417
    QAxBasePrivate *d = object->d;
 
4418
 
 
4419
    d->ptr = iface;
 
4420
    d->initialized = true;
 
4421
 
 
4422
    // no release, since no addref
 
4423
 
 
4424
    return object;
 
4425
}
 
4426
 
 
4427
/*!
 
4428
    \fn void QAxBase::signal(const QString &name, int argc, void *argv)
 
4429
 
 
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.
 
4436
 
 
4437
    \snippet doc/src/snippets/code/src_activeqt_container_qaxbase.cpp 20
 
4438
 
 
4439
    Use this signal if the event has parameters of unsupported data
 
4440
    types. Otherwise, connect directly to the signal \a name.
 
4441
*/
 
4442
 
 
4443
/*!
 
4444
    \fn void QAxBase::propertyChanged(const QString &name)
 
4445
 
 
4446
    If the COM object supports property notification, this signal gets
 
4447
    emitted when the property called \a name is changed.
 
4448
*/
 
4449
 
 
4450
/*!
 
4451
    \fn void QAxBase::exception(int code, const QString &source, const QString &desc, const QString &help)
 
4452
 
 
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]".
 
4457
*/
 
4458
 
 
4459
/*!
 
4460
    \fn QObject *QAxBase::qObject() const
 
4461
    \internal
 
4462
*/
 
4463
 
 
4464
/*!
 
4465
    \fn const char *QAxBase::className() const
 
4466
    \internal
 
4467
*/
 
4468
 
 
4469
QT_END_NAMESPACE
 
4470
#endif //QT_NO_WIN_ACTIVEQT