June 1, 2017

Script Development Services

Filed under: Announcements,Scripting — Marcus Tettmar @ 6:35 am

Did you know that we offer script development services? If you’re pushed for time or need a helping hand we can usually be of assistance. We often help people who don’t have the time or resource to build the automation themselves, or just want to get a jump start.

What sort of things do we do? It’s pretty much anything that needs automating, but a common scenario is data entry – usually reading data from Excel and entering it into either a web form or desktop app.

Recently we’ve written a script for a government agency which searches through hundreds of files looking for patterns and attaching them to emails; We’ve written a data entry script for a large oil company which reads through Excel and outputs the data to a web form; Helped a hospital automate entry of patient referrals into a web based system. We’ve reformatted CSV files; scraped data from a website; extracted data from PDF and output to Excel; Extracted patient data from an online dental patient database; assisted with extracting reports from an ordering system; and more.

So you can see we do all kinds of things. We have been automating processes for 20 years. If you have a project you could use some help with give us a shout and we’ll see what we can do.

November 14, 2016

HTTP Request With Custom Headers using Python

Filed under: Scripting — Marcus Tettmar @ 10:16 am

As you will hopefully already know by now we added the ability to use Python code a while back in Macro Scheduler 14.2.

A customer recently had a need to retrieve some data from a web service which requires some custom authentication headers to be sent with the request.

It’s really easy to do this using Python. Here’s a made-up example:

/*
python_code:
 
import urllib2

custom_headers={"X-Custom-Application-Id" : "4020c4b37ead0a834c0010a9",
                "X-Custom-REST-API-Key": "49eade9c-d70a-4d3d-b552-4bd9f05966fc"}
url="https://api.custom.com/v1/objects/object_1/things"

request = urllib2.Request(url, headers=custom_headers)
contents = urllib2.urlopen(request).read()
*/
 
//Load the Python code to a variable
LabelToVar>python_code,pcode
 
//Run the code and request the value of the contents variable ...
PYExec>pcode,output,contents

//content of request is now in "contents" variable.

For more on Python in Macro Scheduler see here and here.

September 15, 2016

Finding Window Titles You Cannot See

Filed under: Automation,Scripting — Marcus Tettmar @ 11:33 am

Someone emailed today saying they were having problems trying to automate Internet Explorer 11 because it didn’t seem to have a window title.

Actually IE11 does have a window title. Each tab has a different window title. But you don’t see the title in the main title bar of the application.

By default applications show the window title in the title bar. Hence it’s name. But some apps manipulate the appearance of their title bar so that it doesn’t look like a regular Windows title bar. Indeed some apps have all borders removed so that you can’t SEE the title bar. But in all cases, the window will still have a title (unless it’s an empty string!).

So if you can’t see the window title, how do you find out what it is? Well, with Macro Scheduler there are several ways to find it. One is with the View System Windows Tool, which shows a list of all the windows currently available on the system, showing their captions and class names. Another is to use the Code Builders.

Here’s a video demonstrating these two methods. It also shows how I use a substring window match:

September 7, 2016

Toast Notification Window for your Scripts

Filed under: General,Scripting — Marcus Tettmar @ 10:52 am

Over in the forums dtaylor has posted a script library which allows you to show a small notification window in the lower right of your screen. Useful for reporting on progress during your script, in loops etc.

Grab it here.

August 17, 2016

OnEvent – Dealing with Indeterminate Dialogs – [Repost]

Filed under: Automation,Scripting — Marcus Tettmar @ 3:16 pm

This is a repost. The original article is here.

Most of the time when we are automating a process we are able to predict the sequence of events. We are working with a deterministic process and a linear flow of actions. But there are occasions when things can happen during a process that we cannot predict precisely. E.g.:

  • We might know that a dialog or window may appear sometime during the process, but we cannot predict exactly when that will happen.
  • We may have a situation where after entering some data into a text field a dialog may, or may not appear.
  • There might be some other software running on the PC which randomly pops up an error box. And we need a way to clear that when it happens.

