OnEvent SRT enhancement

Ideas for new features & functions

Moderators: Dorian (MJT support), JRL

gdyvig
Automation Wizard
Posts: 447
Joined: Fri Jun 27, 2008 7:57 pm
Location: Seattle, WA

OnEvent SRT enhancement

Post by gdyvig » Tue Mar 03, 2009 5:00 pm

This post discusses problem with OnEvent SRT's calling other SRT's:

http://www.mjtnet.com/usergroup/viewtopic.php?t=5331

Can the OnEvent SRT be enhanced so the OnEvent remains disabled until the SRT returns control? Calling another SRT is NOT returning control.

As mentioned in the other post, if the SRT or a nested SRT contains a GoTo statement, the SRT may not be able to return control. So the enhancement would need a way to handle this, probably a system variable the user sets based on a knowledge of whether downstream GoTo's exist.

Please respond whether you think this is doable and good suggestion

Thanks,

Gale

User avatar
Marcus Tettmar
Site Admin
Posts: 7378
Joined: Thu Sep 19, 2002 3:00 pm
Location: Dorset, UK
Contact:

Post by Marcus Tettmar » Tue Mar 03, 2009 5:06 pm

I agree that control should only return when the End of the called subroutine is reached. So I agree it sounds like there's a bug. We'll get that looked at.

I'm not convinced that it should be possible to override this, but as long as it's not the default it probably won't do any harm - something that advanced users who understand the implications can use.
Marcus Tettmar
http://mjtnet.com/blog/ | http://twitter.com/marcustettmar

Did you know we are now offering affordable monthly subscriptions for Macro Scheduler Standard?

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Post by jpuziano » Tue Mar 03, 2009 8:46 pm

mtettmar wrote:I agree that control should only return when the End of the called subroutine is reached. So I agree it sounds like there's a bug. We'll get that looked at.
Thanks Marcus for looking at this... and thanks Gale for posting about it.

After trying a few things, I ran into something puzzling to me. Let's say we establish an event handler like this:

OnEvent>WINDOW_OPEN,App_Title,2,Do_App_Open

- I thought that when the targeted window opened, the event handler would fire, execution would pass to our subroutine where we'd handle the event and when execution returned from the subroutine... the event would be over and we'd be done (with that occurance of the event).

- I didn't expect the event handler to fire again until the next time another different (as in different handle) target window actually OPENED (was instantiated).

- Instead, the event seems to keep firing continually WHILE one or more of the target windows are open... try the code below:

Code: Select all

Let>App_Title=Untitled - Notepad

//this var counts the number of times the WINDOW_OPEN event fires
//it should be equal to the number of times you OPEN the App window
Let>window_open_event_count=0

//this var counts the number of times the WINDOW_NOTOPEN event fires
//it should be equal to the number of times you CLOSE the App window
Let>window_closed_event_count=0

//2 in the OnEvent lines below means WF_TYPE=2 - Visible Windows Only
OnEvent>WINDOW_OPEN,App_Title,2,Do_App_Open
OnEvent>WINDOW_NOTOPEN,App_Title,2,Do_App_Not_Open

Label>start
Wait>0.5
Goto>start

SRT>Do_App_Open
 Add>window_open_event_count,1
 Message>%App_Title% is open%CRLF%window_open_event_count=%window_open_event_count%%CRLF%window_closed_event_count=%window_closed_event_count%
END>Do_App_Open

SRT>Do_App_Not_Open
 Add>window_closed_event_count,1
 Message>%App_Title% is open%CRLF%window_open_event_count=%window_open_event_count%%CRLF%window_closed_event_count=%window_closed_event_count%
END>Do_App_Not_Open
Marcus, when I run the above code in MS 11.1.05 on XP SP3... the event handlers are firing continuously... question is... why?
Last edited by jpuziano on Wed Mar 04, 2009 6:46 am, edited 5 times in total.
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

User avatar
Marcus Tettmar
Site Admin
Posts: 7378
Joined: Thu Sep 19, 2002 3:00 pm
Location: Dorset, UK
Contact:

Post by Marcus Tettmar » Tue Mar 03, 2009 8:50 pm

