From ab3e8e80fbd81a38039c713189b0422972e0963e Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@digia.com>
Date: Tue, 3 Dec 2013 18:23:31 +0200
Subject: [PATCH] Completely bootstrap idc.

idc dynamically loads libraries depending on QtCore.dll
whose static instances can then cause clashes.

Task-number: QTBUG-35275

Change-Id: Icd219a2bb36b0a5c3927c3163e93dc07bb5317aa
Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
---
 src/tools/idc/idc.pro  |  4 +-
 src/tools/idc/main.cpp | 99 ++++++++++++++++++++++++++++++++----------
 2 files changed, 76 insertions(+), 27 deletions(-)

diff --git a/src/tools/idc/idc.pro b/src/tools/idc/idc.pro
index b9d8dee4..1898ed53 100644
--- a/src/tools/idc/idc.pro
+++ b/src/tools/idc/idc.pro
@@ -1,7 +1,5 @@
 option(host_build)
-
-QT = core
-
+CONFIG += force_bootstrap
 SOURCES = main.cpp
 
 load(qt_tool)
diff --git a/src/tools/idc/main.cpp b/src/tools/idc/main.cpp
index a28d56c4..987d829b 100644
--- a/src/tools/idc/main.cpp
+++ b/src/tools/idc/main.cpp
@@ -41,8 +41,8 @@
 
 #include <QDir>
 #include <QFile>
-#include <QProcess>
-#include <QLibraryInfo>
+#include <QDir>
+#include <QScopedArrayPointer>
 #include <qt_windows.h>
 #include <io.h>
 
@@ -70,33 +70,84 @@ static bool hasDllExtension(const QString &filePath)
     return hasFileExtension(filePath, QStringLiteral(".dll"));
 }
 
+// Prepend the Qt binary directory to PATH.
+static bool prependPath()
+{
+    enum { maxEnvironmentSize = 32767 };
+    wchar_t buffer[maxEnvironmentSize];
+    if (!GetModuleFileName(NULL, buffer, maxEnvironmentSize))
+        return false;
+    wchar_t *ptr = wcsrchr(buffer, L'\\');
+    if (!ptr)
+        return false;
+    *ptr++ = L';';
+    const wchar_t pathVariable[] = L"PATH";
+    if (!GetEnvironmentVariable(pathVariable, ptr, maxEnvironmentSize - (ptr - buffer))
+        || !SetEnvironmentVariable(pathVariable, buffer)) {
+        return false;
+    }
+    return true;
+}
+
+static QString errorString(DWORD errorCode)
+{
+    wchar_t *resultW = 0;
+    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
+                  NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                  (LPWSTR)&resultW, 0, NULL);
+    const QString result = QString::fromWCharArray(resultW);
+    LocalFree((HLOCAL)resultW);
+    return result;
+}
+
 static bool runWithQtInEnvironment(const QString &cmd)
 {
-    QProcess proc;
+    enum { timeOutMs = 30000 };
+    static const bool pathSet = prependPath();
+    if (!pathSet)
+        return false;
 
-    // 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;
-            }
-        }
-    }
+    STARTUPINFO si;
+    ZeroMemory(&si, sizeof(si));
+    si.cb = sizeof(si);
 
-    proc.setEnvironment(env);
-    proc.start(cmd);
-    proc.waitForFinished(-1);
+    STARTUPINFO myInfo;
+    GetStartupInfo(&myInfo);
+    si.hStdInput = myInfo.hStdInput;
+    si.hStdOutput = myInfo.hStdOutput;
+    si.hStdError = myInfo.hStdError;
 
-    return (proc.exitCode() == 0);
+    PROCESS_INFORMATION pi;
+    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
+
+    QScopedArrayPointer<wchar_t> commandLineW(new wchar_t[cmd.size() + 1]);
+    cmd.toWCharArray(commandLineW.data());
+    commandLineW[cmd.size()] = 0;
+    if (!CreateProcessW(0, commandLineW.data(), 0, 0, /* InheritHandles */ TRUE, 0, 0, 0, &si, &pi)) {
+        fprintf(stderr, "Unable to execute \"%s\": %s\n", qPrintable(cmd),
+                qPrintable(errorString(GetLastError())));
+        return false;
+    }
+
+    DWORD exitCode = 1;
+    switch (WaitForSingleObject(pi.hProcess, timeOutMs)) {
+    case WAIT_OBJECT_0:
+        GetExitCodeProcess(pi.hProcess, &exitCode);
+        break;
+    case WAIT_TIMEOUT:
+        fprintf(stderr, "Timed out after %d ms out waiting for \"%s\".\n",
+                int(timeOutMs), qPrintable(cmd));
+        TerminateProcess(pi.hProcess, 1);
+        break;
+    default:
+        fprintf(stderr, "Error waiting for \"%s\": %s\n",
+                qPrintable(cmd), qPrintable(errorString(GetLastError())));
+        TerminateProcess(pi.hProcess, 1);
+        break;
+    }
+    CloseHandle(pi.hThread);
+    CloseHandle(pi.hProcess);
+    return exitCode == 0;
 }
 
 static bool attachTypeLibrary(const QString &applicationName, int resource, const QByteArray &data, QString *errorMessage)
-- 
GitLab