diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp
index 8736769dec83df22b229751877896cd0b6dc4129..ec7c9f34d4194f359f3b100303b5dce1fc5d651a 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp
@@ -135,6 +135,7 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *manager,
     m_mode(AttachCore)
 {
     connect(this, SIGNAL(watchTimerDebugEvent()), this, SLOT(handleDebugEvent()));
+    connect(this, SIGNAL(modulesLoaded()), this, SLOT(slotModulesLoaded()));
 }
 
 bool CdbDebugEnginePrivate::init(QString *errorMessage)
@@ -475,19 +476,14 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6
     }
     // Attaching to crashed: This handshake (signalling an event) is required for
     // the exception to be delivered to the debugger
+    // Also, see special handling in slotModulesLoaded().
     if (m_mode == AttachCrashedExternal) {
         const QString crashParameter = manager()->startParameters()->crashParameter;
         if (!crashParameter.isEmpty()) {
             ULONG64 evtNr = crashParameter.toULongLong();
             const HRESULT hr = interfaces().debugControl->SetNotifyEventHandle(evtNr);
-            // Unless QtCreator is spawned by the debugger and inherits the handles,
-            // the event handling does not work reliably
-            // (that is, the crash event is not delivered).
-            if (SUCCEEDED(hr)) {
-                QTimer::singleShot(0, m_engine, SLOT(slotBreakAttachToCrashed()));
-            } else {
+            if (FAILED(hr))
                 m_engine->warning(QString::fromLatin1("Handshake failed on event #%1: %2").arg(evtNr).arg(CdbCore::msgComFailed("SetNotifyEventHandle", hr)));
-            }
         }
     }
     m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
@@ -877,6 +873,16 @@ bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage)
     return rc;
 }
 
