locked
EndDialog Box Throws Exception RRS feed

  • Question

  • hi,
    need help

    i have an application in VC++ MFC.
    here im creating a modal dialog box using AfxBeginThread (a worker thread)
    and executing the program for multiple times and a specific condition im calling
    EndDialog(IDOK), it works fine but on Windwos XP when program executed for multiple times EndDialog throws Exception.

    i identified the exception iusing try.. catch() block.

    why this abnormal behaviour of EndDialog() method.
    is it because i have created i DialogBox using Worker Thread ??
    but why not EndDialog throws Exception in first execution why afetr 500 - 600 execution ??


    can any one please let me know why such behavior ??

    anisK
    Monday, September 22, 2008 2:32 PM

Answers

  • anisk:

    Never create GUI components in a secondary thread, and most certainly not in a worker thread.

    In this situation you should launch your modal dialog in the main thread, and then launch worker thread (or Window-less UI thread) to do any time-consuming work.


    David Wilkinson | Visual C++ MVP
    • Proposed as answer by Pintu Shukla Monday, September 22, 2008 3:10 PM
    • Marked as answer by Rong-Chun Zhang Friday, September 26, 2008 11:04 AM
    Monday, September 22, 2008 2:52 PM

All replies

  • anisk:

    Never create GUI components in a secondary thread, and most certainly not in a worker thread.

    In this situation you should launch your modal dialog in the main thread, and then launch worker thread (or Window-less UI thread) to do any time-consuming work.


    David Wilkinson | Visual C++ MVP
    • Proposed as answer by Pintu Shukla Monday, September 22, 2008 3:10 PM
    • Marked as answer by Rong-Chun Zhang Friday, September 26, 2008 11:04 AM
    Monday, September 22, 2008 2:52 PM
  • Just to add to this so you will have a better understanding of the problem.

    MFC uses hooks for handling message maps.  Those hooks occur between the main app message pump and UI forms.  This is very bad if you create a UI control on another thread.  The message pump is then dispatching messages between threads, which is not the design of the message loop.  This is a very simple explanation, for more details I suggest reading "MFC Internals" by Shepherd Wingo published by Addison-Wesly.  This may seem to be an ancient text in computer terms but it reveals the guts of MFC unlike anything else I've read including the source.

    Mark
    Monday, September 22, 2008 5:38 PM
  •  
    mtwombley said:

    Just to add to this so you will have a better understanding of the problem.

    MFC uses hooks for handling message maps.  Those hooks occur between the main app message pump and UI forms.  This is very bad if you create a UI control on another thread.  The message pump is then dispatching messages between threads, which is not the design of the message loop.  This is a very simple explanation, for more details I suggest reading "MFC Internals" by Shepherd Wingo published by Addison-Wesly.  This may seem to be an ancient text in computer terms but it reveals the guts of MFC unlike anything else I've read including the source.

    Mark



    Not quite.  The message pump never dispatches message between threads, because it only processes messages in its own queue.  Each thread has its own message queue and if you create widgets from a secondary thread then the second thread's message queue will be used.  If you don't pump messages on the secondary thread then they never would be processed (but DialogBox pumps messages for you, until EndDialog is called).

    Sounds like there is a race condition, but it is not the message processing.  Windows message queues are perfectly thread safe.
    Monday, September 22, 2008 9:34 PM
  • Ben Voigt said:

    Not quite.  The message pump never dispatches message between threads, because it only processes messages in its own queue.  Each thread has its own message queue and if you create widgets from a secondary thread then the second thread's message queue will be used.  If you don't pump messages on the secondary thread then they never would be processed (but DialogBox pumps messages for you, until EndDialog is called).

    Sounds like there is a race condition, but it is not the message processing.  Windows message queues are perfectly thread safe.


    Ben,

    I always try to expand my knowledge and learn new things.  So if you could expand on this that would be great, because I don't completely agree with your statement.  I think the confusion comes from the mixing of terms like pump and message queue.  According to MSDN ‘Using Messages and Message Queues’ “The system automatically creates a message queue for each thread. If the thread creates one or more windows, a message loop must be provided; this message loop retrieves messages from the thread's message queue and dispatches them to the appropriate window procedures.   Because the system directs messages to individual windows in an application, a thread must create at least one window before starting its message loop.”

    Since this comes from Microsoft itself I’ll take that as hard fact.  But the key I think is that the message is dispatched to a window procedure, that is the job of the pump.  What I was trying to point out was that MFC plays with the rules a little here and hooks into the window procedure.  This is described in depth in “MFC Internals”.  That hook is in the main application thread.  If a message is going to be posted to a handler in another thread you need to handle that.  Details can be found in “TNO58 MFC Module State Implementation”.  Now the main part of that article deals with DLL modules but it gives some clues to the problems.

    This isn’t just book knowledge I have, I have a real life project where I’ve tried to resolve this very issue.  The application in question creates threads that load a dll as a sub application.  In the dll we create model and modeless dialogs.  By using the AFX_MODULE_STATE macro we manage this very well.  But one thing has driven me crazy since I started that project 2 years ago…  We can’t get standard tooltips to work.  For some reason the messages that are needed for that don’t get routed correctly.  This is an MFC problem.  I’ve created sample MFC applications to test the problem but if I try to do the same thing in a non-MFC application it works fine.

    One other thing, if you think this doesn’t apply to common dialogs because they are internal to Windows, that isn’t correct.  MFC hooks into them through a hook procedure _AfxCommDlgProc.  Again, read “MFC Internals” (you’d think I have shares in it or something).

    If this comes across poorly please except this as a discussion of the problem and never as a statement like ‘shut up you don’t know what you are talking about’.  No one climbs Everest alone.

    Mark

    Monday, September 22, 2008 10:50 PM
  • but why not the exception is identified by the running process in the first execution and why after so long time ???
    Tuesday, September 23, 2008 6:00 AM
  • Sorry Anisk,
    Didn't realize your question wasn't answered in all the talking.

    There is only one way to really know the exact reason for the exception (if it isn't documented) and that would be to back trace the execution at the moment of the exception.  But with multiple threads that becomes very complex.  Which thread invariably modified the memory that caused the exception?  Multi-threading has great power but also is very fraut with dangers.  There are annals that describe how a program would crash only when the moon was full and John down the hall was picking his nose (hyperbole).  If you wish to continue on this course then you are going to have to do a lot of testing.  First you can create a simple project that creates the worker thread and opens your dialog.  If that never crashes then you know the problem is related to another piece of code.  You could then build up your code until it starts to crash again.  The other way is to except the wise consel from folks like David and Ben who just plainly say don't run a GUI under a worker thread.  You never said why you are running the UI from the worker.  If it is to allow the user to cancel execution or something, then place that in the main thread and have the worker thread check exit if the state changes.  There is much documentation on this.

    Hope this gets you going in the right direction.
    Mark
    Tuesday, September 23, 2008 3:25 PM

  • now i have updated the application in two implementation
    1) by using  Win32 API CreateThread()
    2) by using MFC AfxBeginThread(UI thread)

    even though same problem occurs in both implementaion and only in Windows XP after executing the application for multiple times after count 2000 :-) . but in windows Vista its working fine

    actually im not able to identify the root cause !!!


    anisk



    Tuesday, October 7, 2008 6:15 AM