global variable problem in new v2 version

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
fwejifjjwk2
Posts: 89
Joined: 10 Aug 2019, 01:49

global variable problem in new v2 version

Post by fwejifjjwk2 » 06 Aug 2020, 00:19

In new version my script's global variable show some error.
In older version (maybe around 2020/03) no this problem.
The different in below. Just let people know version's different.

Code: Select all

;;; old version

; If variable not define it seens default define boolean False
; use #if
; gui listview syntax
LV := helper_gui.Add("ListView", "r80 w430", "keywords|refenence")


;;; new version

; can't use if statement estimate no define variable
; use #HotIf
; gui listview syntax
LV := helper_GUI.Add("ListView", "r80 w430", ["keywords", "refenence"])
First issue about global variable in GUI hwnd

my-launcher-demo.7z
(2.16 KiB) Downloaded 48 times
If I active gui_main() than active gui_search than I active a search than it need close main_gui by main_hwnd.
But in new version searchButton_Click function's "WinClose(main_hwnd)" show error "Target window not found."
In older version I can close search_gui by this method. So looks like global variable have different behavior in new version.

Test method is
  • run host.ahk
  • press alt-q
  • press space
  • type any string in text gui
  • press enter

Code: Select all

; host.ahk
SoundBeep(300,150)
DetectHiddenWindows True

#Include gui.ahk
#Include commands.ahk
#Include lib.ahk

Alt & q::
{
    if WinExist(main_hwnd)
        {
            WinClose(main_hwnd)
            Return
        }
    else
        {
            gui_main()
            if WinExist(search_hwnd)
            WinClose(search_hwnd)
            Return
        }
}

Code: Select all

; gui.ahk

global main_hwnd := "", search_hwnd := "", help_hwnd := ""
gui_main()
{
    beginnerSearchHint := "→ h{Space}查詢"

    (main_gui := Gui.New()).Opt("+AlwaysOnTop -caption")
    main_gui.BackColor := "FFFFFF"
    global main_hwnd := main_gui.hwnd
    main_gui.OnEvent("Escape",(this) => this.Hide()) ; 需要在 gui active 的狀態下才能關閉

    ((ref_main := main_gui.Add("Edit", "r0 w220 h30 -vscroll -Wrap -WantReturn +Lowercase", beginnerSearchHint)).OnEvent('Change', 'DetectUserInput'))
    ref_main.SetFont("s14", "Verdana")
    main_gui.Show()
}


gui_search(guiTitle, option, searchTip)
{
    (search_GUI := Gui.New()).Opt("-caption -Border +Owner")
    search_GUI.BackColor := "C0C0C0"
    global search_hwnd := search_GUI.hwnd
    search_GUI.OnEvent("Escape", (this) => this.Hide())

    (ref_search_title := search_GUI.Add("Text","r0 w220 h30", guiTitle)).SetFont("s16", "Verdana")
    (ref_search := search_GUI.Add("Edit", "r0 w220 h30 -WantReturn -Wrap -vscroll", searchTip)).OnEvent('Change', 'searchDetectUserInput')
    ref_search.SetFont("s16", "cBlue")

    ; 搜索 GUI
    searchDetectUserInput(GuiCtrlObj, Info)
    {
        (search_GUI.Add("Button", "yp w0 Default", "Default Hidden")).OnEvent("Click", "searchButton_Click")
        searchStr := GuiCtrlObj.Value
        searchButton_Click(*)
        {
        searchByOption(searchStr, option)
        WinClose(main_hwnd)
        }
        Return
    }
    search_GUI.Show()
}


searchByOption(inputStr, optionString)
{
    if (optionString == "google")
        searchUrl := "http://www.google.com/search?q=" inputStr

    else if (optionString == "autohotkey")
        searchUrl := "https://www.google.com/search?num=50&safe=off&site=&source=hp&q=autohotkey%20" inputStr "&btnG=Search&oq=&gs_l="

    Run(searchUrl)
    Return
}


regexHelp()
{
	helper_GUI := Gui.New()

	global help_hwnd := helper_GUI.hwnd
	LV := helper_GUI.Add("ListView", "r80 w430", ["關鍵字", "說明"])

	; 點擊時顯示清單行號
	LV.OnEvent("Click", "LV_Click")
	LV_Click(LV, RowNumber)
    {
        RowText := LV.GetText(RowNumber)  ; Get the text from the row's first field.
        ToolTip( RowNumber " line. keyword: " RowText)
    	SetTimer () => ToolTip(), -2000
    }


	Loop read, "commands.ahkl"
	{
		If Substr(A_LoopReadLine, 1, 1) != ";"
		{
  		    commandKeyStr := "userInputStr =="
		    EndStr := '")'
		    If InStr(A_LoopReadLine, commandKeyStr, false) ; 搜索不區分大小寫
		    {
		        ; 關鍵字字串
		        keyPos := InStr(A_LoopReadLine, commandKeyStr)
		        headPos := keyPos + 17
		        endPos := InStr(A_LoopReadLine, EndStr)
		        diffs := endPos - headPos
		        baseText := SubStr(A_LoopReadLine, headPos, diffs)
		        commandStr := StrReplace(baseText, " ", "{Space}")

		        ; 說明字串
		        helpStrHead := '") `;'
		        hPos := InStr(A_LoopReadLine, helpStrHead) + 4
		        endPos2 := StrLen(A_LoopReadLine) - hPos + 1
		        helpCommentText := SubStr(A_LoopReadLine, hPos, endPos2)

		        LV.Add(, commandStr, helpCommentText)
		        LV.ModifyCol  ; Auto-size each column to fit its contents.
		        LV.ModifyCol(2, "Sort") ; 以第2欄排序
		    }
		}
	}
	helper_GUI.Show()
	
}

