[v2-beta.1] Persistent is thread specific and not global.

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
iseahound
Posts: 1444
Joined: 13 Aug 2016, 21:04
Contact:

[v2-beta.1] Persistent is thread specific and not global.

25 Sep 2021, 19:17

[Moderator's note: Topic moved from Bug Reports.]

My goal is simple. If I create a window manually I activate persistent. If the user clicks close, I set persistent to 0, and the script should exit. It's not exiting!

Code: Select all

new_window() 
new_window() {
      WindowProc(hwnd, uMsg, wParam, lParam) {

         ; DOES NOT WORK
         if (uMsg = 0x2) ; WM_DESTROY
            return Persistent(false)

         return DllCall("DefWindowProc", "ptr", hwnd, "uint", uMsg, "uptr", wParam, "ptr", lParam, "ptr")
      }

      ; Make it permanent.
      Persistent(true)

      cls := "MyClass"
      pWndProc := CallbackCreate(WindowProc, "Fast")
      hCursor := DllCall("LoadCursor", "ptr", 0, "ptr", 32512, "ptr") ; IDC_ARROW
      hBrush := DllCall("GetStockObject", "int", 5, "ptr") ; Hollow_brush

      _ := (A_PtrSize = 4)
      wc := Buffer(_ ? 48:80, 0)                       ; sizeof(WNDCLASSEX) = 48, 80
         NumPut(   "uint",     wc.size, wc,         0) ; cbSize
         NumPut(   "uint",           0, wc,         4) ; style
         NumPut(    "ptr",    pWndProc, wc,         8) ; lpfnWndProc
         NumPut(    "int",           0, wc, _ ? 12:16) ; cbClsExtra
         NumPut(    "int",           0, wc, _ ? 16:20) ; cbWndExtra
         NumPut(    "ptr",           0, wc, _ ? 20:24) ; hInstance
         NumPut(    "ptr",           0, wc, _ ? 24:32) ; hIcon
         NumPut(    "ptr",     hCursor, wc, _ ? 28:40) ; hCursor
         NumPut(    "ptr",      hBrush, wc, _ ? 32:48) ; hbrBackground
         NumPut(    "ptr",           0, wc, _ ? 36:56) ; lpszMenuName
         NumPut(    "ptr", StrPtr(cls), wc, _ ? 40:64) ; lpszClassName
         NumPut(    "ptr",           0, wc, _ ? 44:72) ; hIconSm

      ; Registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function.
      DllCall("RegisterClassEx", "ptr", wc, "ushort")

         WS_VISIBLE                := 0x10000000
         WS_SYSMENU                :=    0x80000
         WS_CHILD                  := 0x40000000
         WS_EX_TOPMOST             :=        0x8
         WS_EX_LAYERED             :=    0x80000
         WS_TILEDWINDOW            :=   0xCF0000
         WS_CAPTION                :=   0xC00000
         WS_EX_STATICEDGE          :=    0x20000
         WS_EX_WINDOWEDGE          :=      0x100
         WS_SIZEBOX                :=    0x40000
         WS_CLIPCHILDREN           :=  0x2000000
         WS_POPUP                  := 0x80000000
         WS_BORDER                 :=   0x800000
         WS_EX_TOOLWINDOW          :=       0x80
         WS_CLIPSIBLINGS           :=  0x4000000
         WS_EX_TRANSPARENT         :=       0x20
         WS_EX_DLGMODALFRAME       :=        0x1

         style := WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_POPUP | WS_CLIPSIBLINGS
         styleEx := WS_EX_TOPMOST | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME

         hwnd := DllCall("CreateWindowEx"
            ,   "uint", styleEx      ; dwExStyle
            ,    "str", cls          ; lpClassName
            ,    "str", "MyWindow"   ; lpWindowName
            ,   "uint", style        ; dwStyle
            ,    "int", 200          ; X
            ,    "int", 200          ; Y
            ,    "int", 500          ; nWidth
            ,    "int", 500          ; nHeight
            ,    "ptr", 0            ; hWndParent
            ,    "ptr", 0            ; hMenu
            ,    "ptr", 0            ; hInstance
            ,    "ptr", 0            ; lpParam
            ,    "ptr")

      ; This works.
      ; Persistent(false)
}
Last edited by iseahound on 25 Sep 2021, 19:32, edited 2 times in total.
iseahound
Posts: 1444
Joined: 13 Aug 2016, 21:04
Contact:

Re: [v2-beta.1] Persistent does not work when defined in a WindowProc

25 Sep 2021, 19:31

This seems to be fixed with omitting "Fast" from CallbackCreate. However, I still believe this is a bug, since Persistent should change the global state of the script. It is impossible to test this with standard thread creation: e.g.

Code: Select all

Persistent(true)
a:: Persistent(false)
due to the hotkey automatically making the script persistent.

The current behavior of Persistent being thread specific makes absolutely no sense whatsoever since whether or not the script persists is a global scope.
iseahound
Posts: 1444
Joined: 13 Aug 2016, 21:04
Contact:

Re: [v2-beta.1] Persistent is thread specific and not global.

25 Sep 2021, 19:33

To add on, I think using an internal counter for persistent may be better. If I create multiple windows, and a true/false flag is being set, the script will exit even when windows are still open. Having +1 and -1 would make the state of the script as persistent much more manageable. This functionality could be mimicked by the creation of a global or static variable however.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: [v2-beta.1] Persistent is thread specific and not global.

25 Sep 2021, 20:13

CallbackCreate's "Fast" is a red herring. the runtime isnt constantly checking if the script is persistent to know if its ok to close it down already. instead it checks only when certain actions take place:
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: [v2-beta.1] Persistent is thread specific and not global.

25 Sep 2021, 21:57

Persistent unequivocally controls a simple global variable. This is the entire function:

Code: Select all

BIF_DECL(BIF_Persistent)
{
	// (comment omitted)
	_f_set_retval_i(g_persistent);
	g_persistent = ParamIndexToOptionalBOOL(0, true);
}
The script will terminate after completing startup if it lacks hotkeys, hotstrings, visible GUIs, active timers, clipboard monitors and InputHooks, and has not called the Persistent function. Otherwise, it will stay running in an idle state, [...]. If these conditions change after startup completes (for example, the last timer is disabled), the script may exit when the last running thread completes or the last GUI closes.
Source: Scripts - Definition & Usage | AutoHotkey v2
Prevents the script from exiting automatically when its last thread completes, allowing it to stay running in an idle state.
Source: Persistent - Syntax & Usage | AutoHotkey v2
Fast or F: Avoids starting a new thread each time Function is called.
Source: CallbackCreate - Syntax & Usage | AutoHotkey v2
No new thread = no thread to complete.

Also,
Fast or F: ... it must be avoided whenever the thread from which Address is called varies (e.g. when the callback is triggered by an incoming message).
... the fast mode should be used only when it is known exactly which thread(s) the function will be called from.
Source: CallbackCreate - Syntax & Usage | AutoHotkey v2

iseahound wrote:I think using an internal counter for persistent may be better.
Then do that. The logic of when the "persistent" flag should be set is entirely up to you. The flag is set only when you call the Persistent() function. You can even change the function's usage and behaviour, by redefining Persistent.Call.

All of the other conditions are handled dynamically, because maintaining a single counter would be complex and error-prone, due to the need to reliably detect when each condition changes.

swagfag wrote:instead it checks only when certain actions take place: ...
using Pause()
checking #HotIf conditions
checking timer expirations
What do you mean?
  • Pause() just prevents the thread from exiting, like a Wait function. It doesn't cause any persistence checks.
  • Evaluating a #HotIf condition means executing a thread. The #HotIf check is not relevant; only the action of a thread completing.
  • "Checking timer expirations" has the purpose of launching timer threads. The timer check is not relevant; only the action of one or more threads completing.
    (If there are multiple timers eligible to execute, ResumeUnderlyingThread is only called after all eligible timers have executed. The presence of any enabled timers would mark the script as persistent anyway.)
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: [v2-beta.1] Persistent is thread specific and not global.

25 Sep 2021, 22:27

its just a list of places i found ResumeUnderlyingThread() was being called from
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: [v2-beta.1] Persistent is thread specific and not global.

25 Sep 2021, 22:41

ResumeUnderlyingThread is not called by Pause, although PauseUnderlyingThread looks kind of similar...

Return to “Ask for Help (v2)”

Who is online

Users browsing this forum: ntepa, redrum and 21 guests