diff options
Diffstat (limited to 'src/tools/idc/main.cpp')
-rw-r--r-- | src/tools/idc/main.cpp | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/src/tools/idc/main.cpp b/src/tools/idc/main.cpp new file mode 100644 index 0000000..eb04114 --- /dev/null +++ b/src/tools/idc/main.cpp @@ -0,0 +1,369 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QFile> +#include <QSysInfo> +#include <QProcess> +#include <QLibraryInfo> +#include <qt_windows.h> +#include <io.h> + +QT_BEGIN_NAMESPACE + +static QString quotePath(const QString &s) +{ + if (!s.startsWith(QLatin1String("\"")) && s.contains(QLatin1Char(' '))) + return QLatin1String("\"") + s + QLatin1String("\""); + return s; +} + + +static bool runWithQtInEnvironment(const QString &cmd) +{ + QProcess proc; + + // prepend the qt binary directory to the path + QStringList env = QProcess::systemEnvironment(); + for (int i=0; i<env.count(); ++i) { + QString var = env.at(i); + int setidx = var.indexOf(QLatin1Char('=')); + if (setidx != -1) { + QString varname = var.left(setidx).trimmed().toUpper(); + if (varname == QLatin1String("PATH")) { + var = var.mid(setidx + 1); + var = QLatin1String("PATH=") + + QLibraryInfo::location(QLibraryInfo::BinariesPath) + + QLatin1Char(';') + var; + env[i] = var; + break; + } + } + } + + proc.setEnvironment(env); + proc.start(cmd); + proc.waitForFinished(-1); + + return (proc.exitCode() == 0); +} + +static bool attachTypeLibrary(const QString &applicationName, int resource, const QByteArray &data, QString *errorMessage) +{ + HANDLE hExe = 0; + QT_WA({ + TCHAR *resourceName = MAKEINTRESOURCEW(resource); + hExe = BeginUpdateResourceW((TCHAR*)applicationName.utf16(), false); + if (hExe == 0) { + if (errorMessage) + *errorMessage = QString::fromLatin1("Failed to attach type library to binary %1 - could not open file.").arg(applicationName); + return false; + } + if (!UpdateResourceW(hExe,L"TYPELIB",resourceName,0,(void*)data.data(),data.count())) { + EndUpdateResource(hExe, true); + if (errorMessage) + *errorMessage = QString::fromLatin1("Failed to attach type library to binary %1 - could not update file.").arg(applicationName); + return false; + } + }, { + char *resourceName = MAKEINTRESOURCEA(resource); + hExe = BeginUpdateResourceA(applicationName.toLocal8Bit(), false); + if (hExe == 0) { + if (errorMessage) + *errorMessage = QString::fromLatin1("Failed to attach type library to binary %1 - could not open file.").arg(applicationName); + return false; + } + if (!UpdateResourceA(hExe,"TYPELIB",resourceName,0,(void*)data.data(),data.count())) { + EndUpdateResource(hExe, true); + if (errorMessage) + *errorMessage = QString::fromLatin1("Failed to attach type library to binary %1 - could not update file.").arg(applicationName); + return false; + } + }); + + if (!EndUpdateResource(hExe,false)) { + if (errorMessage) + *errorMessage = QString::fromLatin1("Failed to attach type library to binary %1 - could not write file.").arg(applicationName); + return false; + } + + if (errorMessage) + *errorMessage = QString::fromLatin1("Type library attached to %1.").arg(applicationName); + return true; +} + +static bool registerServer(const QString &input) +{ + bool ok = false; + if (input.endsWith(QLatin1String(".exe"))) { + ok = runWithQtInEnvironment(quotePath(input) + QLatin1String(" -regserver")); + } else { + HMODULE hdll = 0; + QT_WA({ + hdll = LoadLibraryW((TCHAR*)input.utf16()); + }, { + hdll = LoadLibraryA(input.toLocal8Bit()); + }); + if (!hdll) { + fprintf(stderr, "Couldn't load library file %s\n", (const char*)input.toLocal8Bit().data()); + return false; + } + typedef HRESULT(__stdcall* RegServerProc)(); + RegServerProc DllRegisterServer = (RegServerProc)GetProcAddress(hdll, "DllRegisterServer"); + if (!DllRegisterServer) { + fprintf(stderr, "Library file %s doesn't appear to be a COM library\n", (const char*)input.toLocal8Bit().data()); + return false; + } + ok = DllRegisterServer() == S_OK; + } + return ok; +} + +static bool unregisterServer(const QString &input) +{ + bool ok = false; + if (input.endsWith(QLatin1String(".exe"))) { + ok = runWithQtInEnvironment(quotePath(input) + QLatin1String(" -unregserver")); + } else { + HMODULE hdll = 0; + QT_WA({ + hdll = LoadLibraryW((TCHAR*)input.utf16()); + }, { + hdll = LoadLibraryA(input.toLocal8Bit()); + }); + if (!hdll) { + fprintf(stderr, "Couldn't load library file %s\n", (const char*)input.toLocal8Bit().data()); + return false; + } + typedef HRESULT(__stdcall* RegServerProc)(); + RegServerProc DllUnregisterServer = (RegServerProc)GetProcAddress(hdll, "DllUnregisterServer"); + if (!DllUnregisterServer) { + fprintf(stderr, "Library file %s doesn't appear to be a COM library\n", (const char*)input.toLocal8Bit().data()); + return false; + } + ok = DllUnregisterServer() == S_OK; + } + return ok; +} + +static HRESULT dumpIdl(const QString &input, const QString &idlfile, const QString &version) +{ + HRESULT res = E_FAIL; + + if (input.endsWith(QLatin1String(".exe"))) { + if (runWithQtInEnvironment(quotePath(input) + QLatin1String(" -dumpidl ") + idlfile + QLatin1String(" -version ") + version)) + res = S_OK; + } else { + HMODULE hdll = 0; + QT_WA({ + hdll = LoadLibraryW((TCHAR*)input.utf16()); + }, { + hdll = LoadLibraryA(input.toLocal8Bit()); + }); + if (!hdll) { + fprintf(stderr, "Couldn't load library file %s\n", (const char*)input.toLocal8Bit().data()); + return 3; + } + typedef HRESULT(__stdcall* DumpIDLProc)(const QString&, const QString&); + DumpIDLProc DumpIDL = (DumpIDLProc)GetProcAddress(hdll, "DumpIDL"); + if (!DumpIDL) { + fprintf(stderr, "Couldn't resolve 'DumpIDL' symbol in %s\n", (const char*)input.toLocal8Bit().data()); + return 3; + } + res = DumpIDL(idlfile, version); + FreeLibrary(hdll); + } + + return res; +} + +static void slashify(QString &s) +{ + if (!s.contains(QLatin1Char('/'))) + return; + + int i = 0; + while (i < (int)s.length()) { + if (s[i] == QLatin1Char('/')) + s[i] = QLatin1Char('\\'); + ++i; + } +} + +int runIdc(int argc, char **argv) +{ + QString error; + QString tlbfile; + QString idlfile; + QString input; + QString version = QLatin1String("1.0"); + + int i = 1; + while (i < argc) { + QString p = QString::fromLocal8Bit(argv[i]).toLower(); + + if (p == QLatin1String("/idl") || p == QLatin1String("-idl")) { + ++i; + if (i > argc) { + error = QLatin1String("Missing name for interface definition file!"); + break; + } + idlfile = QLatin1String(argv[i]); + idlfile = idlfile.trimmed().toLower(); + } else if (p == QLatin1String("/version") || p == QLatin1String("-version")) { + ++i; + if (i > argc) + version = QLatin1String("1.0"); + else + version = QLatin1String(argv[i]); + } else if (p == QLatin1String("/tlb") || p == QLatin1String("-tlb")) { + if (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based) + fprintf(stderr, "IDC requires Windows NT/2000/XP!\n"); + + ++i; + if (i > argc) { + error = QLatin1String("Missing name for type library file!"); + break; + } + tlbfile = QLatin1String(argv[i]); + tlbfile = tlbfile.trimmed().toLower(); + } else if (p == QLatin1String("/v") || p == QLatin1String("-v")) { + fprintf(stdout, "Qt Interface Definition Compiler version 1.0\n"); + return 0; + } else if (p == QLatin1String("/regserver") || p == QLatin1String("-regserver")) { + if (!registerServer(input)) { + fprintf(stderr, "Failed to register server!\n"); + return 1; + } + fprintf(stderr, "Server registered successfully!\n"); + return 0; + } else if (p == QLatin1String("/unregserver") || p == QLatin1String("-unregserver")) { + if (!unregisterServer(input)) { + fprintf(stderr, "Failed to unregister server!\n"); + return 1; + } + fprintf(stderr, "Server unregistered successfully!\n"); + return 0; + } else if (p[0] == QLatin1Char('/') || p[0] == QLatin1Char('-')) { + error = QLatin1String("Unknown option \"") + p + QLatin1String("\""); + break; + } else { + input = QLatin1String(argv[i]); + input = input.trimmed().toLower(); + } + i++; + } + if (!error.isEmpty()) { + fprintf(stderr, "%s", error.toLatin1().data()); + fprintf(stderr, "\n"); + return 5; + } + if (input.isEmpty()) { + fprintf(stderr, "No input file specified!\n"); + return 1; + } + if (input.endsWith(QLatin1String(".exe")) && tlbfile.isEmpty() && idlfile.isEmpty()) { + fprintf(stderr, "No type output file specified!\n"); + return 2; + } + if (input.endsWith(QLatin1String(".dll")) && idlfile.isEmpty() && tlbfile.isEmpty()) { + fprintf(stderr, "No interface definition file and no type library file specified!\n"); + return 3; + } + slashify(input); + if (!tlbfile.isEmpty()) { + slashify(tlbfile); + QFile file(tlbfile); + if (!file.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Couldn't open %s for read\n", (const char*)tlbfile.toLocal8Bit().data()); + return 4; + } + QByteArray data = file.readAll(); + QString error; + bool ok = attachTypeLibrary(input, 1, data, &error); + fprintf(stderr, "%s", error.toLatin1().data()); + fprintf(stderr, "\n"); + return ok ? 0 : 4; + } else if (!idlfile.isEmpty()) { + slashify(idlfile); + idlfile = quotePath(idlfile); + fprintf(stderr, "\n\n%s\n\n", (const char*)idlfile.toLocal8Bit().data()); + quotePath(input); + HRESULT res = dumpIdl(input, idlfile, version); + + switch(res) { + case S_OK: + break; + case -1: + fprintf(stderr, "Couldn't open %s for writing!\n", (const char*)idlfile.toLocal8Bit().data()); + return res; + case 1: + fprintf(stderr, "Malformed appID value in %s!\n", (const char*)input.toLocal8Bit().data()); + return res; + case 2: + fprintf(stderr, "Malformed typeLibID value in %s!\n", (const char*)input.toLocal8Bit().data()); + return res; + case 3: + fprintf(stderr, "Class has no metaobject information (error in %s)!\n", (const char*)input.toLocal8Bit().data()); + return res; + case 4: + fprintf(stderr, "Malformed classID value in %s!\n", (const char*)input.toLocal8Bit().data()); + return res; + case 5: + fprintf(stderr, "Malformed interfaceID value in %s!\n", (const char*)input.toLocal8Bit().data()); + return res; + case 6: + fprintf(stderr, "Malformed eventsID value in %s!\n", (const char*)input.toLocal8Bit().data()); + return res; + + default: + fprintf(stderr, "Unknown error writing IDL from %s\n", (const char*)input.toLocal8Bit().data()); + return 7; + } + } + return 0; +} + +QT_END_NAMESPACE + +int main(int argc, char **argv) +{ + return QT_PREPEND_NAMESPACE(runIdc)(argc, argv); +} |