Announcement

Collapse
No announcement yet.

General questions

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

  • General questions

    Could anyone please clue me in:

    1) If I have STATIC variables in a DIALOG callback Fn, can I assume
    that there will always be only one instance of that callback Fn
    at all times? Ie. Any messages that need to be processed for the
    DIALOG must be processed one at a time?

    2) If a parent window is 'instantiated' with DIALOG SHOW MODAL and
    it initializes child windows with DIALOG SHOW MODELESS, is DIALOG
    DO EVENTS implied in the MODAL statement for the parent window?

    3) I occasionally find that my PB apps leave a dialog image on the
    screen after termination. Is there some style that I need to use to
    prevent this from happening? It is not a consistent behavior and it
    happens to DIALOGS created with different styles, so I'm at a loss to
    figure out what's wrong.



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

  • #2
    Bernard, I am going to repeat what I've seen on thid forum, so it
    is hear-say.

    In regards to question 2:
    A modal dialog includes a message pump, which either does the DoEvents,
    or causes them to be unnecessary. You only need to use DoEvents with
    modeless dialogs.

    Of course, there are those who say you should always (exclusively) use
    modeless dialogs, and supply them with a message pump.


    ------------------
    Thanks,

    John Kovacich
    Thanks,

    John Kovacich
    Ivory Tower Software

    Comment


    • #3
      Bern --

      Regarding #1, that is definitely not a safe assumption. First, callback functions can be called recursively. For example, if you use an API function like ShowWindow (or many others), Windows will call your callback function in the process of performing the requested operation. Second, Windows can and does create "disguised" threads of execution related to GUI windows, and a callback function can be called by what appears to be the main thread, but it is really a secondary thread that is "masquerading" as the main thread. Strange but true.

      STATIC variables can be used in a callback function, but you have to be careful.

      -- Eric


      ------------------
      Perfect Sync: Perfect Sync Development Tools
      Email: mailto:[email protected][email protected]</A>

      [This message has been edited by Eric Pearson (edited February 23, 2001).]
      "Not my circus, not my monkeys."

      Comment


      • #4
        Further to Eric's message, even the simple SendMessage() API (and likewise: CONTROL SEND, DIALOG SEND) can trigger reentrant callback execution. There are many other situations where the callback is used reentrantly, so you should always use GLOBAL and STATIC variables in a callback with reasonable care.

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

        Comment


        • #5
          Aha.

          John, your explanation is in keeping with what I'm experiencing (ie.
          the MODELESS child dialogs seem to work fine inside the MODAL parent),
          but I wasn't sure if a DIALOG DO EVENTS type 'message pump' was implied
          in the MODAL parent dialog such that the child dialogs are processing
          their messages efficiently. Did that make sense? In other words,
          some code that Scott Turchin was kind enough to post for me had a
          situation with the MODELESS child dialogs to a MODAL parent, but it
          included a THREADed Fn to just perform DIALOG DO EVENTS. I was
          wondering if that was necessary/desirable.

          The reason for my questions is to ensure that I am structuring my
          program correctly. This is my first Windows app (you couldn't tell
          from my posts?) and I'm still low on the learning curve.

          Semen was kind enough to post a nice Tab example for me in another
          message thread. He used STATIC variables in the main dialog to
          maintain the window handles for the child DIALOGS which are displayed
          on the tabs. That was the first time I had seen a use of STATIC vars
          in a callback and I was wondering if it was safe to do that with my
          "data" vars.

          In other words, I'm currently structuring my code as thus:

          Code:
          FUNCTION EditDataFile()
          
          
             LOCAL IndexDataArrays(), FileHandles, etc.
          
          
             DIALOG NEW hDlg
             Add controls to hDlg  
             'Note: I'm adding controls here and not in WM_INITDIALOG
             'for no particular reason.  Does it make a difference?
             'Controls include disabled check boxes used as flags to
             'communicate user actions to this function
          
          
             Open required (index) data file(s)
                Set any required file LOCKs
                Read (index) data into local arrays
             Open main data file
                Set any required file LOCKs
                Read main data file into grid control on hDlg
          
          
             DIALOG SHOW MODELESS hDlg TO DlgCallback
          
          
             DO
                DIALOG DO EVENTS
          
          
                'The following is a template
                'There could be several %IDFNBOXes
                CONTROL GET CHECK hDlg, %IDFNBOX TO Dummy&
                IF Dummy& THEN
                   CONTROL SET CHECK hDlg, %IDFNBOX, 0
                   'Process FN here, not in callback
                   'FN may alter local data arrays
                   'FN may access/alter open files
                END IF
          
          
                CONTROL GET SIZE hDlg TO x,x
                IF x = 0 THEN
                   'System menu box closed
                   'Set global flag to close all open windows
                   'UNLOCK & CLOSE any open files
                   EXIT FUNCTION
                END IF
          
          
                CONTROL GET CHECK hDlg, %IDEXITBOX TO Dummy&
             LOOP UNTIL Dummy&
          
          
             CONTROL GET CHECK hDlg, %IDSAVEBOX TO Dummy&
             IF Dummy& THEN 
                'Save main file from grid control
             END IF
             DIALOG END hDlg
             'UNLOCK & CLOSE any open files
             FUNCTION = %Success
          
          
          END FUNCTION
          I thought my code structure was rather convoluted. I imagine there
          is a more elegant way. I was wondering if it was safe to take a cue
          from Semen's code and restructure my code thus:

          Code:
          FUNCTION EditDataFile()
          
          
             DIALOG NEW hDlg
             DIALOG SHOW MODAL hDlg to DlgCallback
          
          
          END FUNCTION
          
          
          CALLBACK FUNCTION DlgCallback
          
          
             STATIC IndexDataArrays(), FileHandles, etc.
          
          
             SELECT CASE CBMSG
                CASE %WM_INITDIALOG
                   Add controls to CBHNDL  
          
          
                   Open required (index) data file(s)
                      Set any required file LOCKs
                      Read (index) data into local arrays
                   Open main data file
                      Set any required file LOCKs
                      Read main data file into grid control on CBHNDL
          
          
                CASE %WM_COMMAND
                   SELECT CASE CBCTL
                      'FNs may alter STATIC data arrays
                      'FNs may access/alter open files
                   END SELECT
          
          
                CASE %WM_DESTROY
                      'UNLOCK & CLOSE any open files
             END SELECT
          
          
          END FUNCTION
          My main concern was that if the callbacks are reentrant, my STATIC
          vars could get corrupted if the callback starts processing multiple
          actions upon the data. I'm reasonably sure that my convoluted code
          forces the app to handle the data/files with a serial processing.

          Any comments?

          ------------------
          Bernard Ertl

          [This message has been edited by Bern Ertl (edited February 24, 2001).]
          Bernard Ertl
          InterPlan Systems

          Comment


          • #6
            Bern:

            It sounds like you are concerned about maintaining the integrity of variables that you want to manipulate/modify
            inside of your dialog's callback function. A callback function can be reentrant, however you should be able to
            safely manipulate "data" variables (static or global) in sections of the callback function that are only entered
            based on user actions... for example, if you had the following code in your dialog's callback...
            Code:
               SELECT CASE CBCTLMSG
               CASE %BN_CLICKED
                  SELECT CASE CBCTL
                  CASE 100
                     ' user clicked button 100 
                     CONTROL DISABLE CBHNDL, 100
                     ' modify static or global data variables
                     CONTROL ENABLE CBHNDL, 100
                  END SELECT
               END SELECT
            ... your user initiates the callback entry with a button click that is immediately disabled until the variable
            manipulation is finished. No possibility of reentry.

            Also, any "data" variable manipulation that is done in the...
            Code:
            CASE %WM_INITDIALOG
            section of your dialog is safe from reentry, since that code is only executed once.

            If you have multiple dialogs, I'd recommend a separate callback function for each dialog to avoid confusion and
            conflicts. Some even like to set up separate callback function for every control on every dialog... too many
            callbacks for my taste.

            Like most things you run into in programming (and life) there's more than one way to do things... try a few
            different ways and see what works best for you. Good luck.

            Timm

            [This message has been edited by Timm Motl (edited February 24, 2001).]
            mailto:[email protected]
            Tsunami Record Manager

            Comment


            • #7
              Code:
               
              ... your user initiates the callback entry with a button click that is immediately disabled until the variable manipulation is finished. No possibility of reentry.
              Unfortunately, this is not true at all. The only safe method in such a situation involves wrapping the code to be protected within a critical section. Doing so is easy and also relatively undemanding in its effects on system performance. By far the best discussion I've seen in print of issues such as this one appears in Richter's _Programming Applications for Windows_ (which is actually the fourth edition of a retitled _Advanced Windows_). Rector and Newcomer's discussion of this issue is no where near as thorough (and, at this point, as up to date) as Richter's.

              ------------------
              -- Greg
              [email protected]

              Comment


              • #8
                Timm, I'm not so much concerned with one particular control (ie.
                your button example) executing twice (although, come to think of it,
                some old mice tend to have bad buttons and double click when they shouldn't)
                but I was more concerned with a user clicking on different controls
                which performed different actions on the data. Your solution would
                require me to disable every control on the dialog while one is processing.
                That doesn't seem any better than what I am currently doing.

                The only safe method in such a situation involves wrapping
                the code to be protected within a critical section.
                Greg, are you implying that my current code structure is not safe?
                I would definately appreciate any input as to any problems with it..

                Thanks for the tips on the books. As soon as I'm back stateside,
                I'll look for them...




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

                Comment


                • #9
                  I used to worry about that as well, but this does seem to cure it.

                  Code:
                          Case %IDM_HELP
                               If CbCtlMsg <> %BN_CLICKED Then Exit Function
                               g_Result = ShellExecute(ByVal %NULL, "open",g_InstallDir & "\help\help.html" + Chr$(0), ByVal %NULL, ByVal %NULL,1)
                  '             If g_Result = 2 Then MsgBox "The helpfile " & g_HelpFile & " is missing, please re-install this package.",%MB_ICONINFORMATION,g_szCCS
                               Function = 0
                               Exit Function
                  ------------------
                  Scott
                  Scott Turchin
                  MCSE, MCP+I
                  http://www.tngbbs.com
                  ----------------------
                  True Karate-do is this: that in daily life, one's mind and body be trained and developed in a spirit of humility; and that in critical times, one be devoted utterly to the cause of justice. -Gichin Funakoshi

                  Comment


                  • #10
                    Timm, Greg --
                    I don't beleive that Windows is able to process some messages from message qquery in the same time.
                    (SendMessage is another question - this is equal direct Call of procedure).
                    When you click a button Windows POSTS message to query.
                    Try following code. You will see that unlike CPU is not busy, you will not be able to press button during 10 sec, because callback doesn't return control to Windows.

                    Code:
                       #Compile Exe
                       #Register None
                       #Dim All
                       #Include "win32Api.Inc"
                    
                       CallBack Function OkProc
                          Dim i As Long
                           SetwindowText CbHndl, Time$
                           For i = 1 To 1000
                              Sleep 10
                           Next
                       End Function
                    
                       Function PbMain
                          Local hDlg As Long
                          Dialog New 0, "DDT",,, 300, 225, %WS_CAPTION Or %WS_SYSMENU To hDlg
                          Control Add Button, hDlg, 101, "Click me", 10, 10, 100, 15 Call OkProc
                          Dialog Show Modal hDlg
                       End Function
                    ------------------
                    E-MAIL: [email protected]

                    Comment


                    • #11
                      Scott, I did not understand the point of your code sample. It does
                      not seem germane to the issue at hand.

                      Semen, your point indicates to me that I could use STATIC "data" vars
                      and handle all my processing the callback(s) versus what I'm doing now
                      as long as I don't call any API functions like SendMessage. If all my
                      processing code is strictly related to the data/file io and does not
                      interact with the Windows API, I guess that everything would be safe.

                      I think I'm going to keep my structure as is for now. It seems to be
                      working (safely) convoluted or not....



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

                      Comment


                      • #12
                        Code:
                        Bern--
                         
                        My main concern was that if the callbacks are reentrant, my STATIC vars could get corrupted if the callback starts processing multiple actions upon the data. I'm reasonably sure that my convoluted code forces the app to handle the data/files with a serial processing.
                        From looking at the code you've posted, I'm not sure which aspect of its design you're most concerned about. However, to address this issue in general terms: Windows makes available quite an assortment of synchronization tools, and it does so for a good reason. Multitasking makes it unwise to depend on many things, even (as Lance has pointed out) that updating a global DWORD will not be interrupted halfway through the memory access. Similarly, action A might occur before action B, but that doesn't mean that the effect of action A will necessarily occur before the effect of action B. In the case of control callbacks, it of course makes sense to disable a control to make clear to the user that a control is unavailable. However, doing so shouldn't be classified as a method of protecting code. As you've mentioned, something as simple as an unintentional double-click can create odd errors that defy even skillful debugging. When dealing with calls, depending exclusively on the sequence of events to protect code is something like betting on your horse to finish first. It might finish first. And it might do so often. Until the day it doesn't. Semen--
                        I don't believe that Windows is able to process some messages from message query in the same time. (SendMessage is another question - this is equal direct Call of procedure). When you click a button Windows POSTS message to query. Try following code. You will see that unlike CPU is not busy, you will not be able to press button during 10 sec, because callback doesn't return control to Windows.
                        I too sometimes enjoy experimenting as a way to figure out what's happening, but why bother? Synchronization tools exist. They're not difficult to implement. When selected and implemented appropriately, their effect on performance is negligible. The messaging that perhaps characterizes any particular version of Win32 seems far more complicated (and exhausting) to unravel.

                        ------------------
                        -- Greg
                        [email protected]

                        Comment


                        • #13
                          Folks,

                          There is no "experimentation" required here. What I think Semen was saying is that Windows _requires_ applications to poll for messages and does not pre-empt them to process another message. The callback functions in DDT are all called as a result of a message arriving so the message loop is not running while your code is and there is no possiblity of corruption while you modify variables within one invokation of your procedure.

                          This is not empirical observation -- this is as specified for windows programming. If this were to ever change it would break just about 100% of all Windows apps. Semen's example merely confirms documented behaviour.

                          So, unless you are doing multithreading, you do NOT need to protect variable access with critical sections or mutexes or the like.

                          -- Jim


                          [This message has been edited by Jim Karabatsos (edited February 25, 2001).]

                          Comment


                          • #14
                            Code:
                            You mean, we're not talking about multithreading? 
                               
                            I have threads on the brain (probably because of the 
                            project I'm working on) and also should have read Bern's 
                            original question more carefully. 
                               
                            However, I'll gladly grovel a bit if I can put in another 
                            plug for Richter's book (Microsoft Press, 1999).  Threads 
                            and synchronization receive 6 chapters, plus a seventh 
                            chapter about thread local storage; structured exception 
                            handling gets a section of the book all to itself (3 
                            chapters); memory-mapped files receive an entire chapter, 
                            as do unicode, jobs (new to Win2000), and even DLL 
                            injection and API hooking.  Sample code is C++ (relatively 
                            high on the ugh scale when converting to PB is the 
                            objective), but Richter's explanations are uniformly clear. 
                               
                            He even includes a nice big chapter on messaging.

                            [This message has been edited by Greg Turgeon (edited February 26, 2001).]

                            Comment

                            Working...
                            X