There are a number of ways we can deal with such situations.

Window Event Schedules

If you have a situation where a known window can randomly appear – say a known error box – which always has the same window title, the simplest approach is to use the Window Event schedule in the Advanced Scheduling properties. Simply create a macro which closes the box – perhaps all it has to do is press enter – and specify the window title under Advanced Options in the macro properties. Then whenever Macro Scheduler sees this window it will run the macro and clear it.

Synchronous Coding

In the case where a window may, or may not appear after entering some data into a field, say a data validation dialog, we could just deal with this after sending the text, in regular fashion – something like:

Send>the_data
Wait>0.5
IfWindowOpen>Verification Alert
  Press Enter
Endif

So we simply send the data then IF the verification window appears, close it. But what if you have hundreds of data fields to enter? Dealing with each one would involve a lot of extra code.

OnEvent Window Event Handlers

Another way is to use the OnEvent function to create an event handler in your main script. There are three types of window events that can be monitored with OnEvent:

  • WINDOW_OPEN – monitors a specific known window title, or window title substring
  • WINDOW_NOTOPEN – fires the event handler when specified window closes
  • WINDOW_NEWACTIVE – fires the event handler when there’s a new foreground window

OnEvent is used to create an “event handler” which is just a subroutine which will be executed whenever the event occurs. So, for example, using OnEvent you can tell the script to run a subroutine whenever a specified window appears, whenever that may be, while the rest of the script is executing.

So let’s say we are working with an application which could, at any time, pop up a warning box titled “Connection Error”, and this can be cleared just by pressing enter to hit the default OK button:

OnEvent>WINDOW_OPEN,Connection Error,2,CloseWarning

..
.. rest of script here
..

SRT>CloseWarning
  Press Enter
End>CloseWarning

Of course there are a whole load of other things you can do. We may have a window whose title is always the same but the content differs and we need to react according to the content. In this case our event handler subroutine would have extra code in it to determine which type of dialog it is. We might do this using the text capture functions to read the text from the dialog, or using Screen Image Recognition to check for the presence of an object.

Maintaining Focus

Here’s an idea for an event handler which ensures the target application is always focused. If another application should steal focus at any point during the running of the script, it just grabs focus back again. It’s always good advice to use SetFocus before sending text. But if you have thousands of Send commands and want to slim down your script and make it more readable you could use this approach. Anyway, it’s just an example:

.. your code here to start and focus the app you want to automate, e.g.:
Run>Notepad.exe
WaitWindowOpen>Untitled - Notepad

//assuming the target window is now focused, get it's handle and process name
Let>WIN_USEHANDLE=1
GetActiveWindow>MyWindowHandle,x,y
GetWindowProcess>MyWindowHandle,pid,MyProcessName
Let>WIN_USEHANDLE=0

//now set up the event that is fired when a new window appears
OnEvent>WINDOW_NEWACTIVE,0,0,HandleNewWindow

..
..
.. rest of script here
..
..

//When a new window that does not belong to our process appears,
// set focus back to our window
SRT>HandleNewWindow
  Let>WIN_USEHANDLE=1
  GetActiveWindow>hwnd,x,y
  GetWindowProcess>hwnd,pid,winProcName
  If>winProcName<>MyProcessName
     SetFocus>MyWindowHandle
  Endif
  Let>WIN_USEHANDLE=0
End>HandleNewWindow

Note how this code gets the window handle and process name of your target window. Then whenever a new window appears the HandleNewWindow subroutine is fired which gets the process name of the active window. If the process name of the new active window is not the process name of your target window (i.e. the new window belongs to some other application) it sets focus back to your original window.

I hope this gives you a useful introduction to OnEvent event handlers and how they can be used to run code at any point during the script in response to events. OnEvent can also be used to detect files, dialog events, dialog changes and keyboard and mouse actions. For further information please see OnEvent in the help file.

