src/tools/idc/main.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tools/idc/main.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,335 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QFile>
+#include <QProcess>
+#include <QLibraryInfo>
+#include <qt_windows.h>
+#include <io.h>
+
+QT_BEGIN_NAMESPACE
+
+static QString quotePath(const QString &s)
+{
+    if (!s.startsWith(QLatin1Char('\"')) && s.contains(QLatin1Char(' ')))
+        return QLatin1Char('\"') + s + QLatin1Char('\"');
+    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 = BeginUpdateResource((const wchar_t *)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 (!UpdateResource(hExe, L"TYPELIB", MAKEINTRESOURCE(resource), 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 = LoadLibrary((const wchar_t *)input.utf16());
+        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 = LoadLibrary((const wchar_t *)input.utf16());
+        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 = LoadLibrary((const wchar_t *)input.utf16());
+        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")) {
+            ++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 + QLatin1Char('\"');
+            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 E_FAIL:
+            fprintf(stderr, "IDL generation failed trying to run program %s!\n", (const char*)input.toLocal8Bit().data());
+            return res;
+        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);
+}