October 3, 2012

Sending/Retrieving Emails via Gmail

Filed under: Automation,Scripting — Marcus Tettmar @ 9:36 pm

Since version 13.2 Macro Scheduler‘s email functions now support SSL. Google’s Gmail and many other email services now insist on SSL secured connections.

To use SSL you first need to install the OpenSSL library files.

Here’s an example of sending an email via Gmail:

Let>SMTP_AUTH=1
Let>[email protected]
Let>SMTP_PASSWORD=your_password
Let>SMTP_PORT=465
Let>SMTP_SSL=1
SMTPSendMail>[email protected],smtp.gmail.com,[email protected],your name,test,hello world,

And to retrieve emails from Gmail via POP3 (make sure you have enabled this in your gmail settings):

Let>POP3_PORT=995
Let>POP3_SSL=1
RetrievePOP3>pop.gmail.com,[email protected],your_password,c:\emails\in\

May 18, 2012

How to do an HTTPS Request Without Installing all of OpenSSL

Filed under: Automation,Scripting — Marcus Tettmar @ 9:52 am

I recently wrote a small macro for a customer which does an HTTPRequest via SSL. This requires that OpenSSL is installed. But the customer wanted to know if there was any way of distributing the macro to his users without having to install OpenSSL on all their PCs.

Thanks to our wonderful forums one of our users has already figured out how to do this and it turns out only 2 DLLs are required and can be placed in either the Macro Scheduler program folder, or, in the case of a compiled macro, the exe’s folder.

Adroege says:

I use this solution:

Download the “binaries” from this page as a zip file
http://gnuwin32.sourceforge.net/packages/openssl.htm

Unzip the contents

find the files libeay32.dll (version 0.9.8.8) and libssl32.dll
(version 0.9.8.8) in the Bin folder

Make a copy of libssl32.dll and call it “ssleay32.dll”

Now just deliver all 3 DLL files in the same folder as the
compiled Macro Scheduler EXE
(libeay32.dll libssl32.dll ssleay32.dll)

Using this method, I didn’t have to do any special SSL “install”,
run regsvr32.exe, or do any registry hacks. It just works.

And rullbandspelare responds:

It appears to work with just putting
ssleay32.dll and libeay32.dll in the same folder.

Even I learn stuff from our forums, or at least find answers more quickly. A great resource. Thanks guys.

March 27, 2012

Sending Keys to Invisible or Unfocused Windows

Filed under: Automation,Scripting — Marcus Tettmar @ 2:32 pm

Can you send keystrokes to invisible or unfocused windows? The answer is yes, if the control you want to send the keystrokes into is a “windowed control”. That is, one that has a handle.

If that’s too technical just try using the “Send Keys to Object Wizard” in Macro Scheduler 13 which generates code that uses the ObjectSendKeys function. Or Watch the video to see it in action.

If the wizard is able to identify the control the code that it generates will work even if the window is not visible or not focused. This is because it works by sending the keyboard codes directly to the specified control.

In contrast the regular Send command sends characters into the global input buffer. In other words it sends keystrokes into whatever happens to have the focus at the time. The great thing about this is that it means it can send keystrokes to ANY thing regardless of whether it is a windowed control or not and regardless of the technology. But the control does need to be focused.

So if your control has a handle then you can use ObjectSendKeys to send keystrokes to it and avoid it having to be focused. This also means it will work even if the window is minimized, or hidden. This could be turned to your advantage if you wanted to manipulate a window and be able to do something else at the same time. Of course this assumes that all the controls have a handle which is not always the case.

As an example, run this script. Notepad will open, then be minimized and then text will be sent into it. When the script has finished restore Notepad and you should see the text inside it.

Run>Notepad.exe
WaitWindowOpen>Untitled - Notepad
WindowAction>2,Untitled - Notepad

GetWindowHandle>Untitled - Notepad,hWndParent
FindObject>hWndParent,Edit,,1,hWnd,X1,Y1,X2,Y2,result
ObjectSendKeys>hWnd,{"Hello World"}

January 24, 2012

WebRecorder 3.0 – Faster, More Reliable, More Functions

Filed under: Automation,Web/Tech — Marcus Tettmar @ 11:04 pm

We have today released WebRecorder 3.0.