August 5, 2016

Capture Screen Text using OCR

Filed under: Automation,General,Scripting — Marcus Tettmar @ 3:37 pm

Here’s a way to get screen text from any application – even from an image – using OCR and a free open source tool called Tesseract.

First, you need to download and install Tesseract. You can get it here.

Tesseract is a command line utility. The most basic syntax is:

tesseract.exe input_image_file output_text_file

So you could call it from a Macro Scheduler script something like this:

//Capture screen to bmp file - you could instead capture only a window or use FindObject to get coordinates of a specific object
GetScreenRes>X2,Y2
ScreenCapture>0,0,X2,Y2,%SCRIPT_DIR%\screen.bmp

//run tesseract on the screen grab and output to temporary file
Let>RP_WAIT=1
Let>RP_WINDOWMODE=0
Run>"C:\Program Files (x86)\Tesseract-OCR\tesseract.exe" "%SCRIPT_DIR%\screen.bmp" "%SCRIPT_DIR%\tmp"

//read temporary file into memory and delete it
ReadFile>%SCRIPT_DIR%\tmp.txt,theText
DeleteFile>%SCRIPT_DIR%\tmp.txt

//Display the text in a message box 
MessageModal>theText

This example simply captures the entire screen. You probably wouldn’t normally want to do this. Instead you could capture a specific window:

//Capture just the Notepad Window
SetFocus>Untitled - Notepad
GetWindowPos>Untitled - Notepad,X1,Y1
GetWindowSize>Untitled - Notepad,w,h
ScreenCapture>X1,Y1,{%X1%+%w%},{%Y1%+%h%},%SCRIPT_DIR%\screen.bmp

Or even a specific object:

//capture just the editor portion of notepad ... 
SetFocus>Untitled - Notepad
GetWindowHandle>Untitled - Notepad,hWndParent
FindObject>hWndParent,Edit,,1,hWnd,X1,Y1,X2,Y2,result
ScreenCapture>X1,Y1,X2,Y2,%SCRIPT_DIR%\screen.bmp

Either way you then have a screen bitmap you can pass into Tesseract.

Once you’ve retrieved the text you would probably want to parse it, using e.g. RegEx. Here’s an article on a RegEx expression useful for parsing out data.

August 4, 2016

How to Run an Access Macro from Macro Scheduler

Filed under: Automation,General,Scripting — Marcus Tettmar @ 4:57 pm

Recently someone asked in the forums how to “Automatically Detect MS Office Install Location” so that they could run an Access macro.

Well, there are ways to get the path of an installed Office application, but it isn’t necessary in order to run an Access macro. This is a rehash of my forum answer:

You can run an Access macro via the command line using the /x switch. The ExecuteFile command lets you pass parameters. So you could just do this:

ExecuteFile>%USERDOCUMENTS_DIR%\MyDb.accdb,/x Macro1

This will open the DB and run macro “Macro1”. Note my DB is in my documents folder here so I’m just using USERDOCUMENTRS_DIR but this could be any path.

Here’s a list of other command line switches.

For more control you could use VBScript:

VBSTART
  Sub RunMacro(accessfile,macroname)
    dim accessApp
    set accessApp = createObject("Access.Application")
    accessApp.OpenCurrentDataBase(accessfile)
    'comment next line out if you don't want access to be visible
    accessApp.visible = true
    accessApp.DoCmd.RunMacro macroname
    'you can run a subroutine or function in module code instead if you want:
    'accessApp.run "routinename"
    accessApp.Quit
    set accessApp = nothing
  End Sub
VBEND

VBRun>RunMacro,%USERDOCUMENTS_DIR%\MyDb.accdb,Macro1

This gives you more control – you could make it invisible, and as you can see you could run VBA code instead if you want – or access any of the other methods. Anything you can do inside Access you can do here – by converting VBA to VBScript:

