Announcement

Collapse
No announcement yet.

Passing parameters to Dialog Callbacks

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

  • Passing parameters to Dialog Callbacks

    I have started creating hidden controls (size 0, disabled) in
    order to pass flags & data to dialogs. After the DIALOG NEW,
    I'll add the controls, set data in them and then DIALOG SHOW.
    It appears to be working just fine, but I'd appreciate any
    feedback if there is any potential problems with doing this.

    Sometimes this approach makes more sense to me than using GLOBALs.



    ------------------
    Bernard Ertl
    Bernard Ertl
    InterPlan Systems

  • #2
    Personally, I prefer to send/post custom messages. ie,
    Code:
    DIALOG SEND hDlg, %WM_USER + 999&, wparam&, lparam&
    or 
    PostMessage hDlg, %WM_USER + 999&, wparam&, lparam&
    and in the callback:
    Code:
    SELECT CASE CBMSG
      CASE %WM_USER + 999&
        ' do something with CBWPARAM and CBLPARAM
    ...
    ------------------
    Lance
    PowerBASIC Support
    mailto:[email protected][email protected]</A>
    Lance
    mailto:[email protected]

    Comment


    • #3
      OK. Thanks Lance. I suppose that approach will only work for
      MODELESS dialogs...

      Any idea how much overhead I'm carrying using hidden checkboxes
      / labels / textboxes versus GLOBAL vars?



      ------------------
      Bernard Ertl
      Bernard Ertl
      InterPlan Systems

      Comment


      • #4
        When you send a message (SendMessage or Control Send/Dialog Send), Windows actually performs an indirect call to the appropriate callback function (that is, it does not create a queued message, but the call is made to the callback and returns a value to the calling code). PostMessage does create a queued message and does not return a value to the calling code.

        In either case, whether the dialog is modal or modeless is totally irrelevent.

        If you are using controls just to hold or pass data, then the overhead will be significantly higher than using global variables, since each of these controls will be using GDI resources, memory, etc, and very likely contribute to the number of callback messages that are generated (slowing the app slightly).

        How much additional overhead is difficult to measure, but even a simple tool like Win2K's TaskManager can help you count memory and GDI object usage.

        Finally, you may be able to use Window Properties to hold data (see SetProp(), GetProp(), etc). However, sending custom messages is still the easiest way to pass data to a callback and/or subclass/superclass function.

        Alternatively, %WM_COPYDATA may work weel for you too, although it is really designed for inter-process communication.

        So, what sort of data are you passing/storing? If we knew more, maybe we could offer more specific suggestions.

        ------------------
        Lance
        PowerBASIC Support
        mailto:[email protected][email protected]</A>
        Lance
        mailto:[email protected]

        Comment


        • #5
          Hi Lance,

          I'm not using any threads, so once I execute a DIALOG SHOW MODAL
          statement, control passes to the dialog/callback and I cannot
          send/post messages to it. Or can I??

          So far, I'm mostly passing flags (yes/no) through checkboxes. For
          instance, I've created a "generic" dialog which can be called by
          several different SUBs in my app. Depending on which SUB is calling
          it, I want to use different defaults. I'll set a flag to indicate
          which defaults to use.

          Are additional messages generated for a callback Fn for disabled (and
          invisible) controls?



          ------------------
          Bernard Ertl
          Bernard Ertl
          InterPlan Systems

          Comment


          • #6
            You can use CONTROL SEND and DIALOG SEND immediately after each control is created, and before the DIALOG SHOW.

            Try it... it works!



            ------------------
            Lance
            PowerBASIC Support
            mailto:[email protected][email protected]</A>
            Lance
            mailto:[email protected]

            Comment


            • #7
              OK. Now I see where you are coming from. I put all the CONTROL ADD
              statements in the WM_INIT handler of the dialog proc. I'd have to move
              them (copies of them) into each SUB which could use that dialog (proc).

              How does the execution flow work for posting/sending messages to a control
              / dialog before the dialog is associated with a callback procedure? Are the
              messages just queued up until the DIALOG SHOW statement?



              ------------------
              Bernard Ertl
              Bernard Ertl
              InterPlan Systems

              Comment


              • #8
                Ok, I see where YOU are coming from now too! No, you can't queue a non-queued message.

                I guess I should have been a little clearer. Yes, if you wish to pass (non-control) "data" to a modal dialog ahead of the DIALO SHOW MODAL statement, you'll have to jump through a few hoops with either using global variables, or using hidden controls.

                Simple manipulations of controls (size, text, location, etc) can be done ahead of DIALOG SHOW MODAL, but once that DIALOG SHOW MODAL executes, the main code is suspended until the dialog is dismissed.

                Using a modeless dialog is the easiest solution by far, but how can you do it with a MODAL dialog?

                Subclassing the dialog is one possible way, since you can use a specific callback ahead of the DIALOG SHOW MODAL.

                Here is a very simplistic example, but hopefully it may give you some ideas...
                Code:
                #COMPILE EXE
                #INCLUDE "win32api.inc"
                 
                %Btn1 = 100
                GLOBAL OldProc&
                 
                CALLBACK FUNCTION cb
                    IF CBMSG = %WM_USER + 999& THEN
                        CONTROL SET TEXT CBHNDL, %Btn1, "Set in &Subclass"
                        CONTROL SET SIZE CBHNDL, %Btn1, 50, 14
                 
                    ELSEIF CBMSG = %WM_DESTROY THEN
                        SetWindowLong x&, %GWL_WNDPROC, OldProc&
                 
                    ELSEIF CBMSG = %WM_COMMAND AND CBCTL = %Btn1 THEN
                        DIALOG END CBHNDL, 1
                 
                    END IF
                
                    FUNCTION = DefDlgProc(CBHNDL, CBMSG, CBWPARAM, CBLPARAM)
                END FUNCTION
                 
                FUNCTION PBMAIN
                    DIM x&, y&
                    DIALOG NEW 0, "test",,,100,100, %WS_SYSMENU TO x&
                    OldProc& = SetWindowLong(x&, %GWL_WNDPROC, CODEPTR(CB))
                    CONTROL ADD BUTTON, x&, 100&, "", 10, 10, 5,5 ' empty 5x5 button
                    DIALOG SEND x&, %WM_USER + 999&, 0, 0 ' trigger our subclass proc
                    DIALOG SHOW MODAL x& ' no callback in this simple case, just use the subclass
                END FUNCTION


                ------------------
                Lance
                PowerBASIC Support
                mailto:[email protected][email protected]</A>
                Lance
                mailto:[email protected]

                Comment


                • #9
                  When is a DDT message loop suspended? Maybe I have misunderstood, but..
                  Code:
                  '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                  ' Declares
                  '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                  #COMPILE EXE
                  #INCLUDE "WIN32API.INC"
                   
                  GLOBAL hDlg AS LONG
                  DECLARE CALLBACK FUNCTION DlgProc() AS LONG
                  DECLARE CALLBACK FUNCTION DlgProc2() AS LONG
                   
                  '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                  ' Create dialog and controls, etc
                  '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                  FUNCTION PBMAIN () AS LONG
                    LOCAL hTimer AS LONG
                    DIALOG NEW 0, "Modal 1..",,, 200, 50, %WS_CAPTION OR %WS_SYSMENU TO hDlg
                    CONTROL ADD BUTTON, hDlg, 10, "Button",    4,  4, 60, 14, %WS_TABSTOP
                    hTimer = SetTimer(hDlg, 11, 1000, BYVAL %NULL )
                    DIALOG SHOW MODAL hDlg CALL DlgProc
                    KillTimer hDlg, hTimer
                  END FUNCTION
                   
                  '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                  ' Main callback
                  '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                  CALLBACK FUNCTION DlgProc() AS LONG
                    STATIC I AS LONG
                    IF CBMSG = %WM_COMMAND THEN
                       IF CBCTL = 10 THEN
                          STATIC hDlg2 AS LONG
                          DIALOG NEW CBHNDL, "Modal 2..",,, 70, 20, %WS_CAPTION OR %WS_SYSMENU TO hDlg2
                          CONTROL ADD BUTTON, hDlg2, 20, "Button", 4,  4, 60, 14, %WS_TABSTOP
                          DIALOG SHOW MODAL hDlg2 CALL DlgProc2
                          hDlg2 = 0
                       END IF
                   
                    ELSEIF CBMSG = %WM_TIMER THEN     '<- Send to 2:nd modal dialog
                       IF hDlg2 THEN SendMessage hDlg2, %WM_USER + 1, 0, 0
                   
                    ELSEIF CBMSG = %WM_USER + 1 THEN  '<- receive from 2:nd modal dialog
                       INCR I
                       CONTROL SET TEXT CBHNDL, 10, "Clicked" & STR$(I)
                       BEEP
                    END IF
                  END FUNCTION
                   
                  '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                  ' Main callback for dialog 2
                  '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                  CALLBACK FUNCTION DlgProc2() AS LONG
                    STATIC J AS LONG
                    IF CBMSG = %WM_COMMAND THEN
                       IF CBCTL = 20 THEN             '<- send to 1:st modal dialog
                          SendMessage hDlg, %WM_USER + 1, 0, 0
                       END IF
                   
                    ELSEIF CBMSG = %WM_USER + 1 THEN  '<- received from 1:st modal dialog's timer
                       INCR J
                       CONTROL SET TEXT CBHNDL, 20, "Clicked" & STR$(J)
                       SendMessage hDlg, %WM_USER + 1, 0, 0  '<- send back to 1:st modal dialog
                    END IF
                  END FUNCTION

                  ------------------

                  Comment


                  • #10
                    Indirect call w/o subclassing
                    Code:
                    CallWindowProc CodePtr(DlgProc), x&, %WM_USER + 999&, 0, 0
                    Direct call w/o subclassing
                    Code:
                    Dim y As Dword
                    y = CodePtr(DlgProc)
                    Call Dword y Using DefWindowProc(x&, %WM_USER + 999&, 0, 0)


                    ------------------
                    E-MAIL: [email protected]

                    Comment


                    • #11
                      Originally posted by Borje Hagsten:
                      When is a DDT message loop suspended? Maybe I have misunderstood, but..
                      The DIALOG SHOW MODAL statement is a "blocking" statement - internally it executes a message pump loop. The section of code that uses this statement is "suspended" until the target Dialog is dismissed, and the DIALOG SHOW MODAL statement completes execution.



                      ------------------
                      Lance
                      PowerBASIC Support
                      mailto:[email protected][email protected]</A>
                      Lance
                      mailto:[email protected]

                      Comment


                      • #12
                        So in theory, the sample above - where two modal DDT dialogs send
                        messages to each other - sholdn't work? Think this is over my head,
                        so better leave it at that..

                        To return to original subject: Bern, something I like to do in large
                        app's is to use a type declared structure to hold global data. Have
                        found this to be much cleaner and easier to maintain and use.
                        One global, nothing more - like:
                        Code:
                        TYPE DLGDATA
                          hWnd   AS LONG
                          hInst  AS LONG
                          value1 AS LONG
                          value2 AS LONG
                          value3 AS LONG 'etc, whatever I need
                        END TYPE
                        GLOBAL dd AS DLGDATA
                        Then I have access to dd.hWnd, etc. all over the program and I can
                        easily add members when/if I need more, without cluttering the code
                        with lots of globals. Sort of puts them all under the same roof.

                        Tip2 is one Lance once gave me. If you need to keep track of many 0 and 1
                        values (like for check- or option controls), one LONG can hold 32 values
                        via for example the BIT statement/function. Good way to optimize memory
                        usage, but it can be a "bit" messy to keep track of what bit belongs to
                        what value..


                        ------------------

                        Comment


                        • #13
                          Borje, we seem to be talking at cross-purposes. When discussing the blocking operation of DIALOG SHOW MODAL, I'm referring to the section of code that creates the dialog, not the actual operation of the callbacks.

                          The BIT array technique is a good one - it can work on a block of data of up to approx 2 billion bits!. Tracking the definition of the individual bits is easy with equates...
                          Code:
                          %Flag1 = 0
                          %Flag2 = 1
                          ...
                          %Flag2147483647 = 2147483646
                             
                          DIM lValue1 AS LONG
                          DIM lValue2(0:2147483647 \ 8) ' give or take 1!   
                          IF BIT(lValue1, %Flag1) THEN <DoSomething>
                          IF BIT(lValue2(0), %Flag2147483647) THEN <DoSomethingElse>
                          This is off the top of my head without a manual nearby, so the format of the second IF..THEN line may need minor alteration.

                          ------------------
                          Lance
                          PowerBASIC Support
                          mailto:[email protected][email protected]</A>
                          Lance
                          mailto:[email protected]

                          Comment


                          • #14
                            Ah, now I understand (finally)..

                            As for equates - doesn't that take away the memory advantage of using
                            bitmask? Here is little sample that shows how easy and clean it can be:
                            (once a good tip from you Lance, as always, and I thank you for it - I
                            often use this way nowadays)
                            Code:
                            '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                            ' Example of how to use one global variable to store settings for
                            ' a bunch of checkboxes, via BIT statement/function.
                            '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                            #COMPILE EXE
                            #INCLUDE "WIN32API.INC"
                            GLOBAL chk AS LONG
                             
                            DECLARE CALLBACK FUNCTION DlgProc() AS LONG
                            DECLARE CALLBACK FUNCTION DlgProc2() AS LONG
                             
                            '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                            ' Create dialog and controls, etc
                            '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                            FUNCTION PBMAIN () AS LONG
                              LOCAL hDlg AS LONG
                              DIALOG NEW 0, "Main Dlg",,, 70, 22, %WS_CAPTION OR %WS_SYSMENU TO hDlg
                              CONTROL ADD BUTTON, hDlg, 10, "Settings..", 5,  5, 60, 14, %WS_TABSTOP
                              BIT SET chk, 0 : BIT SET chk, 2 : BIT SET chk, 5 '<- sample: pre-set some bits at startup
                              DIALOG SHOW MODAL hDlg CALL DlgProc              '   for the checkboxes in Setup dlg.
                            END FUNCTION
                             
                            '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                            ' Main callback
                            '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                            CALLBACK FUNCTION DlgProc() AS LONG
                              IF CBMSG = %WM_COMMAND THEN
                                 IF CBCTL = 10 THEN       'create and show settings dialog
                                    LOCAL hDlg2 AS LONG, I AS LONG
                                    DIALOG NEW CBHNDL, "Settings",,, 80, 150, %WS_CAPTION OR %WS_SYSMENU TO hDlg2
                                    FOR I = 0 TO 11
                                       CONTROL ADD CHECKBOX, hDlg2, I + 30, "Check" + STR$(I + 1), 5,  I * 12 + 4, 60, 12, %WS_TABSTOP
                                       CONTROL SET CHECK hDlg2, I + 30, BIT(chk, I) '<- get settings from variable's different bits
                                    NEXT I
                                    DIALOG SHOW MODAL hDlg2 CALL DlgProc2
                                 END IF
                              END IF
                            END FUNCTION
                             
                            '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                            ' Main callback for dialog 2
                            '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                            CALLBACK FUNCTION DlgProc2() AS LONG
                              IF CBMSG = %WM_DESTROY THEN
                                 LOCAL I AS LONG, lRes AS LONG
                                 FOR I = 0 TO 11
                                    CONTROL GET CHECK CBHNDL, I + 30 TO lRes  'get checkbox settings
                                    IF lRes THEN
                                       BIT SET chk, I  'store all settings in variable's different bits
                                    ELSE
                                       BIT RESET chk, I
                                    END IF
                                 NEXT I
                              END IF
                            END FUNCTION

                            ------------------

                            Comment


                            • #15
                              No, since their value is known at compile time, the compiler should be able to optimize things nicely!


                              ------------------
                              Lance
                              PowerBASIC Support
                              mailto:[email protected][email protected]</A>
                              Lance
                              mailto:[email protected]

                              Comment


                              • #16
                                OK. Thanks everyone. I think I've got a handle on it now.



                                ------------------
                                Bernard Ertl
                                Bernard Ertl
                                InterPlan Systems

                                Comment

                                Working...
                                X