WebRecorder 3.0 - Faster more reliable internet macros

This is a major rewrite with a better recording engine capable of recording more tags and producing leaner, cleaner, code and a faster and more reliable runtime.

It also introduces a download manager so that file downloads can be recorded and scripted more easily without recourse to sending keystrokes to IE’s standard file download box.

We’ve improved the existing commands so that you can script more tags and use more attributes and added new functions for retrieving data, retrieving the screen position of elements and interfacing with the new native IE functions in Macro Scheduler 13.1.

Oh, and you no longer need to use the mouse to record clicks and form fills!

  • Cleaner, leaner, faster code.
  • More reliable method for waiting for documents to complete loading
  • Download manager for scripting file downloads
  • Better error trapping
  • Ability to set timeout for Clicks and Form Fills etc
  • Click and Form fill functions will wait until target tags exist (within timeout)
  • New functions for extracting data
  • New function to get X,Y screen position of elements
  • No need to use the mouse to identify recorded elements
  • New, improved UI look and feel
  • Runtime component integrates better with Macro Scheduler’s script controller (faster termination, less liable to hang ups when aborting scripts etc)
  • Interface easily with Macro Scheduler’s IEGetTags and IETagEvent function
  • New script function for waiting for text in the page before continuing
  • Functions to automatically set extracted tag buffer size and avoid buffer overruns

More information on WebRecorder here.  WebRecorder 3.0 scripts require Macro Scheduler 13.1 to run.

Enterprise customers with in-date maintenance can already download WebRecorder 3.0 from the registered download area.

Other customers can view upgrade options in their registered download account, or download a trial version here.

Trial Downloads | Registered Downloads | Upgrades

May 20, 2011

Scraping Data From Web Pages

Filed under: Automation,Scripting,Web/Tech — Marcus Tettmar @ 1:02 pm

I’ve seen quite a lot of requests lately from people wanting to know how to extract text from web pages.

Macro Scheduler’s optional WebRecorder add-on simplifies the automation of web pages and includes functions for extracting tables, text or HTML from web page elements. WebRecorder’s Tag Extraction wizard makes it easy to create the code.

Sometimes you can choose a specific HTML element and identify it uniquely via it’s ID or NAME attribute. But other times you might want all the text from the whole page, or you may need to extract the entire page and then parse out the bits you’re interested in using RegEx or some other string manipulation functions.

To extract an entire page I specify the BODY element. If you want to extract data from web pages it does help if you know a little about HTML. And if you do you’ll know that each page has just one BODY element which contains the code making up the visible portion of the page.

Here’s code produced using WebRecorder when navigating to mjtnet.com and using the Tag Extraction wizard to extract the BODY text:

IE_Create>0,IE[0]

IE_Navigate>%IE[0]%,http://www.mjtnet.com/,r
IE_Wait>%IE[0]%,r
Wait>delay

//Modify buffer size if required (you may get a crash if buffer size too small for data) ...
Let>BODY0_SIZE=9999
IE_ExtractTag>%IE[0]%,,BODY,0,0,BODY0,r
MidStr>r_6,1,r,BODY0

MessageModal>BODY0

The macro simply displays just the text in a message box but could be set to pull out the full HTML. You could then parse it with RegEx to get the information you are interested in.

You will need WebRecorder installed for the above to work.

If you don’t have WebRecorder you can do the same with a bit more work using VBScript. Some library functions for doing this can be found here and here.

So here’s the equivalent in VBScript:

VBSTART
Dim IE

'Creates IE instance
Sub CreateIE
  Set IE = CreateObject("InternetExplorer.Application")
  IE.Visible=1
End Sub

'Navigate to an IE instance
Sub Navigate(URL)
  IE.Navigate URL
  do while IE.Busy
  loop
End Sub

'This function extracts text from a specific tag by name and index
'e.g. TABLE,0 (1st Table element) or P,1 (2nd Paragraph element)
'set all to 1 to extract all HTML, 0 for only inside text without HTML
Function ExtractTag(TagName,Num,all)
  dim t
  set t = IE.document.getElementsbyTagname(Tagname)
  if all=1 then
    ExtractTag = t.Item(Num).outerHTML
  else
    ExtractTag = t.Item(Num).innerText
  end if
