Announcement

Collapse
No announcement yet.

Msgbox doesn't display after PostQuitMessage

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

  • Msgbox doesn't display after PostQuitMessage

    2/24/09
    This thread from 3 days ago is about preventing the user from closing a dialog with "X" or using ALT+F4
    PostQuitMessage should never have been used.
    Solutions are in post #11.
    --------------------------------------------------------------------------------------------------



    What is wrong with this code?
    If MSGBOX is placed before PostQuitMessage it works.
    If placed after PostQuitMessage the msgbox does not display and dialog can not be closed even if threads have finished.
    Don't plan on using the MSGBOX, but curious.

    Code to prevent user from closing dialog before all threads have finished.

    Code:
    CASE %WM_SYSCOMMAND
              IF THREADCOUNT > 1 THEN
                  PostQuitMessage 0
                  ? "Threads still active" + STR$(THREADCOUNT) 'doesn't display, program can't end
                  FUNCTION =1
              END IF
    Last edited by Mike Doty; 24 Feb 2009, 12:48 PM.
    How long is an idea? Write it down.

  • #2
    One of two things is happening:

    1. MSGBOX is MODAL, creating its own message loop, which executes asynchronously from the program's primary message loop.

    WM_QUIT reaches and is processed by that primary message loop as soon as MSGBOX is started up, and the normal handling of WM_QUIT is to end the GUI thread. (Insufficient code shown).

    I think you could get the messagebox to display by suspending the primary thread after the MSGBOX (SLEEP ought to do it); but that is going to be a timing thing, so it's not going to be terribly reliable in any event.

    2. THREADCOUNT is not greater than one, in which case the default procedure will handle WM_SYSCOMMAND, so what happens is dependent on the notification code in wParam.

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

    Comment


    • #3
      I did try to use Msgbox during a WM_DESTROY ever.
      It may be Windows does not allow this box during a 'critical' message.

      I don't know.
      hellobasic

      Comment


      • #4
        Wrote a smaller test program, here.
        It appears I got pretty lazy in not checking for a mouse click in SYS_COMMAND.
        The dialog couldn't be moved or resized.
        Wrote this improvement, but MSGBOX should still NOT go after PostQuitMessage.
        'SYS_COMMAND thread
        http://www.powerbasic.com/support/pb...=WM_SYSCOMMAND

        Code:
        #PBFORMS CREATED V1.51
        #COMPILE EXE
        #DIM ALL
        '------------------------------------------------------------------------------
        '   ** Includes **
        '------------------------------------------------------------------------------
        #PBFORMS BEGIN INCLUDES
        #IF NOT %DEF(%WINAPI)
            #INCLUDE "WIN32API.INC"
        #ENDIF
        #PBFORMS END INCLUDES
        '------------------------------------------------------------------------------
        '------------------------------------------------------------------------------
        '   ** Constants **
        '------------------------------------------------------------------------------
        #PBFORMS BEGIN CONSTANTS
        %IDD_DIALOG1 = 101
        #PBFORMS END CONSTANTS
        '------------------------------------------------------------------------------
        '------------------------------------------------------------------------------
        '   ** Declarations **
        '------------------------------------------------------------------------------
        DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
        DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
        #PBFORMS DECLARATIONS
        '------------------------------------------------------------------------------
        '------------------------------------------------------------------------------
        '   ** Main Application Entry Point **
        '------------------------------------------------------------------------------
        FUNCTION PBMAIN()
            ShowDIALOG1 %HWND_DESKTOP
            ? "PBMAIN EXIT"
        END FUNCTION
        '------------------------------------------------------------------------------
        '------------------------------------------------------------------------------
        '   ** CallBacks **
        '------------------------------------------------------------------------------
        CALLBACK FUNCTION ShowDIALOG1Proc()
            LOCAL dw AS DWORD
            SELECT CASE AS LONG CBMSG
                CASE %WM_INITDIALOG
                    ' Initialization handler
                    THREAD CREATE t(CBHNDL) TO dw
                    THREAD CLOSE dw TO dw
                    SLEEP 250
         
                CASE %WM_NCACTIVATE
                    STATIC hWndSaveFocus AS DWORD
                    IF ISFALSE CBWPARAM THEN
                        ' Save control focus
                        hWndSaveFocus = GetFocus()
                    ELSEIF hWndSaveFocus THEN
                        ' Restore control focus
                        SetFocus(hWndSaveFocus)
                        hWndSaveFocus = 0
                    END IF
                CASE %WM_COMMAND
                    ' Process control notifications
                    SELECT CASE AS LONG CBCTL
                    END SELECT
         
                CASE %WM_SYSCOMMAND
                    IF (CBWPARAM AND &HFFF0) = %SC_CLOSE THEN
                       FUNCTION = 1
                       IF THREADCOUNT > 1 THEN  'only end if no extra threads
                         MSGBOX "Can not end yet, thread count" + STR$(THREADCOUNT) 'ok
                         PostQuitMessage 0
                         'MSGBOX "THIS IS NOT OKAY
                       ELSE
                         FUNCTION = 1
                         PostMessage CBHNDL, %WM_USER + 2048, 0, 0
                         EXIT FUNCTION
                       END IF
                    END IF
                CASE %WM_USER + 2048
                    ? "2048"
                    DIALOG END CBHNDL
                'CASE %WM_SYSCOMMAND
                '    IF (CB.WPARAM AND &HFFF0) = %SC_CLOSE THEN
                '      IF THREADCOUNT > 1 THEN   'Dialog can't be resized/moved
                '                                'until thread has finished
                '        PostQuitMessage 0
                '        ? "Thread is still running"
                '        FUNCTION = 0
                '      END IF
                '    END IF
            END SELECT
        END FUNCTION
        '------------------------------------------------------------------------------
        '------------------------------------------------------------------------------
        '   ** Dialogs **
        '------------------------------------------------------------------------------
        FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
            LOCAL lRslt AS LONG
        #PBFORMS BEGIN DIALOG %IDD_DIALOG1->->
            LOCAL hDlg  AS DWORD
            DIALOG NEW hParent, "Dialog1", 325, 196, 204, 121, %WS_POPUP OR _
                %WS_BORDER OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR _
                %WS_SYSMENU OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_MODALFRAME OR _
                %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT _
                OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO _
                hDlg
        #PBFORMS END DIALOG
            DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
        #PBFORMS BEGIN CLEANUP %IDD_DIALOG1
        #PBFORMS END CLEANUP
            FUNCTION = lRslt
        END FUNCTION
        '------------------------------------------------------------------------------
        THREAD FUNCTION t(BYVAL hDlg AS DWORD) AS DWORD
          LOCAL x AS LONG
          FOR x = 10 TO 1 STEP -1
              DIALOG SET TEXT hDlg, STR$(x) + " ThreadCount" + STR$(THREADCOUNT)
              SLEEP 1000
          NEXT
        END FUNCTION
        Code:
        CASE %WM_SYSCOMMAND
            IF (CBWPARAM AND &HFFF0) = %SC_CLOSE THEN
              IF THREADCOUNT > 1 THEN  'prevent end if extra threads
                ? "Thread count still" + STR$(THREADCOUNT) 'ok before PostQuitMessage
                PostQuitMessage 0
                'Do not put any MSGBOX statements in here
                FUNCTION = 1
              END IF
            END IF
        Last edited by Mike Doty; 21 Feb 2009, 02:10 PM.
        How long is an idea? Write it down.

        Comment


        • #5
          PostQuitMessage is 'conventionally' called on WM_DESTROY, not on WM_SYSCOMMAND (any).

          Do that=end of problems.
          Michael Mattias
          Tal Systems Inc. (retired)
          Racine WI USA
          [email protected]
          http://www.talsystems.com

          Comment


          • #6
            PostQuitMessage did not stop dialog from ending in my testing within %WM_DESTROY. I would like to see a working example. Thanks for trying.

            Here is a solution and MSGBOX (if used) does not cause a problem.
            Code:
             CASE %WM_SYSCOMMAND
                 IF (CBWPARAM AND &HFFF0) = %SC_CLOSE THEN
                   IF THREADCOUNT > 1 THEN FUNCTION = 1 'prevent dialog end
                 END IF
            Thanks to Bern Ertl (post #3)
            http://www.powerbasic.com/support/pb...5WM_SYSCOMMAND
            Last edited by Mike Doty; 21 Feb 2009, 10:09 PM.
            How long is an idea? Write it down.

            Comment


            • #7
              Here is a solution and MSGBOX (if used) does not cause a problem.

              Code:
               CASE %WM_SYSCOMMAND
                   IF (CBWPARAM AND &HFFF0) = %SC_CLOSE THEN
              If you had said originally you were interested in the SC_CLOSE notification this would have been a lot simpler. Your posted code problem expresses interest in 'any' notification provided via WM_SYSCOMMAND.

              But I think I said that: " ... so what happens is dependent on the notification code in wParam. "

              As far as using WM_DESTROY, a current thread on this subject is at http://www.powerbasic.com/support/pb...ad.php?t=39941. I think the key statement there is "it *IS* too late..." . That may be of interest, too.
              Michael Mattias
              Tal Systems Inc. (retired)
              Racine WI USA
              [email protected]
              http://www.talsystems.com

              Comment


              • #8
                Original posting title was confusing.
                The code did show this:
                Code to prevent user from closing dialog before all threads have finished.

                Off subject, but I dislike postings that are titled "Need help".

                To prevent a dialog from ending when using clicks X or if Alt+F4 is used
                only requires FUNCTION=1 in %WM_SYSCOMMAND
                My use of PostQuitMessage was entirely incorrect.

                Code:
                CASE %WM_SYSCOMMAND
                     IF (CBWPARAM AND &HFFF0) = %SC_CLOSE THEN
                       IF THREADCOUNT > 1 THEN FUNCTION = 1 'prevent dialog end
                     END IF
                Last edited by Mike Doty; 22 Feb 2009, 09:43 AM.
                How long is an idea? Write it down.

                Comment


                • #9
                  Another way to do it is to disable the SC_CLOSE option on the system menu until you wish to permit that action. If the user can't click the "X" or "Close" he knows he ain't ending now.

                  (I'm pretty sure that handles Alt+F4, too).

                  I know there are examples here.

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

                  Comment


                  • #10
                    Good suggestion. I'll post code for that later today.

                    RemoveMenu(GetSystemMenu(CBHNDL, %False), %SC_CLOSE, %MF_BYCOMMAND) 'removes X
                    It does not disable the Alt+F4.
                    Not sure how to force the "X" (caption) to be refreshed. Resizing the window refreshes.
                    Last edited by Mike Doty; 24 Feb 2009, 10:40 AM.
                    How long is an idea? Write it down.

                    Comment


                    • #11
                      Works, but would think a windows handle would have been needed

                      This appears to work, but I would have thought the windows handle rather
                      than CBHNDL would have been necessary.
                      Code:
                      RemoveMenu(GetSystemMenu(CBHNDL, %False), %SC_CLOSE, %MF_BYCOMMAND)
                      DrawMenuBar CBHNDL
                      Before any thread is created the X is disabled (code above.)
                      When threads finish they see if they were the last thread and if so enable X.
                      Code:
                      IF THREADCOUNT = 2 THEN    'allow user to end, thread count about to be 1
                          RemoveMenu(GetSystemMenu(ghDlg, %True), %SC_CLOSE, %MF_BYCOMMAND)
                          DrawMenuBar ghDlg
                      END IF
                      This takes care of Alt+F4. Disabling "X" does not handle it.
                      Code:
                      CASE %WM_SYSCOMMAND
                           IF (CBWPARAM AND &HFFF0) = %SC_CLOSE THEN
                             IF THREADCOUNT > 1 THEN FUNCTION = 1 'prevent dialog end
                           END IF
                      Last edited by Mike Doty; 24 Feb 2009, 12:52 PM.
                      How long is an idea? Write it down.

                      Comment

                      Working...
                      X