Announcement

Collapse
No announcement yet.

WMSYSCOMMAND DIALOG SC_CLOSE anomaly?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • WMSYSCOMMAND DIALOG SC_CLOSE anomaly?

    Looking at ways to close the application. It seems I need to send the parent a message using PostQuitMessage 0 which (I'm guessing) is the same in effect as DIALOG CLOSE 0.

    Looking at messages in my message pump, I can trap the SYSCOMMAND message if the user right-clicks and closes the dialog, or uses F4, but not if the X box gets clicked. I deduce that the message is not passed on by DDT if no callback function is declared. In the code below, if you click the X to close the application, you will have to kill it by other means (Windows Task Manager), but if you right click the dialog caption it closes OK. I don't suppose DDT DIALOGS were designed to be abused this way.

    Code:
      #COMPILE EXE
      #REGISTER NONE
      #DIM ALL
      #INCLUDE "Win32Api.Inc"
    
    '--------------------------------------------------------------------------
    
      FUNCTION PBMAIN()
         LOCAL Msg AS tagMsg, hDlg AS LONG, i AS LONG
    
         DIALOG NEW 0 ,"CLOSE PROBLEM", 7, 62, 408, 161, %WS_CAPTION OR %WS_SYSMENU TO hDlg
         DIALOG SHOW MODELESS hDlg 'CALL DlgProc
         WHILE GetMessage(Msg, %NULL, 0, 0)
             IF msg.message = %WM_syscommand THEN
                 IF (msg.wParam AND &HFFF0) = %SC_CLOSE THEN
                      BEEP
                      PostQuitMessage 0
                 END IF
             END IF
    '
             IF IsDialogMessage(hDlg, Msg) = %FALSE THEN
                  TranslateMessage Msg
                  DispatchMessage Msg
             END IF
         LOOP
    
      END FUNCTION

  • #2
    It seems I need to send the parent a message using PostQuitMessage 0 which (I'm guessing) is the same in effect as DIALOG CLOSE 0.
    Normally you would trap WM_SYSCOMMAND/SC_CLOSE in your dialog procedure (not shown) , not in a separate test outside the 'regular' message loop.

    I'm not a DDT guy, but I can tell you PostQuitMessage() is not how you end a dialog Or any dialog for that matter using either SDK-style or DDT coding; PostQuitMessage does not do that. (See your API reference).

    MCM
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      While it is possible to trap some messages in a message loop (ie. mouse movement, keyboard), not all messages are passed through the message loop.

      Most messages are sent directly to the window procedure of the window (for dialogs they get forwarded to your dialog procedure).

      The message loop only handles messages which are sent to the applications message queue. If a message is sent directly to a window procedure, it will never go through the message loop.

      When you read the API docs notice whether the they say that a message is sent to the window procedure or whether it is posted to the message queue.

      The SendMessage API function sends a message directly to the window procedure and it never passes through the message loop.

      The PostMessage API function puts the message in the message queue and it will get processed in the apps message loop.

      If the API docs say, a message is sent to the window procedure, don't attempt to trap it in the message loop!

      WM_SYSCOMMAND is sent directly to the window procedure (and forwarded to the dialog procedure).
      Chris Boss
      Computer Workshop
      Developer of "EZGUI"
      http://cwsof.com
      http://twitter.com/EZGUIProGuy

      Comment


      • #4
        DDT applications don't normally use a standard message loop.

        They use a slightly different DDT style of a message loop which looks like this:

        Code:
        FUNCTION PBMAIN
            LOCAL Count&
            ' display your main dialog by calling its creation routine
            ShowDialog_Form1
            DO
                DIALOG DOEVENTS TO Count&
            LOOP UNTIL Count&=0
            ' loop will terminate when no dialogs exist
        END FUNCTION
        There is no need to use the PostQuitMessage API function to end a DDT app. That function simply sends a specific value to a message loop which it can test for to determine whether to exit the loop code.

        DDT has its own style of message loop code, which does not require this.
        Chris Boss
        Computer Workshop
        Developer of "EZGUI"
        http://cwsof.com
        http://twitter.com/EZGUIProGuy

        Comment


        • #5
          Originally posted by Michael Mattias View Post
          ... I can tell you PostQuitMessage() is not how you end a dialog Or any dialog for that matter using either SDK-style or DDT coding; PostQuitMessage does not do that.
          Well, I'm just an innocent abroad in these matters. I borrowed the code originally from Mr Matusovski. Here's what MSDN has to say about the dratted function:

          MSDN:
          PostQuitMessage Function
          The PostQuitMessage function indicates to the system that a thread has made a request to terminate (quit). It is typically used in response to a WM_DESTROY message.
          That is why it reminded me of the DIALOG END, 0 DDT command.

          Irrespective of this, it seems curious that whereas F4 and right-click+Close both result in a message escaping back to the application, clicking the red X in the top right of the dialog margin does not.

          Comment


          • #6
            Originally posted by Chris Boss View Post
            The SendMessage API function sends a message directly to the window procedure and it never passes through the message loop.
            OK, so the "X" does not notify through the message queue and the other two close methods do? That would make sense. So to catch it, one would have to have defined a callback function for the control?

            [QUOTE=Chris Boss;272951] If the API docs say, a message is sent to the window procedure, don't attempt to trap it in the message loop!

            Why not? Oh, sorry, you mean if it is NOT in the message queue don't look for it there. OK.

            Originally posted by Chris Boss View Post
            WM_SYSCOMMAND is sent directly to the window procedure (and forwarded to the dialog procedure).
            OK but there is no difficulty in trapping it in the message loop.

            Comment


            • #7
              MSDN:
              PostQuitMessage Function
              The PostQuitMessage function indicates to the system that a thread has made a request to terminate (quit). It is typically used in response to a WM_DESTROY message.
              IMNSHO that is a terrible explanation of PostQuitMessage. PostQuitMessage simply posts a WM_QUIT to the message queue of the calling thread, with wParam set to the argument of PostQuitMessage.

              What happens after that depends on how the programmer has coded his message loop.. but as noted above, you don't use an "SDK" message loop with DDT dialogs.

              I don't enjoy saying "I told you so" (Ok, so I actually am enjoying the hell out of it in this case), but this is the kind of garbage you end up with when you 'mix and match' DDT-style and 'SDK-style' screen-management syntax.



              MCM
              Michael Mattias
              Tal Systems (retired)
              Port Washington WI USA
              [email protected]
              http://www.talsystems.com

              Comment


              • #8
                Originally posted by Michael Mattias View Post
                IMNSHO that is a terrible explanation of PostQuitMessage.
                ...and that's from the horse's mouth! No wonder I have to look for explanations from other parts.

                Originally posted by Michael Mattias View Post
                I don't enjoy saying "I told you so" (Ok, so I actually am enjoying the hell out of it in this case), but this is the kind of garbage you end up with when you 'mix and match' DDT-style and 'SDK-style' screen-management syntax.
                You laugh, I learn - seems fair.

                The pendulum is swinging towards SDK.

                Comment


                • #9
                  Run this test program.

                  Notice that closing via the X button on captionbar which generates the WM_SYSCOMMAND message does not occur in the message loop and is only occurs in the dialog procedure.

                  This demonstrates my point that some messages may not go through the message loop. Only user input (mouse movement and keyboard) and a few other messages (which are posted) go through the message loop. The majority of messages never see the message loop.

                  Interestingly, WM_SYSCOMMAND can be generated and go through the message loop when it occurs via certain situations.
                  For example, clicking the X button, WM_COMMAND goes straight to the dialog procedure, skipping the message loop.
                  Clicking the captionbar icon to display the system menu and clicking "close" will generate the WM_SYSCOMMAND message which is sent to the message queue and go through the message loop.
                  Also pressing ALT-F4 also will generate the WM_SYSCOMMAND message and pass it though the message loop.

                  One should really only process messages in the message loop that are always guaranteed to go through the message loop (ie. mouse movement or keyboard input).
                  Messages that usually go straight to the dialog procedure and which may not (or possibly never) go to the message loop, should always be processed in the dialog procedure.



                  Code:
                   #COMPILE EXE
                    #REGISTER NONE
                    #DIM ALL
                    #INCLUDE "Win32Api.Inc"
                  '--------------------------------------------------------------------------
                    GLOBAL App_ExitFlag&
                    '
                    FUNCTION PBMAIN()
                       LOCAL Msg AS tagMsg, hDlg AS LONG, i AS LONG
                       App_ExitFlag&=0
                       DIALOG NEW 0 ,"CLOSE PROBLEM", 7, 62, 408, 161, %WS_CAPTION OR %WS_SYSMENU TO hDlg
                       DIALOG SHOW MODELESS hDlg CALL MyDlgProc
                       WHILE GetMessage(Msg, %NULL, 0, 0)
                           IF msg.message = %WM_SYSCOMMAND THEN
                               IF (msg.wParam AND &HFFF0) = %SC_CLOSE THEN
                                    ' this event never occurs, because the message never goes through message queue
                                    MSGBOX "Dialog Closed via X button!"+CHR$(13)+CHR$(10)+"Trapped in Message Loop."
                                    App_ExitFlag&=2
                               END IF
                           END IF
                  '
                           IF IsDialogMessage(hDlg, Msg) = %FALSE THEN
                                TranslateMessage Msg
                                DispatchMessage Msg
                           END IF
                           IF App_ExitFlag& THEN EXIT LOOP     ' terminate app
                       LOOP
                       IF App_ExitFlag&=1 THEN MSGBOX "Exit Flag set in Dialog procedure"
                       IF App_ExitFlag&=2 THEN MSGBOX "Exit Flag set in message loop"
                    END FUNCTION
                   
                    CALLBACK FUNCTION MyDlgproc
                       SELECT CASE CBMSG
                            CASE %WM_SYSCOMMAND
                               IF (CBWPARAM AND &HFFF0) = %SC_CLOSE THEN
                                    ' this event occurs because trapped in dialog procedure
                                    MSGBOX "Dialog Closed via X button!"+CHR$(13)+CHR$(10)+"Trapped in Dialog Procedure."
                                    App_ExitFlag&=1
                               END IF
                       END SELECT
                    END FUNCTION
                  Last edited by Chris Boss; 8 Jan 2008, 09:37 PM.
                  Chris Boss
                  Computer Workshop
                  Developer of "EZGUI"
                  http://cwsof.com
                  http://twitter.com/EZGUIProGuy

                  Comment


                  • #10
                    PostQuitMessage is exactly what it means.

                    Post (to message queue) a message (a unique message value, just like any other message) so it is sent through the message loop which indicates an app should terminate the message loop.

                    The programmer has the responsibility to write code in the message loop to test for the WM_QUIT message in the message loop to determine when to exit the loop code (otherwise the loop becomes an infinite loop and the app is never fully terminated, even though all dialogs have closed).

                    You can either test the message retreived via GetMessage to see if it is WM_QUIT or use the return value of the GetMessage function to see if it is zero (it will only be zero if message is WM_QUIT).

                    If you don't exit the loop code in a message loop, an app is not really terminated. If you press ALT CTRL DEL to display the Task manager dialog, you will find the app is still running and in memory, even if all the dialogs are closed.

                    PostQuitMessage does not terminiate an app!

                    It simply sends a message (to the message loop) that tells the message loop it should exit the loop. If you don't code it correctly, the app will never terminate.
                    Chris Boss
                    Computer Workshop
                    Developer of "EZGUI"
                    http://cwsof.com
                    http://twitter.com/EZGUIProGuy

                    Comment


                    • #11
                      I need to thank you for your kind words.

                      Generally when someone compares me to an equine body part it's not its mouth.
                      Michael Mattias
                      Tal Systems (retired)
                      Port Washington WI USA
                      [email protected]
                      http://www.talsystems.com

                      Comment


                      • #12
                        > Generally when someone compares me to an equine body part it's not its mouth.

                        What is it then, generally?

                        Enquiring minds need to know.

                        I think Chris was referring to MSDN.

                        Comment


                        • #13
                          Chris' explanation is MUCH better than MSDN's.

                          Especially...
                          not all messages are passed through the message loop.
                          .. which suggests trying to process specific messages in the message loop rather than in the window procedure is a fool's errand.
                          Michael Mattias
                          Tal Systems (retired)
                          Port Washington WI USA
                          [email protected]
                          http://www.talsystems.com

                          Comment


                          • #14
                            Yes, Chris' explanation is much better but I find terms like 'sending to' or 'posting to' a message loop confusing.

                            It seems to me that 'posting' is analogous to delivering to a mail box - the mail box is the message queue. We pop down the mail box to collect the mail. We are the message loop. The mail is not delivered to us directly.

                            On the other hand 'sending' is analogous to the mail person knocking on our door and they will not leave until we take the mail from them. In this case the mail did not get put into the mail box.

                            Comment


                            • #15
                              > For example, clicking the X button, WM_COMMAND goes straight to the dialog procedure, skipping the message loop.

                              OK

                              > Clicking the captionbar icon to display the system menu and clicking "close" will generate the WM_SYSCOMMAND message which is sent to the message queue and go through the message loop.

                              OK again but also the dialog procedure unless we add Exit Loop

                              Code:
                              If msg.message = %WM_SYSCOMMAND Then
                                If (msg.wParam And &HFFF0) = %SC_CLOSE Then
                                  ' this event never occurs, because the message never goes through message queue
                                  MsgBox "Dialog Closed via X button!"+Chr$(13)+Chr$(10)+"Trapped in Message Loop."
                                  App_ExitFlag&=2
                                End If
                                [COLOR="Red"]Exit Loop[/COLOR]
                              End If

                              Comment


                              • #16
                                It seems to me that 'posting' is analogous to delivering to a mail box - the mail box is the message queue. We pop down the mail box to collect the mail. We are the message loop. The mail is not delivered to us directly.
                                I understand it this way. I want something to be done, so I write a letter to the person I want to do the job. I assume he will do it as soon as he gets the letter. And I carry on with my life without worrying about it. That is "Posting"
                                On the other hand 'sending' is analogous to the mail person knocking on our door and they will not leave until we take the mail from them. In this case the mail did not get put into the mail box.
                                Now, if I not only want the job to be done, but I want a reply, I "Send" the message by a courier, and I sit and wait until the courier has seen the person, delivered the mail and waits for the person to write the reply, which the courier brings back to me. The courier won't leave without a reply. If the person doesn't write a reply, the courier never comes back. I sit there doing nothing (but breathing) until he returns.

                                regards, Ian.
                                :) IRC :)

                                Comment


                                • #17
                                  > so I write a letter to the person I want to do the job

                                  and if you do not specify a person, with a given window handle, then the mail gets delivered to the mail box at the end of the street - the street being the application and the houses being windows.

                                  Comment


                                  • #18
                                    Why not just disable the [X] close button? I mostly do so, because I find it bad practice to start with if a user clicks [X] to end the program...
                                    Regards,
                                    Peter

                                    Comment


                                    • #19
                                      Michael, I may have chosen my words poorly, but if it's given you a chance to advertise, don't knock it!

                                      This SDK/DDT is a headache. There are so many examples of mixed SDK/DDT that it is tempting to assume that they fit together OK. Maybe the do in some hands. Add in a limited knowledge of the underlying platform and you have a heady mix.

                                      I've resolved to work out where to put my event code by writing a C app (having downloaded a suitable IDE and compiler) to do it, then reverse it into PB.

                                      Comment


                                      • #20
                                        MSDN:
                                        PostQuitMessage Function
                                        The PostQuitMessage function indicates to the system that a thread has made a request to terminate (quit).
                                        It is typically used in response to a WM_DESTROY message.
                                        It is an accurate but terse description of what actually happens.
                                        PostQuitMessage does not post any message to the message queue.
                                        Dominic Mitchell
                                        Phoenix Visual Designer
                                        http://www.phnxthunder.com

                                        Comment

                                        Working...
                                        X