End Function
VBEND

VBRun>CreateIE
VBRun>Navigate,www.mjtnet.com

VBEval>ExtractTag("BODY",0,0),BodyText
MessageModal>BodyText

But what if you already have a macro which already opens IE, or works against an already open instance of IE? The above macros need to create the IE instance before they can access them and extract data from them. You may have a macro that already starts IE some other way – maybe just by using a RunProgram or ExecuteFile call, or indirectly via some other application. Many times people tackle the extraction of data from such an IE window by sending keystrokes to do a Select-All, Edit/Copy and then use GetClipboard; or even File/Save As to save the HTML to a file. This of course adds time and can be unreliable. So how else can we do it?

Well, this tip shows us a function we can use to attach to an existing IE instance. So let’s use that and then use our ExtractTag function to pull out the BODY HTML:

VBSTART
Dim IE

' Attaches to an already running IE instance with given URL
Sub GetIE(URL)
  Dim objInstances, objIE
  Set objInstances = CreateObject("Shell.Application").windows
  If objInstances.Count > 0 Then '/// make sure we have instances open.
    For Each objIE In objInstances
      If InStr(objIE.LocationURL,URL) > 0 then
        Set IE = objIE
      End if
    Next
  End if
End Sub

'This function extracts text from a specific tag by name and index
'e.g. TABLE,0 (1st Table element) or P,1 (2nd Paragraph element)
'set all to 1 to extract all HTML, 0 for only inside text without HTML
Function ExtractTag(TagName,Num,all)
  dim t
  set t = IE.document.getElementsbyTagname(Tagname)
  if all=1 then
    ExtractTag = t.Item(Num).outerHTML
  else
    ExtractTag = t.Item(Num).innerText
  end if
End Function
VBEND

VBRun>GetIE,www.mjtnet.com

VBEval>ExtractTag("BODY",0,1),BodyHTML
MessageModal>BodyHTML

This snippet assumes a copy of IE is already open and pointing to www.mjtnet.com. The GetIE call creates a link to that IE window and then we use the ExtractTag function to pull out the HTML of the BODY element.

These examples use the BODY element, which will contain everything displayed on the page. As I mentioned before you can be more specific and specify some other element, and with WebRecorder, or a modified version of the ExtractTag VBScript function use other attributes to identify the element (the existing VBScript ExtractTag function shown above just uses the numeric index). WebRecorder tries to make it simple by giving you a point and click wizard, making some assumptions for you, so that you need not fully understand the HTML of the page. But it still helps you understand HTML. Looking at the source of the page you should be able to identify the element you need to extract from. And whether you extract directly from that or extract the BODY and then use RegEx being prepared to delve into the HTML source is going to get you further.

UPDATE: 19th January 2012

As of version 13.0.06 Macro Scheduler now includes a function called IEGetTags. For a given tag type and IE tab this will retrieve an array of tag contents. It can extract just the text, or html of the tags. This example extracts the inner HTML of all DIV elements in the open IE document currently at www.mjtnet.com:

IEGetTags>mjtnet.com,DIV,H,divArr

You can then cycle through each one with a Repeat Until

If>divArr_count>0
  Let>k=0
  Repeat>k
    Let>k=k+1
    Let>this_div_html=divArr_%k%
    .. 
    .. do something with it
    .. e.g. use RegEx or substring searching to determine 
    .. if this is the DIV you want and extract from it
    .. 
  Until>k=divArr_count
Endif

To further identify the tag you are interested in, or find the data you want, you can use RegEx, EasyPatterns, or string functions.

Macro Scheduler 13.0.06 and above also has a function called IETagEvent which will let you simulate a Click on a given tag, focus it, or modify its value. So once you have identified a tag using IEGetTags and your Repeat/Until loop you can click on it, focus it or modify its value (e.g. for form fields).

February 23, 2011

New Video: Using The Debugger

Filed under: Announcements,Automation,Scripting — Marcus Tettmar @ 9:44 am

Macro Scheduler veteran John Brozycki has put together this fantastic video tutorial all about Macro Scheduler’s debugging capabilities. The video is 18 minutes long and demonstrates every debug feature, showing examples of their use and talks about how useful the debugger can be for problem resolution as well as script creation. Take a look:

