Marcus' Macro Blog

Mostly tips, tutorials, articles and news about Macro Scheduler & Windows Automation
July 2nd, 2009 by Marcus Tettmar

A project I’m currently working on involves populating data into a rather poorly designed user interface.  A particular challenge were the drop down lists and list boxes due to the fact that you can’t “drill down” by sending the text of the item you want selected.

The solution we settled upon uses the text capture function GetTextAtPoint in a loop which arrows down the entire list, with GetTextAtPoint capturing the text in the selection box to see if it’s the value required.  If it is we stop, else we continue to press down and loop.  We stop if the item selected is the same as the previous item, signifying that we’ve reached the end (obviously this assumes the list doesn’t have duplicates appearing together).

Here’s the subroutine:

SRT>dropDownSelect
/*****
Usage: GoSub>dropDownSelect,X,Y,text_to_select

Where X and Y are coordinates in the edit box (where the item appears once selected)
 and text_to_select is the text you want selected  

Important: the drop down needs to have the focus
*****/
  If>dropDownSelect_Var_3<>
    GetTextReset
    Press Home
    Wait>0.1
    Let>prev_comboText=Z@$%#XXX
    Let>dropDownFound=FALSE
    Label>select_drop
    GetTextAtPoint>dropDownSelect_Var_1,dropDownSelect_Var_2,comboText,c
    Pos>dropDownSelect_Var_3,comboText,1,p
    If>p<>1
      If>prev_comboText<>comboText
        Press Down
        Wait>0.2
        Let>prev_comboText=comboText
        Goto>select_drop
      Endif
    Else
      Let>dropDownFound=TRUE
    Endif
  Endif
END>dropDownSelect

So, for example, you could call it something like:

Press Tab
GoSub>dropDownSelect,240,355,Apples

Note that the drop down needs to be focused. Usually you’d be “tabbing” through fields on the form, so once you’ve used “Press Tab” to get focus onto the control you can call dropDownSelect.

This version requires that you pass the X,Y screen position of the text box area of the drop down. In development at the moment we have a new function which returns the handle of the currently focused object, and this can then be used in GetWindowPos to get the X,Y position. So in future you will be able to determine the X,Y position dynamically.

Hopefully you won’t need this function as you can usually “drill down” on a list box or drop down list by sending the text of the item you want as mentioned here. But for those badly designed controls that won’t allow that this function can be a life saver.

[Post to Twitter] Tweet This

June 29th, 2009 by Marcus Tettmar

Macro Scheduler 11.1.12 is now available with the following changes:

  • Fixed: FTPGetDirList issue with format of directory list and wildcard matching with some flavours of FTP server
  • Fixed: Issue with ExportData adding extra erroneous character to end of exported text files
  • Fixed: FindImagePos using SCREEN for haystack fails under Remote Desktop/Terminal Server session

Registered Downloads/UpgradesEvaluation DownloadsNew License Sales

[Post to Twitter] Tweet This

June 26th, 2009 by Marcus Tettmar

Apologies for the quietness on my blog lately.  This month has been a busy one for me personally as on 13th June I - finally - married my partner of 6 years (and the mother of my children), Angela, and went away for a short, but very relaxing, honeymoon last weekend.

We at MJT have also been busy working on some client projects, so it has been a bit of a manic month all round and I didn’t manage to get a newsletter out for June.   But I plan to put one together for next week.  We should also have a Macro Scheduler maintenance release out soon, and have also started on some new video tutorials.  So watch this space!

[Post to Twitter] Tweet This

June 8th, 2009 by Marcus Tettmar

Macro Scheduler 11.1.11 is now available with the following changes:

  • Fixed: Some issues with running macros via msNet (Remote Controller) component (Enterprise)
  • Fixed: Image Capture Tool incorrectly focusing main window after capture when run in standalone editor mode
  • Improvement: StringReplace speed improvements

Registered Downloads/Upgrades | Evaluation Downloads | New License Sales

[Post to Twitter] Tweet This

June 4th, 2009 by Marcus Tettmar

I’m often asked how you can run Macro Scheduler macros from other programming languages, particularly VB.  

Macro Scheduler scripts can be run from the command line.  See the help file topic “Command Line Options”.  E.g.:

msched.exe “c:\someplace\mymacro.scp”

VB/VBA lets you execute external commands/applications via the Shell function:

Shell “”"c:\program files\macro scheduler 11\msched.exe”" “”c:\scripts\example.scp”"”, vbNormalFocus

