Adding a Message Pump to MonitorShutdown
When TextInterpreter starts, a call in _tWinMain to _AtlModule.StartMonitor creates a new thread. This thread's execution starts with the MonitorProc function (added in the Initializing the Debug Engine Object step), which handles the execution of the debug engine and the interpreter. After this, _tWinMain waits in a loop until a WM_QUIT message arrives, indicating that it is time to clean up and exit. When MonitorProc is done setting up the debug engine and interpreter, it calls MonitorShutdown on the CTextInterpreterModule object given to it. This MonitorShutdown waits indefinitely for the spawned thread to exit before sending the WM_QUIT message to the main thread, signaling to _tWinMain that it is time to quit.
The default MonitorShutdown supplied by the ATL COM base class to CTextInterpreterModule watches only for a single shutdown event, that is, the termination of the spawned thread. However, TextInterpreter needs to watch for a Windows-based message (in order to continue execution of the program being debugged) to come through in addition to the shutdown event, so it is necessary to override the default method with a more complicated version. The actual implementation of the specific Windows-based message happens later.
When the text interpreter program starts, it sends startup events to the session debug manager (SDM) and then returns to MonitorProc without waiting for the resulting callbacks. MonitorProc then calls MonitorShutdown, and thread execution continues. MonitorShutdown waits until the shutdown event occurs, after which the function posts a WM_QUIT message to the main thread. This message eventually causes the application to clean up and exit.
Note that because TextInterpreter is single-threaded, the text interpreter, debug engine, and MonitorShutdown function share one thread. While it is not required that the same object implement IDebugProgram2 and IDebugThread2, in this case it is convenient to do so.
To add a message pump to MonitorShutdown
In Class View, right-click the CTextInterpreterModule class and click Add Function to add a public function with the Function name MonitorShutdown, a Return type of void, and no parameters. This overrides the base class's version of the method.
In the TextInterpreter.cpp file, find the method CTextInterpreterModule::MonitorShutdown and insert the following bold lines:
void CTextInterpreterModule::MonitorShutdown(void) { while (1) { DWORD dwWait = MsgWaitForMultipleObjects( 1, &m_hEventShutdown, FALSE, INFINITE, QS_ALLINPUT); // Shutdown event. if (dwWait == WAIT_OBJECT_0) { do { m_bActivity = false; dwWait = WaitForSingleObject(m_hEventShutdown, m_dwTimeOut); } while (dwWait == WAIT_OBJECT_0); // timed out if (!m_bActivity && m_nLockCnt == 0) // if no activity let's really bail { #if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED) CoSuspendClassObjects(); if (!bActivity && m_nLockCnt == 0) #endif break; } } // Windows message. else if (dwWait == WAIT_OBJECT_0 + 1) { MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { //TODO: IMPLEMENT CONTINUE DispatchMessage(&msg); } } } CloseHandle(m_hEventShutdown); PostThreadMessage(m_dwMainThreadID, WM_QUIT, 0, 0); }
Build the project to make sure there are no errors.