diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp
index e79d9dfdb5e952b78f74ee83eef32f53e593675e..a7d60ad7fe7a81b980f30ecf7772a15735c25a23 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp
@@ -594,21 +594,7 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6
     // Clear any saved breakpoints and set initial breakpoints
     m_engine->executeDebuggerCommand(QLatin1String("bc"));
     if (m_debuggerManagerAccess->breakHandler()->hasPendingBreakpoints())
-        m_engine->attemptBreakpointSynchronization();    
-    // At any event, we want a temporary breakpoint at main() to load
-    // the dumpers.
-    if (m_dumper->state() == CdbDumperHelper::NotLoaded) {
-        if (!hasBreakPointAtMain(m_debuggerManagerAccess->breakHandler())) {
-            QString errorMessage;
-            CDBBreakPoint mainBP;
-            // Do not resolve at this point in the rare event someone
-            // has main in a module
-            mainBP.funcName = QLatin1String("main");            
-            mainBP.oneShot = true;
-            if (!mainBP.add(m_cif.debugControl, &errorMessage))
-                m_debuggerManagerAccess->showQtDumperLibraryWarning(errorMessage);
-        }
-    }
+        m_engine->attemptBreakpointSynchronization();        
 }
 
 void CdbDebugEngine::processTerminated(unsigned long exitCode)
@@ -1356,6 +1342,12 @@ void CdbDebugEngine::slotConsoleStubTerminated()
     exitDebugger();
 }
 
+void CdbDebugEnginePrivate::notifyCrashed()
+{
+    // Cannot go over crash point to execute calls.
+    m_dumper->disable();
+}
+
 void CdbDebugEnginePrivate::handleDebugEvent()
 {
     if (debugCDB)
@@ -1367,18 +1359,9 @@ void CdbDebugEnginePrivate::handleDebugEvent()
 
     switch (mode) {
     case BreakEventHandle:
-    case BreakEventMain:
-        if (mode == BreakEventMain)
-            m_dumper->load(m_debuggerManager);
         m_debuggerManagerAccess->notifyInferiorStopped();
         updateThreadList();
-        updateStackTrace();
-        break;
-    case BreakEventMainLoadDumpers:
-        // Temp stop to load dumpers    
-        m_dumper->load(m_debuggerManager);
-        m_engine->startWatchTimer();
-        continueInferiorProcess();
+        updateStackTrace();          
         break;
     case BreakEventIgnoreOnce:
         m_engine->startWatchTimer();
@@ -1492,6 +1475,7 @@ void CdbDebugEnginePrivate::handleModuleLoad(const QString &name)
 {
     if (debugCDB>2)
         qDebug() << Q_FUNC_INFO << "\n    " << name;
+    m_dumper->moduleLoadHook(name, m_hDebuggeeProcess);
     updateModules();
 }
 
@@ -1500,17 +1484,6 @@ void CdbDebugEnginePrivate::handleBreakpointEvent(PDEBUG_BREAKPOINT2 pBP)
     Q_UNUSED(pBP)
     if (debugCDB)
         qDebug() << Q_FUNC_INFO;
-    // Did we hit main() and did the user want that or is that just
-    // our internal BP to load the dumpers?
-    QString errorMessage;
-    CDBBreakPoint bp;
-    if (bp.retrieve(pBP, &errorMessage) && !bp.funcName.isEmpty()) {
-        if (bp.funcName == QLatin1String("main") || bp.funcName.endsWith(QLatin1String("!main"))) {
-            m_breakEventMode = bp.oneShot ? BreakEventMainLoadDumpers : BreakEventMain;
-        }
-        if (debugCDB)
-            qDebug() << bp << " b-mode=" << m_breakEventMode;
-    }
 }
 
 void CdbDebugEngine::reloadSourceFiles()
diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h
index 04636a72167dc0e92123fac421fd14676014e7ba..373257bd8f411ea28c6b6c0bd264173fd471027a 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine_p.h
+++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h
@@ -98,10 +98,6 @@ struct CdbDebugEnginePrivate
     enum HandleBreakEventMode { // Special modes for break event handler.
         BreakEventHandle,
         BreakEventIgnoreOnce,
-        // We hit main (and the user intended it)
-        BreakEventMain,
-        // We hit main (and the user did not intend it, just load dumpers)
-        BreakEventMainLoadDumpers,
         BreakEventSyncBreakPoints,
     };
 
@@ -134,6 +130,7 @@ struct CdbDebugEnginePrivate
     bool continueInferior(QString *errorMessage);
 
     bool attemptBreakpointSynchronization(QString *errorMessage);
+    void notifyCrashed();
 
     static bool executeDebuggerCommand(CIDebugControl *ctrl, const QString &command, QString *errorMessage);
     static bool evaluateExpression(CIDebugControl *ctrl, const QString &expression, DEBUG_VALUE *v, QString *errorMessage);
diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
index 07eab3215e017a6a253b49cef4167e9b1b4ee6d0..42e48b3dc9148a65aab16f3eda4915040e9b1488 100644
--- a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
@@ -300,7 +300,7 @@ void formatException(const EXCEPTION_RECORD64 *e, QTextStream &str)
         str << "attempt to continue execution after noncontinuable exception";
         break;
     case EXCEPTION_PRIV_INSTRUCTION:
-        str << "priviledged instruction";
+        str << "privileged instruction";
         break;
     case EXCEPTION_SINGLE_STEP:
         str << "single step";
@@ -336,6 +336,19 @@ void formatException(const EXCEPTION_RECORD64 *e,
     }
 }
 
+static bool isFatalException(LONG code)
+{
+    switch (code) {
+    case EXCEPTION_BREAKPOINT:
+    case EXCEPTION_SINGLE_STEP:
+    case 0x406d1388: // Mysterious exception at start of application
+        return false;
+    default:
+        break;
+    }
+    return true;
+}
+
 STDMETHODIMP CdbDebugEventCallback::Exception(
     THIS_
     __in PEXCEPTION_RECORD64 Exception,
@@ -347,9 +360,12 @@ STDMETHODIMP CdbDebugEventCallback::Exception(
         QTextStream str(&msg);
         formatException(Exception, m_pEngine->m_d->m_dumper, str);
     }
+    const bool fatal = isFatalException(Exception->ExceptionCode);
     if (debugCDB)
-        qDebug() << Q_FUNC_INFO << '\n' << msg;
+        qDebug() << Q_FUNC_INFO << '\n' << fatal << msg;
     m_pEngine->m_d->m_debuggerManagerAccess->showApplicationOutput(msg);
+    if (fatal)
+        m_pEngine->m_d->notifyCrashed();
     return S_OK;
 }
 
diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.cpp b/src/plugins/debugger/cdb/cdbdumperhelper.cpp
index 3f4ffdab8fd98e8df8241c96408d194109c22fcd..541aa7ea1d0615303b4e67a295364b60ac74a89c 100644
--- a/src/plugins/debugger/cdb/cdbdumperhelper.cpp
+++ b/src/plugins/debugger/cdb/cdbdumperhelper.cpp
@@ -35,6 +35,8 @@
 #include "cdbsymbolgroupcontext.h"
 #include "watchhandler.h"
 
+#include "sharedlibraryinjector.h"
+
 #include <QtCore/QRegExp>
 #include <QtCore/QCoreApplication>
 #include <QtCore/QTextStream>
@@ -45,9 +47,47 @@ static const char *dumperModuleNameC = "gdbmacros";
 static const char *qtCoreModuleNameC = "QtCore";
 static const ULONG waitTimeOutMS = 30000;
 static const char *dumperPrefixC  = "dumper:";
+
+/* Loading the dumpers is 2 step process:
+ * 1) The library must be loaded into the debuggee, for which there are
+ *    2 approaches:
+ *     - Injection loading using the SharedLibraryInjector which
+ *       launches a remote thread in the debuggee which loads the
+ *       library. Drawbacks:
+ *       * The remote thread must not starve.
+ *       * It is not possible to wait loading and loading occurs late,
+ *         after entering main()
+ *     - Debugger Call loading, which has the debuggee execute
+ *       a LoadLibrary call via debugger commands. Drawbacks:
+ *       * Slow
+ *       * Requires presence of a symbol of the same prototype as
+ *         LoadLibraryA as the original prototype is not sufficient.
+ * 2) Call a query function  (protocol 1 of the dumper) to obtain a list
+ *    of handled types and a map of known sizes.
+ *
+ * The class currently launches injection loading from the module
+ * load hook as soon as it sees a Qt module.
+ * The dumpType() function performs the rest of the [delayed] initialization.
+ * If the load has not finished, it attempts call loading and
+ * executes the initial query protocol.
+ *
+ * Note: The main technique here is having the debuggee call functions
+ * using the .call command (which takes a function with a known
+ * prototype and simple, integer parameters).
+ * This does not work from an IDebugEvent callback, as it will cause
+ * WaitForEvent() to fail with unknown errors.
+ * It mostly works from breakpoints, with the addditional restriction
+ * that complex functions only work from 'well-defined'  breakpoints
+ * (such as main()) and otherwise cause access violation exceptions
+ * (for example LoadLibrary).
+ * Exceptions occuring in the functions to be called must be handled
+ * by __try/__except (they show up in the debugger and must acknowledged
+ * by gN (go not handled).  */
+
 namespace Debugger {
 namespace Internal {
 
+// ------- Call load helpers
 // Alloc memory in debuggee using the ".dvalloc" command as
 // there seems to be no API for it.
 static bool allocDebuggeeMemory(CdbComInterfaces *cif,
@@ -144,13 +184,44 @@ static bool debuggeeLoadLibrary(IDebuggerManagerAccessForEngines *access,
     return true;
 }
 
+// ---- Load messages
+static inline QString msgMethod(bool injectOrCall)
+{
+    return injectOrCall ?
+            QCoreApplication::translate("CdbDumperHelper", "injection") :
+            QCoreApplication::translate("CdbDumperHelper", "debugger call");
+}
+
+static QString msgLoading(const QString &library, bool injectOrCall)
+{
+    return QCoreApplication::translate("CdbDumperHelper",
+                                       "Loading the custom dumper library '%1' (%2) ...").
+                                       arg(library, msgMethod(injectOrCall));
+}
+
+static QString msgLoadFailed(const QString &library, bool injectOrCall, const QString &why)
+{
+    return QCoreApplication::translate("CdbDumperHelper",
+                                       "Loading of the custom dumper library '%1' (%2) failed: %3").
+                                       arg(library, msgMethod(injectOrCall), why);
+}
+
+static QString msgLoadSucceeded(const QString &library, bool injectOrCall)
+{
+        return QCoreApplication::translate("CdbDumperHelper",
+                                       "Loaded the custom dumper library '%1' (%2).").
+                                       arg(library, msgMethod(injectOrCall));
+}
+
 // ------------------- CdbDumperHelper
 
-CdbDumperHelper::CdbDumperHelper(IDebuggerManagerAccessForEngines *access,
+CdbDumperHelper::CdbDumperHelper(DebuggerManager *manager,
                                  CdbComInterfaces *cif) :
+    m_tryInjectLoad(true),
     m_messagePrefix(QLatin1String(dumperPrefixC)),
     m_state(NotLoaded),
-    m_access(access),
+    m_manager(manager),
+    m_access(manager),
     m_cif(cif),
     m_inBufferAddress(0),
     m_inBufferSize(0),
@@ -165,6 +236,14 @@ CdbDumperHelper::~CdbDumperHelper()
     clearBuffer();
 }
 
+void CdbDumperHelper::disable()
+{
+    if (loadDebug)
+        qDebug() << Q_FUNC_INFO;
+    m_access->showDebuggerOutput(m_messagePrefix, QCoreApplication::translate("CdbDumperHelper", "Disabling dumpers due to debuggee crash..."));
+    m_state = Disabled;
+}
+
 void CdbDumperHelper::clearBuffer()
 {
     if (m_buffer) {
@@ -175,6 +254,8 @@ void CdbDumperHelper::clearBuffer()
 
 void CdbDumperHelper::reset(const QString &library, bool enabled)
 {
+     if (loadDebug)
+        qDebug() << Q_FUNC_INFO << '\n' << library << enabled;
     m_library = library;
     m_state = enabled ? NotLoaded : Disabled;
     m_dumpObjectSymbol = QLatin1String("qDumpObjectData440");
@@ -185,63 +266,113 @@ void CdbDumperHelper::reset(const QString &library, bool enabled)
     clearBuffer();
 }
 
-// Attempt to load and initialize dumpers, give feedback
-// to user.
-void CdbDumperHelper::load(DebuggerManager *manager)
+void CdbDumperHelper::moduleLoadHook(const QString &module, HANDLE debuggeeHandle)
 {
-    enum Result { Failed, Succeeded, NoQtApp };
-
-    if (m_state != NotLoaded)
-        return;
-    manager->showStatusMessage(QCoreApplication::translate("CdbDumperHelper", "Loading dumpers..."), 10000);
-    QString message;
-    Result result = Failed;
-    do {
-        // Do we have Qt and are we already loaded by accident?
-        QStringList modules;
-        if (!getModuleNameList(m_cif->debugSymbols, &modules, &message))
-            break;
-        if (modules.filter(QLatin1String(qtCoreModuleNameC)).isEmpty()) {
-            message = QCoreApplication::translate("CdbDumperHelper", "The debugger does not appear to be Qt application.");
-            result = NoQtApp;
-        }
-        // Make sure the dumper lib is loaded.
-        if (modules.filter(QLatin1String(dumperModuleNameC), Qt::CaseInsensitive).isEmpty()) {
-            // Try to load
-            if (!debuggeeLoadLibrary(m_access, m_cif, m_library, &message)) {
-                break;
+    if (loadDebug > 1)
+        qDebug() << "moduleLoadHook" << module << m_state << debuggeeHandle;
+    switch (m_state) {
+    case Disabled:
+    case Initialized:
+        break;
+    case NotLoaded:
+        // Try an inject load as soon as a Qt lib is loaded.
+        // for the thread to finish as this would lock up.
+        if (m_tryInjectLoad && module.contains(QLatin1String("Qt"), Qt::CaseInsensitive)) {
+            // Also shows up in the log window.
+            m_manager->showStatusMessage(msgLoading(m_library, true), 10000);
+            QString errorMessage;            
+            SharedLibraryInjector sh(GetProcessId(debuggeeHandle));
+            if (sh.remoteInject(m_library, false, &errorMessage)) {
+                m_state = InjectLoading;
+            } else {
+                m_state = InjectLoadFailed;
+                // Ok, try call loading...
+                m_access->showDebuggerOutput(m_messagePrefix, msgLoadFailed(m_library, true, errorMessage));
             }
-        } else {
-            m_access->showDebuggerOutput(m_messagePrefix, QCoreApplication::translate("CdbDumperHelper", "The dumper module appears to be already loaded."));
         }
-        // Resolve symbols and do call to get types
-        if (!resolveSymbols(&message))
-            break;
-        if (!getKnownTypes(&message))
-            break;
-        message = QCoreApplication::translate("CdbDumperHelper", "Dumper library '%1' loaded.").arg(m_library);
-        result = Succeeded;
-    } while (false);
-    // eval state and notify user
-    switch (result) {
-    case Failed:
-        message = QCoreApplication::translate("CdbDumperHelper", "The dumper library '%1' could not be loaded:\n%2").arg(m_library, message);
-        m_access->showDebuggerOutput(m_messagePrefix, message);
-        m_access->showQtDumperLibraryWarning(message);
-        m_state = Disabled;
-        break;
-    case Succeeded:
-        m_access->showDebuggerOutput(m_messagePrefix, message);
-        m_access->showDebuggerOutput(m_messagePrefix, m_helper.toString());
-        m_state = Loaded;
         break;
-    case NoQtApp:
-        m_access->showDebuggerOutput(m_messagePrefix, message);
-        m_state = Disabled;
+    case InjectLoading:
+        // check if gdbmacros.dll loaded
+        if (module.contains(QLatin1String(dumperModuleNameC), Qt::CaseInsensitive)) {
+            m_state = Loaded;
+            m_access->showDebuggerOutput(m_messagePrefix, msgLoadSucceeded(m_library, true));
+        }
         break;
-    }    
+    }
+}
+
+// Try to load dumpers by triggering calls using the debugger
+CdbDumperHelper::CallLoadResult CdbDumperHelper::initCallLoad(QString *errorMessage)
+{
     if (loadDebug)
-        qDebug() << Q_FUNC_INFO << "\n<" << result << '>' << m_state << message;
+        qDebug() << Q_FUNC_INFO;
+    // Do we have Qt and are we already loaded by accident?
+    QStringList modules;
+    if (!getModuleNameList(m_cif->debugSymbols, &modules, errorMessage))
+        return CallLoadError;
+    // Are we already loaded by some accident?
+    if (!modules.filter(QLatin1String(dumperModuleNameC), Qt::CaseInsensitive).isEmpty())
+        return CallLoadAlreadyLoaded;
+    // Is that Qt application at all?
+    if (modules.filter(QLatin1String(qtCoreModuleNameC), Qt::CaseInsensitive).isEmpty())
+        return CallLoadNoQtApp;
+    // Try to load
+    if (!debuggeeLoadLibrary(m_access, m_cif, m_library, errorMessage))
+        return CallLoadError;
+    return CallLoadOk;
+}
+
+bool CdbDumperHelper::ensureInitialized(QString *errorMessage)
+{
+    if (loadDebug)
+        qDebug() << Q_FUNC_INFO << '\n' << m_state;
+
+    switch (m_state) {
+    case Disabled:
+        *errorMessage = QLatin1String("Internal error, attempt to call disabled dumper");
+        return false;
+    case Initialized:
+        return true;
+        // Injection load failed or disabled: Try a call load.
+    case NotLoaded:
+    case InjectLoading:
+    case InjectLoadFailed:
+        // Also shows up in the log window.
+        m_manager->showStatusMessage(msgLoading(m_library, false), 10000);
+        switch (initCallLoad(errorMessage)) {
+            case CallLoadOk:
+            case CallLoadAlreadyLoaded:
+                m_access->showDebuggerOutput(m_messagePrefix, msgLoadSucceeded(m_library, false));
+                m_state = Loaded;
+                break;
+            case CallLoadError:
+                *errorMessage = msgLoadFailed(m_library, false, *errorMessage);
+                m_access->showDebuggerOutput(m_messagePrefix, *errorMessage);
+                m_access->showQtDumperLibraryWarning(*errorMessage);
+                return false;
+            case CallLoadNoQtApp:
+                m_access->showDebuggerOutput(m_messagePrefix, QCoreApplication::translate("CdbDumperHelper", "The debuggee does not appear to be Qt application."));
+                disable();
+                return true;
+            }
+        break;
+    case Loaded: // Injection load succeeded, ideally
+        break;
+    }
+    // Perform remaining initialization
+    m_manager->showStatusMessage(QCoreApplication::translate("CdbDumperHelper", "Initializing dumpers..."), 10000);
+    const bool ok = initResolveSymbols(errorMessage) && initKnownTypes(errorMessage);
+    if (ok) {
+        m_access->showDebuggerOutput(m_messagePrefix, QCoreApplication::translate("CdbDumperHelper", "Custom dumper library initialized."));
+        m_access->showDebuggerOutput(m_messagePrefix, m_helper.toString());
+        m_state = Initialized;
+    } else {
+        disable();
+        *errorMessage = QCoreApplication::translate("CdbDumperHelper", "The custom dumper library could not be initialized: %1").arg(*errorMessage);
+        m_access->showDebuggerOutput(m_messagePrefix, *errorMessage);
+        m_access->showQtDumperLibraryWarning(*errorMessage);
+    }
+    return ok;
 }
 
 // Retrieve address and optionally size of a symbol.
@@ -275,7 +406,7 @@ static inline bool getSymbolAddress(CIDebugSymbols *sg,
     return true;
 }
 
-bool CdbDumperHelper::resolveSymbols(QString *errorMessage)
+bool CdbDumperHelper::initResolveSymbols(QString *errorMessage)
 {    
     // Resolve the symbols we need (potentially namespaced).
     // There is a 'qDumpInBuffer' in QtCore as well.
@@ -302,7 +433,8 @@ bool CdbDumperHelper::resolveSymbols(QString *errorMessage)
     return true;
 }
 
-bool CdbDumperHelper::getKnownTypes(QString *errorMessage)
+// Call query protocol to retrieve known types and sizes
+bool CdbDumperHelper::initKnownTypes(QString *errorMessage)
 {
     QByteArray output;
     QString callCmd;
@@ -398,15 +530,29 @@ bool CdbDumperHelper::callDumper(const QString &callCmd, const QByteArray &inBuf
     return true;
 }
 
+static inline QString msgDumpFailed(const WatchData &wd, const QString *why)
+{
+    return QString::fromLatin1("Unable to dump '%1' (%2): %3").arg(wd.name, wd.type, *why);
+}
+
 CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool dumpChildren, int source,
                                                       QList<WatchData> *result, QString *errorMessage)
 {
     // Check failure cache and supported types
-    if (m_failedTypes.contains(wd.type))
+    if (m_state == Disabled || m_failedTypes.contains(wd.type))
         return DumpNotHandled;
+
+    // Ensure types are parsed and known.
+    if (!ensureInitialized(errorMessage)) {
+        *errorMessage = msgDumpFailed(wd, errorMessage);
+        m_access->showDebuggerOutput(m_messagePrefix, *errorMessage);
+        return DumpError;
+    }
+
+    // Known type?
     const QtDumperHelper::TypeData td = m_helper.typeData(wd.type);    
     if (loadDebug)
-        qDebug() << wd.type << td;
+        qDebug() << "dumpType" << wd.type << td;
     if (td.type == QtDumperHelper::UnknownType)
         return DumpNotHandled;
 
@@ -415,6 +561,7 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool
                                                         "Querying dumpers for '%1'/'%2' (%3)").
                                                         arg(wd.name, wd.exp, wd.type);
     m_access->showDebuggerOutput(m_messagePrefix, message);
+
     const DumpExecuteResult der = executeDump(wd, td, dumpChildren, source, result, errorMessage);
     if (der == DumpExecuteOk)
         return DumpOk;
@@ -424,7 +571,7 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool
     if (der == DumpExecuteSizeFailed)
         m_failedTypes.push_back(wd.type);    
     // log error
-    *errorMessage = QString::fromLatin1("Unable to dump '%1' (%2): %3").arg(wd.name, wd.type, *errorMessage);
+    *errorMessage = *errorMessage = msgDumpFailed(wd, errorMessage);
     m_access->showDebuggerOutput(m_messagePrefix, *errorMessage);
     return DumpError;
 }
diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.h b/src/plugins/debugger/cdb/cdbdumperhelper.h
index 9500d4d4e01c10e046535badfec348d73aed717b..8ff890630d15b04852e1819b3fac22b2f218dac8 100644
--- a/src/plugins/debugger/cdb/cdbdumperhelper.h
+++ b/src/plugins/debugger/cdb/cdbdumperhelper.h
@@ -46,54 +46,64 @@ class DebuggerManager;
 /* For code clarity, all the stuff related to custom dumpers goes here.
  * "Custom dumper" is a library compiled against the current
  * Qt containing functions to evaluate values of Qt classes
- * (such as QString, taking pointers to their addresses).
- * The library must be loaded into the debuggee.
- * Loading the dumpers requires making the debuggee call functions
- * (LoadLibrary() and the dumper functions). This only works if the
- * debuggee is in a 'well-defined' breakpoint state (such as at 'main()').
- * Calling the load functions from an IDebugEvent callback causes
- * WaitForEvent() to fail with unknown errors. Calling the load functions from an
- * non 'well-defined' (arbitrary) breakpoint state will cause LoadLibrary
- * to trigger an access violations.
- * Currently, we call the load function when stopping at 'main()' for which
- * we set a temporary break point if the user does not want to stop there. */
+ * (such as QString), taking pointers to their addresses.
+ * The dumper functions produce formatted string output which is
+ * converted into WatchData items with the help of QtDumperHelper.
+ *
+ * Usage: When launching the debugger, call reset() with path to dumpers
+ * and enabled flag. From the module load event callback, call
+ * moduleLoadHook() to initialize.
+ * dumpType() is the main query function to obtain a list  of WatchData from
+ * WatchData item produced by the smbol context.
+ * Call disable(), should the debuggee crash (as performing debuggee
+ * calls is no longer possible, then).*/
 
 class CdbDumperHelper
 {
     Q_DISABLE_COPY(CdbDumperHelper)
 public:
    enum State {
-        Disabled,
+        Disabled, // Disabled or failed
         NotLoaded,
+        InjectLoadFailed,
+        InjectLoading,
         Loaded,
-        Failed
+        Initialized, // List of types, etc. retrieved
     };
 
-    explicit CdbDumperHelper(IDebuggerManagerAccessForEngines *access,
+    explicit CdbDumperHelper(DebuggerManager *manager,
                              CdbComInterfaces *cif);
     ~CdbDumperHelper();
 
-    State state() const { return m_state; }
-    operator bool() const { return m_state == Loaded; }
+    State state() const    { return m_state; }
+    bool isEnabled() const { return m_state != Disabled; }
+
+    // Disable in case of a debuggee crash.
+    void disable();
 
     // Call before starting the debugger
     void reset(const QString &library, bool enabled);
 
-    // Call in a temporary breakpoint state to actually load.
-    void load(DebuggerManager *manager);
+    // Call from the module load callback to perform initialization.
+    void moduleLoadHook(const QString &module, HANDLE debuggeeHandle);
 
+    // Dump a WatchData item.
     enum DumpResult { DumpNotHandled, DumpOk, DumpError };
     DumpResult dumpType(const WatchData &d, bool dumpChildren, int source,
                         QList<WatchData> *result, QString *errorMessage);
 
-    // bool handlesType(const QString &typeName) const;
-
     inline CdbComInterfaces *comInterfaces() const { return m_cif; }
 
 private:
+    enum CallLoadResult { CallLoadOk, CallLoadError, CallLoadNoQtApp, CallLoadAlreadyLoaded };
+
     void clearBuffer();
-    bool resolveSymbols(QString *errorMessage);
-    bool getKnownTypes(QString *errorMessage);
+
+    bool ensureInitialized(QString *errorMessage);
+    CallLoadResult initCallLoad(QString *errorMessage);
+    bool initResolveSymbols(QString *errorMessage);
+    bool initKnownTypes(QString *errorMessage);
+
     bool getTypeSize(const QString &typeName, int *size, QString *errorMessage);
     bool runTypeSizeQuery(const QString &typeName, int *size, QString *errorMessage);
     bool callDumper(const QString &call, const QByteArray &inBuffer, const char **outputPtr, QString *errorMessage);
@@ -105,8 +115,10 @@ private:
 
     static bool writeToDebuggee(CIDebugDataSpaces *ds, const QByteArray &buffer, quint64 address, QString *errorMessage);
 
+    const bool m_tryInjectLoad;
     const QString m_messagePrefix;
     State m_state;
+    DebuggerManager *m_manager;
     IDebuggerManagerAccessForEngines *m_access;
     CdbComInterfaces *m_cif;
 
diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
index be04856ccc08eae66127acfbb3d1b54d318c2606..fd59bd0fa6be95d4ca2d4d2a2b787783f8c1168a 100644
--- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp
+++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
@@ -117,8 +117,7 @@ WatchHandlerSorterInserter &WatchHandlerSorterInserter::operator=(WatchData wd)
 // -----------CdbStackFrameContext
 CdbStackFrameContext::CdbStackFrameContext(const QSharedPointer<CdbDumperHelper> &dumper,
                                            CdbSymbolGroupContext *symbolContext) :
-        m_useDumpers(dumper->state() == CdbDumperHelper::Loaded
-                     && theDebuggerBoolSetting(UseDebuggingHelpers)),
+        m_useDumpers(dumper->isEnabled() && theDebuggerBoolSetting(UseDebuggingHelpers)),
         m_dumper(dumper),
         m_symbolContext(symbolContext)
 {
diff --git a/src/plugins/debugger/win/sharedlibraryinjector.cpp b/src/plugins/debugger/win/sharedlibraryinjector.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..628263d3e15239b194956548c6c997f4526b4fa3
--- /dev/null
+++ b/src/plugins/debugger/win/sharedlibraryinjector.cpp
@@ -0,0 +1,479 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+//
+// WinANSI - An ANSI implementation for the modern Windows
+//
+// Copyright (C) 2008- Marius Storm-Olsen <mstormo@gmail.com>
+//
+// Based on work by Robert Kuster in article
+//   http://software.rkuster.com/articles/winspy.htm
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+// -------------------------------------------------------------------------------------------------
+
+#include "sharedlibraryinjector.h"
+#include <utils/winutils.h>
+
+#include <QtCore/QDebug>
+
+enum { debug = 0 };
+
+static QString msgFuncFailed(const char *f, unsigned long error)
+{
+    return QString::fromLatin1("%1 failed: %2").arg(QLatin1String(f), Core::Utils::winErrorMessage(error));
+}
+
+// Resolve a symbol from a library handle
+template <class SymbolType>
+inline bool resolveSymbol(const char *libraryName, HMODULE libraryHandle, const char *symbolName, SymbolType *s, QString *errorMessage)
+{
+    *s = 0;
+    void *vs = ::GetProcAddress(libraryHandle, symbolName);
+    if (vs == 0) {
+        *errorMessage = QString::fromLatin1("Unable to resolve '%2' in '%1'.").arg(QString::fromAscii(symbolName), QString::fromAscii(libraryName));
+        return false;
+    }
+    *s = reinterpret_cast<SymbolType>(vs);
+    return true;
+}
+
+// Resolve a symbol from a library
+template <class SymbolType>
+inline bool resolveSymbol(const char *library, const char *symbolName, SymbolType *s, QString *errorMessage)
+{
+    *s = 0;
+    const HMODULE hm = ::GetModuleHandleA(library);
+    if (hm == NULL) {
+        *errorMessage = QString::fromLatin1("Module '%1' does not exist.").arg(QString::fromAscii(library));
+        return false;
+    }
+    return resolveSymbol(library, hm , symbolName, s, errorMessage);
+}
+
+
+namespace Debugger {
+namespace Internal {
+
+SharedLibraryInjector::SharedLibraryInjector(unsigned long processId,
+                                             unsigned long threadId) :
+    m_processId(processId),
+    m_threadId(threadId),
+    m_hasEscalatedPrivileges(false)
+{
+}
+
+SharedLibraryInjector::~SharedLibraryInjector()
+{
+}
+
+void SharedLibraryInjector::setPid(unsigned long pid)
+{
+    m_processId = pid;
+}
+
+void SharedLibraryInjector::setThreadId(unsigned long tid)
+{
+    m_threadId  = tid;
+}
+
+void SharedLibraryInjector::setModulePath(const QString &modulePath)
+{
+    m_modulePath = modulePath;
+}
+
+bool SharedLibraryInjector::remoteInject(const QString &modulePath,
+                                         bool waitForThread, QString *errorMessage)
+{
+    setModulePath(modulePath);
+    return doRemoteInjection(m_processId, NULL, m_modulePath, waitForThread, errorMessage);
+}
+
+bool SharedLibraryInjector::stubInject(const QString &modulePath, unsigned long entryPoint, QString *errorMessage)
+{
+    setModulePath(modulePath);
+    return doStubInjection(m_processId, m_modulePath, entryPoint, errorMessage);
+}
+
+bool SharedLibraryInjector::unload(HMODULE hFreeModule, QString *errorMessage)
+{
+    return doRemoteInjection(m_processId, hFreeModule, QString(), true, errorMessage);  // Always use remote thread to unload
+}
+
+bool SharedLibraryInjector::unload(const QString &modulePath, QString *errorMessage)
+{
+    const HMODULE hMod = modulePath.isEmpty() ?
+                         findModuleHandle(m_modulePath, errorMessage) :
+                         findModuleHandle(modulePath, errorMessage);
+    if (!hMod)
+        return false;
+
+    return doRemoteInjection(m_processId, hMod, NULL, true, errorMessage); // Always use remote thread to unload
+}
+
+bool SharedLibraryInjector::hasLoaded(const QString &modulePath)
+{
+    QString errorMessage;
+    return findModuleHandle(modulePath.isEmpty() ? m_modulePath : modulePath, &errorMessage) != NULL;
+}
+
+QString SharedLibraryInjector::findModule(const QString &moduleName)
+{
+    const TCHAR *moduleNameC = moduleName.utf16();
+    if (GetFileAttributesW(moduleNameC) != INVALID_FILE_ATTRIBUTES)
+        return moduleName;
+
+    TCHAR testpathC[MAX_PATH];
+    // Check application path first
+    GetModuleFileNameW(NULL, testpathC, MAX_PATH);
+    QString testPath = QString::fromUtf16(testpathC);
+    const int lastSlash = testPath.lastIndexOf(QLatin1Char('\\'));
+    if (lastSlash != -1)
+        testPath.truncate(lastSlash + 1);
+    testPath += moduleName;
+    if (GetFileAttributesW(testPath.utf16()) != INVALID_FILE_ATTRIBUTES)
+        return testPath;
+    // Path Search
+    if (SearchPathW(NULL, moduleName.utf16(), NULL, sizeof(testpathC)/2, testpathC, NULL))
+        return QString::fromUtf16(testpathC);
+    // Last chance, if the module has already been loaded in this process, then use that path
+    const HMODULE loadedModule = GetModuleHandleW(moduleName.utf16());
+    if (loadedModule) {
+        GetModuleFileNameW(loadedModule, testpathC, sizeof(testpathC));
+        if (GetFileAttributes(testpathC) != INVALID_FILE_ATTRIBUTES)
+            return QString::fromUtf16(testpathC);
+    }
+    return QString();
+}
+
+unsigned long SharedLibraryInjector::getModuleEntryPoint(const QString &moduleName)
+{
+    // If file doesn't exist, just treat it like we cannot figure out the entry point
+    if (moduleName.isEmpty() || GetFileAttributesW(moduleName.utf16()) == INVALID_FILE_ATTRIBUTES)
+        return 0;
+
+    // Read the first 1K of data from the file
+    unsigned char peData[1024];
+    unsigned long peDataSize = 0;
+    const HANDLE hFile = CreateFileW(moduleName.utf16(), FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+    if (hFile == INVALID_HANDLE_VALUE
+        || !ReadFile(hFile, peData, sizeof(peData), &peDataSize, NULL))
+        return 0;
+    CloseHandle(hFile);
+
+    // Now we check to see if there is an optional header we can read
+    IMAGE_DOS_HEADER *dosHeader = reinterpret_cast<IMAGE_DOS_HEADER *>(peData);
+    if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE   // DOS signature is incorrect, or
+        || dosHeader->e_lfanew == 0)                // executable's PE data contains no offset to New EXE header
+        return 0;
+
+    IMAGE_NT_HEADERS *ntHeaders = (IMAGE_NT_HEADERS *)(peData + dosHeader->e_lfanew);
+    if (ntHeaders->Signature != IMAGE_NT_SIGNATURE  // NT signature is incorrect, or
+        || !ntHeaders->OptionalHeader.ImageBase     // ImageBase or EntryPoint addresses are incorrect
+        || !ntHeaders->OptionalHeader.AddressOfEntryPoint)
+        return 0;
+
+    return ntHeaders->OptionalHeader.ImageBase
+           + ntHeaders->OptionalHeader.AddressOfEntryPoint;
+}
+
+bool SharedLibraryInjector::escalatePrivileges(QString *errorMessage)
+{
+    if (debug)
+        qDebug() << Q_FUNC_INFO << m_hasEscalatedPrivileges;
+
+    if (m_hasEscalatedPrivileges)
+        return true;
+
+    bool success = false;
+    HANDLE hToken = 0;
+    do {
+        TOKEN_PRIVILEGES Debug_Privileges;
+        if (!LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &Debug_Privileges.Privileges[0].Luid)) {
+            *errorMessage = msgFuncFailed("LookupPrivilegeValue", GetLastError());
+            break;
+        }
+
+        Debug_Privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // set to enable privilege
+        Debug_Privileges.PrivilegeCount = 1;                              // working with only 1
+
+        if (!OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {
+            *errorMessage = msgFuncFailed("OpenProcessToken", GetLastError());
+            break;
+        }
+        if (!AdjustTokenPrivileges(hToken, FALSE, &Debug_Privileges, 0,  NULL, NULL)) {
+            *errorMessage = msgFuncFailed("AdjustTokenPrivileges", GetLastError());
+            break;
+
+        }
+        success = true;
+    } while (false);
+
+    if (hToken)
+        CloseHandle (hToken);
+
+    m_hasEscalatedPrivileges = success;
+    return success;
+}
+
+static void *writeDataToProcess(HANDLE process, void *data, unsigned size, QString *errorMessage)
+{
+    void *memory = VirtualAllocEx(process, NULL, size, MEM_COMMIT, PAGE_READWRITE);
+    if (!memory) {
+        *errorMessage = msgFuncFailed("VirtualAllocEx", GetLastError());
+        return 0;
+    }
+    if (!WriteProcessMemory(process, memory, data, size, NULL)) {
+        *errorMessage = msgFuncFailed("WriteProcessMemory", GetLastError());
+        return 0;
+    }
+    return memory;
+}
+
+static void *writeUtf16StringToProcess(HANDLE process, const QString &what, QString *errorMessage)
+{
+    QByteArray whatData = QByteArray(reinterpret_cast<const char*>(what.utf16()), what.size() * 2);
+    whatData += '\0';
+    whatData += '\0';
+    return writeDataToProcess(process, whatData.data(), whatData.size(), errorMessage);
+}
+
+bool SharedLibraryInjector::doStubInjection(unsigned long pid,
+                                           const QString &modulePath,
+                                           unsigned long entryPoint,
+                                           QString *errorMessage)
+{
+    if (debug)
+        qDebug() << pid << modulePath << entryPoint;
+    if (modulePath.isEmpty())
+        return false;
+
+    if (!escalatePrivileges(errorMessage))
+        return false;
+
+#if (defined(WIN64) || defined(_WIN64) || defined(__WIN64__))
+    *errorMessage = QLatin1String("Not implemented for this architecture.");
+    return false;
+#else
+    byte stubCode[] = {
+        0x68, 0, 0, 0, 0,   // push 0x00000000      - Placeholder for the entrypoint address
+        0x9C,               // pushfd               - Save the flags and registers
+        0x60,               // pushad
+        0x68, 0, 0, 0, 0,   // push 0x00000000      - Placeholder for the string address
+        0xB8, 0, 0, 0, 0,   // mov eax, 0x00000000  - Placeholder for the LoadLibrary address
+        0xFF, 0xD0,         // call eax             - Call LoadLibrary with string address
+        0x61,               // popad                - Restore flags and registry
+        0x9D,               // popfd
+        0xC3                // retn                 - Return (pops the entrypoint, and executes)
+    };
+
+    const HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
+    if (!hProcess)
+        return false;
+
+    const HANDLE hThread = OpenThread(THREAD_GET_CONTEXT | THREAD_SET_CONTEXT, false, m_threadId);
+    if (!hThread) {
+        CloseHandle(hProcess);
+        return false;
+    }
+
+    // Get address of LoadLibraryW in kernel32.dll
+    unsigned long funcPtr;
+    if (!resolveSymbol("kernel32.dll", "LoadLibraryW", &funcPtr, errorMessage))
+        return false;
+
+    // Allocate and write DLL path to target process' memory
+    // 0-terminated Utf16 string.
+    void *dllString = writeUtf16StringToProcess(hProcess, modulePath, errorMessage);
+    if (!dllString)
+        return false;
+
+    // Allocate memory in target process, for the stubCode which will load the module, and execute
+    // the process' entry-point
+    const unsigned long stubLen = sizeof(stubCode);
+    // Modify the stubCode to have the proper entry-point, DLL module string, and function pointer
+    *(unsigned long*)(stubCode+1)  = entryPoint;
+    *(unsigned long*)(stubCode+8)  = reinterpret_cast<unsigned long>(dllString);
+    *(unsigned long*)(stubCode+13) = funcPtr;
+
+    // If we cannot write the stubCode into the process, we simply bail out, and the process will
+    // continues execution as normal
+    void *stub = writeDataToProcess(hProcess, stubCode, stubLen, errorMessage);
+    if (!stub)
+        return false;
+    // Set the process' main thread to start executing from the stubCode address which we've just
+    // allocated in the process' memory.. If we cannot do that, bail out
+    CONTEXT ctx;
+    ctx.ContextFlags = CONTEXT_CONTROL;
+    if(!GetThreadContext(hThread, &ctx))
+        return false;
+    ctx.Eip = reinterpret_cast<DWORD>(stub);
+    ctx.ContextFlags = CONTEXT_CONTROL;
+    if(!SetThreadContext(hThread, &ctx))
+        return false;
+
+    CloseHandle(hProcess);
+    CloseHandle(hThread);
+    return true;
+#endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+bool SharedLibraryInjector::doRemoteInjection(unsigned long pid,
+                                             HMODULE hFreeModule,
+                                             const QString &modulePath,
+                                             bool waitForThread,
+                                             QString *errorMessage)
+{
+    if (debug)
+        qDebug() << Q_FUNC_INFO << '\n' << hFreeModule << pid << waitForThread<< modulePath;
+
+    if (!hFreeModule && modulePath.isEmpty())
+        return false;
+
+    escalatePrivileges(errorMessage);
+
+    const HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
+    if (hProcess == NULL) {
+        *errorMessage = msgFuncFailed("OpenProcess", GetLastError());
+        qDebug() << "Failed to open process PID %d with all access\n" << pid;
+        return false;
+    }
+
+    void *pszLibFileRemote = 0;
+    HANDLE hThread = 0;
+    // Call  "FreeLibrary(hFreeModule)" to unload
+    if (hFreeModule) {
+        PTHREAD_START_ROUTINE pfnThreadRtn;
+        if (!resolveSymbol("Kernel32", "FreeLibrary", &pfnThreadRtn, errorMessage))
+            return false;
+        hThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, hFreeModule, 0, NULL);
+    } else {
+        pszLibFileRemote = writeUtf16StringToProcess(hProcess, modulePath, errorMessage);
+        if (!pszLibFileRemote)
+            return false;
+        // Loadlibrary routine
+        PTHREAD_START_ROUTINE pfnThreadRtn;
+        if (!resolveSymbol("Kernel32",  "LoadLibraryW", &pfnThreadRtn, errorMessage))
+            return false;
+        hThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, pszLibFileRemote, 0, NULL);
+    }
+    if (hThread == NULL) {
+        *errorMessage = msgFuncFailed("CreateRemoteThread", GetLastError());
+        return false;
+    }
+
+    if (!SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST)) {
+        *errorMessage = msgFuncFailed("SetThreadPriority", GetLastError());
+        return false;
+    }
+
+    if (waitForThread) {
+        if (::WaitForSingleObject(hThread, 20000) != WAIT_OBJECT_0) {
+            *errorMessage = QString::fromLatin1("WaitForSingleObject timeout");
+            ::CloseHandle(hThread);
+            ::CloseHandle(hProcess);
+            return false;
+        }
+
+        if (pszLibFileRemote)
+           ::VirtualFreeEx(hProcess, pszLibFileRemote, 0, MEM_RELEASE);
+    }
+
+    if (hThread)
+        ::CloseHandle(hThread);
+
+    if (hProcess)
+        ::CloseHandle(hProcess);
+    if (debug)
+        qDebug() << "success" << Q_FUNC_INFO;
+    return true;
+}
+
+typedef BOOL (WINAPI *PFNENUMPROCESSMODULES) (HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded);
+typedef DWORD (WINAPI *PFNGETMODULEFILENAMEEXW) (HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
+
+// We will require this function to get a module handle of our original module
+HMODULE SharedLibraryInjector::findModuleHandle(const QString &modulePath, QString *errorMessage)
+{
+    if (debug)
+        qDebug() << Q_FUNC_INFO << modulePath;
+
+    if (!escalatePrivileges(errorMessage))
+        return 0;
+
+    HMODULE hMods[1024];
+    DWORD cbNeeded;
+
+    HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_processId);
+    if (hProcess == NULL)
+        return 0;
+
+    const char *psAPI_Lib = "PSAPI.DLL";
+    HMODULE m_hModPSAPI = ::LoadLibraryA(psAPI_Lib);
+    PFNENUMPROCESSMODULES m_pfnEnumProcessModules;
+    PFNGETMODULEFILENAMEEXW m_pfnGetModuleFileNameExW;
+    if (!resolveSymbol(psAPI_Lib, m_hModPSAPI, "EnumProcessModules", &m_pfnEnumProcessModules, errorMessage)
+        || !resolveSymbol(psAPI_Lib, m_hModPSAPI, "GetModuleFileNameExW", &m_pfnGetModuleFileNameExW, errorMessage))
+        return false;
+
+    if(m_pfnEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) {
+        const unsigned count = cbNeeded / sizeof(HMODULE);
+        for (unsigned i = 0; i < count; i++) {
+            TCHAR szModName[MAX_PATH];
+            if (m_pfnGetModuleFileNameExW(hProcess, hMods[i], szModName, sizeof(szModName))) {
+                if (QString::fromUtf16(szModName) == modulePath) {
+                    ::FreeLibrary(m_hModPSAPI);
+                    ::CloseHandle(hProcess);
+                    return hMods[i];
+                }
+            }
+        }
+    }
+
+    ::CloseHandle(hProcess);
+    return 0;
+}
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/win/sharedlibraryinjector.h b/src/plugins/debugger/win/sharedlibraryinjector.h
new file mode 100644
index 0000000000000000000000000000000000000000..f1356b03f19c6faaaf5e441ee147ea6dcd46c291
--- /dev/null
+++ b/src/plugins/debugger/win/sharedlibraryinjector.h
@@ -0,0 +1,109 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+//
+// WinANSI - An ANSI implementation for the modern Windows
+//
+// Copyright (C) 2008- Marius Storm-Olsen <mstormo@gmail.com>
+//
+// Based on work by Robert Kuster in article
+//   http://software.rkuster.com/articles/winspy.htm
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+// -------------------------------------------------------------------------------------------------
+
+#ifndef SHAREDLIBRARYINJECTOR_H
+#define SHAREDLIBRARYINJECTOR_H
+
+#include <windows.h>
+#include <QtCore/QString>
+
+namespace Debugger {
+namespace Internal {
+
+/* SharedLibraryInjector: Injects a DLL into a remote process.
+ * Escalates the calling process rights. */
+class SharedLibraryInjector {
+    Q_DISABLE_COPY(SharedLibraryInjector)
+public:
+
+    explicit SharedLibraryInjector(unsigned long remotePid, unsigned long remoteThreadId = 0);
+    ~SharedLibraryInjector();
+
+    void setModulePath(const QString &modulePath);
+    bool hasLoaded(const QString &modulePath = QString());
+
+    // Remote injection, to be used for running processes
+    bool remoteInject(const QString &modulePath, bool waitForThread, QString *errorMessage);
+
+    // Stub injection, to be used before execution starts
+    bool stubInject(const QString &modulePath, unsigned long entryPoint, QString *errorMessage);
+
+    bool unload(const QString &modulePath /*  = QString()*/, QString *errorMessage);
+    bool unload(HMODULE hFreeModule, QString *errorMessage);
+
+    void setPid(unsigned long pid);
+    void setThreadId(unsigned long tid);
+
+    static QString findModule(const QString &moduleName);
+    static unsigned long getModuleEntryPoint(const QString &moduleName);
+
+private:
+    bool escalatePrivileges(QString *errorMessage);
+    bool doRemoteInjection(unsigned long pid, HMODULE hFreeModule,
+                           const QString &modulePath, bool waitForThread,
+                           QString *errorMessage);
+    bool doStubInjection(unsigned long pid, const QString &modulePath,
+                         unsigned long entryPoint, QString *errorMessage);
+
+    HMODULE findModuleHandle(const QString &modulePath, QString *errorMessage);
+
+    unsigned long m_processId;
+    unsigned long m_threadId;
+    QString m_modulePath;
+    bool m_hasEscalatedPrivileges;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // SHAREDLIBRARYINJECTOR_H
diff --git a/src/plugins/debugger/win/win.pri b/src/plugins/debugger/win/win.pri
index b1edeac92995b31c7665ca1de28500e8766d450a..a0b1ef45cbbeacc7f5defdb36d50bfad1038da67 100644
--- a/src/plugins/debugger/win/win.pri
+++ b/src/plugins/debugger/win/win.pri
@@ -1,5 +1,11 @@
 INCLUDEPATH+=$$PWD
 SOURCES += $$PWD/peutils.cpp \
-           $$PWD/dbgwinutils.cpp
+           $$PWD/dbgwinutils.cpp \
+	   $$PWD/sharedlibraryinjector.cpp
+
 HEADERS += $$PWD/peutils.h \
-           $$PWD/dbgwinutils.h
+           $$PWD/dbgwinutils.h \
+           $$PWD/sharedlibraryinjector.h
+
+# For the Privilege manipulation functions in sharedlibraryinjector.cpp
+LIBS += advapi32.lib