The only problem with the Shell function is that it does not wait until what it is calling has finished running before continuing.  So it fires off the macro and the program continues.  In most cases you’d want to wait for the script to finish before you continue.  To do this you can use the following ShellAndWait function:

    Private Declare Sub Sleep Lib "kernel32" ( _
        ByVal dwMilliseconds As Long)
    Private Declare Function GetExitCodeProcess Lib "kernel32" ( _
        ByVal hProcess As Long, ByVal lpExitCode As Long) As Long
    Private Declare Function timeGetTime Lib "winmm.dll" () As Long
    Private Declare Function OpenProcess Lib "kernel32" ( _
        ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
    Private Const STILL_ACTIVE = &H103
    Private Const PROCESS_QUERY_INFORMATION = &H400
    Private Declare Function CloseHandle Lib "kernel32" ( _
        ByVal hObject As Long) As Long

    Public Function ShellAndWait( _
     ByVal sShell As String, _
            Optional ByVal eWindowStyle As Integer = vbNormalFocus, _
            Optional ByRef sError As String = "", _
            Optional ByVal lTimeOut As Long = 2000000000 _
        ) As Boolean
        Dim hProcess As Long
        Dim lR As Long
        Dim lTimeStart As Long
        Dim bSuccess As Boolean

        On Error GoTo ShellAndWaitError

        ' This is v2 which is somewhat more reliable:
        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, Shell(sShell, eWindowStyle))
        If (hProcess = 0) Then
            sError = "This program could not determine whether the process started." & _
                 "Please watch the program and check it completes."
            ' Only fail if there is an error - this can happen
            ' when the program completes too quickly.
        Else
            bSuccess = True
            lTimeStart = timeGetTime()
            Do
                ' Get the status of the process
                GetExitCodeProcess(hProcess, lR)
                ' Sleep during wait to ensure the other process gets
                ' processor slice:
DoEvents:       Sleep(100)
                If (timeGetTime() - lTimeStart > lTimeOut) Then
                    ' Too long!
                    sError = "The process has timed out."
                    lR = 0
                    bSuccess = False
                End If
            Loop While lR = STILL_ACTIVE
        End If
        ShellAndWait = bSuccess

        Exit Function

ShellAndWaitError:
        sError = Err.Description
        Exit Function
    End Function

So your code becomes:

ShellAndWait “”"c:\program files\macro scheduler 11\msched.exe”" “”c:\scripts\example.scp”"”, vbNormalFocus

If you have Macro Scheduler Pro you can compile the script to an EXE and then just execute the exe, making the command line simpler:

ShellAndWait “c:\someplace\mymacro.exe”, vbNormalFocus

The above code is based on the code found here.

[Post to Twitter] Tweet This

June 3rd, 2009 by Marcus Tettmar

I just posted a script to the Scripts ‘n Tips forum with a function to perform an HTTP file upload.

[Post to Twitter] Tweet This

June 3rd, 2009 by Marcus Tettmar

This month a fancy MJT Net logo T-Shirt goes to Rain for receiving 10 forum reputation points in May.  Thanks, Rain, for your valuable contributions on the forums and for continuing to help others out.  

Don’t forget that each month I send T-Shirts to the people receiving the most reputation points in the previous month.  So if you’re not already active in the forums, get stuck in - you could win a T-Shirt.

[Post to Twitter] Tweet This

June 3rd, 2009 by Marcus Tettmar

Some pre-sales questions we get seem to suggest that the user lacks basic Windows skills.  What surprises me is that these questions are often from people working in company IT departments.  Their ability to comprehend how to automate something appears to be diminished by their inability to use a PC effectively.  Perhaps I’m being unfair - I guess it’s easy to forget that there’s another way to do something.

For example.  We might get asked:

“How do I make my macro click on a desktop shortcut if I don’t know where that desktop shortcut is going to be, and I want the macro to work on any PC where the desktop shortcut could be in different places?”.  

Think about it for a second. The answer is that you do NOT click on the desktop shortcut.  Why would you?  The clue is in the name - a shortcut is .. a shortcut to something.  Why would you record or write a macro that clicks on an icon when the macro simply needs to run whatever the shortcut runs?  Right click on the shortcut to show its properties and look at what the shortcut executes.  Copy that into your script and have the Run or ExecuteFile command run it.

As I said in Top Tips for Reliable Macros: Don’t automate mouse clicks or keystrokes just to start an application!

Now, even if you did want to select a desktop shortcut, there’s still another way to do it without needing to know or care where it is.  Just type it.  If you focus the desktop and type the name of a desktop shortcut on the keyboard it will get selected.  This is what I call “drill down” and it works on most lists.  So your macro could just send the text of the item.

