Re: Problems with a secondary message pump
On Wed, 6 May 2009 12:23:07 -0700, Rob <Rob@discussions.microsoft.com>
wrote:
My application (the bootstrap application for an installer that I'm working
on needs to launch some other applications (my installer and third party
installers for my installer's prerequisites) and wait for them to complete.
In order to allow the GUI to do screen updates while waiting for an app to
complete, I put a message pump in the wait loop using the 'MFC-compatible'
example in the Visual Studio documentation on idle loop processing as a
guideline. My code (which is in a member function of a CWinApp-derived class)
is as follows:
if (::CreateProcess(lpAppName, szCmdLineBuffer, NULL, NULL, TRUE, 0,
NULL, NULL,
&StartupInfo, &ProcessInfo))
{
::GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
if (bWait)
while (dwExitCode == STILL_ACTIVE)
{
// In order to allow updates of the GUI to happen while we're
waiting for
// the application to finish, we must run a mini message pump here
to
// allow messages to go through and get processed. This message
pump
// performs much like MFC's main message pump found in
CWinThread::Run().
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!PumpMessage())
{
// a termination message (e.g. WM_DESTROY)
// was processed, so we need to stop waiting
dwExitCode = ERROR_CANT_WAIT;
::PostQuitMessage(0);
break;
}
}
// let MFC do its idle processing
LONG nIdle = 0;
while (OnIdle(nIdle++))
;
if (dwExitCode == STILL_ACTIVE) // was a termination message
processed?
{
// no; wait for .1 second to see if the application is finished
::WaitForSingleObject(ProcessInfo.hProcess, 100);
::GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
}
}
::CloseHandle(ProcessInfo.hProcess);
::CloseHandle(ProcessInfo.hThread);
}
else
dwExitCode = ::GetLastError();
The problem that I'm having is that, at some point, this message pump seems
to free up window and menu handles on the window that I have open at the time
this code is run. I did a walk through in the debugger, and at no time did it
ever get into the body of the if (!PumpMessage()) statement, so I don't know
what's going on here to cause the window and menu handles to go south. If I
don't have the message pump, everything works fine, except that the GUI can't
update itself while the wait loop is running.
Does anyone have any ideas as to how to make this work? Alternatively, I'd
like to launch a worker thread to launch the second app if bWait is TRUE, but
I've never done anything with threads before, so I'll need some advice on how
to do it without introducing synchronization issues, etc. (Code examples
would be greatly appreciated in either case.)
Sounds like it's the OnIdle processing freeing up temporary MFC objects.
Instead of skipping OnIdle, I'd working on giving those objects some
permanence.
See this web page for info on using CWinThread correctly as well as other
basic multithreading issues:
http://members.cox.net/doug_web/threads.htm
Also, I would use MsgWaitForMultipleObjects as described on that page, and
I would not be using GetExitCodeProcess to control the loop. There is no
point to your timed WFSO call other than to mitigate the busy waiting your
loop does. Using MWFMO as I described eliminates busy waiting and
simplifies the structure.
--
Doug Harrison
Visual C++ MVP