#Hotif WinExist(help_hwnd)
{
Esc::WinClose(help_hwnd)
;Space::WinClose(help_hwnd)
;Enter::WinClose(help_hwnd)
return
}
#Hotif

Code: Select all

; commands.ahk
#1::switchDesktop()

DetectUserInput(GuiCtrlObj, Info)
{
	userInputStr := GuiCtrlObj.Value

	if (userInputStr == "rel") ; 其它 - Reload Script
	{
		GuiCtrlObj.Gui.Submit(Hide := true)
		Sleep(500)
		Reload
	}

	else if (userInputStr == "h ") ; 搜索 - 關鍵字列表 show command list
	{
		GuiCtrlObj.Gui.Submit(Hide := true)
		regexHelp()
	}

	else if (userInputStr == " ") ; 搜索 - Search 搜索
	{
	    GuiCtrlObj.Gui.Submit(Hide := true)
	    gui_search("谷歌搜索", "google","")
	}

	else if (userInputStr == "g ") ; 搜索 - Search 搜索
	{
	    GuiCtrlObj.Gui.Submit(Hide := true)
	    gui_search("谷歌搜索", "google","")
	}


	else if (userInputStr == "a ") ; 搜索 - Search AutoHotkey related stuff
	{
	    gui_search("AutoHotkey 搜索", "autohotkey","")
	    GuiCtrlObj.Gui.Submit(Hide := true)
	}
}


Code: Select all

; lib.ahk
global var_switch := False

switchDesktop()
{
    global ;var_switch := False
	
	if (var_switch)
    {
        SendEvent "^#{Right}"
        var_switch := !var_switch
    }
    else
    {
        SendEvent "^#{Left}"
        var_switch := !var_switch
    }
	Return
}


Another issue about global variable
for-global-variable-test.7z
(481 Bytes) Downloaded 48 times

I have 3 script file that call it host2.ahk file.ahk lib.ahk. This script can use win-1 switch Windows 10 virtual desktop between two desktop.
If only include lib.ahk in shortcut.ahk. When I use shortcut active switchDesktop() function show error "This variable has not been assigned a value."
But if include lib.ahk and inclued shortcut.ahk in host.ahk will no error.

Code: Select all

; host2.ahk
#Include .\lib.ahk
#Include .\shortcut.ahk

Code: Select all

; shortcut.ahk
#Include .\lib.ahk
#1::switchDesktop()

Code: Select all

; lib.ahk
global var_switch := False
switchDesktop()
{
    global
	
	if (var_switch)
    {
        SendEvent "^#{Right}"
        var_switch := False
    }
    else
    {
        SendEvent "^#{Left}"
        var_switch := True
    }
}
Last edited by fwejifjjwk2 on 09 Aug 2020, 08:53, edited 26 times in total.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: global variable problem in new v2 version

Post by swagfag » 06 Aug 2020, 03:47

yeah... it would be more productive if u actually posted the code that exhibits the problem, since these snippets do not
if u pass a hwnd as the wintitle and u get "Target window not found.", then there truly isnt a window by that hwnd at the time of calling the function. whether u used a variable to reference that hwnd and whether that variable actually references a hwnd is irrelevant. on a semirelated note, wintitle accepts objects with a .Hwnd property, so i dont get the point of going through the rigmarole of storing hwnds in separate variables - just pass the gui object itself.
in older version, u had these same problems all along. u just werent made aware of it
fwejifjjwk2
Posts: 89
Joined: 10 Aug 2019, 01:49

Re: global variable problem in new v2 version

Post by fwejifjjwk2 » 06 Aug 2020, 06:46

@swagfag
Thanks reply.
I update my post add full code.
Can you teach me how to send object to another function?
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: global variable problem in new v2 version

