WinWaitCreated() - Wait for a new window

Post your working scripts, libraries and tools for AHK v1.1 and older
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

WinWaitCreated() - Wait for a new window

04 Jan 2014, 14:12

Code: Select all

/*
  Wait for a window to be created, returns 0 on timeout and ahk_id otherwise
  Parameter are the same as WinWait, see http://ahkscript.org/docs/commands/WinWait.htm
  Forum: http://ahkscript.org/boards/viewtopic.php?f=6&t=1274&p=8517#p8517
*/
WinWaitCreated( WinTitle:="", WinText:="", Seconds:=0, ExcludeTitle:="", ExcludeText:="" ) {
    ; HotKeyIt - http://ahkscript.org/boards/viewtopic.php?t=1274
    static Found := 0, _WinTitle, _WinText, _ExcludeTitle, _ExcludeText 
         , init := DllCall( "RegisterShellHookWindow", "UInt",A_ScriptHwnd )
         , MsgNum := DllCall( "RegisterWindowMessage", "Str","SHELLHOOK" )
         , cleanup:={base:{__Delete:"WinWaitCreated"}}
  If IsObject(WinTitle)   ; cleanup
    return DllCall("DeregisterShellHookWindow","PTR",A_ScriptHwnd)
  else if (Seconds <> MsgNum){ ; User called the function
    Start := A_TickCount, _WinTitle := WinTitle, _WinText := WinText
    ,_ExcludeTitle := ExcludeTitle, _ExcludeText := ExcludeText
    ,OnMessage( MsgNum, A_ThisFunc ),  Found := 0
    While ( !Found && ( !Seconds || Seconds * 1000 < A_TickCount - Start ) ) 
      Sleep 16                                                         
    Return Found,OnMessage( MsgNum, "" )
  }
  If ( WinTitle = 1   ; window created, check if it is our window
    && ExcludeTitle = A_ScriptHwnd
    && WinExist( _WinTitle " ahk_id " WinText,_WinText,_ExcludeTitle,_ExcludeText))
    WinWait % "ahk_id " Found := WinText ; wait for window to be shown
}
timeFlies
Posts: 146
Joined: 22 Oct 2013, 20:54
Location: Somewhere in the northern hemisphere.

Re: WinWaitCreated() - Wait for a new window

04 Jan 2014, 14:17

How is this different from WinWait? (Apart from the fact that this is a function.)
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: WinWaitCreated() - Wait for a new window

04 Jan 2014, 14:22

It waits for a new window while WinWait returns existent window, see here.

Code: Select all

Run Explorer.exe /n`,/e`,%A_MyDocuments%
ID := WinWaitCreated("ahk_class CabinetWClass")
WinWaitActive, ahk_id %ID%
ControlClick, DirectUIHWND1, ahk_id %ID%
sendinput *.ahk{Tab}
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
Contact:

Re: WinWaitCreated() - Wait for a new window

04 Jan 2014, 14:44

Very useful, thanks HotKeyIt!
User avatar
trismarck
Posts: 506
Joined: 30 Sep 2013, 01:48
Location: Poland

Re: WinWaitCreated() - Wait for a new window

05 Jan 2014, 15:22

"It's brilliant", as the British would say, thank you HotkeyIt.

So to detect if a new window is created, one can use WinWaitCreated() instead of i.e.
  • listing all of the windows that were present before the new window was created
  • doing something to make the new window show up
  • comparing the list to the list of 'current' windows against the list of old windows, in hope that the 'new' window one is looking for is there.
or using things like window groups or the ExcludeTitle parameter, which doesn't support the handle to the window as the parameter.