+void CdbDebugEnginePrivate::slotModulesLoaded()
+{
+    // Attaching to crashed windows processes: Unless QtCreator is
+    // spawned by the debug handler and inherits the handles,
+    // the event handling does not work reliably (that is, the crash
+    // event is not delivered). In that case, force a break
+    if (m_mode == AttachCrashedExternal && m_engine->state() != InferiorStopped)
+        QTimer::singleShot(10, m_engine, SLOT(slotBreakAttachToCrashed()));
+}
+
 void CdbDebugEngine::slotBreakAttachToCrashed()
 {
     // Force a break when attaching to crashed process (if Creator was not spawned
diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h
index 1db92d231cd93ebe375af4e9131dcc65219bbc46..a4ab5d1acd75c599892265242d484359fb4b5287 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine_p.h
+++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h
@@ -102,8 +102,9 @@ public:
 
     void updateCodeLevel();
 
-public slots:
+private slots:
     void handleDebugEvent();
+    void slotModulesLoaded();
 
 public:
     const QSharedPointer<CdbOptions>  m_options;
diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
index 2251fb0052296410f13ac30734e01621c258efbf..e6b8fc50e59decad5d5add3d0480dd29c5874f92 100644
--- a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
@@ -50,10 +50,9 @@ CdbDebugEventCallback::CdbDebugEventCallback(CdbDebugEngine* dbg) :
 STDMETHODIMP CdbDebugEventCallback::GetInterestMask(THIS_ __out PULONG mask)
 {
     *mask = DEBUG_EVENT_CREATE_PROCESS  | DEBUG_EVENT_EXIT_PROCESS
-            | DEBUG_EVENT_LOAD_MODULE   | DEBUG_EVENT_UNLOAD_MODULE
             | DEBUG_EVENT_CREATE_THREAD | DEBUG_EVENT_EXIT_THREAD
             | DEBUG_EVENT_BREAKPOINT
-            | DEBUG_EVENT_EXCEPTION;
+            | DEBUG_EVENT_EXCEPTION | baseInterestMask();
     return S_OK;
 }
 
@@ -168,13 +167,13 @@ STDMETHODIMP CdbDebugEventCallback::LoadModule(
 {
     Q_UNUSED(ImageFileHandle)
     Q_UNUSED(BaseOffset)
-    Q_UNUSED(ModuleName)
     Q_UNUSED(ModuleSize)
     Q_UNUSED(ImageName)
     Q_UNUSED(CheckSum)
     Q_UNUSED(TimeDateStamp)
     if (debugCDB > 1)
         qDebug() << Q_FUNC_INFO << ModuleName;
+    handleModuleLoad();
     m_pEngine->m_d->handleModuleLoad(QString::fromUtf16(reinterpret_cast<const ushort *>(ModuleName)));
     return S_OK;
 }
@@ -189,6 +188,7 @@ STDMETHODIMP CdbDebugEventCallback::UnloadModule(
     Q_UNUSED(BaseOffset)
     if (debugCDB > 1)
         qDebug() << Q_FUNC_INFO << ImageBaseName;
+    handleModuleUnload();
     m_pEngine->m_d->updateModules();
     return S_OK;
 }
@@ -216,7 +216,7 @@ CdbExceptionLoggerEventCallback::CdbExceptionLoggerEventCallback(int logChannel,
 
 STDMETHODIMP CdbExceptionLoggerEventCallback::GetInterestMask(THIS_ __out PULONG mask)
 {
-    *mask = DEBUG_EVENT_EXCEPTION;
+    *mask = DEBUG_EVENT_EXCEPTION | baseInterestMask();
     return S_OK;
 }
 
diff --git a/src/plugins/debugger/cdb/coreengine.cpp b/src/plugins/debugger/cdb/coreengine.cpp
index bfab160023b65f172e5596635df8472425818c60..6705906759a55e3c009adf5fd32fda5c1c76e76e 100644
--- a/src/plugins/debugger/cdb/coreengine.cpp
+++ b/src/plugins/debugger/cdb/coreengine.cpp
@@ -224,7 +224,10 @@ bool DebuggerEngineLibrary::init(const QString &path,
 // ------ Engine
 CoreEngine::CoreEngine(QObject *parent) :
     QObject(parent),
-    m_watchTimer(-1)
+    m_watchTimer(-1),
+    m_moduleCount(0),
+    m_lastTimerModuleCount(0),
+    m_modulesLoadedEmitted(true)
 {
 }
 
@@ -323,9 +326,12 @@ CoreEngine::DebugOutputBasePtr
 CoreEngine::DebugEventCallbackBasePtr
         CoreEngine::setDebugEventCallback(const DebugEventCallbackBasePtr &e)
 {
+    // Keep the module count.
+    const unsigned oldModuleCount = moduleCount();
     const CoreEngine::DebugEventCallbackBasePtr old = m_debugEventCallback;
     m_debugEventCallback = e;
     m_cif.debugClient->SetEventCallbacksWide(m_debugEventCallback.data());
+    setModuleCount(oldModuleCount);
     return old;
 }
 
@@ -366,13 +372,24 @@ void CoreEngine::timerEvent(QTimerEvent* te)
     // (such as step over,etc).
     if (te->timerId() != m_watchTimer)
         return;
-
     switch (waitForEvent(1)) {
         case S_OK:
             killWatchTimer();
             emit watchTimerDebugEvent();
             break;
         case S_FALSE:
+            // Detect startup (all modules loaded) if the module
+            // count no longer changes in a time-out.
+            if (!m_modulesLoadedEmitted) {
+                const int newModuleCount = moduleCount();
+                if (newModuleCount && newModuleCount == m_lastTimerModuleCount) {
+                    m_modulesLoadedEmitted = true;
+                    emit modulesLoaded();
+                } else {
+                    m_lastTimerModuleCount = newModuleCount;
+                }
+            }
+            break;
         case E_PENDING:
         case E_FAIL:
             break;
@@ -382,12 +399,20 @@ void CoreEngine::timerEvent(QTimerEvent* te)
     }
 }
 
+void CoreEngine::resetModuleLoadTimer()
+{
+    m_lastTimerModuleCount = 0;
+    setModuleCount(0);
+    m_modulesLoadedEmitted = false;
+}
+
 bool CoreEngine::startDebuggerWithExecutable(const QString &workingDirectory,
                                              const QString &filename,
                                              const QStringList &args,
                                              const QStringList &envList,
                                              QString *errorMessage)
 {
+    resetModuleLoadTimer();
     DEBUG_CREATE_PROCESS_OPTIONS dbgopts;
     memset(&dbgopts, 0, sizeof(dbgopts));
     dbgopts.CreateFlags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
@@ -437,7 +462,8 @@ bool CoreEngine::startAttachDebugger(qint64 pid,
                                      bool suppressInitialBreakPoint,
                                      QString *errorMessage)
 {
-    // Need to attrach invasively, otherwise, no notification signals
+    resetModuleLoadTimer();
+    // Need to attach invasively, otherwise, no notification signals
     // for for CreateProcess/ExitProcess occur.
     // Initial breakpoint occur:
     // 1) Desired: When attaching to a crashed process
@@ -865,6 +891,20 @@ bool CoreEngine::setInterrupt(QString *errorMessage)
     return true;
 }
 
+// Module count is normally kept in the event callback.
+// Should we have none, we do the book-keeping ourselves.
+unsigned CoreEngine::moduleCount() const
+{
+    return m_debugEventCallback.isNull() ? m_moduleCount : m_debugEventCallback->moduleCount();
+}
+
+void CoreEngine::setModuleCount(unsigned m)
+{
+    m_moduleCount = m;
+    if (!m_debugEventCallback.isNull())
+        m_debugEventCallback->setModuleCount(m);
+}
+
 // ------------- DEBUG_VALUE formatting helpers
 
 // format an array of integers as "0x323, 0x2322, ..."
diff --git a/src/plugins/debugger/cdb/coreengine.h b/src/plugins/debugger/cdb/coreengine.h
index 4391823a15c53d83c364e6424b1a6127f11cab1c..eff131807dcccf46ba17836c97f53f5dff22d631 100644
--- a/src/plugins/debugger/cdb/coreengine.h
+++ b/src/plugins/debugger/cdb/coreengine.h
@@ -149,19 +149,33 @@ public:
     static bool autoDetectPath(QString *outPath,
                                QStringList *checkedDirectories = 0);
 
+    unsigned moduleCount() const;
+
 signals:
     void watchTimerDebugEvent();
 
+    // Emitted in the first time-out of the event handler in which
+    // the number of modules no longer changes. Can be used as a
+    // "startup" signal due to lack of a reliable "startup" detection
+    // feature of the engine.
+    void modulesLoaded();
+
 protected:
     virtual void timerEvent(QTimerEvent* te);
 
 private:
+    void setModuleCount(unsigned m);
+    void resetModuleLoadTimer();
+
     ComInterfaces m_cif;
     DebugOutputBasePtr m_debugOutput;
     DebugEventCallbackBasePtr m_debugEventCallback;
     QString m_dbengDLL;
     QString m_baseImagePath;
     int m_watchTimer;
+    unsigned m_moduleCount;
+    unsigned m_lastTimerModuleCount;
+    bool m_modulesLoadedEmitted;
 };
 
 // Utility messages
diff --git a/src/plugins/debugger/cdb/debugeventcallbackbase.cpp b/src/plugins/debugger/cdb/debugeventcallbackbase.cpp
index 9cad433aa114065de4f992f3781b72d87dc1eb8c..7ef52846e5f047c7292c6dfbbeff2495e27b9607 100644
--- a/src/plugins/debugger/cdb/debugeventcallbackbase.cpp
+++ b/src/plugins/debugger/cdb/debugeventcallbackbase.cpp
@@ -140,6 +140,7 @@ STDMETHODIMP DebugEventCallbackBase::LoadModule(
     __in ULONG /* TimeDateStamp */
     )
 {
+    handleModuleLoad();
     return S_OK;
 }
 
@@ -149,6 +150,7 @@ STDMETHODIMP DebugEventCallbackBase::UnloadModule(
     __in ULONG64 /* BaseOffset */
     )
 {
+    handleModuleUnload();
     return S_OK;
 }
 
@@ -204,6 +206,33 @@ IDebugEventCallbacksWide *DebugEventCallbackBase::getEventCallback(CIDebugClient
     return 0;
 }
 
+void DebugEventCallbackBase::handleModuleLoad()
+{
+    m_moduleCount++;
+}
+
+void DebugEventCallbackBase::handleModuleUnload()
+{
+    m_moduleCount--;
+}
+
+unsigned DebugEventCallbackBase::moduleCount() const
+{
+    return m_moduleCount;
+}
+
+void DebugEventCallbackBase::setModuleCount(unsigned m)
+{
+    m_moduleCount = m;
+}
+
+ULONG DebugEventCallbackBase::baseInterestMask() const
+{
+    return DEBUG_EVENT_LOAD_MODULE | DEBUG_EVENT_UNLOAD_MODULE;
+}
+
+// ----------- EventCallbackRedirector
+
 EventCallbackRedirector::EventCallbackRedirector(CoreEngine *engine,
                                                  const DebugEventCallbackBasePtr &cb) :
     m_engine(engine),
@@ -216,4 +245,5 @@ EventCallbackRedirector::~EventCallbackRedirector()
     m_engine->setDebugEventCallback(m_oldCallback);
 }
 
+
 } // namespace CdbCore
diff --git a/src/plugins/debugger/cdb/debugeventcallbackbase.h b/src/plugins/debugger/cdb/debugeventcallbackbase.h
index cb7360fbebc03b4fbd265fbb99cac4a1913b1c2f..6d8e589c780eabc8cfafcddcb6ac854d344ce357 100644
--- a/src/plugins/debugger/cdb/debugeventcallbackbase.h
+++ b/src/plugins/debugger/cdb/debugeventcallbackbase.h
@@ -40,7 +40,13 @@ class CoreEngine;
 
 // Base class for event callbacks that takes care
 // Active X magic. Provides base implementations with
-// the exception of GetInterestMask
+// the exception of GetInterestMask(). The base class
+// needs to do some book-keeping on the modules loaded to
+// be able to detect the startup/completed attach of a
+// debuggee (see CoreEngine::modulesLoaded()).
+// So, the interest mask must be at least baseInterestMask()
+// and handleModuleLoad/Unload must be called from derived
+// classes when overwriting the handlers.
 class DebugEventCallbackBase : public IDebugEventCallbacksWide
 {
 protected:
@@ -104,6 +110,7 @@ public:
             __in ULONG ExitCode
             );
 
+    // Call handleModuleLoad() when reimplementing this
     STDMETHOD(LoadModule)(
             THIS_
             __in ULONG64 ImageFileHandle,
@@ -115,6 +122,7 @@ public:
             __in ULONG TimeDateStamp
             );
 
+    // Call handleModuleUnload() when reimplementing this
     STDMETHOD(UnloadModule)(
             THIS_
             __in_opt PCWSTR ImageBaseName,
@@ -152,6 +160,17 @@ public:
 
 
     static IDebugEventCallbacksWide *getEventCallback(CIDebugClient *clnt);
+
+    unsigned moduleCount() const;
+    void setModuleCount(unsigned m);
+
+protected:
+    void handleModuleLoad();
+    void handleModuleUnload();
+    ULONG baseInterestMask() const;
+
+private:
+    unsigned m_moduleCount;
 };
 
 // Utility class to temporarily redirect events to another handler