A larger version of the video can be found here.

John Brozycki is an information security professional who uses Macro Scheduler as a tool to accomplish a wide range of tasks in his daily activities. His personal web site is www.trueinsecurity.com.

I think this is an excellent tutorial which all script developers should benefit from. Thanks John!

December 15, 2010

Mixing the Native Excel Functions with VBScript

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

Macro Scheduler comes complete with some native functions for controlling Excel, such as XLOpen, XLGetCell, XLSetCell and others. Obviously, although we intend to add more functions over time, not every possible Excel function has been duplicated. So sometimes you may want to utilise COM via VBScript which allows you to access the entire Excel API. There are plenty of examples of this here in the blog and on the forums.

But what if you want to use a combination of both? You might already have a script which uses the native XL functions to open a sheet and get or set some data. Let’s say you now want to augment this with an Excel method which is not exposed by the native functions. Rather than re-writing your entire script to use VBScript, is there a way we can let VBScript take over?

While it’s not possible to share native XL references with VBScript object references, what we can do is have VBScript attach to an open instance of Excel using the GetObject function. So sometime after running XLOpen we could then run a VBScript function which does a GetObject to get an object reference to Excel and then after that we are able to utlise any Excel function we like via VBScript.

The following script demonstrates:

VBSTART
  Dim xlApp
  Dim xlBook
  Sub GetXL
    Set xlApp = GetObject(,"Excel.Application")
    Set xlBook = xlApp.ActiveWorkbook
  End Sub

  Function FindCell(Sheet,Data)
    Dim theCell
    Dim xlValues
    xlValues = -4163

    Dim xlSheet
    Set xlSheet = xlBook.Worksheets(Sheet)
    xlSheet.Range("A1").Select
    Set theCell = xlSheet.Cells.Find(Data, xlApp.ActiveCell, xlValues)
    FindCell = CStr(theCell.Row) & ":" & CStr(theCell.Column)
  End Function
VBEND

//Open an XLS file natively
XLOpen>%SCRIPT_DIR%\example.xls,1,xlH

//Call GetXL to give VBScript a reference to the XL instance
VBRun>GetXL

//now we can access any XL function via VBScript
VBEval>FindCell("Sheet1","Price"),res

The only thing to be careful of is that there are no existing copies of Excel open before the one opened by XLOpen because according to the Microsoft docs GetObject will attach to the first opened instance. You could of course make the script check for this.

December 2, 2010

Video Tutorial – Macro Scheduler for Non-Technical Beginners – Part 2

Filed under: Announcements,Automation,Tutorials — Marcus Tettmar @ 9:59 am

Another contribution from Peter Begelsdorf which takes off from where his last video left off. Aimed at complete beginners this video demonstrates how to execute a file and wait for it to be ready before sending text and keystrokes to it.

Part 1 of this sequence and other videos can be found on the Video Tutorials Page.

This video is a result of my recent offer for free licenses and updates in exchange for video tutorial contributions. If you want to have a go at creating a tutorial please let me know.

November 3, 2010

Is a File Ready? Waiting for a File Process to Complete.

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

In the comments to my last post Richard asked how we can wait for a process to finish updating a file.

In my reply to Richard I point out that most of the time we can use a visual cue. Where possible this is the approach I would use. Usually an application would present some kind of visual cue when the file operation finishes. A dialog box might appear, or disappear, an object may become enabled or disabled, some text may appear on the screen, etc. We might be able to use commands such as WaitWindowOpen, WaitWindowClosed, WaitWindowChanged, WaitScreenText, WaitScreenImage, WaitCursorChanged, WaitPixelColor, or WaitRectChanged. Or we might even create our own wait loop which checks for some value or property. I mention this approach in Top Tips for Reliable Macros.

Unfortunately there are sometimes scenarios where there is no visual cue and we have nothing we can “see” which tells us the file operation has completed.

If the file is locked by the application that is writing to it, we could create a wait loop which checks to see if the file is still locked or not.

How might we achieve that? Well, why not just try to read from the file. If the file is locked we’re not going to be able to read it right? So we could just do:

Label>wait_file
ReadLn>file,1,res
Pos>##ERR##,res,1,pErr
If>pErr>0
  Wait>0.2
  Goto>wait_file
Endif

