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
When you say that window and menu handles seem to be being freed, do you mean that you've got actual HWND and HMENU values that no longer seem to work, or have you got MFC CWnd* and CMenu* variables that fail?
If the latter, the problem is most likely that you're getting the CWnd* pointers by calling CWnd::FromHandle() (or CMenu::FromHandle()) somewhere (or calling something that calls them), and OnIdle() is discarding them.
The underlying reason is that MFC maintains a map from window (or menu, etc.) handles to CWnd* objects in the system. When CWnd::FromHandle() is called, it looks for a match in the map: if one is found, it's returned. If not, a new, temporary CWnd is created, added to the map, and returned. The idea behind OnIdle() is that when it's called all message processing is done, so OnIdle() discards any of these temporary CWnd objects that still exist. That's why the CWnd::FromHandle() documentation warns that the returned pointer may be temporary.
The "correct" solution to this is to not hang onto the CWnd* pointers returned from CWnd::FromHandle(). Given the simplicity of your application, it might be easier to just remove the call OnIdle(): this shouldn't have any negative effects on an installer.
Of course, this is all something of a guess, but it sounds plausible...
There is a Windows function called DisableProcessWindowsGhosting (see http://msdn.microsoft.com/en-us/library/ms648415(v=vs.85).aspx) that prevents Windows from 'ghosting' your window, and continue updating the window (your animation).
I think your problem is in WaitForSingleObject
Looking in MSDN you see this
Use caution when calling the wait functions and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. A thread that uses a wait function with no time-out interval may cause the system to become deadlocked. Two examples of code that indirectly creates windows are DDE and the CoInitialize function. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than WaitForSingleObject.
In my code in the message pump use use MsgWaitForMultipleObjects
(doc).
With a call this call.
MsgWaitForMultipleObjects(1, &ProcessInfo.hProcess, FALSE, 100, QS_ALLEVENTS);
This should stop your problem with the resources dissapearing.
I've also posted this question on the Microsoft forums, and thanks to the help of one Doug Harris at Microsoft, I found out my problem with my HWND and HMENU values was, indeed due to stale CWwnd* and CMenu* pointers (obtained using GetMenu() and GetDialogItem() calls. Getting the pointers again after launching the second app solved that problem. Also, he pointed me to a web site* that showed a better way of doing my loop using MsgWaitForMultipleObjects() to control it that doesn't involve the busy work of waiting a set amount of time and polling the process for an exit code.
My loop now looks like this:
if (bWait)
{
// In order to allow updates of the GUI to happen while we're
// waiting for the application to finish, we must run a message
// pump here to allow messages to go through and get processed.
LONG nIdleCount = 0;
for (;;)
{
MSG msg;
if (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
PumpMessage();
else //if (!OnIdle(nIdleCount++))
{
nIdleCount = 0;
if (!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
DWORD nRes = ::MsgWaitForMultipleObjects(1, &ProcessInfo.hProcess,
FALSE, INFINITE, QS_ALLEVENTS);
if (nRes == WAIT_OBJECT_0)
break;
}
}
}
}
::GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
*That Web site, if you're curious, is: http://members.cox.net/doug_web/threads.htm