Some notes:
  • maybe use 'New": Gui, WinWaitCreated:New
  • maybe use '+Hwnd' Gui, WinWaitCreated:New, +LastFound, +HwndHwnd (and change RegisterShellHookWindow() accordingly)
  • the first parameter of RegisterShellHookWindow() should be of type Ptr?
  • should DeregisterWindowMessage() be called when the function ends / at the end of the script?
  • not sure if this:

    Code: Select all

    if (WinTitle=1
     && WinExist(_WinTitle " ahk_id " WinText ,_WinText,_ExcludeTitle,_ExcludeText))
    	WinWait % "ahk_id " found:=WinText
    
    could be swapped to just:

    Code: Select all

    if(WinTitle=1)
    	found := winText
    
    ; or maybe
    if(WinTitle=1 && WinExist(…) )
    	found := winText
    
    • WinExist() already sets the window as the Last Found window, but the last found window is actually irrelevant, as the variable found already contains the handle to the correct window
    • when WinExist() finds the window, WinWait() looks unnecessary
    • I guess && WinExist(_WinTitle " ahk_id " WinText,_WinText,_ExcludeTitle,_ExcludeText) is a hack to prevent the situation in which A_Gui was not set by OnMessage() but rather by some other event, i.e. AHK Gui event and WinWaitCreated() was called in the same thead that triggered the event. In that case, A_Gui is set by the AHK Gui event and upon invoking WinWaitCreated() the second part of the function could be invoked and could? set the value of found to a wrong value
      No I guess this couldn't happen as found is reset to 0 in the if !A_Gui section.
  • are there any circumstances where WinWaitCreated() would fail to receive the message upon the window is created? (window drawn on other desktop / some special window / sth else)
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: WinWaitCreated() - Wait for a new window

05 Jan 2014, 17:14

Awesome, HotKeyIt :)

Avoiding the GUI.

Code: Select all

_WinWaitCreated( WinTitle:="", WinText:="", Seconds:=0, ExcludeTitle:="", ExcludeText:="" ) {
; HotKeyIt - http://ahkscript.org/boards/viewtopic.php?t=1274

Static Found := 0, MsgNum, _WinTitle, _WinText, _ExcludeTitle, _ExcludeText 

  If ( MsgNum = "" ) 
    DllCall( "RegisterShellHookWindow", UInt,A_ScriptHwnd )
  , MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" )

  If ( WinTitle <> 1 && Seconds <> MsgNum )  {

    _WinTitle := WinTitle, _WinText := WinText
    _ExcludeTitle := ExcludeTitle, _ExcludeText := ExcludeText

    OnMessage( MsgNum, A_ThisFunc ),  Found := 0,  Start := A_TickCount 
    While ( !Found && ( !Seconds || Seconds * 1000 < A_TickCount - Start ) ) 
      Sleep 100                                                               
    OnMessage( MsgNum )

    Return Found
  }
  
  If ( WinTitle = 1 
   &&  WinExist( _WinTitle " ahk_id " WinText,_WinText,_ExcludeTitle,_ExcludeText) )
       WinWait % "ahk_id " Found := WinText
}
PS: IMHO, SHWinWait() or ShellWinWait() or the likes would be a better function name - since this function will work only with top-level windows.
My Scripts and Functions: V1  V2
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: WinWaitCreated() - Wait for a new window

06 Jan 2014, 06:48

Many thanks for your input SKAN ;)

I have now eliminated creation of Gui. Further I would like to keep WinWaitCreated because it fits better in AHK terminology and is self-explanatory.

@tismark, from my tests when we do not use WinWait the window might not be visible when function returns.
I have updated your suggestions and also implemented DeregisterShellHookWindow for cleanup.
Thanks for your feedback ;)
Guest10
Posts: 578
Joined: 01 Oct 2013, 02:50

Re: WinWaitCreated() - Wait for a new window

06 Jan 2014, 11:21

i can get this function to work. any simple examples to give me a head start? :ugeek:
strobo
Posts: 125
Joined: 30 Sep 2013, 15:24

Re: WinWaitCreated() - Wait for a new window

06 Jan 2014, 15:00

In http://ahkscript.org/boards/viewtopic.php?f=9&t=542, I pointed out an idea to a pedestrian AHK version of "winwaitcreated". It turns out to be considerably shorter (or was it my use of identifiers?) and doesn't keep the script alive, and, it falls back to "winwait" which makes it reacting faster if there is not already such a window.

Code: Select all

