We help IT Professionals succeed at work.

How to make long process in MFC modal dlg “responsive” in Win7

RainbowGuy asked
Hi. I have a (dialog-based) app written in C++ with MFC. It puts up a modal dialog, which does a scan of a drive, which obviously takes a few minutes. To give feedback to the user, I have the modal dialog display a count of files processed, which increments with each file. All is fine in Win XP, but under Win 7 I get a problem with the window “freezing”. It stays frozen until the scan is complete, and then comes alive again. I’ve read online that this is because Windows 7 decides that the window isn’t responding, and over-writes it with a “dummy window”, which has the effect of stopping my file count from being updated.
So, an an attempt to prevent this, I added a PeekMessage to the modal dialog’s file handling loop, to pump any messages it found. And although that seemed to work, in that the window doesn’t freeze up any more, I seem to have replaced that problem with several different problems. Now, if I click on the main window while the modal “sub” window is doing its file scan, the Exit button on the top-right of the window turns red. If I click the window again, it gets “greyed” and the modal dialog disappears behind it – and the main window icon in the taskbar says Not Responding. But actually it is responding, because if I click the minimize button, it does minimize itself, and I then see my modal dialog updating its progress count, and all looks well. But, when the modal dialog’s process finishes, it disappears. And the taskbar now has two icons, “nested” together, which when I hover over them both show the modal dialog (neither of them say “not responding”). And – this is the real problem – when I click on them, nothing comes up. The program is now effectively dead.
I’ve come up against a couple of complications while researching this – one, it seems that MFC “modal” dialogs aren’t really modal, they’re modeless, simulated to behave like modal, and two, it seems that there is a bug in Win 7 to do with taskbar icons not working. So all in all, I’m really confused at the moment how I should make my app behave nicely in Windows 7 – can anyone help? I should emphasize that I don't want users doing anything with the main window - except possibly minimizing it - while the file scan is going on.

Sorry, I misdiagnosed this slightly. Just realized that what I thought were my "secondary" problems weren't in fact caused by my message pumping, they were there all along, but showed a bit differently. So without any message pumping, it's still possible to minimize the main window - but this time I only get one icon in the taskbar - and again when the sub dialog finishes it disappears, and the program is dead - clicking the taskbar icon doesn't bring it up.
Watch Question

The most strait forward answer in my mind is multi-threading.  Allow the long process to execute in one thread, while you have the user interface execute in another thread.

Check out this link on Multi-threading.  http://msdn.microsoft.com/en-us/library/69644x60%28v=vs.100%29.aspx

Starting a Worker Thread is really simple.  It basically just requires defining a function and calling it with AfxBeginThread.  Your two threads can "talk" to each other.  That way, you have the worker thread doing the "work" that normally locks up your application while the dialog continues to respond to the user.  By having the worker thread update variables, you can easily display progress in the dialog.  You can even include an abort button in your dialog.  Have the abort button simply update a flag that the worker thread can check every once in a while and abort its task if the abort flag gets set.

There are two types of threads.  There are worker threads and UI threads.  The UI threads involve setting up message looks and require multiple steps to get working right.  So for now, don't bother with UI threads.  But just a quick bit of research should get you up and running with worker threads in little time.


HooKooDooKu, this is not the way I want to go. I know about threads - I already use them to do animation. But as I said in my original question, I don't want the user doing anything while the modal dialog is up - it's updating their basic data and I don't want them making changes which will then potentially be over-written.
Really, the crux of my question is - how to stop Win7 from allowing my parent window from being minimised. It's not supposed to be active, as there is a "modal" dialog up, but the fact that MFC simulates modal is messing things up - that's what I need an answer to.
Top Expert 2016
You could try to call BeginWaitCursor() before scan and EndWaitCursor() after scan. I would assume it prevents from "freezing" as those functions actually are designed for such purposes.

if it doesn't help you could call another modal dialog which has only a cancel button and could not be minimized. you would move the scan to the OnTimer function if you could divide the task into smaller parts or use a thread as suggested by HooKooDooKoo. if using a thread you would pass the hwnd of the modal dialog as parameter and so could post a WM_CLOSE message to end the dialog after scan (always use PostMessage and not SendMessage for messages from thread).



OK, I'm going to close this one now. I've split the points equally between my two responders (and thanks for the suggestions), but I have now sorted it out myself, after two days intensive research online! In case anyone else looks at this, here is what I did.
To prevent the main window from being minimized while the "modal" dialog was up, I called ModifyStyle to remove the minimize box just before the DoModal, and then called it again afterwards to put it back. That was the easy bit!
The other bit of the problem, where clicking in the main window made it go faded and hide the modal dialog, well, the key to fixing that was finding out about "ghost" windows. This is where Windows 7 steps in to allow the user to minimize, move, or close a non-responsive window. It does this by slapping an image of the last known state of the window over the top of it, and then monitoring interaction with that window. Unfortunately in my case, that ghost window was obliterating my modal dialog as well - bad news as you then couldn't see the progress count. So, the fix was to put a call in from my modal dialog - in the function which was iterating through the files on the drive - to call a new function (which I called "pumper") in the main dialog. And that function just did a PeekMessage and removed any messages from the queue - and so because the main window now isn't seen to be non-responding, it doesn't get "ghosted".
There is also apparently an API called DisableProcessWindowsGhosting() which I'm sure would have worked, but as that isn't part of my ancient Visual Studio 6.0, I didn't use it.