Post by swagfag » 06 Aug 2020, 11:56

  1. u call gui_main(). inside it u create a gui, store its hwnd in the global main_hwnd, then u .Show() the gui
  2. now pay close attention:
    • the gui was created inside a function and was assigned to a local variable
    • when u return from the function, all local variables are cleared
    • the gui is a raii wrapper, so if its refcount drops to 0, it .Destroy()s itself. read https://lexikos.github.io/v2/docs/objects/Gui.htm#deleted
    • since uve .Show()n the gui, its refcount is guaranteed to be at least 1 for as long as the gui remains visible
  3. u trigger DetectUserInput()(by typing into the editbox)
  4. u call GuiCtrlObj.Gui.Submit(Hide := true), the gui is hidden, its refcount drops to 0, it gets destroyed
  5. much later: u use (the destroyed gui's now invalid) hwnd, which u had previously stored in main_hwnd, to WinClose() the window. of course, it fails
overall, i have no idea whats going on in this code or why its written this way. if i had to guess, it looks like a bad port of a bad v1 script, eg look at GuiCtrlObj.Gui.Submit(Hide := true) which is apparently being used purely for its side-effect
create all of ur guis in the auto-exec section, make them global, Show/Hide them instead of destroying/recreating them, make some context-sensitive hotkeys instead of hidden focused dummy controls
Can you teach me how to send object to another function
if u know how to send variables to other functions(which i must assume u do), then u know how to send objects, too. theyre no different. what was meant with the ".Hwnd property", was:

Code: Select all

myGui := Gui.New('', 'this is my gui title')
MsgBox WinGetTitle(myGui)


ur code after the preprocessor:

Code: Select all

; host.ahk
SoundBeep(300,150)
DetectHiddenWindows True

; a bunch of functions from gui.ahk
; ...

#Hotif WinExist(help_hwnd)
{
Esc::WinClose(help_hwnd)
;Space::WinClose(help_hwnd)
;Enter::WinClose(help_hwnd)
return ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}
#Hotif

; ...
; a bunch of hotkeys/functions from commands.ahk
; ...

global var_switch := False


switchDesktop() {
    global ;var_switch := False
    
    ; 變量沒有定義會被 if 視為 False ??
    if (var_switch)
    {
        SendEvent "^#{Right}"
        var_switch := !var_switch
    }
    else
    {
        SendEvent "^#{Left}"
        var_switch := !var_switch
    }
    Return
}


Alt & q::
{
    if WinExist(main_hwnd)
        {
            WinClose(main_hwnd)
            Return
        }
    else
        {
            gui_main()
            if WinExist(search_hwnd)
            WinClose(search_hwnd)
            Return
        }
}
it should be obvious why its complaining about var_switch not being initialized: global var_switch := False is unreachable code due to a return in the auto-exec section preceding it
normally, a warning should have been emitted. whether this is a bug or its cause the feature isnt fully fleshed out yet, i cant say. regardless, ill file a report on ur behalf
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: global variable problem in new v2 version

Post by Helgef » 06 Aug 2020, 12:36

whether this is a bug or its cause the feature isnt fully fleshed out yet, i cant say.
warn wrote: Before the script starts to run, show a warning for each line that immediately follows a Return, Break, Continue, Throw or Goto at the same nesting level,
My bold. The block which starts below the #hotif counts as another nesting level.
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: global variable problem in new v2 version

Post by lexikos » 08 Aug 2020, 20:35

The return explains why the var_switch assignment isn't evaluated, and the block explains why there's no warning. But why is a return there in the first place?

It does not belong to the hotkey; single-line hotkeys end at the end of the line (and in v2, other hotkeys must have braces, and do not require return).

The #Hotif code has been written like "if the window exists, define this hotkey and then return". You really don't want the "and then return" part, since you want to do other things afterward (like assign var_switch).

Anyway, that's not how #HotIf works. Think of it more like #SetConditionForTheFollowingHotkeys.
The #HotIf directive sets the expression which will be used by subsequently created hotkeys to determine whether they should activate. This expression is evaluated when the key, mouse button or combination is pressed, or at other times when the program needs to know whether the hotkey is active.
...
The #HotIf directive is positional: it affects all hotkeys and hotstrings physically beneath it in the script, until the next #HotIf directive.

Note: Unlike if statements, braces have no effect with the #HotIf directive.
Source: #HotIf - Syntax & Usage | AutoHotkey v2
@Helgef Perhaps renaming #If to #HotIf wasn't enough...
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: global variable problem in new v2 version

Post by Helgef » 11 Aug 2020, 00:58

lexikos wrote:
08 Aug 2020, 20:35
Perhaps renaming #If to #HotIf wasn't enough...
Perhaps the word If shouldn't be in there. The word If might also cause newcomers to think they define the hotkeys conditionally. Perhaps something like #HotkeyContext would be clearer, although a bit long
Note: Unlike if statements, braces have no effect with the #HotIf directive.
Maybe this could change. We could demand the braces and prohibit code which doesn't belong to a hotkey inside the block. Eg,

Code: Select all

#HotIf expr {
	a:: { ; context sensitive
	}
	msgbox ; error
}
b:: { ; not context sensitive
}
I think this would also be a better way to turn off context sensitivity, which seems to be a recurring problem for newcomers.
Cheers.
fwejifjjwk2
Posts: 89
Joined: 10 Aug 2019, 01:49

Re: global variable problem in new v2 version

Post by fwejifjjwk2 » 17 Aug 2020, 01:46

@swagfag
Thank you remaind me we can use gui object close gui. :facepalm:

Code: Select all

; in searchByOption() function
; WinClose(main_hwnd)
GuiCtrlObj.Gui.Submit(Hide := true)
@lexikos
Thanks. I make some syntax mistake.
Post Reply

Return to “Ask for Help (v2)”