src/tools/idc/main.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the tools applications of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QFile>
       
    43 #include <QProcess>
       
    44 #include <QLibraryInfo>
       
    45 #include <qt_windows.h>
       
    46 #include <io.h>
       
    47 
       
    48 QT_BEGIN_NAMESPACE
       
    49 
       
    50 static QString quotePath(const QString &s)
       
    51 {
       
    52     if (!s.startsWith(QLatin1Char('\"')) && s.contains(QLatin1Char(' ')))
       
    53         return QLatin1Char('\"') + s + QLatin1Char('\"');
       
    54     return s;
       
    55 }
       
    56 
       
    57 
       
    58 static bool runWithQtInEnvironment(const QString &cmd)
       
    59 {
       
    60     QProcess proc;
       
    61     
       
    62     // prepend the qt binary directory to the path
       
    63     QStringList env = QProcess::systemEnvironment();
       
    64     for (int i=0; i<env.count(); ++i) {
       
    65         QString var = env.at(i);
       
    66         int setidx = var.indexOf(QLatin1Char('='));
       
    67         if (setidx != -1) {
       
    68             QString varname = var.left(setidx).trimmed().toUpper();
       
    69             if (varname == QLatin1String("PATH")) {
       
    70                 var = var.mid(setidx + 1);
       
    71                 var = QLatin1String("PATH=") + 
       
    72                     QLibraryInfo::location(QLibraryInfo::BinariesPath) +
       
    73                     QLatin1Char(';') + var;
       
    74                 env[i] = var;
       
    75                 break;
       
    76             }
       
    77         }
       
    78     }
       
    79 
       
    80     proc.setEnvironment(env);
       
    81     proc.start(cmd);
       
    82     proc.waitForFinished(-1);
       
    83     
       
    84     return (proc.exitCode() == 0);
       
    85 }
       
    86 
       
    87 static bool attachTypeLibrary(const QString &applicationName, int resource, const QByteArray &data, QString *errorMessage)
       
    88 {
       
    89     HANDLE hExe = BeginUpdateResource((const wchar_t *)applicationName.utf16(), false);
       
    90     if (hExe == 0) {
       
    91         if (errorMessage)
       
    92             *errorMessage = QString::fromLatin1("Failed to attach type library to binary %1 - could not open file.").arg(applicationName);
       
    93         return false;
       
    94     }
       
    95     if (!UpdateResource(hExe, L"TYPELIB", MAKEINTRESOURCE(resource), 0, (void*)data.data(), data.count())) {
       
    96         EndUpdateResource(hExe, true);
       
    97         if (errorMessage)
       
    98             *errorMessage = QString::fromLatin1("Failed to attach type library to binary %1 - could not update file.").arg(applicationName);
       
    99         return false;
       
   100     }
       
   101 
       
   102     if (!EndUpdateResource(hExe,false)) {
       
   103         if (errorMessage)
       
   104             *errorMessage = QString::fromLatin1("Failed to attach type library to binary %1 - could not write file.").arg(applicationName);
       
   105         return false;
       
   106     }
       
   107     
       
   108     if (errorMessage)
       
   109         *errorMessage = QString::fromLatin1("Type library attached to %1.").arg(applicationName);
       
   110     return true;
       
   111 }
       
   112 
       
   113 static bool registerServer(const QString &input)
       
   114 {
       
   115     bool ok = false;    
       
   116     if (input.endsWith(QLatin1String(".exe"))) {
       
   117         ok = runWithQtInEnvironment(quotePath(input) + QLatin1String(" -regserver"));
       
   118     } else {
       
   119         HMODULE hdll = LoadLibrary((const wchar_t *)input.utf16());
       
   120         if (!hdll) {
       
   121             fprintf(stderr, "Couldn't load library file %s\n", (const char*)input.toLocal8Bit().data());
       
   122             return false;
       
   123         }
       
   124         typedef HRESULT(__stdcall* RegServerProc)();
       
   125         RegServerProc DllRegisterServer = (RegServerProc)GetProcAddress(hdll, "DllRegisterServer");
       
   126         if (!DllRegisterServer) {
       
   127             fprintf(stderr, "Library file %s doesn't appear to be a COM library\n", (const char*)input.toLocal8Bit().data());
       
   128             return false;
       
   129         }
       
   130         ok = DllRegisterServer() == S_OK;
       
   131     }
       
   132     return ok;
       
   133 }
       
   134 
       
   135 static bool unregisterServer(const QString &input)
       
   136 {
       
   137     bool ok = false;
       
   138     if (input.endsWith(QLatin1String(".exe"))) {        
       
   139         ok = runWithQtInEnvironment(quotePath(input) + QLatin1String(" -unregserver"));
       
   140     } else {
       
   141         HMODULE hdll = LoadLibrary((const wchar_t *)input.utf16());
       
   142         if (!hdll) {
       
   143             fprintf(stderr, "Couldn't load library file %s\n", (const char*)input.toLocal8Bit().data());
       
   144             return false;
       
   145         }
       
   146         typedef HRESULT(__stdcall* RegServerProc)();
       
   147         RegServerProc DllUnregisterServer = (RegServerProc)GetProcAddress(hdll, "DllUnregisterServer");
       
   148         if (!DllUnregisterServer) {
       
   149             fprintf(stderr, "Library file %s doesn't appear to be a COM library\n", (const char*)input.toLocal8Bit().data());
       
   150             return false;
       
   151         }
       
   152         ok = DllUnregisterServer() == S_OK;
       
   153     }
       
   154     return ok;
       
   155 }
       
   156 
       
   157 static HRESULT dumpIdl(const QString &input, const QString &idlfile, const QString &version)
       
   158 {
       
   159     HRESULT res = E_FAIL;
       
   160     
       
   161     if (input.endsWith(QLatin1String(".exe"))) {
       
   162         if (runWithQtInEnvironment(quotePath(input) + QLatin1String(" -dumpidl ") + idlfile + QLatin1String(" -version ") + version))
       
   163             res = S_OK;
       
   164     } else {
       
   165         HMODULE hdll = LoadLibrary((const wchar_t *)input.utf16());
       
   166         if (!hdll) {
       
   167             fprintf(stderr, "Couldn't load library file %s\n", (const char*)input.toLocal8Bit().data());
       
   168             return 3;
       
   169         }
       
   170         typedef HRESULT(__stdcall* DumpIDLProc)(const QString&, const QString&);
       
   171         DumpIDLProc DumpIDL = (DumpIDLProc)GetProcAddress(hdll, "DumpIDL");
       
   172         if (!DumpIDL) {
       
   173             fprintf(stderr, "Couldn't resolve 'DumpIDL' symbol in %s\n", (const char*)input.toLocal8Bit().data());
       
   174             return 3;
       
   175         }
       
   176         res = DumpIDL(idlfile, version);
       
   177         FreeLibrary(hdll);
       
   178     }
       
   179     
       
   180     return res;
       
   181 }
       
   182 
       
   183 static void slashify(QString &s)
       
   184 {
       
   185     if (!s.contains(QLatin1Char('/')))
       
   186         return;
       
   187     
       
   188     int i = 0;
       
   189     while (i < (int)s.length()) {
       
   190         if (s[i] == QLatin1Char('/'))
       
   191             s[i] = QLatin1Char('\\');
       
   192         ++i;
       
   193     }
       
   194 }
       
   195 
       
   196 int runIdc(int argc, char **argv)
       
   197 {
       
   198     QString error;
       
   199     QString tlbfile;
       
   200     QString idlfile;
       
   201     QString input;
       
   202     QString version = QLatin1String("1.0");
       
   203     
       
   204     int i = 1;
       
   205     while (i < argc) {
       
   206         QString p = QString::fromLocal8Bit(argv[i]).toLower();
       
   207         
       
   208         if (p == QLatin1String("/idl") || p == QLatin1String("-idl")) {
       
   209             ++i;
       
   210             if (i > argc) {
       
   211                 error = QLatin1String("Missing name for interface definition file!");
       
   212                 break;
       
   213             }
       
   214             idlfile = QLatin1String(argv[i]);
       
   215             idlfile = idlfile.trimmed().toLower();            
       
   216         } else if (p == QLatin1String("/version") || p == QLatin1String("-version")) {
       
   217             ++i;
       
   218             if (i > argc)
       
   219                 version = QLatin1String("1.0");
       
   220             else
       
   221                 version = QLatin1String(argv[i]);
       
   222         } else if (p == QLatin1String("/tlb") || p == QLatin1String("-tlb")) {
       
   223             ++i;
       
   224             if (i > argc) {
       
   225                 error = QLatin1String("Missing name for type library file!");
       
   226                 break;
       
   227             }
       
   228             tlbfile = QLatin1String(argv[i]);
       
   229             tlbfile = tlbfile.trimmed().toLower();            
       
   230         } else if (p == QLatin1String("/v") || p == QLatin1String("-v")) {
       
   231             fprintf(stdout, "Qt Interface Definition Compiler version 1.0\n");
       
   232             return 0;
       
   233         } else if (p == QLatin1String("/regserver") || p == QLatin1String("-regserver")) {
       
   234             if (!registerServer(input)) {
       
   235                 fprintf(stderr, "Failed to register server!\n");
       
   236                 return 1;
       
   237             }
       
   238             fprintf(stderr, "Server registered successfully!\n");
       
   239             return 0;
       
   240         } else if (p == QLatin1String("/unregserver") || p == QLatin1String("-unregserver")) {
       
   241             if (!unregisterServer(input)) {
       
   242                 fprintf(stderr, "Failed to unregister server!\n");
       
   243                 return 1;
       
   244             }
       
   245             fprintf(stderr, "Server unregistered successfully!\n");
       
   246             return 0;
       
   247         } else if (p[0] == QLatin1Char('/') || p[0] == QLatin1Char('-')) {
       
   248             error = QLatin1String("Unknown option \"") + p + QLatin1Char('\"');
       
   249             break;
       
   250         } else {
       
   251             input = QLatin1String(argv[i]);
       
   252             input = input.trimmed().toLower();            
       
   253         }
       
   254         i++;
       
   255     }
       
   256     if (!error.isEmpty()) {
       
   257         fprintf(stderr, "%s", error.toLatin1().data());
       
   258         fprintf(stderr, "\n");
       
   259         return 5;
       
   260     }
       
   261     if (input.isEmpty()) {
       
   262         fprintf(stderr, "No input file specified!\n");
       
   263         return 1;
       
   264     }
       
   265     if (input.endsWith(QLatin1String(".exe")) && tlbfile.isEmpty() && idlfile.isEmpty()) {
       
   266         fprintf(stderr, "No type output file specified!\n");
       
   267         return 2;
       
   268     }
       
   269     if (input.endsWith(QLatin1String(".dll")) && idlfile.isEmpty() && tlbfile.isEmpty()) {
       
   270         fprintf(stderr, "No interface definition file and no type library file specified!\n");
       
   271         return 3;
       
   272     }
       
   273     slashify(input);
       
   274     if (!tlbfile.isEmpty()) {
       
   275         slashify(tlbfile);
       
   276         QFile file(tlbfile);
       
   277         if (!file.open(QIODevice::ReadOnly)) {
       
   278             fprintf(stderr, "Couldn't open %s for read\n", (const char*)tlbfile.toLocal8Bit().data());
       
   279             return 4;
       
   280         }
       
   281         QByteArray data = file.readAll();
       
   282         QString error;
       
   283         bool ok = attachTypeLibrary(input, 1, data, &error);
       
   284         fprintf(stderr, "%s", error.toLatin1().data());
       
   285         fprintf(stderr, "\n");
       
   286         return ok ? 0 : 4;
       
   287     } else if (!idlfile.isEmpty()) {
       
   288         slashify(idlfile);
       
   289         idlfile = quotePath(idlfile);
       
   290         fprintf(stderr, "\n\n%s\n\n", (const char*)idlfile.toLocal8Bit().data());
       
   291         quotePath(input);
       
   292         HRESULT res = dumpIdl(input, idlfile, version);
       
   293         
       
   294         switch(res) {
       
   295         case S_OK:
       
   296             break;
       
   297         case E_FAIL:
       
   298             fprintf(stderr, "IDL generation failed trying to run program %s!\n", (const char*)input.toLocal8Bit().data());
       
   299             return res;
       
   300         case -1:
       
   301             fprintf(stderr, "Couldn't open %s for writing!\n", (const char*)idlfile.toLocal8Bit().data());
       
   302             return res;
       
   303         case 1:
       
   304             fprintf(stderr, "Malformed appID value in %s!\n", (const char*)input.toLocal8Bit().data());
       
   305             return res;
       
   306         case 2:
       
   307             fprintf(stderr, "Malformed typeLibID value in %s!\n", (const char*)input.toLocal8Bit().data());
       
   308             return res;
       
   309         case 3:
       
   310             fprintf(stderr, "Class has no metaobject information (error in %s)!\n", (const char*)input.toLocal8Bit().data());
       
   311             return res;
       
   312         case 4:
       
   313             fprintf(stderr, "Malformed classID value in %s!\n", (const char*)input.toLocal8Bit().data());
       
   314             return res;
       
   315         case 5:
       
   316             fprintf(stderr, "Malformed interfaceID value in %s!\n", (const char*)input.toLocal8Bit().data());
       
   317             return res;
       
   318         case 6:
       
   319             fprintf(stderr, "Malformed eventsID value in %s!\n", (const char*)input.toLocal8Bit().data());
       
   320             return res;
       
   321             
       
   322         default:
       
   323             fprintf(stderr, "Unknown error writing IDL from %s\n", (const char*)input.toLocal8Bit().data());
       
   324             return 7;
       
   325         }
       
   326     }
       
   327     return 0;
       
   328 }
       
   329 
       
   330 QT_END_NAMESPACE
       
   331 
       
   332 int main(int argc, char **argv)
       
   333 {
       
   334     return QT_PREPEND_NAMESPACE(runIdc)(argc, argv);
       
   335 }