source: trunk/tools/activeqt/dumpcpp/main.cpp@ 890

Last change on this file since 890 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 59.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the tools applications of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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
54QT_BEGIN_NAMESPACE
55
56static ITypeInfo *currentTypeInfo = 0;
57
58enum 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
74enum 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
92enum 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
104extern QMetaObject *qax_readEnumInfo(ITypeLib *typeLib, const QMetaObject *parentObject);
105extern QMetaObject *qax_readClassInfo(ITypeLib *typeLib, ITypeInfo *typeInfo, const QMetaObject *parentObject);
106extern QMetaObject *qax_readInterfaceInfo(ITypeLib *typeLib, ITypeInfo *typeInfo, const QMetaObject *parentObject);
107extern QList<QByteArray> qax_qualified_usertypes;
108extern QString qax_docuFromName(ITypeInfo *typeInfo, const QString &name);
109extern bool qax_dispatchEqualsIDispatch;
110
111QByteArray nameSpace;
112QMap<QByteArray, QByteArray> namespaceForType;
113
114void 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
132void 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
151void 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
160static 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
172QByteArray 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
185void 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
566void 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
857bool 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
956bool 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
1314QT_END_NAMESPACE
1315
1316QT_USE_NAMESPACE
1317
1318int 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}
Note: See TracBrowser for help on using the repository browser.