When we get asked questions like this I’m always a little surprised.  I would have expected someone in an IT department to know what a desktop shortcut is and also to know that you can control Windows via the keyboard.

Of course, if you really, really want to create a macro that double clicks on a shortcut using the mouse and want it to find its position you can do that with image recognition.  In some applications, like the one I wrote about yesterday, that is the only way to go.  But it’s overkill if you just want to start an application, or run a file.

See also: Keyboard Shortcuts; Top Tips for Reliable Macros

[Post to Twitter] Tweet This

June 1st, 2009 by Marcus Tettmar

I’ve just finished writing a routine for a customer that automates what I can only describe as a truly horrendous user interface.  I’m not sure who designed it or why they designed it the way they did but I feel sorry for people who have to use this software.  And apparently it is the industry leading software in its niche.

The software is devoid of keyboard shortcuts and there are no menu items. The only way around the software is by clicking the mouse on icons which have no way at all of gaining keyboard focus - no keyboard short cuts and you cannot even Tab to them.

The main data entry screen has a few accelerator keys (shown by an underlined character) dotted around but they are duplicated and don’t seem to work anyway!  So on one screen ALT-S would appear to focus three different fields, but in fact focuses none.

Once logged into the system it would seem the only way back to the main menu is to exit the app and restart it.

The only way to add a customer record is first to search for one.

And this is just the start of it.  

Luckily Macro Scheduler gives us image recognition and screen scraping abilities so even this dreadful user interface can be automated.  We did it.  But I had to spare a thought for the people who use this software every day.  Everything takes twice as long to do as it needs to.  It can’t be fun. It also suggests that the UI wasn’t tested and no consideration was made to its accessibility.

As I said in Why it’s Good to Automate:

Build an application with good keyboard support and your application can be automated more easily. If it can be automated easily it will be easy to use!

Sure there are some types of software where only an image based approach makes sense. But this particular app is just a way to view and manage customer information.

Sorry for the rant. But it just helps to demonstrate how a decent UI can be more easily automated. While we have tools such as image recognition and screen text capture that will help us automate cumbersome interfaces, a well designed UI can be automated more quickly and more efficiently. It also shows how automation can help test an application and ensure it is accessible. If a UI is well designed the UI can be tested, and looking at it the other way around, if the app can’t be automated easily then perhaps the UI is hard to use, especially for people who cannot use a mouse, or rely on screen readers.

[Post to Twitter] Tweet This

May 19th, 2009 by Marcus Tettmar

If you’re not using more than one monitor, you are missing out big time.  For one thing, some research by the University of Utah found that using two monitors increases productivity 44%.  There’s a good summary and more comment on this on the coding horror blog.

A huge benefit of multiple monitors for Macro Scheduler developers is that it makes developing and debugging automation macros a lot easier.  When I’m building a script that controls another application I will often put the Macro Scheduler editor on one monitor and the application I’m automating on another.  I can then see both side by side, so I don’t need to switch focus back and forth.  I can run my macro as I’m developing it and see the script at the same time as the results.  If I need to debug I can step through the script and see the progress of the script at the same time as the outcome without the changing of focus effecting it.

Debugging a script that simulates a user and needs to change focus can be a bit of a conundrum, since the act of debugging introduces delays, allowing more time for events to complete, and causes loss of focus.  In Macro Scheduler there’s a “Refocus Windows” setting in the Debugger, but even that isn’t enough in some cases.  Being able to work on the macro and see the target application at the same time without either interfering with each other is therefore the best solution.  

If you don’t have a PC or video adaptor that can support more than one monitor you could use ZoneScreen along with a laptop or second PC to act as your second screen.  A single monitor big enough to let you put the editor and target apps side by side without them overlapping would work too.

If you’re stuck with a small monitor and simply can’t have both editor and target application visible at the same time - you may be at a client’s site or working on a notebook - and need to debug code that needs to see the screen, don’t forget you can also set and run to breakpoints.  With a breakpoint you can step through the code and at any time run to the next breakpoint, allowing the macro to whizz through the code to that point without switching focus back to the editor between each step.  So for crucial sections of code which need to, say, capture a screen or scrape some text, it can be very useful.  Once the script reaches the breakpoint you will be returned to the editor where you can continue stepping line by line, or run to the next breakpoint or end.

In my opinion multiple monitors are an absolute must.  But there are limits!

[Post to Twitter] Tweet This