This will work for any kind of file.

Of course this assumes that the file is locked for reading by other processes.

It’s possible that the application locks the file only for writing. In that situation we could use WriteLn to attempt to write an empty string to the file:

Let>WLN_NOCRLF=1
Label>wait_file
WriteLn>file,res,{""}
If>RES<>0
  Wait>0.2
  Goto>wait_file
Endif

But that’s a bit invasive in the instance that the file IS available as although we’re writing nothing, we’re still modifying it so updating it’s timestamp.

We can get a bit more control over this with VBScript where we can attempt to open a file for appending without actually modifying it:

VBSTART
Function TestFile(filename)
   Set oFSO = CreateObject("Scripting.FileSystemObject") 
   On Error Resume Next 
   Set f = oFSO.OpenTextFile(filename, 8, True)
   TestFile = Err.Number 
End Function
VBEND

Let>file=C:\files\bmp.bmp

Label>wait_file
VBEval>TestFile("%file%"),fRes
If>fRes<>0
  Wait>0.2
  Goto>wait_file
Endif

All the TestFile function does is try to open the file for appending, and if an error occurs it returns the error code. So if we get zero back, there’s no error and the file must be available for writing and therefore not locked.

Don’t be put off by the fact that this uses the OpenTextFile method. It will still work with any kind of file. We’re not actually going to attempt to modify it. We’re just trying to see if we can open it. So the file type is unimportant.

Note that in these samples I haven’t checked for any specific error code nor have I checked for the existence of the file first – I’m assuming any error means the file isn’t available. An error will also be returned if the file does not exist, so you’d probably want to use IfFileExists first. You might even want to put FileExists in a loop so that you can wait until it exists.

Note also the small wait in each loop. This is just to make sure the loop isn’t so tight that it hogs CPU. Better to be nice to the system and give other processes a chance to breathe.

November 2, 2010

Waiting for the Clipboard

Filed under: Automation,Scripting — Marcus Tettmar @ 2:58 pm

Today I was helping someone who was wanting to write a script to take screen-shots from one application and then paste those screen-shots into Microsoft Excel.

Initially things weren’t working reliably because the script didn’t factor in the time taken for the large bitmap of a screen-shot to exist in the clipboard after pressing the print screen button, before attempting to paste into Excel. E.g. consider:

Press Print Screen
SetFocus>Microsoft - Excel*
Press CTRL
Send>v
Release CTRL

The above is probably going to fail most of the time because a screen shot is a large bitmap and is going to take some time to arrive on the clipboard, but the script above performs a paste in Excel immediately after pressing print screen. The print screen key being depressed and the clipboard containing the bitmap are not the same thing.

While we could have just said “wait 5 seconds” and that would probably have been fine for evermore, it isn’t very sensitive and wouldn’t be ideal for a script that needs to run as fast as possible. Ideally we only want to wait until we know the bitmap is in the clipboard.

Text is usually smaller than a bitmap, but for large text items one way to make things bulletproof is to do something like this:

PutClipBoard>dummy

SetFocus>source_app_title
Press CTRL
Send>c
Release CTRL

Label>wait_for_data
Wait>0.2
GetClipBoard>clipdata
If>clipdata=dummy
  Goto>wait_for_data
Endif

By putting a known value onto the clipboard in the first place we can then have a little loop which keeps checking the clipboard until the returned value is not our known value. We then know our CTRL-V has worked and that we can safely paste to the target application.

But how can we do the same thing when the clipboard data is an image? The above won’t work because GetClipBoard won’t return anything for non-textual data.

Well, Windows has a function called IsClipboardFormatAvailable which will allow us to determine what kind of data is on the clipboard. So we could use this in a similar way to above to see if the clipboard contains a bitmap or not. Like this:

Let>CF_BITMAP=2

Let>haveBMP=0
PutClipBoard>dummy

Press Print Screen

While>haveBMP=0
  LibFunc>user32,IsClipboardFormatAvailable,haveBMP,CF_BITMAP
  Wait>0.2
EndWhile

We could then paste it somewhere:

SetFocus>Document - WordPad
Press CTRL
Send>v
Release CTRL

It’s always nice to wait only as long as we have to and it makes the script more reliable and portable.

« Newer PostsOlder Posts »