src/activeqt/container/qaxbase.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     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