Results 1 to 12 of 12

Thread: Question about modality (I think)

  1. #1

    Thread Starter
    Member
    Join Date
    Oct 2014
    Posts
    42

    Question about modality (I think)

    I was under the illusion that if there was a message box open that no program code was executing because the program was waiting for an response from the user.
    I was under the same wrong impression about when a modal form was open and the user hadn't performed any actions on it.

    However I am now aware that timer events (probably only on other open forms though?) can also fire and other code can execute. Makes sense but I didn't think that this was the case.
    I am still a bit unclear on things though.

    Say I click on a button and the click event's code fires and in the middle of its code are calls to other subs and functions and maybe objects.
    Also say that in none of the code that is called is there a DoEvents or a message box.
    Then I am guessing that no timer can fire until all that code has executed.
    Is that correct or wrong?
    Is there anything else that can cause a pause and allow other code to execute?

  2. #2
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Question about modality (I think)

    As a single threaded application, the timer can't fire while you have active code running (i.e. code that is running in an event handler (calling subs and functions from an event handler is still running code within the event handler)
    .
    When you create a modal window, the code that opened the window is suspended and the modal window takes over the processing of window events for the application, so events for timers and paint events will still be handled for the whole application, not just the modal window, (you don't want the other forms in your project to not refresh just because a modal window is showing).

    But keyboard events and mouse events can only occur in the modal window and once the modal window is closed, your code continues and when your code exits the event handler it was in, then other events can be processed, e.g. timer and paint events as well as other mouse or keyboard inputs.

  3. #3

    Thread Starter
    Member
    Join Date
    Oct 2014
    Posts
    42

    Re: Question about modality (I think)

    Thanks for the prompt response. I think I understand things better now.

  4. #4
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: Question about modality (I think)

    I don't think this issue is well worked out, at least not for VB6.

    Now, as we all know, VB6 is single-threaded. However, with respect to the timer, where that thread is and where it's allowed to go seems to be a bit of a mystery. With a MsgBox or a modal form, we all know that the procedure that invoked the Msgbox or modal form is suspended on the line that called it. And, it resumes when the MsgBox or modal form is closed (or made non-modal in some way).

    However, from a larger perspective, that thread is either in one of two places: 1) It's executing some of our code, or 2) It's being handled by Windows, waiting on some event to happen so it can hand the thread back to some of our code.

    Now, when a Msgbox or modal form is loaded, the question becomes: which of our code is Windows allowed to hand the thread back to? (Still remembering that some procedure somewhere is suspended that called the MsgBox or modal form). Ok, sure, in the case of a modal form, we could call other procedures in form that invoked the modal form. In fact, we could call pretty much anything we've got access to.

    Now, the case of the timer. The timer is just something else that's handled by Windows which hands the thread to one of our procedures (i.e., the timer event). So, when will Windows (via a timer) be allowed to hand the thread to the timer event, and when will it not? That's essentially your question, and I don't have a clear answer, but I'd sure like to see it worked out.

    Here was one hypothesis that I made: That all code in a parent that invoked the MsgBox or a child modal form would be suspended (unless specifically called by the child modal form). However, this turned out to be only partially true. For instance, clicking Command1 in the following code suspends the timer:

    Code:
    
    Option Explicit
    
    Private Sub Command1_Click()
        MsgBox "some message"
    End Sub
    
    Private Sub Form_Load()
        Timer1.Interval = 3000
        Timer1.Enabled = True
    End Sub
    
    Private Sub Timer1_Timer()
        Debug.Print "timer1"
    End Sub
    
    
    In case it's not obvious, the above is a Form1 with a Timer1 control and a Command1 button.

    Now, that made sense to me. The MsgBox was a child of Form1; therefore all the code in Form1 was suspended until the MsgBox closed.

    However, the following code did not suspend the timer:

    Code:
    
    Option Explicit
    
    Private Sub Command1_Click()
        Form2.Show vbModal, Me
    End Sub
    
    Private Sub Form_Load()
        Timer1.Interval = 3000
        Timer1.Enabled = True
    End Sub
    
    Private Sub Timer1_Timer()
        Debug.Print "timer1"
    End Sub
    
    Again, in case it's not obvious, that's a project with a Form1 with a Timer1 and Command1, and a Form2 with nothing.

    The fact that the timer was not suspended in the second case was a mystery to me. It makes me want to explore how the API SetTimer call might work, but I'll possibly mess with that a bit later. I'm just wondering if the parent of Form2 is being correctly set for Windows to see it.

    I'm curious about what others have to say about this.

    Best Regards,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  5. #5
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Question about modality (I think)

    I'm not sure about the message box as that may be a system modal type window which suspends your whole application until you respond to it (including all events in your application, and even the IDE if you're running from the IDE, i.e. try clicking on the IDE when the message box is showing and see what happens).

    A form that is shown modal creates its own message pump, so while the original message pump is suspended the new message pump continues to service the events for the application, which includes all active timers regardless of what form they are on. It is just that the form also captures the focus so you can't click or do keyboard input to any other form.
    A modal form can show another modal form which continues the chain.
    A modal form can not show a non-modal form.

  6. #6

    Thread Starter
    Member
    Join Date
    Oct 2014
    Posts
    42

    Re: Question about modality (I think)

    Quote Originally Posted by passel View Post
    I'm not sure about the message box as that may be a system modal type window which suspends your whole application until you respond to it (including all events in your application, and even the IDE if you're running from the IDE, i.e. try clicking on the IDE when the message box is showing and see what happens).
    I think maybe it suspends everything in the IDE but it doesn't in a compiled exe.
    It was some logging code, writing to a file, that showed me the timer events were still firing when a message box was open waiting for user input.

  7. #7
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: Question about modality (I think)

    Wow C++, that's actually pretty weird.

    I just took some of my code from above and modified it as follows, and then compiled it:

    Code:
    
    Option Explicit
    
    Private Sub Command1_Click()
        MsgBox "some message"
    End Sub
    
    Private Sub Form_Load()
        Timer1.Interval = 3000
        Timer1.Enabled = True
    End Sub
    
    Private Sub Timer1_Timer()
        MsgBox "timer1"
    End Sub
    
    
    Obviously, a Form1 with a Timer1 and Command1.

    The timer fires as expected, showing the modal MsgBox. However, when you click Command1, thereby getting the "some message" MsgBox, the timer still fires. In fact, it shows yet another modal MsgBox ("timer1" as message). Now what's particularly weird is that you can click between these two message boxes, as if they're not modal. However, they are modal to Form1. It's almost as if a hierarchy of modality has been created.

    Furthermore, once the timer's MsgBox is showing, the timer is suspended until you click on that one. I'm assuming that the timer is disabled until its event terminates.

    This is all pretty weird stuff that I hadn't fully appreciated before. And it's quite fascinating that it's possible to have two modal forms on the screen that you can click between. I'm now wondering how to accomplish that with regular VB6 forms.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  8. #8

    Thread Starter
    Member
    Join Date
    Oct 2014
    Posts
    42

    Re: Question about modality (I think)

    I made up a little project with 2 forms like Elroy has in his example.
    It has trace logging built in and in the ide just prints to the debug window but in the compiled version prints to a file.
    (The tracer class is based on code in Francesco Balena's vb6 book)
    It shows the differences between the way things happen in in the ide vs the exe.
    In the exe the timers keep firing, in the ide the timers stop firing if the msgbox is visible.
    Attached Files Attached Files

  9. #9

    Thread Starter
    Member
    Join Date
    Oct 2014
    Posts
    42

    Re: Question about modality (I think)

    Quote Originally Posted by Elroy View Post
    Wow C++, that's actually pretty weird.

    I just took some of my code from above and modified it as follows, and then compiled it:

    Code:
    
    Option Explicit
    
    Private Sub Command1_Click()
        MsgBox "some message"
    End Sub
    
    Private Sub Form_Load()
        Timer1.Interval = 3000
        Timer1.Enabled = True
    End Sub
    
    Private Sub Timer1_Timer()
        MsgBox "timer1"
    End Sub
    
    
    Obviously, a Form1 with a Timer1 and Command1.

    The timer fires as expected, showing the modal MsgBox. However, when you click Command1, thereby getting the "some message" MsgBox, the timer still fires. In fact, it shows yet another modal MsgBox ("timer1" as message). Now what's particularly weird is that you can click between these two message boxes, as if they're not modal. However, they are modal to Form1. It's almost as if a hierarchy of modality has been created.

    Furthermore, once the timer's MsgBox is showing, the timer is suspended until you click on that one. I'm assuming that the timer is disabled until its event terminates.

    This is all pretty weird stuff that I hadn't fully appreciated before. And it's quite fascinating that it's possible to have two modal forms on the screen that you can click between. I'm now wondering how to accomplish that with regular VB6 forms.
    I just copied what you did and that's pretty weird all right watching a second msgbox pop up while the other is still there!

  10. #10
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: Question about modality (I think)

    Okay, more mystery to the puzzle. I threw together an API timer test just to see what would happen.

    Done this way, there doesn't seem to be any difference between the IDE and compiled. But, be forewarned, you have to do some clicking to terminate your program. (I suppose a kill in task manager is also a possibility).

    There are two modules to this one, a BAS piece and a Form1 piece. Here's the BAS piece:

    Code:
    
    Option Explicit
    '
    Public Declare Function SetTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
    Public Declare Function KillTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long) As Long
    '
    
    
    Public Function TimerProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, ByVal dwTime As Long) As Long
        MsgBox "ApiTimer"
    End Function
    
    And here's the Form1 piece:

    Code:
    
    Option Explicit
    '
    Public mlTimerID As Long
    '
    
    Private Sub Command1_Click()
        MsgBox "Command1 click"
    End Sub
    
    Private Sub Form_Load()
        mlTimerID = SetTimer(Me.hWnd, 0&, 3000&, AddressOf TimerProc)
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
        KillTimer Me.hWnd, mlTimerID
    End Sub
    
    
    Form1 just has a single Command1 control on it.

    This time nothing seems to stop the timer from firing. In other words, it puts a new modal MsgBox on the screen every three seconds, making as many for as long as you let it run. That's where the clicking comes in to get it shut down because you can't close Form1 until you get all the MsgBox's shut down.

    Now, regarding Command1, it really makes no difference if that MsgBox is on the screen or not. The timer still fires.

    So, in this situation, nothing slows down the timer. And, in a sense, API timers are more predictable than the timer control.

    It's still puzzling (and interesting) how we can get multiple modal forms (all at the same hierarchical level) on the screen at the same time.

    Okay, I had one more idea. I was thinking that we could manage a series of modal forms (all at the same hierarchical level) with some novel use of the API timer. But no cigar. I used the same above Form1 code, but added a (blank) Form2, and modified the BAS code as follows:

    Code:
    
    Option Explicit
    '
    Public Declare Function SetTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
    Public Declare Function KillTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long) As Long
    '
    Dim c As New Collection
    
    Public Function TimerProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, ByVal dwTime As Long) As Long
        Dim f As Form
        Set f = New Form2   ' New copy of form2.
        c.Add f             ' Put instantiation in collection so a reference is maintained.
        f.Show vbModal      ' Show it modal.
    End Function
    
    
    Yes, I get lots of copies of Form2 loaded modally. However, this time, the latest loaded Form2 is modal to all the others. All the loaded Form2's are not at the same modal hierarchy level, and must be shut down in the reverse order they were loaded. And this is different from the way the message boxes behaved. However, if I manage to get the Command1 clicked, that MsgBox shares modality with the latest loaded Form2.

    All very bizarre.


    EDIT1: So, one conclusion ... if you want to load a modal form over another modal form, but it's not code from the first modally loaded form that will load the second, start an API timer, use appropriate global flags, and then load the second modal form from within the timer event. Not sure where/when this'll be useful, but you never know.
    Last edited by Elroy; Oct 6th, 2017 at 01:10 PM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  11. #11
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: Question about modality (I think)

    I'm not sure if it's helpful, but you might check out this this StackOverflow link.

    It's important to recognize that a modal dialog is still running an active message loop. That means it is still receiving window messages (like WM_TIMER) and dispatching them accordingly. If it didn't do this, all kinds of things would go wrong (e.g. underlying windows couldn't repaint). The main thing that changes is that the modal window's loop gets priority, meaning it can intercept messages before relaying them. It will typically consume input events like keyboard and mouse events, while relaying non-input events (like WM_TIMER) the same way that your main message pump would.

    Raymond Chen did a whole series on modality if anyone wants a deeper dive into the topic.

    edit: I realize now that passel already covered most of this. Argh, I need to read whole threads before commenting! Sorry!
    Last edited by Tanner_H; Oct 9th, 2017 at 11:41 AM.
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  12. #12
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Question about modality (I think)

    FYI. Another tip regarding modal windows when compiled and when in IDE.

    Events are blocked when in IDE and a modal window is displayed (msgbox, common dialog, etc). Those same events, when compiled, are not blocked. For any of you that create usercontrols, RaiseEvent is blocked when in IDE while a modal window is shown. However, methods called via the Implements keyword are not. Regarding the timer, I'm guessing that the timer control, internally, uses a RaiseEvent call.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width