winwaitcreated2(WinTitle = "", WinText = "", Seconds = "", ExcludeTitle = "", ExcludeText = "")
	{
	static dt := 10
	t := WinTitle, txt := WinText, s := Seconds, ext := ExcludeTitle, extxt := ExcludeText, ft := s != "" ? s*1000+a_tickcount : ""
	winget, pwl, list,% t,% txt,% ext,% extxt
	a0 := {}
	loop,% pwl
		a0[pwl%a_index%] := true
	loop
		{
		winget, pwl, list,% t,% txt,% ext,% extxt
		if (!pwl)
			{
			winwait,% t,% txt,% ft ? (ft-a_tickcount)/1000 : "",% ext,% extxt
			return winexist("")
			}
		loop,% pwl
			if (!a0[pwl%a_index%])
				return pwl%a_index%+0
		if (ft && ft <= a_tickcount)
			return 0
		sleep,% dt
		}
	}
Regex support for ahk_id in titlematchmode or more dynamic ahk_groups (don't wanna create a persistent(?) group per call) would make this obsolete (and not only this) ... psst, Lexikos, are you reading...;)
Guest10
Posts: 578
Joined: 01 Oct 2013, 02:50

Re: WinWaitCreated() - Wait for a new window

07 Jan 2014, 07:35

does winwaitcreated2 do all that winwaitcreated does? :geek:
Guest10
Posts: 578
Joined: 01 Oct 2013, 02:50

Re: WinWaitCreated() - Wait for a new window

07 Jan 2014, 12:31

i tested with winwaitcreated2 and it works great (but not with the original winwaitcreated)! i ran a simple text file with Title in its title. :lol: :ugeek:

Code: Select all

ID := WinWaitCreated2("Title")
Clipboard := ID
msgbox % ID
ExitApp

winwaitcreated2(WinTitle = "", WinText = "", Seconds = "", ExcludeTitle = "", ExcludeText = "")
   {
   static dt := 10
   t := WinTitle, txt := WinText, s := Seconds, ext := ExcludeTitle, extxt := ExcludeText, ft := s != "" ? s*1000+a_tickcount : ""
   winget, pwl, list,% t,% txt,% ext,% extxt
   a0 := {}
   loop,% pwl
      a0[pwl%a_index%] := true
   loop
      {
      winget, pwl, list,% t,% txt,% ext,% extxt
      if (!pwl)
         {
         winwait,% t,% txt,% ft ? (ft-a_tickcount)/1000 : "",% ext,% extxt
         return winexist("")
         }
      loop,% pwl
         if (!a0[pwl%a_index%])
            return pwl%a_index%+0
      if (ft && ft <= a_tickcount)
         return 0
      sleep,% dt
      }
   }
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: WinWaitCreated() - Wait for a new window

07 Jan 2014, 14:24

Guest10 wrote:i tested with winwaitcreated2 and it works great (but not with the original winwaitcreated)! i ran a simple text file with Title in its title. :lol: :ugeek:
So you changed the Title of a window?
That is exactly the difference between these 2 methods.

For original WinWaitCreated the window must match the parameters when it is created and not later or when it was hidden before.
  1. Imagine we call WinWaitCreated("Test.ahk - Notepad") and open new Notepad window, then save it as Test.ahk,
  2. Same when we call WinWaitCreated("C:\ ahk_class CabinetWClass") and user navigates to C:\ in existent explorer window.
For both WinWaitCreated2 would return the hwnd of existent window but not WinWaitCreated.
Also WinWaitCrated should be using less CPU and respond better when another thread like Hotkey is executed while waiting.
Guest10
Posts: 578
Joined: 01 Oct 2013, 02:50

Re: WinWaitCreated() - Wait for a new window

07 Jan 2014, 19:45

this is what i did and it still did not work:
created an empty text file in notepad and called it (saved it as) Test. So the full title is "Test - Notepad".
ran the following script and THEN opened the saved Test file. Nothing happened with winwaitcreated.

Code: Select all

#Persistent
#SingleInstance FORCE
#NoEnv
SendMode, Input
SetWorkingDir, %A_ScriptDir%

ID := WinWaitCreated("Test - Notepad")
Clipboard := ID
msgbox % ID
ExitApp

WinWaitCreated( WinTitle:="", WinText:="", Seconds:=0, ExcludeTitle:="", ExcludeText:="" ) {
    ; HotKeyIt - http://ahkscript.org/boards/viewtopic.php?t=1274
    static Found := 0, _WinTitle, _WinText, _ExcludeTitle, _ExcludeText
                ,init := DllCall( "RegisterShellHookWindow", "UInt",A_ScriptHwnd )
                ,MsgNum := DllCall( "RegisterWindowMessage", "Str","SHELLHOOK" )
                ,cleanup:={base:{__Delete:"WinWaitCreated"}}
  If (Seconds <> MsgNum){ ; User called the function
    Start := A_TickCount, _WinTitle := WinTitle, _WinText := WinText
    ,_ExcludeTitle := ExcludeTitle, _ExcludeText := ExcludeText
    ,OnMessage( MsgNum, A_ThisFunc ),  Found := 0
    While ( !Found && ( !Seconds || Seconds * 1000 < A_TickCount - Start ) )
      Sleep 16                                                        
    Return Found,OnMessage( MsgNum )
  } else if IsObject(WinTitle)   ; cleanup
        return DllCall("DeregisterShellHookWindow","PTR",A_ScriptHwnd)
   
    If ( WinTitle = 1   ; window crated, check if it is our window
            && WinExist( _WinTitle " ahk_id " WinText,_WinText,_ExcludeTitle,_ExcludeText))
      WinWait % "ahk_id " Found := WinText ; wait for window to be shown
}
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: WinWaitCreated() - Wait for a new window

08 Jan 2014, 01:46

I had a look and I see now that notepad opens as Untitled and renames the title afterwards.

Code: Select all

Run notepad C:\Test.txt
ID := WinWaitCreated("ahk_class Notepad")
WinWait,Test.txt
msgbox % ID
strobo
Posts: 125
Joined: 30 Sep 2013, 15:24

Re: WinWaitCreated() - Wait for a new window

08 Jan 2014, 06:08

That is exactly the difference between these 2 methods.
Not imho, replacing the first winget command by "winget, pwl, list" (no window params) should imitate that behaviour of winwaitcreate quite well although the method does not really change.
Also WinWaitCreated should be using less CPU
I have no numbers, just 0% in taskmgr.exe.
and respond better when another thread like Hotkey is executed while waiting.
I'd expect it also, but the loop-body is buisy only for less than a msec (here, ~60µsec), which is hardly dinstinguishable from any shorter thread-interruption.
Btw, HotkeyIts original WinWaitCreated itself is not (ahk-)thread-safe, which destroys response with two or more WinWaitCreated threads.
Last edited by strobo on 08 Jan 2014, 16:00, edited 1 time in total.
Guest10
Posts: 578
Joined: 01 Oct 2013, 02:50

Re: WinWaitCreated() - Wait for a new window

08 Jan 2014, 10:25

when i run the following script with ExitApp added the script does not quit after i dismiss the message box (it does pop up in this script with an ID). why is that? :? :ugeek:
HotKeyIt wrote:I had a look and I see now that notepad opens as Untitled and renames the title afterwards.

Code: Select all

Run notepad C:\Test.txt
ID := WinWaitCreated("ahk_class Notepad")
WinWait,Test.txt
msgbox % ID
ExitApp
User avatar
trismarck
Posts: 506
Joined: 30 Sep 2013, 01:48
Location: Poland

Re: WinWaitCreated() - Wait for a new window

08 Jan 2014, 14:12

Guest10, there is a small bug in the function as the destructor part of the function was mistakenly put _after_ the user part of the function and thus the destructor part didn't fire when it should. Here is a partly updated version of the function. One of the concerns I have about the function is of whether the function should be Critical or not (so that no shell message is lost), but this is yet _maybe_ if ever to be investigated.

Code: Select all

WinWaitCreated( WinTitle:="", WinText:="", Seconds:=0, ExcludeTitle:="", ExcludeText:="" ) {
	static Found := 0 
	, _WinTitle, _WinText, _ExcludeTitle, _ExcludeText
	
	,init := DllCall( "RegisterShellHookWindow"
		, "Ptr", A_ScriptHwnd )
	
	,MsgNum := DllCall( "RegisterWindowMessage", "Str","SHELLHOOK" )
	
	,cleanup:= {base: {__Delete: Func(A_ThisFunc) } }

	; Destructor:
	if IsObject(WinTitle)   ; cleanup
		return DllCall("DeregisterShellHookWindow","Ptr",A_ScriptHwnd)
	
	; OnMessage: HSHELL_WINDOWCREATED, our window
	else If ( WinTitle = 1   ; window crated, check if it is our window
	 && WinExist( _WinTitle " ahk_id " WinText,_WinText,_ExcludeTitle,_ExcludeText)
	 && Seconds = MsgNum
	 && ExcludeTitle = A_ScriptHwnd) 
	{
		;Sleep % A_WinDelay, Found := WinText
			; this of course will assign new value to 'found' too soon
		Sleep % A_WinDelay
		return, "", Found := WinText
			; not sure if the return value is interpreted by
			; The Shell, but in case it is, it's better not
			; to return anything?
			; 
	}
	
	; OnMessage: other message from the Shell:
	else if( ( (WinTitle >= 1 and WinTitle <= 14) or WinTitle = 0x8004)
	 && WinText > 0
	 && Seconds = MsgNum
	 && ExcludeTitle = A_ScriptHwnd)
	{
		return "" ; skip that message
	}
	
	; User called the function: (all other cases)
	else
	{
		Start := A_TickCount
			, _WinTitle := WinTitle, _WinText := WinText
			,_ExcludeTitle := ExcludeTitle, _ExcludeText := ExcludeText

		,OnMessage( MsgNum, A_ThisFunc ),  Found := 0
		
		While ( !Found 
		 && ( !Seconds || Seconds * 1000 < A_TickCount - Start ) )
			Sleep, 16
		
		SetFormat, IntegerFast, hex
		Found += 0, Found .= ""
		SetFormat, IntegerFast, dec
		
		Return Found, OnMessage( MsgNum, "" )
	} 
}
Two notes:
  • WinWait() worked whereas WinExist() failed, because internally, even thoughWinWait() calls WinExist(), WinWait() _always_ waits for A_WinDelay, even if it finds the window right away. WinExist() never waits. This is probably why in HotkeyIt's tests w/o WinWait() the window
    HotkeyIt wrote:might not be visible
    . Another reason for WinWait() or for sleeping is that the message from The Shell means: the window _is being created_ (vs the window _was_ just created).
  • OnMessage() - to stop waiting for messages, the second parameter has to be blank _explicitly_.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: WinWaitCreated() - Wait for a new window

12 May 2015, 04:46

Thanks. Just wanted to use this function, but...

Code: Select all

#Include WinWaitCreated.ahk

Gui, Show, w500 h200
Return

GuiClose:
	MsgBox, bye...
ExitApp
When I click 'X' button to close the GUI, the GUI still there.

this will fix the problem.

Code: Select all

  if IsObject(WinTitle)  ; cleanup
    return DllCall("DeregisterShellHookWindow","PTR",A_ScriptHwnd)
  Else If (Seconds <> MsgNum){ ; User called the function
    Start := A_TickCount, _WinTitle := WinTitle, _WinText := WinText
    ,_ExcludeTitle := ExcludeTitle, _ExcludeText := ExcludeText
    ,OnMessage( MsgNum, A_ThisFunc ),  Found := 0
    While ( !Found && ( !Seconds || Seconds * 1000 < A_TickCount - Start ) ) 
      Sleep 16                                                         
    Return Found,OnMessage( MsgNum )
  }
Last edited by tmplinshi on 12 May 2015, 11:12, edited 1 time in total.
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: WinWaitCreated() - Wait for a new window

12 May 2015, 10:54

I have updated the function, let me know if something does not work.
5ball
Posts: 12
Joined: 28 Feb 2016, 10:04

Re: WinWaitCreated() - Wait for a new window

01 Mar 2016, 15:05

this works like a charm for me within AHK(L) but is failing me heavily in AHK_H. Is there any reason why that should be the case?
to elaborate, when I run the script with AHK_H it isn't nearly as reliable - it will somewhat often miss windows that have opened (and hang) and sometimes open more windows than requested. this isn't an issue (at least not in my testing) in L

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 106 guests