AltSubmit breaks onExit() Topic is solved

Report problems with documented functionality
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

AltSubmit breaks onExit()

31 Jan 2019, 04:44

I noticed a problem: when using AltSubmit for ListView, there are situations that break the onExit() command.

see here for details
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: AltSubmit breaks onExit()

21 Sep 2019, 17:52

The problem is not exclusive to ListViews.

AutoHotkey handles most messages within an internal function called MsgSleep. MsgSleep retrieves messages from our message queue, handles or dispatches them, and (usually) sleeps.

When an event occurs, AutoHotkey posts a message to itself. Normally MsgSleep will then start a new thread and call a subroutine or function, after processing any other messages that preceded the event in the queue.

If the current thread is uninterruptible, MsgSleep filters messages so that most system-defined messages can be processed, while event messages and user messages are left in the queue until the thread becomes interruptible. (This is the "event buffering" that the documentation for Critical refers to.)

When you display a modal dialog or Menu, or perform some other modal GUI action (such as click and drag in a ListView or activating a MonthCal's drop-down), the program enters a modal message loop. That is, some code outside our control runs in a loop, retrieving messages from the queue and dispatching them or handling them directly. This defeats the filtering done by MsgSleep, since MsgSleep isn't the one processing the message queue. When an event message is dispatched to the script's main window procedure or GUI window procedure, it is posted back into the queue and MsgSleep is called to immediately process all messages and handle the event.

However, if the current thread is uninterruptible, MsgSleep will neither handle the message nor remove it from the queue. Therefore, when control returns to the modal message loop, the message is again dispatched to our window procedure, and we again post it back into the queue and call MsgSleep, and so on. This can become an infinite loop.

The problem occurs under these conditions:
  • A modal message loop is running.
  • An event has been posted to the queue which is eligible to be re-posted.
  • The script is uninterruptible.
  • Timing?
Events:
  • Menu command messages sent to the script's main window are re-posted unconditionally.
  • GUI events and menu command messages sent to a GUI window are re-posted and MsgSleep is called, but not if a menu is being displayed (in that case they are discarded).
  • Hotkey, hotstring, OnClipboardChange and InputHook End events are always re-posted but MsgSleep is not called if the thread is uninterruptible (and since they're posted with a NULL hWnd, it's very likely that the message will be discarded by the modal message loop).
  • Timer messages are not re-posted.
As documented, Critical makes the current thread uninterruptible, but is temporarily overridden when a MsgBox or other dialog is displayed. However, other conditions that temporarily disable interruption are not affected by dialogs:
  • Running OnExit functions.
  • The internal SLEEP_WITHOUT_INTERRUPTION macro, which is used by Send when performing delays, and for other very small delays by various commands (e.g. after changing the foreground window, to let the change be processed).
  • While displaying the #MaxHotkeysPerInterval error message or failure to activate the hooks.
  • While a menu is being displayed or a menu bar has the focus (but this also prevents GUI events from being re-posted).
In your case, MsgBox begins running a modal message loop and at the same time generates a ListView focus-lost event. The script is uninterruptible because it is running an OnExit function, so the focus-lost event "bounces" between the message queue and the GUI window procedure, inhibiting the MsgBox's normal initialization and preventing it from appearing.

This also demonstrates the problem:

Code: Select all

ListLines  ; One of the script's own windows is active.
OnExit("ExitFunc")
ExitApp

ExitFunc() {
    Menu M, Add, Clickme
    Menu M, Show  ; An event is queued.
    MsgBox,,,, 3  ; MsgBox is displayed while the thread is uninterruptible.
}

Clickme:
return
If none of the script's windows are active, this has no problem. I'm guessing it has to do with additional messages being in the queue when the window loses focus.

Commit ec631b5c should fix it, by causing GUI and menu events to be discarded when they can't be handled or kept in the queue.
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: AltSubmit breaks onExit()

28 Sep 2019, 23:43

@wolf_II
See if v1.1.31.00 fixes your problem.
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: AltSubmit breaks onExit()  Topic is solved

29 Sep 2019, 05:28

Thank you for your detailed explanation. I appreciate it.
There is a lot of stuff going on with regards to MsgBox, and that came as a surprise to me.
I will test with v1.1.31 and report back, Thank you for looking into this issue.

Edit:
I did a first test, and it went well. Thank you for fixing this issue.

I feel I should give more Background, b/c I am not sure how important all this Uninterruptable business concerning MsgBox really is.
My choice of using a MsgBox to show the occurrance of the error was to eliminate all distractions.
I feel this was a useless attempt in this case, sry.

My ExitFunction does not contain any MsgBox at all:

Code: Select all



;-------------------------------------------------------------------------------
ExitFunc() { ; ExitFunc
;-------------------------------------------------------------------------------

    ; avoid bug, Thx just me
    ;~ GuiControl, -g, % Main.hLView

    ; close help files
    if WinExist(_AppName " ahk_class HH Parent")
        WinClose

    ; isMax => store last pos
    if (Main.LastPos.isMax := Main.isMax)
        Ini.WriteSection("Position", Main.LastPos)

    ; isMin => store nothing, else => store pos and size
    else if not Main.isMin {
        Gui, Main: +LastFound
        WinGetPos, WinX, WinY, WinW, WinH
        Ini.WriteSection("Position"
            , { isMax: 0
            ,   WinX:  WinX
            ,   WinY:  WinY
            ,   WinW:  WinW - 16
            ,   WinH:  WinH - 59})
    }
}
As you can see, the workaround suggested by just me is still in there, but is now commented out.
I have not found any problems so far. Thank you again. :D

Return to “Bug Reports”

Who is online

Users browsing this forum: No registered users and 92 guests