February 26, 2009

Sneak Peak: Simplified Regular Expression Support

Filed under: Announcements, Scripting — Marcus Tettmar @ 4:52 pm

I don’t know many people who find Regular Expressions easy. If the following makes no sense to you, don’t worry, you’re not alone:

([a-z0-9!#$%&’*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&’*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)

It’s actually a regular expression pattern which will match an email address in a string. I’m sure you knew that.

At present to use Regular Expressions in Macro Scheduler you have to use VBScript’s regular expression object:

VBSTART
Function RegExpTest(sEmail)
  RegExpTest = false
  Dim regEx, retVal
  Set regEx = New RegExp

  regEx.Pattern ="([a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)"

  regEx.IgnoreCase = true

  Set retMatches = regEx.Execute(sEmail)
  
  If retMatches.Count > 0 then
    RegExpTest = retMatches(0).Value
  End If

End Function
VBEND

VBEval>RegExpTest("My email address is: [email protected]"),theEmail
MessageModal>theEmail

In order to simplify things we’re currently working on a native Regular Expression function called, appropriately enough, RegEx. Using this, the following code will find the email address in the given string:

Let>text=My Email Address: [email protected]
Let>pattern=([a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)
RegEx>pattern,text,0,matches,num,0
MessageModal>matches_1

A bit simpler, as you don’t need to use VBScript. But you still need to use that weird and wonderful regular expression syntax.

Luckily our friends at DataMystic have created something called EasyPatterns which maps real English to regular expression syntax. Thanks to DataMystic we are able to use EasyPatterns in Macro Scheduler. Setting the EasyPatterns flag in the new RegEx command allows us to turn the above into:

Let>text=My Email Address: [email protected]
Let>pattern=[EmailAddress]
RegEx>pattern,text,1,matches,num,0
MessageModal>matches_1

Note the second line has been simplified to Let>pattern=[EmailAddress]. Nice. Now it makes sense!

Check out the EasyPatterns Reference here to find out what else you can do.

Watch out for the next Macro Scheduler maintenance update, which, all being well, will have this function included as a bonus.

Please note this post refers to work in progress. The syntax in the released version may differ slightly. I will update with changes when they happen.

February 19, 2009

View System Windows – Windows and Objects

Filed under: Automation, Scripting — Marcus Tettmar @ 10:12 am

syswindows1

Macro Scheduler has a “View System Windows” tool which you can get to from the Tools menu. This displays a tree of all windows, their child windows and objects open in the system. For each entity you see its handle, class name and title/caption text.

The help file talks about windows and child windows. For windows you can read “objects”. In Windows a “windows control” is not necessarily a window in the sense that you are familiar with but could be a button, a status bar or edit box, or pretty much anything else you see inside a window or on the screen.

So the View System Windows tool shows the hierarchy of “windows” that currently exist on your system. You can expand one to see it’s child windows/objects and so on.

In the picture above I have highlighted the entry for what is commonly referred to as the “System Tray”. Its official title is “Notification Area”. If we right click this entry and select “Identify” a border will be drawn around the system tray icon area. This “Identify” option is a useful way to help locate a window or object and be sure that the entry you see in the list is the object you’re looking for.

A word about handles. These are the numbers that appear in the list. In the above snapshot the notification area has a handle of 131104. It will be different on your system. It will be different after you reboot. Handles are simply identification numbers that are allocated at run time when a window is first created by the system. So don’t go thinking you can grab that number and put it in your script and use it to identify your window. Next time you reboot the script won’t work.

After the handle you will see the “class name”. For the system tray this is “ToolbarWindow32”. This is static but not unique. It is just the type of object – the object class – that is used. We can use this to find an object, but it is not unique.

Macro Scheduler has a function called GetControlText which takes a window title (or handle), a class name and an index. This will return the text associated with an object of the specified class and index on the specified window. If there were two objects of that class an index of 1 would return the first and an index of 2 the second, in the order of creation (some trial and error is usually required). GetControlText is great for objects on regular windows and makes life simple. But for objects deeper in the hierarchy we might have to be a bit more clever.

Some objects also have captions and these are displayed after the class name. Here we see it is “Notification Area”. E.g. windows have captions and we’re used to seeing these in the title bar. Button objects have captions that appear on the button. Some other objects also have captions although they may not be visible (equally what you see on an object is not necessarily the caption that appears in the tree). If we have a caption we can also use this to help us find an object. If we don’t we would have to rely on indexes as in GetControlText – iterate through each instance of an object.

As an example, the following code gets us the handle of the system tray:

LibFunc>User32,FindWindowA,h1,Shell_TrayWnd,
LibFunc>User32,FindWindowExA,h2,h1,0,TrayNotifyWnd,
LibFunc>User32,FindWindowExA,h3,h2,0,SysPager,
LibFunc>User32,FindWindowExA,h4,h3,0,ToolbarWindow32,Notification Area

This code mirrors the hierarchy we see in the View System Windows tree above.

FindWindow takes a class name and caption to return a top level window. So this gives us the handle of the parent Shell_TrayWnd object. FindWindowEx finds an object on the given parent window. So the second line above looks for an object with class “TrayNotifyWnd” on the Shell_TrayWnd window (h1 returned by FindWindow) with no caption. It looks for the first match since the “child after” handle is set to zero. The next two lines continue to walk the tree. What we end up with in h4 is the handle of the system tray.

I use this code here in Activating System Tray Icons.

If all this sounds rather complicated, don’t worry. Most of us will never use code like this. I just wanted to explain more about what View System Windows shows us. There are much easier ways of identifying objects and scraping text from the screen that work in a much more human like way. Objects can be identified visually with Image Recognition and the Text Capture functions let us screen scrape by just specifying a window title or screen area. And most of the time we can automate a window by sending keystrokes to it and never have to care what an object is called.

February 13, 2009

Image Recognition Common Mistakes

Filed under: Automation — Marcus Tettmar @ 12:16 pm

This is a copy of a reply I gave in the forums recently which I thought would be useful posted here.

It sometimes seems to surprise people that the only reason FindImagePos will fail to find an image on the screen is because …. that image is NOT on the screen! I’ve had people swear blind the image they are seeking is on the screen but when I’ve opened up the screen image and the needle image in Paint I can see big differences.

Here are some common mistakes I’ve seen that can lead to not finding the image you want Macro Scheduler to find (or rather, looking for the wrong image):

Mistake 1: Not using the built in Image Capture Tool. ALWAYS use the Macro Scheduler Image Capture tool. Other image editors may save with a different colour depth etc. To ensure like-with-like comparisons ALWAYS use the Macro Scheduler Image Capture Tool.

Mistake 2: Capturing the object when it is in a different state to how it appears at run time. E.g. buttons look different when they are focused, menus look different when they are selected, tooltips appear when the mouse is over objects, sometimes even window captions appear different when the window is not focused, sometimes objects look different when the mouse is hovered over them. Take all these things into consideration and make sure you capture the image as it will appear at the point in the process where you want to find it. You may need to use the delayed capture feature of the Image Capture Tool so that you can arrange focus before you capture the object. Consider making the script move the mouse to 0,0 in case the mouse ends up hovering over the button you’re looking for at runtime. I’ve seen buttons look different if the window is focused. If you have the window focused when you captured it you’ll need to make the script focus it before looking for it. Or vice-versa. Etc etc

Mistake 3: Capturing too much of the screen. FindImagePos compares a random sampling of pixels in the needle image and target area. So if you capture an area with lots of background it’s feasible that only the background pixels get chosen and you’ll end up with lots of matches. Be more specific in your captures, and if you need to, increase FIP_SCANPIXELS to make it scan more pixels. Update: in V12 you can set FIP_SCANPIXELS to ALL.

Mistake 3a: Thinking it didn’t find the image when in fact it DID find it, but it also found other possible matches. The function returns the number of images found and an array of matches. If you are clicking on the first match and it is not the right place, look at the number found. Consider what to do if number of matches is more than 1.

Mistake 4: Looking for the image at the wrong time – getting the order of events all wrong.

Some issues that can cause problems:

Graduated or patterned backgrounds. If you capture an object that is on a non-smooth background and have to capture some of the background as well, then if the object appears at a different position at runtime you may fail to find a match, because the background is not smooth. As with Mistake 3 above you probably just need to be more specific about what you capture. Or, if that isn’t possible, see if you can change the background. There’s no harm in making life easier for ourselves by setting the environment up to be a little more predictable so that we can automate/test more reliably. Don’t forget you can also change the colour tolerance parameter to handle small differences in colours.

Sometimes it’s helpful for diagnostic purposes to use ScreenCapture to capture the screen to a file prior to your FindImagePos call. Then, later, if it didn’t work as you expected you can open up the screen image and work out why.

See also: How to use Image Recognition.

February 12, 2009

Macro Scheduler 11.1.04 Update

Filed under: Announcements — Marcus Tettmar @ 3:27 pm

Macro Scheduler 11.1.04 Update is now available with the following fixes:

  • Fixed: Autologon failing to save password correctly
  • Fixed: Backup on Save not working for standalone editor
  • Fixed: Editor status bar not always reflecting modified status
  • Fixed: Improvements to dialog block updating from “Update Dialog” menu
  • Fixed: Debugger: Breakpoint after an Include not showing Include lines/line number confusion
  • Fixed: Step Over confused by GoSub inside a subroutine
  • Change: Debugger no longer temporarily disables wordwrap – no longer required
  • Change: Editor line numbers now show at top of wrapped lines
  • Added: Clicking in editor margin selects entire line

Registered Downloads/Upgrades | Evaluation Downloads | New License Sales

February 5, 2009

Twitter – What, Why, How?

Filed under: General, Web/Tech — Marcus Tettmar @ 2:20 pm

If you’re one of those who has heard of Twitter but just doesn’t quite “get it” yet you should find Scott Hanselman’s How To Twitter – First Steps and a Twitter Glossary useful. It explains what Twitter is, why it’s useful and how to tweet.

I didn’t get it at first. I wasn’t quite sure what I would get out of it. Most people who now use Twitter regularly were probably the same to begin with. Now I realise how useful it is. I follow friends, people and companies that I find interesting and I want to stay up to date with. I follow news sites like the BBC and CNN. I probably get most of my news via Twitter now (In our house the TV seems to be permanently tuned to Nick Jr these days!). Most of the bloggers I read now tweet their blog updates, so I no longer need to monitor their RSS feeds.

It’s useful. It’s fun too. Even if you don’t have anything to say, you can get a lot out of following people that interest you. And, as Scott says, the nice thing is if you want to respond you can just jump in and reply to anyone.

So if you’ve been wondering what all the fuss is about, read Scott’s blog post, jump in and join the conversation. You can start by following me. My twitter ID is http://twitter.com/marcustettmar 🙂

Generating Random Characters and Strings

Filed under: Scripting — Marcus Tettmar @ 1:10 pm

Macro Scheduler has a Random function which will give you a random number between a specified range. Every now and then I am asked how you can create a random character or random character string.

The solution is to use VBScript’s Chr function which returns the character for the specified Ascii code. So we can use Random to get a random number within the required Ascii range, and then use Chr to get the corresponding character. There are a few examples in the forums, such as this one.

I was recently asked how to generate a random character from A to Z. Here’s my response:

Look at the ASCII table: http://www.asciitable.com/

Let’s look at upper case only first:

A is ascii code decimal 65
Z is ascii code decimal 90

So if we want a random character from A-Z inclusive we want to get a random number in that range (65 to 90).

Clearly it’s a range of 26. Random gives a value from 0 to range-1. So:

Random>26,random_number

So to get that into our range we clearly need to add it to 65, because the ascii range begins at 65 for “A”:

Let>ascii_code=65+random_number

Now we have an ascii code in the required range. So now use VBScript’s Chr function which returns the corresponding character for the ascii code:

VBEval>chr(%ascii_code%),random_char

So, in long form:

Random>26,random_number
Let>ascii_code=65+random_number
VBEval>chr(%ascii_code%),random_char

Or, shorter version:

Random>26,random_number
VBEval>chr(%random_number%+65),random_char

That will give you a random character between A and Z inclusive.

If you want lower case then the range is 97 – 122. There are some characters in between. So if you want to mix lower case and upper case, you could either look at the entire range, discarding any results that appear between the two, or throw a coin (Random>2) to determine whether to do the upper case range or the lower case range, or, I think simpler, randomly convert to lower case, e.g.:

Random>26,random_number
VBEval>chr(%random_number%+65),random_char

Random>2,UpperOrLower
If>UpperOrLower=0
  VBEval>LCase("%random_char%"),random_char
Endif

MessageModal>random_char

Remember, to use VBScript you need a VBSTART/VBEND block in your script, even if it is empty. Stick it at the top. So the whole example script becomes:

VBSTART
VBEND

Random>26,random_number
VBEval>chr(%random_number%+65),random_char

Random>2,UpperOrLower
If>UpperOrLower=0
  VBEval>LCase("%random_char%"),random_char
Endif

MessageModal>random_char

February 2, 2009

T-Shirt Winners for January 2009

Filed under: Announcements — Marcus Tettmar @ 11:02 am

Well I only announced the new forum reputation system on the 21st Jan, but I did say that awards will be made based on the previous month. So it was a short month last month. The top three reputation point winners, and the points awarded were as follows:

mtettmar: 21
Me_again: 13
Bob Hansen: 10

Now, clearly I’m excluding myself from this promo (I already have a T-shirt anyway) so T-shirts (or mug, or mousemat) go to Me_again and Bob Hansen. Congratulations, and thanks for your contributions.

Winners: please PM/email me with your requirements/preferred size and mailing address.

January 30, 2009

Macro Scheduler 11.1.03 Update

Filed under: Announcements — Marcus Tettmar @ 10:45 am

Macro Scheduler 11.1.03 Update is now available with the following fixes:

– Compiled exes with NOSTOPKEY set will show APP_TITLE in tray icon hint
– Fixed: Editor code folding/autoinsertion confused by nested subroutines
– Fixed: Step Over (Shift-F8) not working

Registered Downloads/Upgrades | Evaluation Downloads | New License Sales

My apologies for another update so soon after the last. Thanks to Keith for reporting the issue with nested subroutines confusing the editor’s syntax highlighter, and to Tim for spotting that Step Over wasn’t working. These issues probably don’t effect 99.9% of people, but for Keith and Tim they were a big pain. It was tempting to just provide the fix to them rather than interrupt everyone with yet another update announcement. But there could be others out there with the same issues and I’d rather everyone benefited. So here it is.

January 29, 2009

We Eat Our Own Dogfood

Filed under: General — Marcus Tettmar @ 3:54 pm

I just read this post on the Coding Horror blog and it struck a chord:

In software circles, dogfooding refers to the practice of using your own products. It was apparently popularized by Microsoft:

The idea originated in television commercials for Alpo brand dog food; actor Lorne Greene would tout the benefits of the dog food, and then would say it’s so good that he feeds it to his own dogs. In 1988, Microsoft manager Paul Maritz sent Brian Valentine, test manager for Microsoft LAN Manager, an email titled “Eating our own Dogfood” challenging him to increase internal usage of the product. 

We certainly eat our own dogfood here at MJT Net Ltd. Macro Scheduler was written to solve a pain I had at a previous job many years ago, and I still use it day in day out. Not only is it used for automating various business processes within the company, it is also used for creating small tools and for building parts of other projects.

But what struck me most about the coding horror article was this SawStop video:

It’s an impressive video. Perhaps the reason it struck a chord with me is that my father is a very keen woodworker and has a workshop full of very dangerous machinery which makes me wince every time I step inside. For some reason all I can think of when I watch him work is which limb is going to fly off first!

The creator actually did stick his own finger in a SawStop on camera, apparently on the Discovery Channel show Time Warp, but I can’t locate any web video of it.

Now, THAT is eating your own dogfood!

January 28, 2009

Macro Scheduler 11.1.02 Update

Filed under: Announcements — Marcus Tettmar @ 11:31 am

Macro Scheduler 11.1.02 Update is now available with the following fixes:

– Fixed: Access Violation when closing dialog editor if dialog has a MainMenu
– Fixed: Clicking “type a hotkey” checkbox in macro properties didn’t cause warning to save changes if nothing else changed
– Fixed: Compile Includes not including scripts specified with %SCRIPT_DIR% when compiled from Editor
– Fixed: Press End inside a SRT called End would fool the lexer into thinking the SRT ended at Press End
– Added: When typing SRT in editor, End is added automatically with SRT name.

Registered Downloads/Upgrades | Evaluation Downloads | New License Sales