That's correct. The event fires when the window is visible. So if its always visible it will always fire. It's up to you how you handle that - often its used to close the window. Or set a flag to indicate whether or not the window has already been spied.
Marcus Tettmar
http://mjtnet.com/blog/ | http://twitter.com/marcustettmar

Did you know we are now offering affordable monthly subscriptions for Macro Scheduler Standard?

User avatar
JRL
Automation Wizard
Posts: 3497
Joined: Mon Jan 10, 2005 6:22 pm
Location: Iowa

Post by JRL » Tue Mar 03, 2009 10:03 pm

jpuziano,
For your convenience, here is your script with the event triggers controlled by variable flags.
Window_Open_Flag
Window_Closed_Flag

I've highlighted the additions. To do that I "Quoted" the text. To select and copy the code go all the way to the text area at the bottom.

Let>App_Title=Untitled - Notepad

//this var counts the number of times the WINDOW_OPEN event fires
//it should be equal to the number of times you OPEN the App window
Let>window_open_event_count=0

//this var handles the application of the Window_Open event trigger
Let>Window_Open_Flag=0


//this var counts the number of times the WINDOW_NOTOPEN event fires
//it should be equal to the number of times you CLOSE the App window
Let>window_closed_event_count=0

//this var handles the application of the Window_Closed event trigger
Let>Window_Closed_Flag=0


//2 in the OnEvent lines below means WF_TYPE=2 - Visible Windows Only
OnEvent>WINDOW_OPEN,App_Title,2,Do_App_Open
OnEvent>WINDOW_NOTOPEN,App_Title,2,Do_App_Not_Open

Label>start
Wait>0.5
Goto>start

SRT>Do_App_Open
If>Window_Open_Flag>0,Skip_App_Open
Let>Window_Closed_Flag=0
Let>Window_Open_Flag=1

Add>window_open_event_count,1
Message>%App_Title% is

open%CRLF%window_open_event_count=%window_open_event_count%

%CRLF%window_closed_event_count=%window_closed_event_count%

Label>Skip_App_Open
END>Do_App_Open

SRT>Do_App_Not_Open
If>Window_Closed_Flag>0,Skip_App_Not_Open
Let>Window_Open_Flag=0
Let>Window_Closed_Flag=1

Add>window_closed_event_count,1
Message>%App_Title% is not

open%CRLF%window_open_event_count=%window_open_event_count%

%CRLF%window_closed_event_count=%window_closed_event_count%

Label>Skip_App_Not_Open
END>Do_App_Not_Open

Code: Select all

Let>App_Title=Untitled - Notepad

//this var counts the number of times the WINDOW_OPEN event fires
//it should be equal to the number of times you OPEN the App window
Let>window_open_event_count=0

//this var handles the application of the Window_Open event trigger
Let>Window_Open_Flag=0

//this var counts the number of times the WINDOW_NOTOPEN event fires
//it should be equal to the number of times you CLOSE the App window
Let>window_closed_event_count=0

//this var handles the application of the Window_Closed event trigger
Let>Window_Closed_Flag=0

//2 in the OnEvent lines below means WF_TYPE=2 - Visible Windows Only
OnEvent>WINDOW_OPEN,App_Title,2,Do_App_Open
OnEvent>WINDOW_NOTOPEN,App_Title,2,Do_App_Not_Open

Label>start
  Wait>0.5
Goto>start

SRT>Do_App_Open
  If>Window_Open_Flag>0,Skip_App_Open
     Let>Window_Closed_Flag=0
     Let>Window_Open_Flag=1
     Add>window_open_event_count,1
     Message>%App_Title% is open%CRLF%window_open_event_count=%window_open_event_count%%CRLF%window_closed_event_count=%window_closed_event_count%
  Label>Skip_App_Open
END>Do_App_Open

SRT>Do_App_Not_Open
  If>Window_Closed_Flag>0,Skip_App_Not_Open
     Let>Window_Open_Flag=0
     Let>Window_Closed_Flag=1
     Add>window_closed_event_count,1
     Message>%App_Title% is not open%CRLF%window_open_event_count=%window_open_event_count%%CRLF%window_closed_event_count=%window_closed_event_count%
  Label>Skip_App_Not_Open
END>Do_App_Not_Open

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Post by jpuziano » Wed Mar 04, 2009 12:02 am