http://help.mjtnet.com/article/19-converting-office-vba-to-vbscript

But if you do really want to get the path, how about querying the mime-type in the registry:

RegistryReadKey>HKEY_CLASSES_ROOT,ms-access\shell\open\command,,accPath
ExtractFilePath>accPath,accPath

Enjoy!

July 25, 2016

Relative Paths for Portable Macros – SCRIPT_DIR and BMP_DIR Explained [Recap]

Filed under: General,Scripting — Marcus Tettmar @ 2:19 pm

Are your macros reading from other files? Find out how to avoid hard coding file paths and use relative folders:

http://help.mjtnet.com/article/167-relative-paths-for-portable-macros-explaining-scriptdir-and-bmpdir

May 12, 2016

Customizing Message/Input Boxes

Filed under: General,Scripting — Marcus Tettmar @ 12:30 pm

Every now and then someone asks something like “How do I change the font in a modal dialog box?” or “Can I make an Input box multi-line?”.

Well, no, you can’t do those things to the standard Message/MessageModal or Input box functions. But, don’t forget that with Macro Scheduler you have the ability to create your own dialogs and make them act and feel pretty much any way you like. So the answer to the above questions, is “Create your own versions”.

As an example, let’s say you want a modal dialog that looks and acts much like the standard modal message box created by MessageModal. Only you want the text to be green in an italicized aerial font. Here you go:

//this would go at the top - customize as you wish
Dialog>CustomMsgBox
object CustomMsgBox: TForm
  Left = 493
  Top = 208
  HelpContext = 5000
  BorderIcons = [biSystemMenu]
  BorderStyle = bsSingle
  Caption = 'My Message'
  ClientHeight = 170
  ClientWidth = 319
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = True
  ShowHint = True
  OnTaskBar = False
  PixelsPerInch = 96
  TextHeight = 13
  object MSMemo1: tMSMemo
    Left = 0
    Top = 0
    Width = 321
    Height = 137
    Font.Charset = ANSI_CHARSET
    Font.Color = clGreen
    Font.Height = -11
    Font.Name = 'Arial'
    Font.Style = [fsBold, fsItalic]
    ParentFont = False
    TabOrder = 0
  end
  object MSButton1: tMSButton
    Left = 121
    Top = 143
    Width = 75
    Height = 25
    Caption = 'OK'
    DoubleBuffered = True
    ModalResult = 2
    ParentDoubleBuffered = False
    TabOrder = 1
    DoBrowse = False
    BrowseStyle = fbOpen
  end
end
EndDialog>CustomMsgBox

SRT>ShowMsg
  SetDialogProperty>CustomMsgBox,,Position,poScreenCenter
  SetDialogProperty>CustomMsgBox,MSMemo1,Text,ShowMsg_Var_1
  Show>CustomMsgBox,r
END>ShowMsg

//do this to call your message
Let>MyMsg=Hello world, this is a lovely custom message box
GoSub>ShowMsg,MyMsg

And don’t forget that once created you can call the dialog any time you like. And if you want to use it in lots of scripts then put the dialog block and subroutine into an include file and use Include> at the top of each script you want to use it in.

Now, it’s over to you. Use your imagination and style the dialog any way you like. We have some Custom Dialog tutorials here: Part1, Part2

December 10, 2015

Variable Breakpoints

Filed under: Scripting — Marcus Tettmar @ 2:02 pm

You may already be familiar with the Macro Scheduler debugger and know how to set code breakpoints. But did you know you can set variable breakpoints too? With a variable breakpoint you can cause execution to pause when a specified variable becomes equal to a given value.

You will find the “Variable Breakpoints” option under the “Debug” menu in the code editor.

You can set one or more variables and values. Then at any point during execution when one of those conditions occurs the macro will pause and allow you to debug.

This can be very useful when you are not sure where an issue is occurring but you may know that a specific set of data causes a problem that you want to debug.

« Newer PostsOlder Posts »