tools/activeqt/dumpcpp/main.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
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 tools applications of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QAxObject>
       
    43 #include <QFile>
       
    44 #include <QMetaObject>
       
    45 #include <QMetaEnum>
       
    46 #include <QTextStream>
       
    47 #include <QSettings>
       
    48 #include <QStringList>
       
    49 #include <QUuid>
       
    50 #include <QWidget>
       
    51 #include <qt_windows.h>
       
    52 #include <ocidl.h>
       
    53 
       
    54 QT_BEGIN_NAMESPACE
       
    55 
       
    56 static ITypeInfo *currentTypeInfo = 0;
       
    57 
       
    58 enum ObjectCategory
       
    59 {
       
    60     DefaultObject    = 0x00,
       
    61     SubObject        = 0x001,
       
    62     ActiveX          = 0x002,
       
    63     NoMetaObject     = 0x004,
       
    64     NoImplementation = 0x008,
       
    65     NoDeclaration    = 0x010,
       
    66     NoInlines        = 0x020,
       
    67     OnlyInlines      = 0x040,
       
    68     DoNothing        = 0x080,
       
    69     Licensed         = 0x100,
       
    70     TypeLibID        = 0x101
       
    71 };
       
    72 
       
    73 // this comes from moc/qmetaobject.cpp
       
    74 enum ProperyFlags  {
       
    75     Invalid = 0x00000000,
       
    76     Readable = 0x00000001,
       
    77     Writable = 0x00000002,
       
    78     Resetable = 0x00000004,
       
    79     EnumOrFlag = 0x00000008,
       
    80     StdCppSet = 0x00000100,
       
    81     Override = 0x00000200,
       
    82     Designable = 0x00001000,
       
    83     ResolveDesignable = 0x00002000,
       
    84     Scriptable = 0x00004000,
       
    85     ResolveScriptable = 0x00008000,
       
    86     Stored = 0x00010000,
       
    87     ResolveStored = 0x00020000,
       
    88     Editable = 0x00040000,
       
    89     ResolveEditable = 0x00080000
       
    90 };
       
    91 
       
    92 enum MemberFlags {
       
    93     AccessPrivate = 0x00,
       
    94     AccessProtected = 0x01,
       
    95     AccessPublic = 0x02,
       
    96     MemberMethod = 0x00,
       
    97     MemberSignal = 0x04,
       
    98     MemberSlot = 0x08,
       
    99     MemberCompatibility = 0x10,
       
   100     MemberCloned = 0x20,
       
   101     MemberScriptable = 0x40,
       
   102 };
       
   103 
       
   104 extern QMetaObject *qax_readEnumInfo(ITypeLib *typeLib, const QMetaObject *parentObject);
       
   105 extern QMetaObject *qax_readClassInfo(ITypeLib *typeLib, ITypeInfo *typeInfo, const QMetaObject *parentObject);
       
   106 extern QMetaObject *qax_readInterfaceInfo(ITypeLib *typeLib, ITypeInfo *typeInfo, const QMetaObject *parentObject);
       
   107 extern QList<QByteArray> qax_qualified_usertypes;
       
   108 extern QString qax_docuFromName(ITypeInfo *typeInfo, const QString &name);
       
   109 extern bool qax_dispatchEqualsIDispatch;
       
   110 
       
   111 QByteArray nameSpace;
       
   112 QMap<QByteArray, QByteArray> namespaceForType;
       
   113 
       
   114 void writeEnums(QTextStream &out, const QMetaObject *mo)
       
   115 {
       
   116     // enums
       
   117     for (int ienum = mo->enumeratorOffset(); ienum < mo->enumeratorCount(); ++ienum) {
       
   118         QMetaEnum metaEnum = mo->enumerator(ienum);
       
   119         out << "    enum " << metaEnum.name() << " {" << endl;
       
   120         for (int k = 0; k < metaEnum.keyCount(); ++k) {
       
   121             QByteArray key(metaEnum.key(k));
       
   122             out << "        " << key.leftJustified(24) << "= " << metaEnum.value(k);
       
   123             if (k < metaEnum.keyCount() - 1)
       
   124                 out << ",";
       
   125             out << endl;
       
   126         }
       
   127         out << "    };" << endl;
       
   128         out << endl;
       
   129     }
       
   130 }
       
   131 
       
   132 void writeHeader(QTextStream &out, const QByteArray &nameSpace)
       
   133 {
       
   134     out << "#ifndef QAX_DUMPCPP_" << nameSpace.toUpper() << "_H" << endl;
       
   135     out << "#define QAX_DUMPCPP_" << nameSpace.toUpper() << "_H" << endl;
       
   136     out << endl;
       
   137     out << "// Define this symbol to __declspec(dllexport) or __declspec(dllimport)" << endl;
       
   138     out << "#ifndef " << nameSpace.toUpper() << "_EXPORT" << endl;
       
   139     out << "#define " << nameSpace.toUpper() << "_EXPORT" << endl;
       
   140     out << "#endif" << endl;
       
   141     out << endl;
       
   142     out << "#include <qaxobject.h>" << endl;
       
   143     out << "#include <qaxwidget.h>" << endl;
       
   144     out << "#include <qdatetime.h>" << endl;
       
   145     out << "#include <qpixmap.h>" << endl;
       
   146     out << endl;
       
   147     out << "struct IDispatch;" << endl;
       
   148     out << endl;
       
   149 }
       
   150 
       
   151 void generateNameSpace(QTextStream &out, const QMetaObject *mo, const QByteArray &nameSpace)
       
   152 {
       
   153     out << "namespace " << nameSpace << " {" << endl;
       
   154     out << endl;
       
   155     writeEnums(out, mo);
       
   156 
       
   157     // don't close on purpose
       
   158 }
       
   159 
       
   160 static QByteArray joinParameterNames(const QList<QByteArray> &parameterNames)
       
   161 {
       
   162     QByteArray slotParameters;
       
   163     for (int p = 0; p < parameterNames.count(); ++p) {
       
   164         slotParameters += parameterNames.at(p);
       
   165         if (p < parameterNames.count() - 1)
       
   166             slotParameters += ',';
       
   167     }
       
   168 
       
   169     return slotParameters;
       
   170 }
       
   171 
       
   172 QByteArray constRefify(const QByteArray &type)
       
   173 {
       
   174     QByteArray ctype(type);
       
   175     if (type == "QString" || type == "QPixmap" 
       
   176         || type == "QVariant" || type == "QDateTime"
       
   177         || type == "QColor" || type == "QFont"
       
   178         || type == "QByteArray" || type == "QValueList<QVariant>"
       
   179         || type == "QStringList")
       
   180         ctype = "const " + ctype + "&";
       
   181 
       
   182     return ctype;
       
   183 }
       
   184 
       
   185 void generateClassDecl(QTextStream &out, const QString &controlID, const QMetaObject *mo, const QByteArray &className, const QByteArray &nameSpace, ObjectCategory category)
       
   186 {
       
   187     QList<QByteArray> functions;
       
   188 
       
   189     QByteArray indent;
       
   190     if (!(category & OnlyInlines))
       
   191         indent = "    ";
       
   192 
       
   193     if (!(category & OnlyInlines)) {
       
   194         // constructors
       
   195         out << "class " << nameSpace.toUpper() << "_EXPORT " << className << " : public ";
       
   196         if (category & ActiveX)
       
   197             out << "QAxWidget";
       
   198         else
       
   199             out << "QAxObject";
       
   200         out << endl;
       
   201 
       
   202         out << "{" << endl;
       
   203         out << "public:" << endl;
       
   204         out << "    " << className << "(";
       
   205         if (category & Licensed)
       
   206             out << "const QString &licenseKey = QString(), ";
       
   207         if (category & ActiveX)
       
   208             out << "QWidget *parent = 0, Qt::WindowFlags f";
       
   209         else if (category & SubObject)
       
   210             out << "IDispatch *subobject = 0, QAxObject *parent";
       
   211         else
       
   212             out << "QObject *parent";
       
   213         out << " = 0)" << endl;
       
   214         out << "    : ";
       
   215         if (category & ActiveX)
       
   216             out << "QAxWidget(parent, f";
       
   217         else if (category & SubObject)
       
   218             out << "QAxObject((IUnknown*)subobject, parent";
       
   219         else
       
   220             out << "QAxObject(parent";
       
   221         out << ")" << endl;
       
   222         out << "    {" << endl;
       
   223         if (category & SubObject)
       
   224             out << "        internalRelease();" << endl;
       
   225         else if (category & Licensed) {
       
   226             out << "        if (licenseKey.isEmpty())" << endl;
       
   227             out << "            setControl(\"" << controlID << "\");" << endl;
       
   228             out << "        else" << endl;
       
   229             out << "            setControl(\"" << controlID << ":\" + licenseKey);" << endl;
       
   230         } else {
       
   231             out << "        setControl(\"" << controlID << "\");" << endl;
       
   232         }
       
   233         out << "    }" << endl;
       
   234         out << endl;
       
   235 
       
   236         for (int ci = mo->classInfoOffset(); ci < mo->classInfoCount(); ++ci) {
       
   237             QMetaClassInfo info = mo->classInfo(ci);
       
   238             QByteArray iface_name = info.name();
       
   239             if (iface_name.startsWith("Event "))
       
   240                 continue;
       
   241 
       
   242             QByteArray iface_class = info.value();
       
   243 
       
   244             out << "    " << className << "(" << iface_class << " *iface)" << endl;
       
   245 
       
   246             if (category & ActiveX)
       
   247                 out << "    : QAxWidget()" << endl;
       
   248             else
       
   249                 out << "    : QAxObject()" << endl;
       
   250             out << "    {" << endl;
       
   251             out << "        initializeFrom(iface);" << endl;
       
   252             out << "        delete iface;" << endl;
       
   253             out << "    }" << endl;
       
   254             out << endl;
       
   255         }
       
   256     }
       
   257 
       
   258     functions << className;
       
   259 
       
   260     // enums
       
   261     if (nameSpace.isEmpty() && !(category & OnlyInlines)) {
       
   262         for (int ienum = mo->enumeratorOffset(); ienum < mo->enumeratorCount(); ++ienum) {
       
   263             QMetaEnum metaEnum = mo->enumerator(ienum);
       
   264             out << "    enum " << metaEnum.name() << " {" << endl;
       
   265             for (int k = 0; k < metaEnum.keyCount(); ++k) {
       
   266                 QByteArray key(metaEnum.key(k));
       
   267                 out << "        " << key.leftJustified(24) << "= " << metaEnum.value(k);
       
   268                 if (k < metaEnum.keyCount() - 1)
       
   269                     out << ",";
       
   270                 out << endl;
       
   271             }
       
   272             out << "    };" << endl;
       
   273             out << endl;
       
   274         }
       
   275     }
       
   276     // QAxBase public virtual functions.
       
   277     QList<QByteArray> axBase_vfuncs;
       
   278     axBase_vfuncs.append("metaObject");
       
   279     axBase_vfuncs.append("qObject");
       
   280     axBase_vfuncs.append("className");
       
   281     axBase_vfuncs.append("propertyWritable");
       
   282     axBase_vfuncs.append("setPropertyWritable");
       
   283 
       
   284     // properties
       
   285     for (int iprop = mo->propertyOffset(); iprop < mo->propertyCount(); ++iprop) {
       
   286         QMetaProperty property = mo->property(iprop);
       
   287         if (!property.isReadable())
       
   288             continue;
       
   289         
       
   290         QByteArray propertyName(property.name());
       
   291         if (propertyName == "control" || propertyName == className)
       
   292             continue;
       
   293 
       
   294         if (!(category & OnlyInlines)) {
       
   295             out << indent << "/*" << endl << indent << "Property " << propertyName << endl;
       
   296             QString documentation = qax_docuFromName(currentTypeInfo, QString::fromLatin1(propertyName.constData()));
       
   297             if (!documentation.isEmpty()) {
       
   298                 out << endl;
       
   299                 out << indent << documentation << endl;
       
   300             }
       
   301             out << indent << "*/" << endl;
       
   302         }
       
   303 
       
   304         // Check whether the new function conflicts with any of QAxBase public virtual functions.
       
   305         // If so, prepend the function name with '<classname>_'. Since all internal metaobject magic 
       
   306         // remains the same, we have to use the original name when used with QObject::connect or QMetaObject
       
   307         QByteArray propertyFunctionName(propertyName);
       
   308         if (axBase_vfuncs.contains(propertyFunctionName)) {
       
   309             propertyFunctionName = className + "_" + propertyName;
       
   310             qWarning("property conflits with QAXBase: %s changed to %s", propertyName.constData(), propertyFunctionName.constData());
       
   311         }
       
   312 
       
   313         QByteArray propertyType(property.typeName());
       
   314         QByteArray castType(propertyType);
       
   315 
       
   316         QByteArray simplePropType = propertyType;
       
   317         simplePropType.replace('*', "");
       
   318 
       
   319         out << indent << "inline ";
       
   320         bool foreignNamespace = true;
       
   321         if (!propertyType.contains("::") && 
       
   322             (qax_qualified_usertypes.contains(simplePropType) || qax_qualified_usertypes.contains("enum "+ simplePropType))
       
   323            ) {
       
   324             propertyType = nameSpace + "::" + propertyType;
       
   325             foreignNamespace = false;
       
   326         }
       
   327 
       
   328         out << propertyType << " ";
       
   329 
       
   330         if (category & OnlyInlines)
       
   331             out << className << "::";
       
   332         out << propertyFunctionName << "() const";
       
   333 
       
   334         if (!(category & NoInlines)) {
       
   335             out << endl << indent << "{" << endl;
       
   336             if (qax_qualified_usertypes.contains(simplePropType)) {
       
   337                 out << indent << "    " << propertyType << " qax_pointer = 0;" << endl;
       
   338                 out << indent << "    qRegisterMetaType(\"" << property.typeName() << "\", &qax_pointer);" << endl;
       
   339                 if (foreignNamespace)
       
   340                     out << "#ifdef QAX_DUMPCPP_" << propertyType.left(propertyType.indexOf("::")).toUpper() << "_H" << endl;
       
   341                 out << indent << "    qRegisterMetaType(\"" << simplePropType << "\", qax_pointer);" << endl;
       
   342                 if (foreignNamespace)
       
   343                     out << "#endif" << endl;
       
   344             }
       
   345             out << indent << "    QVariant qax_result = property(\"" << propertyName << "\");" << endl;
       
   346             if (propertyType.length() && propertyType.at(propertyType.length()-1) == '*')
       
   347                 out << indent << "    if (!qax_result.constData()) return 0;" << endl;
       
   348             out << indent << "    Q_ASSERT(qax_result.isValid());" << endl;
       
   349             if (qax_qualified_usertypes.contains(simplePropType)) {
       
   350                 simplePropType = propertyType;
       
   351                 simplePropType.replace('*', "");
       
   352                 if (foreignNamespace)
       
   353                     out << "#ifdef QAX_DUMPCPP_" << propertyType.left(propertyType.indexOf("::")).toUpper() << "_H" << endl;
       
   354                 out << indent << "    return *(" << propertyType << "*)qax_result.constData();" << endl;
       
   355                 if (foreignNamespace) {
       
   356                     out << "#else" << endl;
       
   357                     out << indent << "    return 0; // foreign namespace not included" << endl;
       
   358                     out << "#endif" << endl;
       
   359                 }
       
   360 
       
   361             } else {
       
   362                 out << indent << "    return *(" << propertyType << "*)qax_result.constData();" << endl;
       
   363             }
       
   364             out << indent << "}" << endl;
       
   365         } else {
       
   366             out << "; //Returns the value of " << propertyName << endl;
       
   367         }
       
   368 
       
   369         functions << propertyName;
       
   370         
       
   371         if (property.isWritable()) {
       
   372             QByteArray setter(propertyName);
       
   373             QChar firstChar = QLatin1Char(setter.at(0));
       
   374             if (isupper(setter.at(0))) {
       
   375                 setter = "Set" + setter;
       
   376             } else {
       
   377                 setter[0] = toupper(setter[0]);
       
   378                 setter = "set" + setter;
       
   379             }
       
   380             
       
   381             out << indent << "inline " << "void ";
       
   382             if (category & OnlyInlines)
       
   383                 out << className << "::";
       
   384             out << setter << "(" << constRefify(propertyType) << " value)";
       
   385             
       
   386             if (!(category & NoInlines)) {
       
   387                 if (propertyType.endsWith('*')) {
       
   388                     out << "{" << endl;
       
   389                     out << "    int typeId = qRegisterMetaType(\"" << propertyType << "\", &value);" << endl;
       
   390                     out << "    setProperty(\"" << propertyName << "\", QVariant(typeId, &value));" << endl;
       
   391                     out << "}" << endl;
       
   392                 } else {
       
   393                     out << "{ setProperty(\"" << propertyName << "\", QVariant(value)); }" << endl;
       
   394                 }
       
   395             } else {
       
   396                 out << "; //Sets the value of the " << propertyName << " property" << endl;
       
   397             }
       
   398 
       
   399             functions << setter;
       
   400         }
       
   401 
       
   402         out << endl;
       
   403     }
       
   404 
       
   405     // slots - but not property setters
       
   406     int defaultArguments = 0;
       
   407     for (int islot = mo->methodOffset(); islot < mo->methodCount(); ++islot) {
       
   408         const QMetaMethod slot(mo->method(islot));
       
   409         if (slot.methodType() != QMetaMethod::Slot)
       
   410             continue;
       
   411 
       
   412 #if 0
       
   413         // makes not sense really to respect default arguments...
       
   414         if (slot.attributes() & Cloned) {
       
   415             ++defaultArguments;
       
   416             continue;
       
   417         }
       
   418 #endif
       
   419 
       
   420         QByteArray slotSignature(slot.signature());
       
   421         QByteArray slotName = slotSignature.left(slotSignature.indexOf('('));
       
   422         if (functions.contains(slotName))
       
   423             continue;
       
   424 
       
   425         if (!(category & OnlyInlines)) {
       
   426             out << indent << "/*" << endl << indent << "Method " << slotName << endl;
       
   427             QString documentation = qax_docuFromName(currentTypeInfo, QString::fromLatin1(slotName.constData()));
       
   428             if (!documentation.isEmpty()) {
       
   429                 out << endl;
       
   430                 out << indent << documentation << endl;
       
   431             }
       
   432             out << indent << "*/" << endl;
       
   433         }
       
   434 
       
   435         QByteArray slotParameters(joinParameterNames(slot.parameterNames()));
       
   436         QByteArray slotTag(slot.tag());
       
   437         QByteArray slotType(slot.typeName());
       
   438 
       
   439         QByteArray simpleSlotType = slotType;
       
   440         simpleSlotType.replace('*', "");
       
   441         if (!slotType.contains("::") && qax_qualified_usertypes.contains(simpleSlotType))
       
   442             slotType = nameSpace + "::" + slotType;
       
   443 
       
   444 
       
   445         QByteArray slotNamedSignature;
       
   446         if (slotSignature.endsWith("()")) { // no parameters - no names
       
   447             slotNamedSignature = slotSignature;
       
   448         } else {
       
   449             slotNamedSignature = slotSignature.left(slotSignature.indexOf('(') + 1);
       
   450             QByteArray slotSignatureTruncated(slotSignature.mid(slotNamedSignature.length()));
       
   451             slotSignatureTruncated.truncate(slotSignatureTruncated.length() - 1);
       
   452 
       
   453             QList<QByteArray> signatureSplit = slotSignatureTruncated.split(',');
       
   454             QList<QByteArray> parameterSplit;
       
   455             if (slotParameters.isEmpty()) { // generate parameter names
       
   456                 for (int i = 0; i < signatureSplit.count(); ++i)
       
   457                     parameterSplit << QByteArray("p") + QByteArray::number(i);
       
   458             } else {
       
   459                 parameterSplit = slotParameters.split(',');
       
   460             }
       
   461             
       
   462             for (int i = 0; i < signatureSplit.count(); ++i) {
       
   463                 QByteArray parameterType = signatureSplit.at(i);
       
   464                 if (!parameterType.contains("::") && namespaceForType.contains(parameterType))
       
   465                     parameterType = namespaceForType.value(parameterType) + "::" + parameterType;
       
   466 
       
   467                 slotNamedSignature += constRefify(parameterType);
       
   468                 slotNamedSignature += " ";
       
   469                 slotNamedSignature += parameterSplit.at(i);
       
   470                 if (defaultArguments >= signatureSplit.count() - i) {
       
   471                     slotNamedSignature += " = ";
       
   472                     slotNamedSignature += parameterType + "()";
       
   473                 }
       
   474                 if (i + 1 < signatureSplit.count())
       
   475                     slotNamedSignature += ", ";
       
   476             }
       
   477             slotNamedSignature += ')';
       
   478         }
       
   479 
       
   480         out << indent << "inline ";
       
   481 
       
   482         if (!slotTag.isEmpty())
       
   483             out << slotTag << " ";
       
   484         if (slotType.isEmpty())
       
   485             out << "void ";
       
   486         else
       
   487             out << slotType << " ";
       
   488         if (category & OnlyInlines)
       
   489             out << className << "::";
       
   490 
       
   491         // Update function name in case of conflicts with QAxBase public virtual functions.
       
   492         int parnIdx = slotNamedSignature.indexOf('(');
       
   493         QByteArray slotOriginalName =  slotNamedSignature.left(parnIdx);
       
   494         if (axBase_vfuncs.contains(slotOriginalName)) {
       
   495             QByteArray newSignature = className + "_" + slotOriginalName;
       
   496             newSignature += slotNamedSignature.mid(parnIdx);
       
   497             qWarning("function name conflits with QAXBase %s changed to %s", slotNamedSignature.constData(), newSignature.constData());
       
   498             slotNamedSignature = newSignature;
       
   499         }
       
   500 
       
   501         out << slotNamedSignature;
       
   502 
       
   503         if (category & NoInlines) {
       
   504             out << ";" << endl;
       
   505         } else {
       
   506             out << endl;
       
   507             out << indent << "{" << endl;
       
   508             
       
   509             if (!slotType.isEmpty()) {
       
   510                 out << indent << "    " << slotType << " qax_result";
       
   511                 if (slotType.endsWith('*'))
       
   512                     out << " = 0";
       
   513                 out << ";" << endl;
       
   514                 if (qax_qualified_usertypes.contains(simpleSlotType)) {
       
   515                     out << indent << "    qRegisterMetaType(\"" << simpleSlotType << "*\", &qax_result);" << endl;
       
   516                     bool foreignNamespace = simpleSlotType.contains("::");
       
   517                     if (foreignNamespace)
       
   518                         out << "#ifdef QAX_DUMPCPP_" << simpleSlotType.left(simpleSlotType.indexOf(':')).toUpper() << "_H" << endl;
       
   519                     out << indent << "    qRegisterMetaType(\"" << simpleSlotType << "\", qax_result);" << endl;
       
   520                     if (foreignNamespace)
       
   521                         out << "#endif" << endl;
       
   522                 }
       
   523             }
       
   524             out << indent << "    void *_a[] = {";
       
   525             if (!slotType.isEmpty())
       
   526                 out << "(void*)&qax_result";
       
   527             else
       
   528                 out << "0";
       
   529             if (!slotParameters.isEmpty()) {
       
   530                 out << ", (void*)&";
       
   531                 out << slotParameters.replace(",", ", (void*)&");
       
   532             }
       
   533             out << "};" << endl;
       
   534 
       
   535             out << indent << "    qt_metacall(QMetaObject::InvokeMetaMethod, " << islot << ", _a);" << endl;
       
   536             if (!slotType.isEmpty())
       
   537                 out << indent << "    return qax_result;" << endl;
       
   538             out << indent << "}" << endl;
       
   539         }
       
   540 
       
   541         out << endl;
       
   542         defaultArguments = 0;
       
   543     }
       
   544 
       
   545     if (!(category & OnlyInlines)) {
       
   546         if (!(category & NoMetaObject)) {
       
   547             out << "// meta object functions" << endl;
       
   548             out << "    static const QMetaObject staticMetaObject;" << endl;
       
   549             out << "    virtual const QMetaObject *metaObject() const { return &staticMetaObject; }" << endl;
       
   550             out << "    virtual void *qt_metacast(const char *);" << endl;
       
   551         }
       
   552 
       
   553         out << "};" << endl;
       
   554     }
       
   555 }
       
   556 
       
   557 #define addString(string, stringData) \
       
   558     out << stringDataLength << ", "; \
       
   559     stringData += string; \
       
   560     stringDataLength += qstrlen(string); \
       
   561     stringData += "\\0"; \
       
   562     lineLength += qstrlen(string) + 1; \
       
   563     if (lineLength > 200) { stringData += "\"\n    \""; lineLength = 0; } \
       
   564     ++stringDataLength;
       
   565 
       
   566 void generateClassImpl(QTextStream &out, const QMetaObject *mo, const QByteArray &className, const QByteArray &nameSpace, ObjectCategory category)
       
   567 {
       
   568     QByteArray qualifiedClassName;
       
   569     if (!nameSpace.isEmpty())
       
   570         qualifiedClassName = nameSpace + "::";
       
   571     qualifiedClassName += className;
       
   572 
       
   573     QByteArray stringData(qualifiedClassName);
       
   574     int stringDataLength = stringData.length();
       
   575     stringData += "\\0\"\n";
       
   576     ++stringDataLength;
       
   577     int lineLength = 0;
       
   578 
       
   579     int classInfoCount = mo->classInfoCount() - mo->classInfoOffset();
       
   580     int enumCount = mo->enumeratorCount() - mo->enumeratorOffset();
       
   581     int methodCount = mo->methodCount() - mo->methodOffset();
       
   582     int propertyCount = mo->propertyCount() - mo->propertyOffset();
       
   583     int enumStart = 10;
       
   584 
       
   585     out << "static const uint qt_meta_data_" << qualifiedClassName.replace(':', '_') << "[] = {" << endl;
       
   586     out << endl;
       
   587     out << " // content:" << endl;
       
   588     out << "       1,       // revision" << endl;
       
   589     out << "       0,       // classname" << endl;
       
   590     out << "       " << classInfoCount << ",    " << (classInfoCount ? enumStart : 0) << ", // classinfo" << endl;
       
   591     enumStart += classInfoCount * 2;
       
   592     out << "       " << methodCount << ",    " << (methodCount ? enumStart : 0) << ", // methods" << endl;
       
   593     enumStart += methodCount * 5;
       
   594     out << "       " << propertyCount << ",    " << (propertyCount ? enumStart : 0) << ", // properties" << endl;
       
   595     enumStart += propertyCount * 3;
       
   596     out << "       " << enumCount << ",    " << (enumCount ? enumStart : 0)
       
   597         << ", // enums/sets" << endl;
       
   598     out << endl;
       
   599 
       
   600     if (classInfoCount) {
       
   601         out << " // classinfo: key, value" << endl;
       
   602         stringData += "    \"";
       
   603         for (int i = 0; i < classInfoCount; ++i) {
       
   604             QMetaClassInfo classInfo = mo->classInfo(i + mo->classInfoOffset());
       
   605             out << "       ";
       
   606             addString(classInfo.name(), stringData);
       
   607             addString(classInfo.value(), stringData);
       
   608             out << endl;
       
   609         }
       
   610         stringData += "\"\n";
       
   611         out << endl;
       
   612     }
       
   613     if (methodCount) {
       
   614         out << " // signals: signature, parameters, type, tag, flags" << endl;
       
   615         stringData += "    \"";
       
   616         for (int i = 0; i < methodCount; ++i) {
       
   617             const QMetaMethod signal(mo->method(i + mo->methodOffset()));
       
   618             if (signal.methodType() != QMetaMethod::Signal)
       
   619                 continue;
       
   620             out << "       ";
       
   621             addString(signal.signature(), stringData);
       
   622             addString(joinParameterNames(signal.parameterNames()), stringData);
       
   623             addString(signal.typeName(), stringData);
       
   624             addString(signal.tag(), stringData);
       
   625             out << (AccessProtected | signal.attributes() | MemberSignal) << "," << endl;
       
   626         }
       
   627         stringData += "\"\n";
       
   628         out << endl;
       
   629 
       
   630         out << " // slots: signature, parameters, type, tag, flags" << endl;
       
   631         stringData += "    \"";
       
   632         for (int i = 0; i < methodCount; ++i) {
       
   633             const QMetaMethod slot(mo->method(i + mo->methodOffset()));
       
   634             if (slot.methodType() != QMetaMethod::Slot)
       
   635                 continue;
       
   636             out << "       ";
       
   637             addString(slot.signature(), stringData);
       
   638             addString(joinParameterNames(slot.parameterNames()), stringData);
       
   639             addString(slot.typeName(), stringData);
       
   640             addString(slot.tag(), stringData);
       
   641             out << (0x01 | slot.attributes() | MemberSlot) << "," << endl;
       
   642         }
       
   643         stringData += "\"\n";
       
   644         out << endl;
       
   645     }
       
   646     if (propertyCount) {
       
   647         out << " // properties: name, type, flags" << endl;
       
   648         stringData += "    \"";
       
   649         for (int i = 0; i < propertyCount; ++i) {
       
   650             QMetaProperty property = mo->property(i + mo->propertyOffset());
       
   651             out << "       ";
       
   652             addString(property.name(), stringData);
       
   653             addString(property.typeName(), stringData);
       
   654 
       
   655             uint flags = 0;
       
   656             uint vartype = property.type();
       
   657             if (vartype != QVariant::Invalid && vartype != QVariant::UserType)
       
   658                 flags = vartype << 24;
       
   659             else if (QByteArray(property.typeName()) == "QVariant")
       
   660                 flags |= 0xff << 24;
       
   661 
       
   662             if (property.isReadable())
       
   663                 flags |= Readable;
       
   664             if (property.isWritable())
       
   665                 flags |= Writable;
       
   666             if (property.isEnumType())
       
   667                 flags |= EnumOrFlag;
       
   668             if (property.isDesignable())
       
   669                 flags |= Designable;
       
   670             if (property.isScriptable())
       
   671                 flags |= Scriptable;
       
   672             if (property.isStored())
       
   673                 flags |= Stored;
       
   674             if (property.isEditable())
       
   675                 flags |= Editable;
       
   676 
       
   677             out << "0x" << QString::number(flags, 16).rightJustified(8, '0') << ", \t\t // " << property.typeName() << " " << property.name();
       
   678             out << endl;
       
   679         }
       
   680         stringData += "\"\n";
       
   681         out << endl;
       
   682     }
       
   683 
       
   684     QByteArray enumStringData;
       
   685     if (enumCount) {
       
   686         out << " // enums: name, flags, count, data" << endl;
       
   687         enumStringData += "    \"";
       
   688         enumStart += enumCount * 4;
       
   689         for (int i = 0; i < enumCount; ++i) {
       
   690             QMetaEnum enumerator = mo->enumerator(i + mo->enumeratorOffset());
       
   691             out << "       ";
       
   692             addString(enumerator.name(), enumStringData);
       
   693             out << (enumerator.isFlag() ? "0x1" : "0x0") << ", " << enumerator.keyCount() << ", " << enumStart << ", " << endl;
       
   694             enumStart += enumerator.keyCount() * 2;
       
   695         }
       
   696         enumStringData += "\"\n";
       
   697         out << endl;
       
   698 
       
   699         out << " // enum data: key, value" << endl;
       
   700         for (int i = 0; i < enumCount; ++i) {
       
   701             enumStringData += "    \"";
       
   702             QMetaEnum enumerator = mo->enumerator(i + mo->enumeratorOffset());
       
   703             for (int j = 0; j < enumerator.keyCount(); ++j) {
       
   704                 out << "       ";
       
   705                 addString(enumerator.key(j), enumStringData);
       
   706                 if (nameSpace.isEmpty())
       
   707                     out << className << "::";
       
   708                 else
       
   709                     out << nameSpace << "::";
       
   710                 out << enumerator.key(j) << "," << endl;
       
   711             }
       
   712             enumStringData += "\"\n";
       
   713         }
       
   714         out << endl;
       
   715     }
       
   716     out << "        0        // eod" << endl;
       
   717     out << "};" << endl;
       
   718     out << endl;
       
   719 
       
   720     QByteArray stringGenerator;
       
   721 
       
   722     if (!nameSpace.isEmpty()) {
       
   723         static bool firstStringData = true;
       
   724         if (firstStringData) { // print enums only once
       
   725             firstStringData = false;
       
   726             if (!enumStringData.isEmpty()) {
       
   727                 // Maximum string length supported is 64K
       
   728                 int maxStringLength = 65535;
       
   729                 if (enumStringData.size() < maxStringLength)  {
       
   730                     out << "static const char qt_meta_enumstringdata_" << nameSpace << "[] = {" << endl;
       
   731                     out << enumStringData << endl;
       
   732                     out << "};" << endl;
       
   733                     out << endl;
       
   734                 } else {
       
   735                     // split the string into fragments of 64k
       
   736                     int fragments = (enumStringData.size() / maxStringLength);
       
   737                     fragments += (enumStringData.size() % maxStringLength) ? 1 : 0;
       
   738                     int i, index;
       
   739                     // define the fragments (qt_meta_enumstringdata_<nameSpace>fragment#)
       
   740                     for (i = 0 , index = 0; i < fragments; i++, index += maxStringLength) {
       
   741                         out << "static const char qt_meta_enumstringdata_" << nameSpace << "fragment"<< QString::number(i) << "[] = {" << endl;
       
   742                         QByteArray fragment = enumStringData.mid(index, maxStringLength);
       
   743                         if (!(fragment[0] == ' ' || fragment[0] == '\n' || fragment[0] == '\"'))
       
   744                             out << "\"";
       
   745                         out << fragment;
       
   746                         int endIx  = fragment.size() - 1;
       
   747                         if (!(fragment[endIx] == ' ' || fragment[endIx] == '\n' || fragment[endIx] == '\"' || fragment[endIx] == '\0'))
       
   748                             out << "\"" << endl;
       
   749                         else 
       
   750                             out << endl;
       
   751                         out << "};" << endl;
       
   752                     }
       
   753                     // original array definition, size will be the combined size of the arrays defined above
       
   754                     out << "static char qt_meta_enumstringdata_" << nameSpace << "[" << endl;
       
   755                     for (i = 0; i < fragments; i++, index += maxStringLength) {
       
   756                          out << "        ";
       
   757                         if (i)
       
   758                             out << "+ ";
       
   759                         out << "sizeof(qt_meta_enumstringdata_" << nameSpace << "fragment"<< QString::number(i) <<")" << endl;
       
   760                     }
       
   761                     out << "] = {0};" << endl << endl;
       
   762                     // this class will initializes the original array in constructor
       
   763                     out << "class qt_meta_enumstringdata_" << nameSpace << "_init " << endl <<"{" <<endl;
       
   764                     out << "public:"<<endl;
       
   765                     out << "    qt_meta_enumstringdata_" << nameSpace << "_init() " << endl <<"    {" <<endl;
       
   766                     out << "        int index = 0;" << endl;
       
   767                     for (i = 0; i < fragments; i++, index += maxStringLength) {
       
   768                         out << "        memcpy(qt_meta_enumstringdata_" << nameSpace << " + index, " <<"qt_meta_enumstringdata_" << nameSpace << "fragment"<< QString::number(i);
       
   769                         out << ", sizeof(qt_meta_enumstringdata_" << nameSpace << "fragment"<< QString::number(i) <<") - 1);" << endl;
       
   770                         out << "        index += sizeof(qt_meta_enumstringdata_" << nameSpace << "fragment"<< QString::number(i) <<") - 1;" << endl;
       
   771                     }
       
   772                     out << "    }" << endl << "};" << endl;
       
   773                     // a global variable of the class
       
   774                     out << "static qt_meta_enumstringdata_" << nameSpace << "_init qt_meta_enumstringdata_"  << nameSpace << "_init_instance;" << endl << endl;
       
   775                 }
       
   776             }
       
   777         }
       
   778         stringGenerator = "qt_meta_stringdata_" + qualifiedClassName.replace(':','_') + "()";
       
   779         out << "static const char *" << stringGenerator << " {" << endl;
       
   780         QList<QByteArray> splitStrings;
       
   781 
       
   782         // workaround for compilers that can't handle string literals longer than 64k
       
   783         int splitCount = 0;
       
   784         do {
       
   785             int lastNewline = stringData.lastIndexOf('\n', 64000);
       
   786             QByteArray splitString = stringData.left(lastNewline);
       
   787 
       
   788             splitStrings << splitString;
       
   789             out << "    static const char stringdata" << splitCount << "[] = {" << endl;
       
   790             out << "    \"" << splitString << endl;
       
   791             out << "    };" << endl;
       
   792             stringData = stringData.mid(lastNewline + 1);
       
   793             if (stringData.startsWith("    \""))
       
   794                 stringData = stringData.mid(5);
       
   795             ++splitCount;
       
   796         } while (!stringData.isEmpty());
       
   797 
       
   798         out << "    static char data[";
       
   799         for (int i = 0; i < splitCount; ++i) {
       
   800             out << "sizeof(stringdata" << i << ") + ";
       
   801         }
       
   802         if (!enumStringData.isEmpty()) {
       
   803             out << "sizeof(qt_meta_enumstringdata_" << nameSpace << ")";
       
   804         } else {
       
   805             out << "0";
       
   806         }
       
   807         out << "];" << endl;
       
   808         out << "    if (!data[0]) {" << endl;
       
   809         out << "        int index = 0;" << endl;
       
   810 
       
   811         int dataIndex = 0;
       
   812         for (int i = 0; i < splitCount; ++i) {
       
   813             out << "        memcpy(data + index";
       
   814             out << ", stringdata" << i << ", sizeof(stringdata" << i << ") - 1);" << endl;
       
   815             out << "        index += sizeof(stringdata" << i << ") - 1;" << endl;
       
   816             dataIndex += splitStrings.at(i).length();
       
   817         }
       
   818         if (!enumStringData.isEmpty()) {
       
   819             out << "        memcpy(data + index, qt_meta_enumstringdata_" << nameSpace << ", sizeof(qt_meta_enumstringdata_" << nameSpace << "));" << endl;
       
   820         }
       
   821         out << "    }" << endl;
       
   822         out << endl;
       
   823         out << "    return data;" << endl;
       
   824         out << "};" << endl;
       
   825         out << endl;
       
   826     } else {
       
   827         stringData += enumStringData;
       
   828         stringGenerator = "qt_meta_stringdata_" + qualifiedClassName.replace(':','_');
       
   829         out << "static const char qt_meta_stringdata_" << stringGenerator << "[] = {" << endl;
       
   830         out << "    \"" << stringData << endl;
       
   831         out << "};" << endl;
       
   832         out << endl;
       
   833     }
       
   834 
       
   835     out << "const QMetaObject " << className << "::staticMetaObject = {" << endl;
       
   836     if (category & ActiveX)
       
   837         out << "{ &QWidget::staticMetaObject," << endl;
       
   838     else
       
   839         out << "{ &QObject::staticMetaObject," << endl;
       
   840     out << stringGenerator << "," << endl;
       
   841     out << "qt_meta_data_" << qualifiedClassName.replace(':','_') << " }" << endl;
       
   842     out << "};" << endl;
       
   843     out << endl;
       
   844 
       
   845     out << "void *" << className << "::qt_metacast(const char *_clname)" << endl;
       
   846     out << "{" << endl;
       
   847     out << "    if (!_clname) return 0;" << endl;
       
   848     out << "    if (!strcmp(_clname, " << stringGenerator << "))" << endl;
       
   849     out << "        return static_cast<void*>(const_cast<" << className << "*>(this));" << endl;
       
   850     if (category & ActiveX)
       
   851         out << "    return QAxWidget::qt_metacast(_clname);" << endl;
       
   852     else
       
   853         out << "    return QAxObject::qt_metacast(_clname);" << endl;
       
   854     out << "}" << endl;
       
   855 }
       
   856 
       
   857 bool generateClass(QAxObject *object, const QByteArray &className, const QByteArray &nameSpace, const QByteArray &outname, ObjectCategory category)
       
   858 {
       
   859     IOleControl *control = 0;
       
   860     object->queryInterface(IID_IOleControl, (void**)&control);
       
   861     if (control) {
       
   862         category = ActiveX;
       
   863         control->Release();
       
   864     }
       
   865 
       
   866     const QMetaObject *mo = object->metaObject();
       
   867 
       
   868     if (!nameSpace.isEmpty() && !(category & NoDeclaration)) {
       
   869         QFile outfile(QString::fromLatin1(nameSpace.toLower().constData()) + QLatin1String(".h"));
       
   870 		if (!outfile.open(QIODevice::WriteOnly | QIODevice::Text)) {
       
   871             qWarning("dumpcpp: Could not open output file '%s'", qPrintable(outfile.fileName()));
       
   872             return false;
       
   873         }
       
   874         QTextStream out(&outfile);
       
   875 
       
   876         out << "/****************************************************************************" << endl;
       
   877         out << "**" << endl;
       
   878         out << "** Namespace " << nameSpace << " generated by dumpcpp" << endl;
       
   879         out << "**" << endl;
       
   880         out << "****************************************************************************/" << endl;
       
   881         out << endl;
       
   882 
       
   883         writeHeader(out, nameSpace);
       
   884         generateNameSpace(out, mo, nameSpace);
       
   885 
       
   886         // close namespace file
       
   887         out << "};" << endl;
       
   888         out << endl;
       
   889 
       
   890         out << "#endif" << endl;
       
   891         out << endl;
       
   892     }
       
   893 
       
   894     if (!(category & NoDeclaration)) {
       
   895         QFile outfile(QString::fromLatin1(outname.constData()) + QLatin1String(".h"));
       
   896         if (!outfile.open(QIODevice::WriteOnly | QIODevice::Text)) {
       
   897             qWarning("dumpcpp: Could not open output file '%s'", qPrintable(outfile.fileName()));
       
   898             return false;
       
   899         }
       
   900         QTextStream out(&outfile);
       
   901 
       
   902         out << "/****************************************************************************" << endl;
       
   903         out << "**" << endl;
       
   904         out << "** Class declaration generated by dumpcpp" << endl;
       
   905         out << "**" << endl;
       
   906         out << "****************************************************************************/" << endl;
       
   907         out << endl;
       
   908 
       
   909         out << "#include <qdatetime.h>" << endl;
       
   910         if (category & ActiveX)
       
   911             out << "#include <qaxwidget.h>" << endl;
       
   912         else
       
   913             out << "#include <qaxobject.h>" << endl;
       
   914         out << endl;
       
   915 
       
   916         out << "struct IDispatch;" << endl,
       
   917         out << endl;
       
   918 
       
   919         if (!nameSpace.isEmpty()) {
       
   920             out << "#include \"" << nameSpace.toLower() << ".h\"" << endl;
       
   921             out << endl;
       
   922             out << "namespace " << nameSpace << " {" << endl;
       
   923         }
       
   924 
       
   925         generateClassDecl(out, object->control(), mo, className, nameSpace, category);
       
   926 
       
   927         if (!nameSpace.isEmpty()) {
       
   928             out << endl;
       
   929             out << "};" << endl;
       
   930         }
       
   931     }
       
   932 
       
   933     if (!(category & (NoMetaObject|NoImplementation))) {
       
   934         QFile outfile(QString::fromLatin1(outname.constData()) + QLatin1String(".cpp"));
       
   935         if (!outfile.open(QIODevice::WriteOnly | QIODevice::Text)) {
       
   936             qWarning("dumpcpp: Could not open output file '%s'", qPrintable(outfile.fileName()));
       
   937             return false;
       
   938         }
       
   939         QTextStream out(&outfile);
       
   940 
       
   941         out << "#include <qmetaobject.h>" << endl;
       
   942         out << "#include \"" << outname << ".h\"" << endl;
       
   943         out << endl;
       
   944 
       
   945         if (!nameSpace.isEmpty()) {
       
   946             out << "using namespace " << nameSpace << ";" << endl;
       
   947             out << endl;
       
   948         }
       
   949 
       
   950         generateClassImpl(out, mo, className, nameSpace, category);
       
   951     }
       
   952 
       
   953     return true;
       
   954 }
       
   955 
       
   956 bool generateTypeLibrary(const QByteArray &typeLib, const QByteArray &outname, ObjectCategory category)
       
   957 {
       
   958     QString typeLibFile(QString::fromLatin1(typeLib.constData()));
       
   959     typeLibFile = typeLibFile.replace(QLatin1Char('/'), QLatin1Char('\\'));
       
   960     QString cppFile(QString::fromLatin1(outname.constData()));
       
   961 
       
   962     ITypeLib *typelib;
       
   963     LoadTypeLibEx(reinterpret_cast<const wchar_t *>(typeLibFile.utf16()), REGKIND_NONE, &typelib);
       
   964     if (!typelib) {
       
   965         qWarning("dumpcpp: loading '%s' as a type library failed", qPrintable(typeLibFile));
       
   966         return false;
       
   967     }
       
   968 
       
   969     QString libName;
       
   970     BSTR nameString;
       
   971     typelib->GetDocumentation(-1, &nameString, 0, 0, 0);
       
   972     libName = QString::fromWCharArray(nameString);
       
   973     SysFreeString(nameString);
       
   974     if (!nameSpace.isEmpty())
       
   975         libName = QString(nameSpace);
       
   976 
       
   977     QString libVersion(QLatin1String("1.0"));
       
   978 
       
   979     TLIBATTR *tlibattr = 0;
       
   980     typelib->GetLibAttr(&tlibattr);
       
   981     if (tlibattr) {
       
   982         libVersion = QString::fromLatin1("%1.%2").arg(tlibattr->wMajorVerNum).arg(tlibattr->wMinorVerNum);
       
   983         typelib->ReleaseTLibAttr(tlibattr);
       
   984     }
       
   985 
       
   986     if (cppFile.isEmpty())
       
   987         cppFile = libName.toLower();
       
   988 
       
   989     if (cppFile.isEmpty()) {
       
   990         qWarning("dumpcpp: no output filename provided, and cannot deduce output filename");
       
   991         return false;
       
   992     }
       
   993 
       
   994     QMetaObject *namespaceObject = qax_readEnumInfo(typelib, 0);
       
   995 
       
   996     QFile implFile(cppFile + QLatin1String(".cpp"));
       
   997     QTextStream implOut(&implFile);
       
   998     if (!(category & (NoMetaObject|NoImplementation))) {
       
   999         if (!implFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
       
  1000             qWarning("dumpcpp: Could not open output file '%s'", qPrintable(implFile.fileName()));
       
  1001             return false;
       
  1002         }
       
  1003 
       
  1004         implOut << "/****************************************************************************" << endl;
       
  1005         implOut << "**" << endl;
       
  1006         implOut << "** Metadata for " << libName << " generated by dumpcpp from type library" << endl;
       
  1007         implOut << "** " << typeLibFile << endl;
       
  1008         implOut << "**" << endl;
       
  1009         implOut << "****************************************************************************/" << endl;
       
  1010         implOut << endl;
       
  1011 
       
  1012         implOut << "#define QAX_DUMPCPP_" << libName.toUpper() << "_NOINLINES" << endl;
       
  1013 
       
  1014         implOut << "#include \"" << cppFile << ".h\"" << endl;
       
  1015         implOut << endl;
       
  1016         implOut << "using namespace " << libName << ";" << endl;
       
  1017         implOut << endl;
       
  1018     }
       
  1019 
       
  1020     QFile declFile(cppFile + QLatin1String(".h"));
       
  1021     QTextStream declOut(&declFile);
       
  1022     QByteArray classes;
       
  1023     QTextStream classesOut(&classes, QIODevice::WriteOnly);
       
  1024     QByteArray inlines;
       
  1025     QTextStream inlinesOut(&inlines, QIODevice::WriteOnly);
       
  1026 
       
  1027     QMap<QByteArray, QList<QByteArray> > namespaces;
       
  1028 
       
  1029     if(!(category & NoDeclaration)) {
       
  1030         if (!declFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
       
  1031             qWarning("dumpcpp: Could not open output file '%s'", qPrintable(declFile.fileName()));
       
  1032             return false;
       
  1033         }
       
  1034 
       
  1035         declOut << "/****************************************************************************" << endl;
       
  1036         declOut << "**" << endl;
       
  1037         declOut << "** Namespace " << libName << " generated by dumpcpp from type library" << endl;
       
  1038         declOut << "** " << typeLibFile << endl;
       
  1039         declOut << "**" << endl;
       
  1040         declOut << "****************************************************************************/" << endl;
       
  1041         declOut << endl;
       
  1042 
       
  1043         writeHeader(declOut, libName.toLatin1());
       
  1044 
       
  1045         UINT typeCount = typelib->GetTypeInfoCount();
       
  1046         if (declFile.isOpen()) {
       
  1047             declOut << endl;
       
  1048             declOut << "// Referenced namespace" << endl;
       
  1049             for (UINT index = 0; index < typeCount; ++index) {
       
  1050                 ITypeInfo *typeinfo = 0;
       
  1051                 typelib->GetTypeInfo(index, &typeinfo);
       
  1052                 if (!typeinfo)
       
  1053                     continue;
       
  1054 
       
  1055                 TYPEATTR *typeattr;
       
  1056                 typeinfo->GetTypeAttr(&typeattr);
       
  1057                 if (!typeattr) {
       
  1058                     typeinfo->Release();
       
  1059                     continue;
       
  1060                 }
       
  1061 
       
  1062                 TYPEKIND typekind;
       
  1063                 typelib->GetTypeInfoType(index, &typekind);
       
  1064 
       
  1065                 QMetaObject *metaObject = 0;
       
  1066 
       
  1067                 // trigger meta object to collect references to other type libraries
       
  1068                 switch (typekind) {
       
  1069                 case TKIND_COCLASS:
       
  1070                     if (category & ActiveX)
       
  1071                         metaObject = qax_readClassInfo(typelib, typeinfo, &QWidget::staticMetaObject);
       
  1072                     else
       
  1073                         metaObject = qax_readClassInfo(typelib, typeinfo, &QObject::staticMetaObject);
       
  1074                     break;
       
  1075                 case TKIND_DISPATCH:
       
  1076                     if (category & ActiveX)
       
  1077                         metaObject = qax_readInterfaceInfo(typelib, typeinfo, &QWidget::staticMetaObject);
       
  1078                     else
       
  1079                         metaObject = qax_readInterfaceInfo(typelib, typeinfo, &QObject::staticMetaObject);
       
  1080                     break;
       
  1081                 case TKIND_RECORD:
       
  1082                 case TKIND_ENUM:
       
  1083                 case TKIND_INTERFACE: // only for forward declarations
       
  1084                     {
       
  1085                         QByteArray className;
       
  1086                         BSTR bstr;
       
  1087                         if (S_OK != typeinfo->GetDocumentation(-1, &bstr, 0, 0, 0))
       
  1088                             break;
       
  1089                         className = QString::fromWCharArray(bstr).toLatin1();
       
  1090                         SysFreeString(bstr);
       
  1091                         switch (typekind) {
       
  1092                         case TKIND_RECORD:
       
  1093                             className = "struct " + className;
       
  1094                             break;
       
  1095                         case TKIND_ENUM:
       
  1096                             className = "enum " + className;
       
  1097                             break;
       
  1098                         default:
       
  1099                             break;
       
  1100                         }
       
  1101                         namespaces[libName.toLatin1()].append(className);
       
  1102                         if (!qax_qualified_usertypes.contains(className))
       
  1103                             qax_qualified_usertypes << className;
       
  1104                     }
       
  1105                     break;
       
  1106                 default:
       
  1107                     break;
       
  1108                 }
       
  1109 
       
  1110                 delete metaObject;
       
  1111                 typeinfo->ReleaseTypeAttr(typeattr);
       
  1112                 typeinfo->Release();
       
  1113             }
       
  1114 
       
  1115             for (int i = 0; i < qax_qualified_usertypes.count(); ++i) {
       
  1116                 QByteArray refType = qax_qualified_usertypes.at(i);
       
  1117                 QByteArray refTypeLib;
       
  1118                 if (refType.contains("::")) {
       
  1119                     refTypeLib = refType;
       
  1120                     refType = refType.mid(refType.lastIndexOf("::") + 2);
       
  1121                     if (refTypeLib.contains(' ')) {
       
  1122                         refType = refTypeLib.left(refTypeLib.indexOf(' ')) + ' ' + refType;
       
  1123                     }
       
  1124                     refTypeLib = refTypeLib.left(refTypeLib.indexOf("::"));
       
  1125                     refTypeLib = refTypeLib.mid(refTypeLib.lastIndexOf(' ') + 1);
       
  1126                     namespaces[refTypeLib].append(refType);
       
  1127                 } else {
       
  1128                     namespaces[libName.toLatin1()].append(refType);
       
  1129                 }
       
  1130             }
       
  1131 
       
  1132             QList<QByteArray> keys = namespaces.keys();
       
  1133             for (int n = 0; n < keys.count(); ++n) {
       
  1134                 QByteArray nspace = keys.at(n);
       
  1135                 if (QString::fromLatin1(nspace.constData()) != libName) {
       
  1136                     declOut << "namespace " << nspace << " {" << endl;
       
  1137                     QList<QByteArray> classList = namespaces.value(nspace);
       
  1138                     for (int c = 0; c < classList.count(); ++c) {
       
  1139                         QByteArray className = classList.at(c);
       
  1140                         if (className.contains(' ')) {
       
  1141                             declOut << "    " << className << ";" << endl;
       
  1142                             namespaceForType.insert(className.mid(className.indexOf(' ') + 1), nspace);
       
  1143                         } else {
       
  1144                             declOut << "    class " << className << ";" << endl;
       
  1145                             namespaceForType.insert(className, nspace);
       
  1146                             namespaceForType.insert(className + "*", nspace);
       
  1147                         }
       
  1148                     }
       
  1149                     declOut << "}" << endl << endl;
       
  1150                 }
       
  1151             }
       
  1152 
       
  1153             declOut << endl;
       
  1154         }
       
  1155         generateNameSpace(declOut, namespaceObject, libName.toLatin1());
       
  1156 
       
  1157         QList<QByteArray> classList = namespaces.value(libName.toLatin1());
       
  1158         if (classList.count())
       
  1159             declOut << "// forward declarations" << endl;
       
  1160         for (int c = 0; c < classList.count(); ++c) {
       
  1161             QByteArray className = classList.at(c);
       
  1162             if (className.contains(' ')) {
       
  1163                 declOut << "    " << className << ";" << endl;
       
  1164                 namespaceForType.insert(className.mid(className.indexOf(' ') + 1), libName.toLatin1());
       
  1165             } else {
       
  1166                 declOut << "    class " << className << ";" << endl;
       
  1167                 namespaceForType.insert(className, libName.toLatin1());
       
  1168                 namespaceForType.insert(className + "*", libName.toLatin1());
       
  1169             }
       
  1170         }
       
  1171 
       
  1172         declOut << endl;
       
  1173     }
       
  1174 
       
  1175     QList<QByteArray> subtypes;
       
  1176 
       
  1177     UINT typeCount = typelib->GetTypeInfoCount();
       
  1178     for (UINT index = 0; index < typeCount; ++index) {
       
  1179         ITypeInfo *typeinfo = 0;
       
  1180         typelib->GetTypeInfo(index, &typeinfo);
       
  1181         if (!typeinfo)
       
  1182             continue;
       
  1183 
       
  1184         TYPEATTR *typeattr;
       
  1185         typeinfo->GetTypeAttr(&typeattr);
       
  1186         if (!typeattr) {
       
  1187             typeinfo->Release();
       
  1188             continue;
       
  1189         }
       
  1190 
       
  1191         TYPEKIND typekind;
       
  1192         typelib->GetTypeInfoType(index, &typekind);
       
  1193 
       
  1194         uint object_category = category;
       
  1195         if (!(typeattr->wTypeFlags & TYPEFLAG_FCANCREATE))
       
  1196             object_category |= SubObject;
       
  1197         else if (typeattr->wTypeFlags & TYPEFLAG_FCONTROL)
       
  1198             object_category |= ActiveX;
       
  1199 
       
  1200         QMetaObject *metaObject = 0;
       
  1201         QUuid guid(typeattr->guid);
       
  1202 
       
  1203         if (!(object_category & ActiveX)) {
       
  1204             QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes\\CLSID\\") + guid.toString(), QSettings::NativeFormat);
       
  1205             if (settings.childGroups().contains(QLatin1String("Control"))) {
       
  1206                 object_category |= ActiveX;
       
  1207                 object_category &= ~SubObject;
       
  1208             }
       
  1209         }
       
  1210 
       
  1211         switch (typekind) {
       
  1212         case TKIND_COCLASS:
       
  1213             if (object_category & ActiveX)
       
  1214                 metaObject = qax_readClassInfo(typelib, typeinfo, &QWidget::staticMetaObject);
       
  1215             else
       
  1216                 metaObject = qax_readClassInfo(typelib, typeinfo, &QObject::staticMetaObject);
       
  1217             break;
       
  1218         case TKIND_DISPATCH:
       
  1219             if (object_category & ActiveX)
       
  1220                 metaObject = qax_readInterfaceInfo(typelib, typeinfo, &QWidget::staticMetaObject);
       
  1221             else
       
  1222                 metaObject = qax_readInterfaceInfo(typelib, typeinfo, &QObject::staticMetaObject);
       
  1223             break;
       
  1224         case TKIND_INTERFACE: // only stub
       
  1225             {
       
  1226                 QByteArray className;
       
  1227                 BSTR bstr;
       
  1228                 if (S_OK != typeinfo->GetDocumentation(-1, &bstr, 0, 0, 0))
       
  1229                     break;
       
  1230                 className = QString::fromWCharArray(bstr).toLatin1();
       
  1231                 SysFreeString(bstr);
       
  1232 
       
  1233                 declOut << "// stub for vtable-only interface" << endl;
       
  1234                 declOut << "class " << className << " : public QAxObject {};" << endl << endl;
       
  1235             }
       
  1236             break;
       
  1237         default:
       
  1238             break;
       
  1239         }
       
  1240 
       
  1241         if (metaObject) {
       
  1242             currentTypeInfo = typeinfo;
       
  1243             QByteArray className(metaObject->className());
       
  1244             if (!(typeattr->wTypeFlags & TYPEFLAG_FDUAL) 
       
  1245                 && (metaObject->propertyCount() - metaObject->propertyOffset()) == 1 
       
  1246                 && className.contains("Events")) {
       
  1247                 declOut << "// skipping event interface " << className << endl << endl;
       
  1248             } else {
       
  1249                 if (declFile.isOpen()) {
       
  1250                     if (typeattr->wTypeFlags & TYPEFLAG_FLICENSED)
       
  1251                         object_category |= Licensed;
       
  1252                     if (typekind == TKIND_COCLASS) { // write those later...
       
  1253                         generateClassDecl(classesOut, guid.toString(), metaObject, className, libName.toLatin1(), (ObjectCategory)(object_category|NoInlines));
       
  1254                         classesOut << endl;
       
  1255                     } else {
       
  1256                         generateClassDecl(declOut, guid.toString(), metaObject, className, libName.toLatin1(), (ObjectCategory)(object_category|NoInlines));
       
  1257                         declOut << endl;
       
  1258                     }
       
  1259                     subtypes << className;
       
  1260                     generateClassDecl(inlinesOut, guid.toString(), metaObject, className, libName.toLatin1(), (ObjectCategory)(object_category|OnlyInlines));
       
  1261                     inlinesOut << endl;
       
  1262                 }
       
  1263                 if (implFile.isOpen()) {
       
  1264                     generateClassImpl(implOut, metaObject, className, libName.toLatin1(), (ObjectCategory)object_category);
       
  1265                     implOut  << endl;
       
  1266                 }
       
  1267             }
       
  1268             currentTypeInfo = 0;
       
  1269         }
       
  1270 
       
  1271         delete metaObject;
       
  1272 
       
  1273         typeinfo->ReleaseTypeAttr(typeattr);
       
  1274         typeinfo->Release();
       
  1275     }
       
  1276 
       
  1277     delete namespaceObject;
       
  1278 
       
  1279     classesOut.flush();
       
  1280     inlinesOut.flush();
       
  1281 
       
  1282     if (declFile.isOpen()) {
       
  1283         if (classes.size()) {
       
  1284             declOut << "// Actual coclasses" << endl;
       
  1285             declOut << classes;
       
  1286         }
       
  1287         if (inlines.size()) {
       
  1288             declOut << "// member function implementation" << endl;
       
  1289             declOut << "#ifndef QAX_DUMPCPP_" << libName.toUpper() << "_NOINLINES" << endl;
       
  1290             declOut << inlines << endl;
       
  1291             declOut << "#endif" << endl << endl;
       
  1292         }
       
  1293         // close namespace
       
  1294         declOut << "}" << endl;
       
  1295         declOut << endl;
       
  1296 
       
  1297         // partial template specialization for qMetaTypeConstructHelper
       
  1298         for (int t = 0; t < subtypes.count(); ++t) {
       
  1299             QByteArray subType(subtypes.at(t));
       
  1300             declOut << "template<>" << endl;
       
  1301             declOut << "inline void *qMetaTypeConstructHelper(const " << libName << "::" << subType << " *t)" << endl;
       
  1302             declOut << "{ Q_ASSERT(!t); return new " << libName << "::" << subType << "; }" << endl;
       
  1303             declOut << endl;
       
  1304         }
       
  1305 
       
  1306         declOut << "#endif" << endl;
       
  1307         declOut << endl;
       
  1308     }
       
  1309 
       
  1310     typelib->Release();
       
  1311     return true;
       
  1312 }
       
  1313 
       
  1314 QT_END_NAMESPACE
       
  1315 
       
  1316 QT_USE_NAMESPACE
       
  1317 
       
  1318 int main(int argc, char **argv)
       
  1319 {
       
  1320     qax_dispatchEqualsIDispatch = false;
       
  1321 
       
  1322     CoInitialize(0);
       
  1323 
       
  1324     uint category = DefaultObject;
       
  1325 
       
  1326     enum State {
       
  1327         Default = 0,
       
  1328         Output,
       
  1329         NameSpace,
       
  1330         GetTypeLib
       
  1331     } state;
       
  1332     state = Default;
       
  1333     
       
  1334     QByteArray outname;
       
  1335     QByteArray typeLib;
       
  1336     
       
  1337     for (int a = 1; a < argc; ++a) {
       
  1338         QByteArray arg(argv[a]);
       
  1339         const char first = arg[0];
       
  1340         switch(state) {
       
  1341         case Default:
       
  1342             if (first == '-' || first == '/') {
       
  1343                 arg = arg.mid(1);
       
  1344                 arg.toLower();
       
  1345 
       
  1346                 if (arg == "o") {
       
  1347                     state = Output;
       
  1348                 } else if (arg == "n") {
       
  1349                     state = NameSpace;
       
  1350                 } else if (arg == "v") {
       
  1351                     qWarning("dumpcpp: Version 1.0");
       
  1352                     return 0;
       
  1353                 } else if (arg == "nometaobject") {
       
  1354                     category |= NoMetaObject;
       
  1355                 } else if (arg == "impl") {
       
  1356                     category |= NoDeclaration;
       
  1357                 } else if (arg == "decl") {
       
  1358                     category |= NoImplementation;
       
  1359                 } else if (arg == "donothing") {
       
  1360                     category = DoNothing;
       
  1361                     break;
       
  1362                 } else if (arg == "compat") {
       
  1363                     qax_dispatchEqualsIDispatch = true;
       
  1364                     break;
       
  1365                 } else if (arg == "getfile") {
       
  1366                     state = GetTypeLib;
       
  1367                     break;
       
  1368                 } else if (arg == "h") {
       
  1369                     qWarning("dumpcpp Version1.0\n\n"
       
  1370                         "Generate a C++ namespace from a type library.\n\n"
       
  1371                         "Usage:\n"
       
  1372                         "dumpcpp input [-[-n <namespace>] [-o <filename>]\n\n"
       
  1373                         "   input:     A type library file, type library ID, ProgID or CLSID\n\n"
       
  1374                         "Optional parameters:\n"
       
  1375                         "   namespace: The name of the generated C++ namespace\n"
       
  1376                         "   filename:  The file name (without extension) of the generated files\n"
       
  1377                         "\n"
       
  1378                         "Other parameters:\n"
       
  1379                         "   -nometaobject Don't generate meta object information (no .cpp file)\n"
       
  1380                         "   -impl Only generate the .cpp file\n"
       
  1381                         "   -decl Only generate the .h file\n"
       
  1382                         "   -compat Treat all coclass parameters as IDispatch\n"
       
  1383                         "\n"
       
  1384                         "Examples:\n"
       
  1385                         "   dumpcpp Outlook.Application -o outlook\n"
       
  1386                         "   dumpcpp {3B756301-0075-4E40-8BE8-5A81DE2426B7}\n"
       
  1387                         "\n");
       
  1388                     return 0;
       
  1389                 }
       
  1390             } else {
       
  1391                 typeLib = arg;
       
  1392             }
       
  1393             break;
       
  1394 
       
  1395         case Output:
       
  1396             outname = arg;
       
  1397             state = Default;
       
  1398             break;
       
  1399 
       
  1400         case NameSpace:
       
  1401             nameSpace = arg;
       
  1402             state = Default;
       
  1403             break;
       
  1404 
       
  1405         case GetTypeLib:
       
  1406             typeLib = arg;
       
  1407             state = Default;
       
  1408             category = TypeLibID;
       
  1409             break;
       
  1410         default:
       
  1411             break;
       
  1412         }
       
  1413     }
       
  1414 
       
  1415     if (category == TypeLibID) {
       
  1416         QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes\\TypeLib\\") +
       
  1417                            QString::fromLatin1(typeLib.constData()), QSettings::NativeFormat);
       
  1418         typeLib = QByteArray();
       
  1419         QStringList codes = settings.childGroups();
       
  1420         for (int c = 0; c < codes.count(); ++c) {
       
  1421             typeLib = settings.value(QLatin1String("/") + codes.at(c) + QLatin1String("/0/win32/.")).toByteArray();
       
  1422             if (QFile::exists(QString::fromLatin1(typeLib))) {
       
  1423                 break;
       
  1424             }
       
  1425         }
       
  1426 
       
  1427         if (!typeLib.isEmpty())
       
  1428             fprintf(stdout, "\"%s\"\n", typeLib.data());
       
  1429         return 0;
       
  1430     }
       
  1431 
       
  1432     if (category == DoNothing)
       
  1433         return 0;
       
  1434     
       
  1435     if (typeLib.isEmpty()) {
       
  1436         qWarning("dumpcpp: No object class or type library name provided.\n"
       
  1437             "         Use -h for help.");
       
  1438         return -1;
       
  1439     }
       
  1440 
       
  1441     // not a file - search registry
       
  1442     if (!QFile::exists(QString::fromLatin1(typeLib.constData()))) {
       
  1443         bool isObject = false;
       
  1444         QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Classes"), QSettings::NativeFormat);
       
  1445 
       
  1446         // regular string and not a file - must be ProgID
       
  1447         if (typeLib.at(0) != '{') {
       
  1448             CLSID clsid;
       
  1449             if (CLSIDFromProgID(reinterpret_cast<const wchar_t *>(QString(QLatin1String(typeLib)).utf16()), &clsid) != S_OK) {
       
  1450                 qWarning("dumpcpp: '%s' is not a type library and not a registered ProgID", typeLib.constData());
       
  1451                 return -2;
       
  1452             }
       
  1453             QUuid uuid(clsid);
       
  1454             typeLib = uuid.toString().toLatin1();
       
  1455             isObject = true;
       
  1456         }
       
  1457 
       
  1458         // check if CLSID
       
  1459         if (!isObject) {
       
  1460             QVariant test = settings.value(QLatin1String("/CLSID/") +
       
  1461                                            QString::fromLatin1(typeLib.constData()) + QLatin1String("/."));
       
  1462             isObject = test.isValid();
       
  1463         }
       
  1464 
       
  1465         // search typelib ID for CLSID
       
  1466         if (isObject)
       
  1467             typeLib = settings.value(QLatin1String("/CLSID/") +
       
  1468                                      QString::fromLatin1(typeLib.constData()) + QLatin1String("/Typelib/.")).toByteArray();
       
  1469 
       
  1470         // interpret input as type library ID
       
  1471         QString key = QLatin1String("/TypeLib/") + QLatin1String(typeLib);
       
  1472         settings.beginGroup(key);
       
  1473         QStringList versions = settings.childGroups();
       
  1474         QStringList codes;
       
  1475         if (versions.count()) {
       
  1476             settings.beginGroup(QLatin1String("/") + versions.last());
       
  1477             codes = settings.childGroups();
       
  1478             key += QLatin1String("/") + versions.last();
       
  1479             settings.endGroup();
       
  1480         }
       
  1481         settings.endGroup();
       
  1482 
       
  1483         for (int c = 0; c < codes.count(); ++c) {
       
  1484             typeLib = settings.value(key + QLatin1String("/") + codes.at(c) + QLatin1String("/win32/.")).toByteArray();
       
  1485             if (QFile::exists(QString::fromLatin1(typeLib.constData()))) {
       
  1486                 break;
       
  1487             }
       
  1488         }
       
  1489     }
       
  1490 
       
  1491     if (!QFile::exists(QString::fromLatin1(typeLib.constData()))) {
       
  1492         qWarning("dumpcpp: type library '%s' not found", typeLib.constData());
       
  1493         return -2;
       
  1494     }
       
  1495 
       
  1496     if (!generateTypeLibrary(typeLib, outname, (ObjectCategory)category)) {
       
  1497         qWarning("dumpcpp: error processing type library '%s'", typeLib.constData());
       
  1498         return -1;
       
  1499     }
       
  1500 
       
  1501     return 0;
       
  1502 }