Hi JRL,

A sense of déjà vu is telling me I've raised this topic before... and the reply from Marcus confirms that the OnEvent> commands were designed this way... i.e. while the target window is open, the OnEvent> handler will keep firing continually and you must handle that with flags.

And you did... thanks for those mods JRL, but try this:

- get the macro (your modified version) running
- open notepad
- Message> shows window_open_event_count=1 (so far so good)
- open a second copy of notepad
- Message> shows window_open_event_count=1 (it didn't see the second one)
- what now?

I am just trying to keep a running count of:

- how many times a certain app window was instantiated
- how many times a certain app window was closed

Since the title of a Notepad window can change if a file has been saved, let's simplify by looking for Calc.exe instead... so change the first line to:

Let>App_Title=Calculator

It should handle multiple copies of the same window title... i.e. once the macro is running... if 10 Calculator apps open and 3 close, I need it to read 10 and 3.

Also, if one or more pre-existing Calculator apps are already open when the macro starts, they should be ignored with respect to the open count because the macro did not "see" them open. Conversely, if one of them is later closed, that should add to the close count because the macro did "see" it close.
Last edited by jpuziano on Thu Mar 05, 2009 3:23 pm, edited 3 times in total.
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

User avatar
Bob Hansen
Automation Wizard
Posts: 2475
Joined: Tue Sep 24, 2002 3:47 am
Location: Salem, New Hampshire, US
Contact:

Post by Bob Hansen » Wed Mar 04, 2009 12:23 am

For jpuziano:
I am trying to keep a running count of:

- how many times a certain app window was instantiated
- how many times a certain app window was closed
Another approach: How about using pslist and just looping and looking at the PID and incrementing a counter if the values change? Could use pslist>file and then use RegEx on the file to grab the PIDs, compare them to last harvest ID. If multiple instances are open, you will see a PID for each one.
Hope this was helpful..................good luck,
Bob
A humble man and PROUD of it!

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Post by jpuziano » Wed Mar 04, 2009 1:28 am

Bob Hansen wrote:Another approach: How about using pslist and just looping and looking at the PID and incrementing a counter if the values change? Could use pslist>file and then use RegEx on the file to grab the PIDs, compare them to last harvest ID. If multiple instances are open, you will see a PID for each one.
Thanks Bob, I hadn't thought of that.

One problem with that approach might be, if the app is opened and immediately closed, that pid is not around for very long and may not be seen at all. To counter that, I'd have to be checking very aggressively, maybe constantly... and I'd rather avoid that if possible so I'd still like to know if its possible to do this using OnEvent.
Last edited by jpuziano on Thu Mar 05, 2009 3:22 pm, edited 2 times in total.
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

User avatar
Bob Hansen
Automation Wizard
Posts: 2475
Joined: Tue Sep 24, 2002 3:47 am
Location: Salem, New Hampshire, US
Contact:

Post by Bob Hansen » Wed Mar 04, 2009 2:04 am

Thinking about your problem .......

I am not familiar with Windows Script Host (WSH), but I suspect a script could be written that could access triggers like WhenWindowLoads or WhenWindowUnloads vs. the triggers we have now WhileWindowIsOpen/Closed.

If not WSH, there has to be another language to do that. Don't think VBS has the tools, but VB might, and you could just call a vbs script.

AutoIt may also have the event triggers that you need.

How about two short macros, each using triggers from the Scheduler WhenWindowOpens/Closes. Scripts just increment an INI Opened/Closed counter and closes the macro, waiting for next trigger. These are the triggers you want to put in your script, so just use them to trigger the smaller macros.
Hope this was helpful..................good luck,
Bob
A humble man and PROUD of it!

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Post by jpuziano » Wed Mar 04, 2009 8:22 am

Hi Bob,

Thanks for the pointers... I appreciate the help.
Bob Hansen wrote:I am not familiar with Windows Script Host (WSH), but I suspect a script could be written that could access triggers like WhenWindowLoads or WhenWindowUnloads vs. the triggers we have now WhileWindowIsOpen/Closed.

If not WSH, there has to be another language to do that. Don't think VBS has the tools, but VB might, and you could just call a vbs script.
I did some Googling on this and found out that I would need to be able to set a trigger on:

- the WindowActivate event
- the WindowDeactivate event
- or possibly the WindowDestroy event

I am not sure if an event handler could be written in VBScript to deal with those events.

Setting up the triggers involves setting up Windows Hooks using the SetWindowsHookEx and UnhookWindowsHookEx Win32 API calls.

The article below is all about exactly what I'm trying to do:
Cutting Edge - Windows Hooks in the .NET Framework wrote:http://msdn.microsoft.com/en-ca/magazine/cc188966.aspx

All the key source code available with this article is written in C# but, again, thanks to the language neutrality of the .NET Framework you can easily use Visual Basic .NET to build new hook classes or consumer applications. The sample application is also available in Visual Basic .NET.
Again, unsure if the above could be translated to VBScript that could be run from inside a marco.
Bob Hansen wrote: AutoIt may also have the event triggers that you need.
I looked, no system OnEvent function for that... perhaps a UDF but couldn't find one.
Bob Hansen wrote: How about two short macros, each using triggers from the Scheduler WhenWindowOpens/Closes. Scripts just increment an INI Opened/Closed counter and closes the macro, waiting for next trigger. These are the triggers you want to put in your script, so just use them to trigger the smaller macros.
I'm not sure I understand what you mean... I get the "increment an INI Opened/Closed counter" part... but how would I deal with the fact that I could have 5 target windows open at the same time now... then one gets closed so I need to increment my closed counter... but since there are still 4 open, only OnEvent>WINDOW_OPEN is firing... continually. How do I "see" the one window being closed if OnEvent>WINDOW_NOTOPEN won't even fire?

Thanks for your help so far Bob and JRL... and if anyone else sees a method, please let me know.

P.S. to gdyvig the original poster... sorry for apparently hijacking this thread Gale, not my intention.
Good luck with your enhancement request for: GOTO_CONSTRAINT new system variable
Last edited by jpuziano on Thu Mar 05, 2009 3:21 pm, edited 1 time in total.
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

User avatar
JRL
Automation Wizard
Posts: 3497
Joined: Mon Jan 10, 2005 6:22 pm
Location: Iowa

Post by JRL » Wed Mar 04, 2009 2:45 pm

You could use the code you already have and add some functionality using tools you already know. Create and maintain either a list or an array of Notepad window handles. Each loop checks to make sure all the windows are open, if one drops out, rewrite the list or reorder the array and report the current count. If a new one starts up, rewrite the list or the array and report.

Your Window_Closed OnEvent will remain pretty much the same, its only going to detect that no Notepads are open. Your Window_Open OnEvent will have more to do, checking and maintaining the list.

Yes, your Window_Open OnEvent will be firing all the time... but the only time it will do any work is when there is a change in Notepad windows count. Otherwise you will be adding a couple hundred thousandths of a second to each loop cycle. Hardly noticeable.

Or (probably easier) you could drop the Onevents and use the "IsProcessRunning" portion of this VBScript that Marcus provided, Run a process. Kill & restart if it runs too long Each time it runs it will tell you how many NotePad windows are open.

gdyvig
Automation Wizard
Posts: 447
Joined: Fri Jun 27, 2008 7:57 pm
Location: Seattle, WA

WINDOW_OPEN vs WINDOW_NOTOPEN

Post by gdyvig » Wed Mar 04, 2009 3:52 pm

If the WINDOW_OPEN OnEvent detects one of many instances of a window it should be responsible for closing that instance, which would be the currently active window. It could verify that it's instance was closed by checking the window handle. Then another WINDOW_OPEN OnEvent would fire on the next instance of that window, which should be the next currently active window.

If WINDOW_OPEN OnEvent detects many instances of a window all having the same title but different in some other way, the SRT would need to examine all instances to determine which one(s) it wants to act on, assuming that instance can be brought into focus. Otherwise an enhancement to OnEvent would be required to check for multiple window properties (WINDOW_OPEN plus class, position, height, width, owner, etc).

The WINDOW_NOTOPEN OnEvent would best be used IMO for cases where a required window other than the one the macro is currently acting on could close at any time in the script.

Gale

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Post by jpuziano » Wed Mar 04, 2009 8:06 pm

JRL wrote: You could use the code you already have and add some functionality using tools you already know. Create and maintain either a list or an array of Notepad window handles. Each loop checks to make sure all the windows are open, if one drops out, rewrite the list or reorder the array and report the current count. If a new one starts up, rewrite the list or the array and report.
OK, back to notepad windows... The first thing I need to do when the macro starts is to find all the windows that are currently open and if there are any Notepad windows, I would need to get their handles and add them to my list of Notepad window handles. Later, if one of them disappears, I know that the window closed and I can increment a counter. Here's where I started:

GetWindowList>winlist

That gives me a list of open top-level windows. Since the list is CRLF delimited, it also shows nicely in an MDL>
MDL>winlist wrote:Macro - GetWindowList
Macro Scheduler 11
Windows Scripting, Windows Macro Automation, Windows Macro Recorder - Automate your PC for Wind - Microsoft Internet Explorer p
Macro Scheduler
Untitled - Notepad
Untitled - Notepad
Untitled - Notepad
Inbox - Microsoft Outlook
Program Manager
So three Notepad windows are already open and I need their handles. Problem is, I can't play around with changing the focus to this window or that to get a handle... and I certainly can't just grab the first one, get handle, close the window, get the next and repeat. This has to happen in the background without affecting what the user sees.

Any ideas? Anyone?

Possible enhancement request: Perhaps the GetWindowList> command could be enhanced to have a second mode... that would return a list of window title / window handle pairs.
Last edited by jpuziano on Thu Mar 05, 2009 3:19 pm, edited 1 time in total.
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

User avatar
JRL
Automation Wizard
Posts: 3497
Joined: Mon Jan 10, 2005 6:22 pm
Location: Iowa

Post by JRL » Wed Mar 04, 2009 9:00 pm

jpuziano wrote:So three Notepad windows are already open and I need their handles.
Problem is, I can't play around with changing the focus to this window
or that to get a handle... and I certainly can't just grab the first
one, get handle, close the window, get the next and repeat. This has to
happen in the background without affecting what the user sees.

Any ideas? Anyone?
Help wrote:GetWindowHandle>window_title,handle
Returns the window handle of the window specified by it's window title

User avatar
Bob Hansen
Automation Wizard
Posts: 2475
Joined: Tue Sep 24, 2002 3:47 am
Location: Salem, New Hampshire, US
Contact:

Post by Bob Hansen » Wed Mar 04, 2009 9:21 pm

Does this help?

A combination of these commands:
GetWindowList
GetWindowHandle
GetWindowProcess
RegEx

Code: Select all

//==================================
// Forum 3/3/09
// How to get list of Window IDs
//Test with three copies of Calculator open
// Messages for testing steps of process only, not needed in final.

Input>vWindowName,What Window are you checking for?,Calculator
GetWindowList>vWindowsList
RegEx>%vWindowName%,%vWindowsList%,0,vWindow,vMatchCount,0
Let>vCount=0

Label>Loop1
Let>vCount=%vCount%+1
Let>vWindow=vWindow_%vCount%
// MessageModal>Window %vCount% is %vWindow%
GetWindowHandle>%vWindow%,vHandle
// MessageModal>Handle %vCount% is %vHandle%
GetWindowProcess>%vWindow%,vPID,vProcess
// MessageModal>Process %vCount% info is are %vPID% - %vProcess%
// MessageModal>Window %vCount% is PID: %vPID% - Process: %vProcess% - Window: %vWindow% - Handle: %vHandle%
Let>vDetails=Window %vCount% is PID: %vPID% - Process: %vProcess% - Window: %vWindow% - Handle: %vHandle%
WriteLn>ProcessList.txt,vResult,%vDetails%
ReadFile>ProcessList.txt,vAnswer
If>%vCount%<vMatchCount>%vAnswer%

DeleteFile>ProcessList.txt
I thought this might work but I get the same info for all three windows. I missed something somewhere. Cannot dig into it right now, got ot get back to work .... maybe later....
Think it has to do with missing WIN_USEHANDLE=1
Hope this was helpful..................good luck,
Bob
A humble man and PROUD of it!

Post Reply
Sign up to our newsletter for free automation tips, tricks & discounts