Announcement

Collapse
No announcement yet.

How to use a message pump? how to communicate between two dialogs?

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

  • How to use a message pump? how to communicate between two dialogs?

    Hello PB guys!
    I couldn't find posts about 'message pump' for DIALOG MODELESS and ways to communicate between dialogs. Hope you may give some ideas.

    I have a program using two dialogs for a laboratory activity.
    a) the first one is DIALOG MODAL and is the main interface to my students, it can receive texts, actions and close when the lab activity is finished.
    b) the 2nd one is DIALOG MODELESS, where I take notes about some inputs or other actions done in the first dialog and could send new instructions or messages. I want to have the first dialog free of messages to reduce distractions.

    To communicate between those 2 dialogs I use a text file created by the 1st dialog. The 2nd dialog has a timer looking if the message file has been created. In such case it reads its content and kills it, waiting for another event. According to the content of the file, the 2nd dialog makes a process (send a response, writes to a log file or whatever I want).

    To close the 2nd dialog the message file just need the text "close" . The first window may continue working until the student closes it.

    I am including a reduced code of this program (just to have an idea of how it works). The program works according to my needs.

    These are the questions:
    1) as I'm using DIALOG MODELESS (that is quite new to me), I've read from PBHelp that I have to use a 'message pump', including DIALOG DOEVENTS, but I cannot find if I really need it, because the program looks to work fine. When I include a loop with DOEVENTS, the program only shows the 2nd dialog. Probably I do not know where to put the message pump. I've looked for more information on windows webpages but it is not clear to me how to use the message pump.
    2) Is there another simpler way to communicate between the 2 dialogs instead of the message file? I've tried sendmessage but I cannot retrieve the message in the 2nd window.

    Thank you in advance for your comments

    TwoDialogCommunication.bas

  • #2
    Code:
    GLOBAL hDlg2  AS DWORD
    
    '%TEXTBOX1013=1013:%BTN =1014:%LABEL1011 =1011:%LABEL1012 =1012:%BUTTON1014 =1014:%LABEL1021 =1021
    
    FUNCTION PBMAIN()
     ShowDIALOG2 %HWND_DESKTOP
     ShowDIALOG1 %HWND_DESKTOP
    END FUNCTION
    
    CALLBACK FUNCTION ShowDIALOG1Proc()
     LOCAL a AS STRING
        SELECT CASE AS LONG CB.MSG
            CASE %WM_CLOSE
                DIALOG END CB.HNDL
            CASE %WM_COMMAND
                SELECT CASE AS LONG CB.CTL
                    CASE 1014
                        IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN
                            CONTROL GET TEXT CB.HNDL,1013 TO a
                            CONTROL SET TEXT hDlg2,1021, "My message = " + a
                        END IF
                END SELECT
        END SELECT
    END FUNCTION
    
    FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
        LOCAL lRslt AS LONG, hDlg AS DWORD
        DIALOG NEW hParent, "hDlg", 1, 1, 300, 120, %WS_POPUP OR %WS_BORDER OR %WS_DLGFRAME 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
        CONTROL ADD LABEL,   hDlg, 1011 , "1011"        ,   5,  20, 100, 12
        CONTROL ADD TEXTBOX, hDlg, 1013 , "1013"        ,   5,  40, 100, 12
        CONTROL ADD LABEL,   hDlg, 1012 , "1012 Write a message or" & $CRLF & "Write 'close' to end 2nd dialog", 110,40,180,24
        CONTROL ADD BUTTON,  hDlg, 1014 , "1014 Send message to 1021 2nd window" , 100, 60,  140, 20
        DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
    END FUNCTION
    
    FUNCTION ShowDIALOG2(BYVAL hParent AS DWORD) AS LONG
        DIALOG NEW hParent, "hDlg2",1,138,300,120, %WS_POPUP OR %WS_BORDER OR %WS_DLGFRAME 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 hDlg2
        CONTROL ADD LABEL, hDlg2, 1021, "1021", 5, 20, 100, 12
        DIALOG SHOW MODELESS hDlg2
    END FUNCTION
    How long is an idea? Write it down.

    Comment


    • #3
      You don't need a message pump for the second modeless dialog. You only need one in your application and the Modal Dialog creates it.

      There are many ways to communicate between the dialogs. This demonstrates two ways:
      1. Set Text (similar to Mike's)
      2. Sending a message

      '
      Code:
      #COMPILE EXE
      #DIM ALL
      %UNICODE = 1
      #INCLUDE ONCE "WIN32API.INC"
      
      ENUM ctrls SINGULAR
        IDC_Quit = 1001
        IDC_Send
        IDC_Send2
        IDC_txt
      
        WM_GetData = %WM_USER + 1000
      END ENUM
      
      GLOBAL  hDlg AS DWORD
      GLOBAL hDlg2 AS DWORD
      GLOBAL gstrMessage AS STRING
      FUNCTION PBMAIN() AS LONG
          MainDLg 0
      END FUNCTION
      
      FUNCTION MainDlg (hParent AS DWORD) AS LONG
         LOCAL lRslt AS LONG
          DIALOG NEW hParent, "Main Dialog",100 ,100 , 250, 200, %WS_POPUP OR %WS_BORDER _
              OR %WS_DLGFRAME OR %WS_MINIMIZEBOX OR %WS_SYSMENU OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR _
              %DS_MODALFRAME, TO hDlg
           CONTROL ADD TEXTBOX , hDlg,%IDC_txt,"",20,10,200,60, %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %ES_WANTRETURN OR _
              %WS_HSCROLL OR %WS_VSCROLL OR %ES_LEFT OR %ES_MULTILINE OR %ES_AUTOHSCROLL OR %ES_AUTOVSCROLL, %WS_EX_CLIENTEDGE OR %WS_EX_LEFT _
              OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR
          CONTROL ADD BUTTON , hDlg,%IDC_quit,"Quit",40,170,80,20
          DIALOG SHOW MODAL hDlg, CALL MainDlgCB TO lRslt
      END FUNCTION
      
      CALLBACK FUNCTION MainDlgCB()
          LOCAL pMsg AS STRING PTR
          SELECT CASE AS LONG CB.MSG
      
              CASE %WM_INITDIALOG
                  Dlg2 CB.HNDL 'create second modeless dalog as child of ths one
              CASE %wM_GetData
                  pMsg = CB.WPARAM
                  ?  @pMsg,,"Message received by main dialog"
                  CONTROL SET FOCUS hDLg, %IDC_quit
      
              CASE %WM_COMMAND
                  SELECT CASE AS LONG CB.CTL
                      CASE %IDC_QUIT
                          IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN
                              DIALOG END CBHNDL
                           END IF
                  END SELECT
          END SELECT
      END FUNCTION
      
      
      FUNCTION Dlg2 (hParent AS DWORD) AS LONG
         LOCAL lRslt AS LONG
      
          DIALOG NEW hDlg, "2nd Dialog",300 ,0 , 250, 200, %WS_POPUP OR %WS_BORDER _
              OR %WS_DLGFRAME OR %WS_MINIMIZEBOX OR %WS_SYSMENU OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR  %DS_MODALFRAME, _
              TO hDlg2
          CONTROL ADD TEXTBOX , hDlg2,%IDC_txt,"Enter somethng here and press a button",20,10,200,60, _
              %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %ES_WANTRETURN OR _
              %WS_HSCROLL OR %WS_VSCROLL OR %ES_LEFT OR %ES_MULTILINE OR %ES_AUTOHSCROLL OR %ES_AUTOVSCROLL, %WS_EX_CLIENTEDGE OR %WS_EX_LEFT _
              OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR
          CONTROL ADD BUTTON , hDlg2,%IDC_Send,"Add text to Man Dalog Textbox",40,80,140,20
          CONTROL ADD BUTTON , hDlg2,%IDC_Send2,"Send as message",40,110,140,20
          DIALOG SHOW MODELESS hDlg2, CALL Dlg2CB TO lRslt
      END FUNCTION
      
      CALLBACK FUNCTION Dlg2CB()
          LOCAL strT,strT2 AS STRING
          SELECT CASE AS LONG CB.MSG
      
           CASE %WM_SYSCOMMAND
                 IF CB.WPARAM = %SC_CLOSE THEN  ' trap red X
                     ? "You can't close ths window whle the main one is open"
                     FUNCTION = 1
                 END IF
      
              CASE %WM_COMMAND
                  SELECT CASE AS LONG CB.CTL
                      CASE %IDC_Send
                          IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN
                              CONTROL GET TEXT CB.HNDL, %IDC_txt TO strT
                              CONTROL GET TEXT hDLg, %IDC_txt TO strT2
                              strT2 += IIF$(ISNULL(strT2),"",$CRLF) & strT
                              CONTROL SET TEXT hDLg, %IDC_txt ,strT2
                              CONTROL SEND hDLg, %IDC_txt,%em_setsel,(LEN(strT2)+1),(LEN(strT2)+1)
                              CONTROL SEND hDLg, %IDC_txt,%em_scrollcaret,0,0
                              CONTROL SET FOCUS hDLg, %IDC_txt
                            END IF
      
                      CASE %IDC_Send2
                          IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN
                              CONTROL GET TEXT CB.HNDL, %IDC_txt TO gstrMessage
                              DIALOG SEND hDlg ,%WM_GetData,VARPTR(gstrMessage),0
                          END IF
      
      
                  END SELECT
          END SELECT
      END FUNCTION
      '
      Last edited by Stuart McLachlan; 18 Oct 2020, 01:14 AM.

      Comment


      • #4
        Originally posted by Mike Doty View Post
        Code:
        ...
        Crashes for me when you close the modal dialog.

        Comment


        • #5
          I don't know?
          Being called after event?
          CASE %WM_CLOSE
          DIALOG END hDlg2 'added this and still does not crash
          DIALOG END CB.HNDL

          I can' get to crash using 32-bit Windows 10.
          Also tried using ALT + F4
          How long is an idea? Write it down.

          Comment


          • #6
            This is the culprit:

            Code:
                 CASE %WM_CLOSE
                    DIALOG END CB.HNDL
            No idea how it can be working on your 32bit Windows. It's definitely incorrect code.

            %WM_CLOSE is received when the Dialog is closing.
            In theory this is infinite recursion since DIALOG END will trigger another %WM_CLOSE which will trigger another ....
            In effect this results in sending a message to a dialog handle after the dialog has closed and the handle is no longer valid

            Just remove the whole CASE %WM_CLOSE and it works fine.

            Comment


            • #7
              Updated code in Post #3 to be more useful. it now appends entered text scrolls to the end of the text and returns focus to the man dialog

              Comment


              • #8
                Post #3 comments:

                The modal dialog sends a custom message within CASE %IDC_Send2 to main dialog and waits for response.
                The main dialog can optionally modify those values and return the new values to the modal dialog.

                The values do not need to be global (gstrMessage.)

                Very nice, Stuart.
                How long is an idea? Write it down.

                Comment


                • #9
                  Originally posted by Mike Doty View Post
                  Post #3 comments:

                  The modal dialog sends a custom message within CASE %IDC_Send2 to main dialog and waits for response.
                  The main dialog can optionally modify those values and return the new values to the modal dialog.

                  The values do not need to be global (gstrMessage.)
                  .
                  Good point. If the data is gong to be acted on straight away and discarded then you just need
                  '
                  Code:
                          CASE %wM_GetData
                              pMsg = CB.WPARAM
                              ?  @pMsg
                              @pMsg = "Main dialog got the message" 'return a different message
                  
                  ...
                              CASE %IDC_Send2
                                  LOCAL strMsg AS STRING
                                  IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN
                                      CONTROL GET TEXT CB.HNDL, %IDC_txt TO gstrMessage
                                      strT = "Test" 'original message
                                      DIALOG SEND hDlg ,%WM_GetData,VARPTR(strMsg),0
                                      ? strT   'display the changed message
                                  END IF
                  '
                  And if you don't need a response or strng data, you don't need to use a pointer at all.
                  You can use integers or numeric equates directly in WPARAM wth SELECT CASE AS LONG in %WM_GetData.

                  Comment


                  • #10
                    Thank you Mike and Stuart! I am learning about the defects you've found in my code. I shall practice what you've proposed.

                    Comment


                    • #11
                      You don't need a message pump for the second modeless dialog. You only need one in your applicatio
                      Actually, you need one message pump per GUI thread in your program. Meaniing if your program creates additional threads of execution, if an additional thread creates a window or dialog it requires its own message pump.

                      I have posted a demo here but I think at this point that would be skipping ahead several chapters. For now the message (no pun intended) should be you usually only need one message pump per program.

                      FWIW, the PB Win 10 doc shows under DIALOG SHOW MODELESS how to create the required message loop:

                      A DIALOG SHOW MODELESS statement is usually followed by a message pump loop. For more information, please refer to the examples under DIALOG DOEVENTS.
                      Well, at least the doc directs you to the right place, but is IMO deficient in not telling you you MUST create a message loop UNLESS a DIALOG SHOW MODAL statement has been used in this thread of execution.

                      MCM

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

                      Comment


                      • #12
                        Thank you Stuart, sorry I didn't respond before. It is really cryptic of defective the information on this part of the PBHelp, but I can understand it is hard to explain everything to different users' levels. My regards for your help.

                        Comment


                        • #13
                          %WM_CLOSE is received when the Dialog is closing.

                          Not necessarily.. WM_CLOSE is not a notification, it is in fact an opportunity message.

                          WM_DESTROY is, I think, what you are thinking of.

                          BUt back to WM_CLOSE. Thuss sayeth Microsoft:


                          The WM_CLOSE message is sent as a signal that a window or an application should terminate.

                          ....

                          Return Value
                          If an application processes this message, it should return zero.

                          Remarks
                          An application can prompt the user for confirmation, prior to destroying a window, by processing the WM_CLOSE message and calling the function only if the user confirms the choice.
                          By default, the function calls the DestroyWindow function to destroy the window.
                          As you can see, if you don't process a WM_CLOSE message, it will result in the destruction of this window...

                          It is much like the "PostQuitMessage" function... which is called by the application to post a WM_QUIT message to the calling thread, which is how your message loop "lnows" to exit.

                          We don't know (well, I sure don't know) what PowerBASIC uses as its default dialog procedure for DDT, but the standard processing for WM_CLOSE in the standard DefDlgProc is described here : https://docs.microsoft.com/en-us/win...considerations

                          and as far as..

                          In theory this is infinite recursion since DIALOG END [on WM_CLOSE processing] will trigger another %WM_CLOSE which will trigger another ....
                          That the DIALOG END statement will generate a WM_CLOSE message is not documented as far as I can find; but if it does, you are 100% correct that you will put your dialog into an infinite loop by issuing DIALOG END in response to WM_CLOSE .. maybe.

                          Except I don't think it does that.

                          WM_CLOSE is typically sent or posted to the window when the user has taken an action meaning "end proceessing this screen" - actions like clicking a "done" button or hitting the "X" on a system menu - and the user may now take any action up to and including preempting the termination of the screen depending on the application state (e.g, "Save before exiting?" or the ubiquitous "Are you sure you want to quit?") .

                          So... DIALOG END on WM_CLOSE actually makes really good sense to me... but without knowing PowerBASICs default dialog procedure I could not bet the ranch on this, and if maybe the dialog procedure should be exited after issuing a DIALOG END to avoid entering an infinite loop as you suggest.

                          Disclaimer: I am not a "DDT Guy."


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

                          Comment


                          • #14
                            DIALOG END CB.HNDL, 0

                            does not work well in Windows 10 , there is a work around at

                            https://forum.powerbasic.com/forum/u...696#post753696

                            and Jose's explanation at

                            https://forum.powerbasic.com/forum/u...620#post702620

                            Comment


                            • #15
                              DIALOG END CB.HNDL, 0

                              does not work well in Windows 10 , there is a work around is at . . .
                              ???Under what circumstances do you think it does not work?

                              Right click on task bar icon and clicking close is not , repeat NOT, a DIALOG END thing. It is a %wm_syscommand action. That is referred to links subject.

                              DIALOG END was used incorrectly here, see post 6 above.

                              Also, in thread you linked to, no failing code was ever shown.

                              Perhaps Windows 10 has a system menu problem. There is no PB problem apparent!
                              Dale

                              Comment


                              • #16
                                Originally posted by Anne Wilson View Post
                                DIALOG END CB.HNDL, 0

                                does not work well in Windows 10 , there is a work around at

                                https://forum.powerbasic.com/forum/u...696#post753696

                                and Jose's explanation at

                                https://forum.powerbasic.com/forum/u...620#post702620
                                Those posts' relevant parts read..
                                [from Pierre B]
                                Problem is that we are not sure of what DDT is going on under the hood.
                                A modal DDT dialog is suppose to end via DIALOG END.
                                PostQuitMessage(0) is not supposed to be used, nor WM_QUIT.

                                [from Jose:R]
                                When clicking the X button, Windows DOES NOT destroy the dialog, but sends an WM_CLOSE message and leaves you to decide what to do, i.e. ignore it or destroy the dialog with DestroyWindow, and after calling DestroyWindow, WM_DESTROY will be received. Don't send PostQuitMessage in WM_CLOSE because, at this point, the dialog has not been destroyed.
                                I think the bottom line is, "We don't know what DDT is doing on DIALOG END' and so at this point we cannot definitively say any "won't close" problem is being caused by "DIALOG END on WM_CLOSE"

                                (Something related to mixing a DIALOG SHOW MODAL and DIALOG SHOW MODELESS on the same thread of execution?)

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

                                Comment


                                • #17
                                  Originally posted by Anne Wilson View Post
                                  DIALOG END CB.HNDL, 0

                                  does not work well in Windows 10 , there is a work around at

                                  https://forum.powerbasic.com/forum/u...696#post753696

                                  and Jose's explanation at

                                  https://forum.powerbasic.com/forum/u...620#post702620

                                  Your first link does not show a problem with DIALOG END.

                                  Jose's explanation is not only irrelevant to the question, , it is also incorrect. "When clicking the X button, Windows DOES NOT destroy the dialog, but sends an WM_CLOSE message". is not true. As Dale points out, it sends a %WM_SYSCOMMAND message.

                                  Comment


                                  • #18
                                    Question: how do you abort a %WM_CLOSE?
                                    Code:
                                    lRslt = mgsbox("Are you sure?", %MB_YESNO)
                                    If lRslt = %IDNO then what?
                                    Andrea Mariani
                                    AS/400 expert
                                    Basic programmer @ Home

                                    Comment


                                    • #19
                                      Originally posted by Andrea
                                      Question: how do you abort a %WM_CLOSE?
                                      From the manual:
                                      Callback Return Values

                                      Callback functions always return a long integer result. The primary purpose of this return value is to tell the PowerBASIC DDT engine and the Windows operating system whether your Callback Function has processed this particular message. If you return the value TRUE (any non-zero value), you are asserting that the message was processed and no further handling is needed. If you return the value FALSE (zero), the PowerBASIC DDT engine will manage the message for you, using the default message procedures in Windows. If you do not specify a return value in the function, PowerBASIC chooses the value FALSE (zero) for you.

                                      So, If lRslt = %IDNO Then Function = %True

                                      Comment


                                      • #20
                                        You cannot prevent a Dialog closing once %WM_CLOSE is received. You do have the opportunity to save your work but the dialog will close in DDT.

                                        You can abort %WM_CLOSE for a SDK Window.
                                        Rgds, Dave

                                        Comment

                                        Working...
                                        X