Thread: Message loop not working...

  1. #1
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879

    Exclamation Message loop not working...

    Ok, here I have some code (very stripped down so it isn't too boring to read):
    Code:
    HWND dlg = CreateDialog(hinst, MAKEINTRESOURCE(IDD_TRANSFER),
                   parent, UploadProc);
    ShowWindow(dlg, SW_SHOW);
    
    MSG msg;
    bool done = false;
    while(!done && !file.eof()) //I don't think file is the problem
    {
        while(PeekMessage(&msg, dlg, 0, 0, PM_REMOVE))
        {
            if(msg.message == WM_CLOSE ||
                (msg.message == WM_COMMAND && LOWORD(msg.wParam) == IDCANCEL))
            {
                done = true;
                server->send(ICV_OP_CANCEL);
                break;
            }
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        if(done)
            break;
        //Other stuff
    }
    
    DestroyWindow(dlg);
    IDCANCEL is a button that says "cancel". For some reason, this message loop doesn't seem to want to quit, and I can't figure out for the life of me why, since clicking the x in the corner of the dialogbox should (in my world) send WM_CLOSE. Can anybody help me out here? It's sorta a big thing for me, since I thought I had Windows messages all sorted out already
    Last edited by Hunter2; 06-26-2003 at 06:15 PM.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  2. #2
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    Try this:

    Code:
        while(PeekMessage(&msg, dlg, 0, 0, PM_REMOVE))
        {
            id (msg.message == WM_QUIT){
                done = true;
                server->send(ICV_OP_CANCEL);
                break;
            }
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    Then, in your message handler (Window Procedure), do the following:

    WM_DESTROY calls PostQuitMessage()
    WM_CLOSE calls DestroyWindow()
    Your button posts a WM_CLOSE message (or, alternately, it can just do the same thing as WM_CLOSE, but this way any other function of WM_CLOSE needs to be coded only once).

    The traditional end of a window is as follows:

    * WM_CLOSE is sent; the application chooses how to respond. At this point, the application can still choose not to terminate.

    Default action of WM_CLOSE is to call DestroyWindow(), which will do some things, including posting the WM_DESTROY and WM_NCDESTROY messages. Once DestroyWindow() happens, the window must be killed; there is no longer any option for the program to keep running.

    * WM_DESTROY is processed; the client must handle this message. You should call PostQuitMessage() at this point; that is typically the only thing you do in response to WM_DESTROY.

    * WM_NCDESTROY is sent; this is the last message that the callback will handle, so final cleanup can be done here (memory can be freed, etc.)

    * WM_QUIT causes the message loop to terminate (and is NOT sent to the callback).

    The message pump is NOT the place to make choices based on the message; the callback (window procedure) is there for specifically this reason. It's rarely if ever a good idea to mess around in the actual message pump itself. The message pump should only be terminated at WM_QUIT.
    Last edited by Cat; 06-26-2003 at 06:35 PM.

  3. #3
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Hmm, I see. Well, thanks, I'll try that soon (gotta go somewhere now) and let you know if it works.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  4. #4
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Hmm, looking at your summary, I'm sort of not too sure about calling PostQuitMessage(). When this window ends, I don't want the program to end - I only want to close the window, end the message loop for this window, and keep going with the program. In fact, the window is created as a response to a button-press in another dialogbox!

    Am I heading in the wrong direction to start off with by using CreateDialog()? I didn't want to use DialogBox() which is blocking, since then I can't do stuff in the background until a message is sent, which would drastically affect file-transfer rates ( that's what this is for).
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  5. #5
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    Hmm, there should BE no "message loop for this window". There should only be one message loop per program (or more technically, at most one message loop in each thread).

    You are correct, in a child dialog, WM_DESTROY should not call PostQuitMessage().

  6. #6
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Hmm, there should BE no "message loop for this window". There should only be one message loop per program (or more technically, at most one message loop in each thread).
    Erm.. come again? What about DialogBox()? On MSDN it says that DialogBox() calls CreateWindowEx() and then starts up an internal message loop. Why should dialog boxes created with CreateDialog() be any different?

    Also, I found out one oddity with my whole setup. When I hit the X in the upper-right hand corner of this dialog, it'll send a WM_COMMAND message instead of WM_CLOSE. So if I check for the WM_COMMAND message instead of WM_CLOSE, it will close *properly* when I hit the X. Why is this?

    **EDIT**
    One more thing, if the child shouldn't call PostQuitMessage(), then how does it get the WM_QUIT message and disappear?
    Last edited by Hunter2; 06-26-2003 at 09:37 PM.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  7. #7
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    Originally posted by Hunter2
    Erm.. come again? What about DialogBox()? On MSDN it says that DialogBox() calls CreateWindowEx() and then starts up an internal message loop. Why should dialog boxes created with CreateDialog() be any different?
    That's because it's a modal dialog. A modal dialog has its own message loop, because a modal dialog (by definition) pauses the thread's message pump until the dialog is done.

    You specifically are trying *not* to create a modal dialog, correct? Modeless dialogs don't have their own message pump, because the main message pump of that thread is not interrupted.

    The child never calls PostQuitMessage() on WM_DESTROY because the child's destruction shouldn't end the program. The main window, however, SHOULD call PostQuitMessage() on WM_DESTROY, because when that window is destroyed, the message loop should terminate.

    FYI: If you WANTED the child's destruction to end the program, the proper way to do it is to have the child's WM_DESTROY call DestroyWindow() for the main window. Only the main window's WM_DESTROY should call PostQuitMessage().
    Last edited by Cat; 06-26-2003 at 10:00 PM.

  8. #8
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Ahh, shoot. Looks like I have some re-structuring to do in my program... I have everything using modal dialogs up until this point, where I don't have a choice and I need to use modeless Currently, this is my (non-message) loop in WinMain() To change a dialogbox, all I do is change dlgState and call EndDialog().
    Code:
    while(!quit)
    {
    	switch(dlgState)
    	{
    	case DS_CONNECT:
    		DialogBox(...);
    		break;
    	case DS_LOGIN:
    		DialogBox(...);
    		break;
    	case DS_FILES:
    		DialogBox(...);
    		break;
    	}
    }
    If I just put a message loop in my WinMain(), it'll be blocked by the modal dialogs; and if I put it in this function, I have the PostQuitMessage() problem. So does that mean that I'll have to change everything to modeless and screw around with my beautifully-simple setup in order to get this to work properly?
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  9. #9
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    Hmm, not sure. Do you actually HAVE a main window, or only one of a set of dialogs? It may well be possible to keep a lot of the dialogs modal and then use modeless only where needed.

    It could also be workable to have a thread without a main message loop, like you originally planned, and just create a message loop when you have a modeless dialog. Your original plan, IF you have no main window, may be workable; I've not tried anything exactly like that, but it should be workable in theory.

    If you have no main message pump, you have no PostQuitMessage() -- you just break your message loop when done. Probably the best way is to check for the WM_NCDESTROY message, and break the loop AFTER dispatching it -- it's guaranteed to be the last message of a window's life, and if you know you only need one window, then the loop can die when you are done dispatching that message.

    The whole means of PostQuitMessage(), etc., is useful when dealing with multiple windows, but it's not needed in cases like this.

    However, it probably WILL work just fine to use PostQuitMessage(), because at the time it happens, you are already wanting to break out of the only message pump you have. As far as I know, PostQuitMessage does nothing more than add the WM_QUIT message to the queue which is supposed to cause the message loop to break.
    Last edited by Cat; 06-26-2003 at 10:15 PM.

  10. #10
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Your original plan, IF you have no main window, may be workable
    Nope, no main window. Up until now, only a bunch of modal dialogs that take turns showing up when they're needed.
    As far as I know, PostQuitMessage does nothing more than add the WM_QUIT message to the queue which is supposed to cause the message loop to break.
    I thought so too, until I looked into MSDN and it said:
    The PostQuitMessage function indicates to the system that a thread has made a request to terminate (quit)...

    the function simply indicates to the system that the thread is requesting to quit at some time in the future
    Unless, of course, "system" just refers to the message loop.

    And also, I still don't get why clicking the X will send WM_COMMAND instead of WM_CLOSE, with a control ID of 2 which isn't used in my resource.h
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  11. #11
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    Originally posted by Hunter2

    And also, I still don't get why clicking the X will send WM_COMMAND instead of WM_CLOSE, with a control ID of 2 which isn't used in my resource.h
    Ahh, that makes sense, though: 2 is "IDCANCEL", and so they make clicking the 'X' return the cancel value.

    In any event, it should be very safe to just break the loop directly after WM_NCDESTROY is processed.

  12. #12
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Ok, thanks. But should I actually dispatch WM_NCDESTROY, or do I just check and kill the loop if I receive it?

    **EDIT**
    And also, why would pressing my cancel button not cause a WM_COMMAND message? That's also a problem, 'cuz it's not very cool if clicking the "cancel" button does nothing, right?
    Last edited by Hunter2; 06-27-2003 at 03:38 PM.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  13. #13
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    Yeah, dispatch it and then return just after.

    And the button SHOULD generate a WM_COMMAND message as well.

  14. #14
    I lurk
    Join Date
    Aug 2002
    Posts
    1,361
    Not sure if this was mentioned, but you can use EndDialog() to end a dialog box.

  15. #15
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    From MSDN:
    The application destroys the dialog box (created with CreateDialog()) by using the DestroyWindow function.
    EndDialog() is used to end modal dialogs, which I've been happy with 'till the non-modal came up.
    And the button SHOULD generate a WM_COMMAND message as well.
    Strange, because when I go through the messages, I had it check for just WM_COMMAND and then log the control ID to a file and quit. Nothing happens when I hit the cancel button... Should I post some code? The whole program?
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. trying to understand the message loop
    By bling in forum Windows Programming
    Replies: 4
    Last Post: 08-08-2008, 09:27 AM
  2. Message loop
    By beene in forum Game Programming
    Replies: 2
    Last Post: 11-26-2007, 05:19 PM
  3. "try again" loop not working
    By scwizzo in forum Game Programming
    Replies: 5
    Last Post: 04-01-2007, 09:56 PM
  4. Pausing in the message loop
    By IdioticCreation in forum Game Programming
    Replies: 7
    Last Post: 01-22-2007, 07:21 PM
  5. Message class ** Need help befor 12am tonight**
    By TransformedBG in forum C++ Programming
    Replies: 1
    Last Post: 11-29-2006, 11:03 PM