|
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> ¶meterNames) |
|
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 } |