Yupp - that was it. Thx for your effort - really nice work ...Coco wrote:Please try the updated demo.hoppfrosch wrote:I've tested with all available current variants of Autohotkey (Test/NonTest, AHK1/AHK2) - all with the same results: the callback NP_EXist() is never called ...
I've changed the demo to use Calculator, I' not sure if the window title is the same in German but it should be easier to replace.amun wrote:By the demo in German you have to change "notepad" to "editor"
OnWin() - call function on window event (WinWaitXXX async)
- hoppfrosch
- Posts: 443
- Joined: 07 Oct 2013, 04:05
- Location: Rhine-Maine-Area, Hesse, Germany
- Contact:
Re: OnWin() - call function on window event (WinWaitXXX asyn
Re: OnWin() - call function on window event (WinWaitXXX asyn
Updated to v1.0.03.00 - mostly internal changes
Re: OnWin() - call function on window event (WinWaitXXX asyn
This is probably a stupid question but can i put multiple OnWin("Exist", "Calculator", "C") events in a single script?
So for example:
OnWin("Exist", "Calculator", "C")
OnWin("Exist", "Word", "W")
OnWin("Exist", "Notepad", "N")
etc ?
So for example:
OnWin("Exist", "Calculator", "C")
OnWin("Exist", "Word", "W")
OnWin("Exist", "Notepad", "N")
etc ?
Re: OnWin() - call function on window event (WinWaitXXX asyn
Coco,
I have noticed that a new instance of AutoHotKey appears in task manager for each "OnWin" that is pending. They each have a CPU usage of 13 and the fan on my machine kicks into high gear.
Just an observation.
Relayer
I have noticed that a new instance of AutoHotKey appears in task manager for each "OnWin" that is pending. They each have a CPU usage of 13 and the fan on my machine kicks into high gear.
Just an observation.
Relayer
Re: OnWin() - call function on window event (WinWaitXXX asyn
Nice. Does this work with Lexikos' Bind()?
eg
eg
Code: Select all
Class blah {
__New(){
fn := Bind(this.SomeMethod, this)
OnWin("Exist", "Calculator", fn)
}
SomeMethod(){
[...]
}
}
Re: OnWin() - call function on window event (WinWaitXXX asyn
@Pinkfloydd, the child process(es) should terminate once the parent script exits. Are you using the latest version from the main post?
Perhaps you're terminating the main script from within task manager? I tried this and indeed, the subprocess(es) are not terminated. For now, you should exit the main script via ExitApp or Tray menu->Exit. I'll come up with a fix for cases wherein the user tries to exit from the task manager or similar(e.g.: Process, Close). Although ideally, one should allow the script to quit properly(ExitApp or Tray menu) instead of prematurely terminating the process.
Perhaps you're terminating the main script from within task manager? I tried this and indeed, the subprocess(es) are not terminated. For now, you should exit the main script via ExitApp or Tray menu->Exit. I'll come up with a fix for cases wherein the user tries to exit from the task manager or similar(e.g.: Process, Close). Although ideally, one should allow the script to quit properly(ExitApp or Tray menu) instead of prematurely terminating the process.
Re: OnWin() - call function on window event (WinWaitXXX async)
I have been trying to adapt OnWin to use function binding:
Library:
Test Script:
However, the #Singleinstance force directive in the test script breaks it ("Could not close previous instance of script. Keep Waiting?" error).
Does anyone know how to fix this?
Library:
Code: Select all
OnWin(event, WinTitle, CbProc, reserved:=0)
{
static host
if !IsObject(host)
host := new OnWinHost()
host.AddClient(client := new OnWinClient(event, WinTitle, CbProc))
code := Format("
(LTrim Join`n
{5}
ListLines Off
OnWin_Main({1}{2}{1}, {1}{3}{1})
ExitApp
#Include {4}
#NoTrayIcon
#KeyHistory 0
)", Chr(34), host.Id, client.Id, A_LineFile, A_AhkVersion<"2" ? "SetBatchLines -1" : "")
cmd := Format("{1}{2}{1} /ErrorStdOut *", Chr(34), A_AhkPath)
exec := ComObjCreate("WScript.Shell").Exec(cmd)
exec.StdIn.Write(code), exec.StdIn.Close()
while !client.__Handle && (exec.Status == 0)
Sleep 10
; taken from Lexikos' LoadFile() [http://goo.gl/y6ctxp], make script #Persistent
Hotkey IfWinActive, % host.Id
Hotkey vk07, _onwin_persistent, Off
_onwin_persistent:
}
class OnWinHost
{
__New()
{
this.Clients := {}
proxy := ObjClone(this)
VarSetCapacity(CLSID, 16, 0)
if DllCall("ole32\CoCreateGuid", "Ptr", &CLSID) != 0
throw Exception("Failed to generate CLSID", -1)
HR := DllCall("oleaut32\RegisterActiveObject"
, "Ptr", &proxy, "Ptr", &CLSID, "UInt", 0, "UInt*", hReg, "UInt")
if (HR < 0)
throw Exception(Format("HRESULT: 0x{:x}", HR), -1)
this.__Handle := hReg, proxy.__Handle := 0 ; avoid calling RevokeActiveObject twice
VarSetCapacity(sGUID, 38 * 2 + 1)
DllCall("ole32\StringFromGUID2", "Ptr", &CLSID, "Ptr", &sGUID, "Int", 38 + 1)
this.Id := StrGet(&sGUID, "UTF-16")
}
__Delete() ; called on script's exit
{
if hReg := this.__Handle ; 0 if proxy(active object)
{
DllCall("oleaut32\RevokeActiveObject", "UInt", hReg, "Ptr", 0)
for i, client in ObjRemove(this, "Clients") ; terminate any running listener(s)
client.Terminate()
}
}
AddClient(client)
{
this.Clients[ client.Id ] := client
}
FreeClient(client)
{
return ObjRemove(this.Clients, client.Id)
}
}
class OnWinClient
{
__New(event, WinTitle, CbProc)
{
if (WinTitle ~= "i)^ahk_group .*$")
throw Exception("Invalid argument. To specify a window group, pass an array of WinTitle(s).", -1, WinTitle)
this.Event := event
this.Window := WinTitle
;this.Callback := IsObject(CbProc) ? CbProc : Func(CbProc)
this.Callback := CbProc
this.MatchMode := A_TitleMatchMode
this.MatchModeSpeed := A_TitleMatchModeSpeed
this.Id := "#" . &this
this.__Handle := 0
}
__Call(callee, args*)
{
if (callee == "") || (callee = "Call") || IsObject(callee)
{
/*
if CbProc := this.Callback
return %CbProc%(this)
*/
return this.Callback.(this.Event, this.Window)
}
}
Terminate()
{
if hWnd := this.__Handle
return DllCall("PostMessage", "Ptr", hWnd, "UInt", 0x10, "Ptr", 0, "Ptr", 0) ; WM_CLOSE
}
}
OnWin_Main(HostId, ClientId)
{
host := ComObjActive(HostId)
client := host.Clients[ClientId], client.__Handle := A_ScriptHwnd + 0
event := client.Event
if !(event ~= "i)^(Exist|(Not|!)?Active|(Close|(Not|!)Exist)(All)?|Show|Hide|M(in|ax)imize|Move)$")
return
prev_DHW := A_DetectHiddenWindows
DetectHiddenWindows On
SetWinDelay -1
SetTitleMatchMode % client.MatchMode
SetTitleMatchMode % client.MatchModeSpeed
if IsObject(WinTitle := client.Window) ; ahk_group GroupName workaround
{
Loop % WinTitle[A_AhkVersion<"2" ? "MaxIndex" : "Length"]() ; can't use for-loop :(
GroupAdd WinGroup, % WinTitle[A_Index]
WinTitle := "ahk_group WinGroup"
}
if InStr(" Exist Show Minimize Maximize Move ", Format(" {} ", event))
WinWait %WinTitle%
if (event = "Active")
WinWaitActive %WinTitle%
else if (event = "NotActive" || event = "!Active")
WinWaitNotActive %WinTitle%
else if (event ~= "i)^(Close|(Not|!)Exist)(All)?$") && WinExist(WinTitle)
WinWaitClose % InStr(event, "All") ? WinTitle : ""
else if (event = "Show") || (event = "Hide" && WinExist(WinTitle))
{
DetectHiddenWindows Off
if (event = "Show")
WinWait %WinTitle%
else
WinWaitClose
}
else if (event = "Minimize" || event = "Maximize")
{
hWnd := WinExist() ; get handle of "Last Found" Window
showCmd := event="Minimize" ? 2 : 3
VarSetCapacity(WINDOWPLACEMENT, 44, 0)
NumPut(44, WINDOWPLACEMENT, 0, "UInt") ; sizeof(WINDOWPLACEMENT)
Loop
DllCall("GetWindowPlacement", "Ptr", hWnd, "Ptr", &WINDOWPLACEMENT)
until NumGet(WINDOWPLACEMENT, 8, "UInt") == showCmd
}
else if (event = "Move")
{
WinGetPos prevX, prevY, prevW, prevH ; use last found (for ahk_group WinGroup)
Loop
WinGetPos x, y, w, h
until (x != prevX || y != prevY || w != prevW || h != prevH)
}
DetectHiddenWindows %prev_DHW%
try %client%() ; suppress error
return host.FreeClient(client)
}
Code: Select all
#SingleInstance force
#Include <OnWin>
mc := new MyClass()
return
GuiClose:
ExitApp
return
class myclass {
__New(){
fn := this.C.Bind(this)
OnWin("Exist", "Calculator", fn)
Sleep 1000
Run calc.exe
}
C(event, window)
{
;static window
;event := this.Event, window := this.Window
MsgBox CEvent: %event%`nWindow: %window%
;OnWin("Close", window, "X")
fn := this.X.Bind(this)
OnWin("Close", window, fn)
;SetTimer close, -1000
return
}
X(event, window)
{
;event := this.Event, window := this.Window
MsgBox XEvent: %event%`nWindow: %window%
;SetTimer exit, -1 ; allow function to return
return
}
}
Does anyone know how to fix this?
Re: OnWin() - call function on window event (WinWaitXXX async)
I've been wanting to update this script for a while but my focus has been on other things. Perhaps due to not having the need for this now. I'll see what I can do to fix the bugs and improve the script.
Re: OnWin() - call function on window event (WinWaitXXX async)
Thanks for the work~
And , how to stop watching, does it necessary? I didn't found infomation in Parameter.
Using empty callback? OnWin( event, WinTitle)
And , how to stop watching, does it necessary? I didn't found infomation in Parameter.
Using empty callback? OnWin( event, WinTitle)
我为人人,人人为己?
Re: OnWin() - call function on window event (WinWaitXXX async)
Oops, I even forgot how to use this script, lol. Okay, so after reviewing the source, I believe that stopping window monitoring is possible via the OnWinClient class Terminate() method. However, the client object is not exposed to the caller as it is stored in an array kept by the host which itself is stored in a static variable. Thanks for pointing this out, I'll implement this in the next release.RobertL wrote:Thanks for the work~
And , how to stop watching, does it necessary? I didn't found infomation in Parameter.
Using empty callback? OnWin( event, WinTitle)
Re: OnWin() - call function on window event (WinWaitXXX async)
I've pushed a new rewritten version(for testing) with the following changes:
Edit:
Apparently, this line(#77): static level := A_AhkVersion<"2" ? -2 : -1 is bug in v2 and should be static level := A_AhkVersion<"2" ? -2 : -3. I haven't really tested this for v2 but I have written it to be compatible(majority of the code, I hope).
- Monitoring can be performed in-process(same process as the main script) - this is the default when calling OnWin(). To have a window event monitor run in a separate child process, the caller must now use OnWin_Ex()
- Previously, each window event monitor runs it in its own process(w/c is kinda lame). With the new version, the caller may specify on whether to run an event monitor in its own dedicated process or push it into an existing running process(hosting previously set event monitor(s))
- Added OnWin_Stop() to allow disabling of specific active window event monitor(s) via a user-defined event monitor ItemId
- Improved termination of child process(es) that are sometimes left running even when the main script has exited.
Edit:
Apparently, this line(#77): static level := A_AhkVersion<"2" ? -2 : -1 is bug in v2 and should be static level := A_AhkVersion<"2" ? -2 : -3. I haven't really tested this for v2 but I have written it to be compatible(majority of the code, I hope).
Re: OnWin() - call function on window event (WinWaitXXX async)
Thanks for the update!
I am not sure as to the reason why your example code uses this as the passed param.
If you altered the sample code to be like this...
... then it would also work in a class-based, function binding scenario, and would not override the "this" property of the class method.
I am not sure as to the reason why your example code uses this as the passed param.
If you altered the sample code to be like this...
Code: Select all
#Include <OnWin>
OnWin("Exist", "Calculator", "C")
Sleep 1000
Run calc.exe
return
C(e)
{
static window
event := e.Event, window := e.Window
MsgBox Event: %event%`nWindow: %window%
OnWin("Close", window, "X")
SetTimer close, -1000
return
close:
WinClose %window%
return
}
X(e)
{
event := e.Event, window := e.Window
MsgBox Event: %event%`nWindow: %window%
SetTimer exit, -1 ; allow function to return
return
exit:
ExitApp
}
Code: Select all
#Include <OnWin>
mc := new MyClass()
return
Class MyClass {
__New(){
this.test := "Hello World"
OnWin("Exist", "Calculator", this.C.Bind(this))
Sleep 1000
Run calc.exe
}
C(e)
{
static window
event := e.Event, window := e.Window
msgbox % this.test ; "this" is preserved
MsgBox Event: %event%`nWindow: %window%
OnWin("Close", window, this.X.Bind(this))
SetTimer close, -1000
return
close:
WinClose %window%
return
}
X(e)
{
event := e.Event, window := e.Window
MsgBox Event: %event%`nWindow: %window%
SetTimer exit, -1 ; allow function to return
return
exit:
ExitApp
}
}
Re: OnWin() - call function on window event (WinWaitXXX async)
What are the advantages to using this script over just a bunch of SetTimer functions ? Ease of use? Performance?
Re: OnWin() - call function on window event (WinWaitXXX async)
@evilC: The sample code is not updated. Regardless, it's just an example to demonstrate OnWin().
@Skrell: Ease of use, reusable, additional functionality esp. the ability to have the monitoring done in a separate process. You can group certain window event monitors, etc. We occasionally see help requests like: "Do this when certain window appears", "Do that when this window is closed" so this lib will really come in handy for those users.
@Skrell: Ease of use, reusable, additional functionality esp. the ability to have the monitoring done in a separate process. You can group certain window event monitors, etc. We occasionally see help requests like: "Do this when certain window appears", "Do that when this window is closed" so this lib will really come in handy for those users.
Re: OnWin() - call function on window event (WinWaitXXX async)
but performance wise it will typically be the same right?Coco wrote:@evilC: The sample code is not updated. Regardless, it's just an example to demonstrate OnWin().
@Skrell: Ease of use, reusable, additional functionality esp. the ability to have the monitoring done in a separate process. You can group certain window event monitors, etc. We occasionally see help requests like: "Do this when certain window appears", "Do that when this window is closed" so this lib will really come in handy for those users.
Re: OnWin() - call function on window event (WinWaitXXX async)
While this script is a good demonstration of inter-process communication for multi-tasking, if the purpose is to monitor for windows appearing, activating or closing, a shell hook would be more suitable.
Re: OnWin() - call function on window event (WinWaitXXX async)
shell hook can only monitor top windows belong to Shell, not contain its child window, so..lexikos wrote:While this script is a good demonstration of inter-process communication for multi-tasking, if the purpose is to monitor for windows appearing, activating or closing, a shell hook would be more suitable.
inter-process communication for multi-tasking, if the sub tasks could be organizated as threads (not processes), that would be more nice in Windows Task Manager.
我为人人,人人为己?
Re: OnWin() - call function on window event (WinWaitXXX async)
I thought that this is what the SetTimer routine did which is why I originally questioned the advantage of this script over one that simply uses a bunch of SetTimers. Am I incorrect in this understanding ?RobertL wrote:if the sub tasks could be organizated as threads (not processes), that would be more nice in Windows Task Manager.
Re: OnWin() - call function on window event (WinWaitXXX async)
The dev version I posted here, by default, does not use a separate process to perform the monitoring, but instead uses a timer. Only in cases wherein you think that the timer is conflicting with your main script that you can opt in for the alternate method of using a separate child process by calling the newly added function OnWin_Ex(). So in answer to Skrell, performance(in comparison with a script that uses a bunch of SetTimer(s)) should be the same since after all, the method(SetTimer) used is the same. For optimum reliability, shell hook is the best choice.
@RobertL: With the dev version, if you choose to have the monitoring performed in a separate process(by calling OnWin_Ex()), by default, only one child process is used so it's somehow more "friendly" to Windows Task Manager compared to the previous version. Subsequently added event monitors are just pushed into the queue/list. I will be merging this into the main branch.
@RobertL: With the dev version, if you choose to have the monitoring performed in a separate process(by calling OnWin_Ex()), by default, only one child process is used so it's somehow more "friendly" to Windows Task Manager compared to the previous version. Subsequently added event monitors are just pushed into the queue/list. I will be merging this into the main branch.
Re: OnWin() - call function on window event (WinWaitXXX async)
What's your point? This script doesn't handle controls, does it? If you want to monitor for controls, you can use SetWinEventHook, but it fires far more frequently than a shell hook.RobertL wrote:shell hook can only monitor top windows belong to Shell, not contain its child window, so..
In that case it wouldn't be inter-process communication. Is not the whole point of the technique to work around the fact that AutoHotkey doesn't support multi-threading?inter-process communication for multi-tasking, if the sub tasks could be organizated as threads (not processes),
Return to “Scripts and Functions (v1)”
Who is online
Users browsing this forum: Chunjee, CoffeeChaton and 39 guests