May 25, 2010

Tweetlib: A DLL Plugin for Tweeting Status Updates via oAuth

Filed under: Announcements,Automation,Scripting,Web/Tech — Marcus Tettmar @ 4:23 pm

As noted yesterday I have been waiting on Twitter to provide xAuth access. They declined, saying it was not appropriate. I’m not really sure why.

No matter, I decided to make a small DLL to simplify Tweeting from Macro Scheduler. It uses the full oAuth interface.

Implementing oAuth in Macro Scheduler code would require lots of VBScript code and would be very complicated (although doable in theory). So instead I decided to create a DLL which you can use in Macro Scheduler to tweet in one line of code.

You can download it here.

And then to post a status update all you need to do is something like this:

Let>message=Hello from Macro Scheduler
LibFunc>%SCRIPT_DIR%\tweetlib.dll,UpdateStatus,r,message,buff,1024

Note that the first time you call UpdateStatus you will be asked to log into Twitter and click “Allow” to authorise Macro Scheduler to access your account. You will then be given a PIN to enter. You only need to do this once. If you ever need to revoke access and start over call the RemoveCredentials function. Your Twitter username and password are NOT stored anywhere. This uses the oAuth authorisation scheme which provides an access token. It is the access token which is stored and this only allows Macro Scheduler to access the API for your account.

The return buffer will contain the XML of the status update operation if successful or an error message if not.

See readme.txt and sample .scp in the zip file. Enjoy.

May 24, 2010

Tweeting from Macro Scheduler Without the API

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

A while back I posted an article showing how to Tweet via Twitter‘s API. It uses basic authentication which Twitter plan to turn off in the near future. The alternative, oAuth is awkward for desktop based apps, but xAuth is now available and should be doable in Macro Scheduler. I have requested xAuth access from Twitter and, assuming it’s doable, will try and provide an example once I’ve received it and tried it out.

In the mean time it occurred to me that we don’t really need an API if all we want to do is send a status update. We can do that easily using Macro Scheduler and WebRecorder functions by controlling an instance of Internet Explorer, which can be done in the background.

Below is a script which demonstrates this. It offers a function called LoginToTwitter which need only be called once per session, and an UpdateStatus function to update your status. Just set your Twitter username and password in the first two lines and you should be all set.

Let>TW_USERNAME=XXXXX
Let>TW_PASSWORD=XXXXX

//only need do this once per session
GoSub>LoginToTwitter

GoSub>UpdateStatus,This is a test

GoSub>UpdateStatus,This is a test 2

GoSub>LogOut

// END

//*** SUBROUTINES ***//
SRT>LoadWR
  //load the WebRecorder runtime
  LibLoad>IEAuto.dll,hIE
  If>hIE=0
    MessageModal>Could not load IEAuto.dll, make sure it is in the path or edit the LibLoad line.
    Exit>0
  EndIf
END>LoadWR

SRT>LoginToTwitter
  GoSub>LoadWR
  //open IE
  LibFunc>hIE,CreateIE,ieTwitter,0
  LibFunc>hIE,ShowIE,res,ieTwitter,1

  //log in to Twitter
  LibFunc>hIE,Navigate,r,ieTwitter,http://twitter.com/login
  LibFunc>hIE,WaitIE,r,ieTwitter
  LibFunc>hIE,FormFill,r,ieTwitter,,,session[username_or_email],TW_USERNAME,0
  LibFunc>hIE,FormFill,r,ieTwitter,,,session[password],TW_PASSWORD,submit

  LibFunc>hIE,WaitIE,r,ieTwitter
  Wait>1
  LibFunc>hIE,WaitIE,r,ieTwitter
  Wait>1
END>LoginToTwitter

SRT>UpdateStatus
  LibFunc>hIE,FormFill,r,ieTwitter,,,status,UpdateStatus_VAR_1,submit
  LibFunc>hIE,WaitIE,r,ieTwitter
  Wait>1
END>UpdateStatus

SRT>LogOut
  LibFunc>hIE,KillIE,r,ieTwitter
END>LogOut

You need the IEAuto.DLL library which is installed with WebRecorder.

For a bit of fun the following code copies the currently highlighted text to the clipboard and tweets it. So assigned to a hot key it can be used to tweet any text from any application.

Press CTRL
Send>c
Release CTRL
WaitClipBoard
GetClipBoard>theText
GoSub>UpdateStatus,theText

The real challenge is finding something useful to do with it! 🙂

May 21, 2010

Weekly Forum Round-up

Filed under: Automation,General,Scripting,Testing — Marcus Tettmar @ 10:34 am

I thought I might start a weekly round up of some of the Macro Scheduler forum posts that caught my eye during the week. Not everyone gets a chance to browse the forums all the time, so it might help to link to some here. Then those that subscribe to the blog via RSS/Email will see them and they’ll also show up in Macro Scheduler’s News Feed window.

The forums are quite active but I won’t link to every little discussion or request for support – just those that demonstrate a new feature, or work as a “how to” or anything else that I think could be useful. We’ll see how it goes.

So here’s my list for week ending 21st May 2010:

How to trim spaces from the ends of, or within, a string

A Progress Bar Demo using Macro Scheduler 12

How to make a custom dialog minimize to the task bar

Putting a status bar with multiple panels on a custom dialog

Finding a drive based on its label (volume name)

Getting the HTML source of a page using WebRecorder

Running Automated Testing scripts in the background via VMWare

May 7, 2010

Run All Macros in a Folder/Group

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

Someone asked me today how to run all macros found in a folder. This simple script will run all macros it finds in its own folder in turn:

GetFileList>%SCRIPT_DIR%\*.scp,MacroFiles
Separate>MacroFiles,;,Macros
If>Macros_count>0
  Let>k=0
  Repeat>k
    Let>k=k+1
    Let>this_macro=Macros_%k%
    If>this_macro<>SCRIPT_FILE
      Macro>this_macro
    Endif
  Until>k=Macros_count
Endif

Note the check to make sure it doesn’t run itself!

This could be useful where you want a quick way to schedule a series of macros. Schedule this script and then all you need to do to add another to the schedule is to drop it into the same folder (or macro group).

For a bit more control consider naming each macro with a numeric prefix and then sort the array to determine the order in which they are run. Version 12 (currently in beta) has a built in ArraySort function. Or use this QuickSort algorithm.

March 8, 2010

Screen Magnifier In Only 34 Lines of Code

Filed under: General,Scripting — Marcus Tettmar @ 9:46 am

Check out this screen magnifier, written by Dick Lockey in only 34 lines of Macro Scheduler code.   Paste it into a macro, hit run and then as you move the mouse around your screen you’ll see a 5x magnification of the cursor area.

Dialog>Dialog1
   Caption=5X Magnify
   Width=800
   Height=500
   Top=500
   Left=48
EndDialog>Dialog1
Show>Dialog1
  LibFunc>user32,GetDC,HDC1,Dialog1.handle
  LibFunc>user32,GetDC,HDC3,0

Label>Loop
  GetDialogAction>Dialog1,res1
  If>res1=2
    Exit>0
  EndIf
  GetCursorPos>CurX,CurY
  Sub>CurX,80
  Sub>CurY,50
  Wait>0.01
  LibFunc>Gdi32,StretchBlt,SBres,HDC1,0,0,800,500,HDC3,CURX,CURY,160,100,13369376
  GoSub>DrawLine,Dialog1.handle,1,0,390,250,410,250
  GoSub>DrawLine,Dialog1.handle,1,0,400,240,400,260
Goto>Loop

SRT>DrawLine
  LibFunc>user32,GetDC,HDC,%DrawLine_var_1%
  LibFunc>gdi32,CreatePen,Penres,0,%DrawLine_var_2%,%DrawLine_var_3%
  LibFunc>gdi32,SelectObject,SOPres,hdc,Penres
  Libfunc>gdi32,MoveToEx,mtres,HDC,%DrawLine_var_4%,%DrawLine_var_5%,0
  LibFunc>gdi32,LineTo,ltres,hdc,%DrawLine_var_6%,%DrawLine_var_7%
  LibFunc>gdi32,DeleteObject,DOres,Penres
  LibFunc>user32,ReleaseDC,RDCres,HDC_1,HDC
END>DrawLine

Yes, as Dick Says, you get one of these with Windows. But it’s kind of cool to see you can do the same thing with Macro Scheduler, and the code might come in handy elsewhere.

Enjoy.

March 1, 2010

Convert raw VBScript .vbs files to Macro Scheduler Scripts

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

As you probably know Macro Scheduler scripts can include Microsoft VBScript. Not only can you CALL VBScript code you can also pass values into it and retrieve values out of it (I’ve seen many competitors claim you can use VBScript in their macros when what they really mean is you can only call external VBScripts and not get results and data back).

This means you can take VBScript code and embed it into your macros. However, you may need to make some small modifications to VBScript code samples you find out there in the wild, and I’m often being asked how to do this.

Usually the only changes necessary involve the fact that many sample scripts are designed to run as standalone .VBS files and make use of the WScript object. This object is instantiated automatically by the Windows Scripting Host and offers methods like “Echo” and “Sleep” which you’ll often see in sample scripts. But in the case of Macro Scheduler VBScript is being hosted by Macro Scheduler, not the Windows Scripting Host, so WScript is not available.

Therefore anything starting with WScript will need to be removed or replaced with something else.

The most common one is WScript.Echo. This simply displays a message. When the VBS file is run on the command line the message is output to the command line. Otherwise it appears in a pop up message box. Most of the time in sample scripts it is just there as an example, so you can see the code working. You’d probably end up not wanting the script popping lots of message boxes anyway. But if you do you could replace it with MsgBox.

So, remove references to WScript and you should find you’re good to go.

Update: Macro Scheduler 12 (currently in beta) ships with a built-in WScript object which implements the Echo and Sleep functions. This means that Wscript.Echo and WScript.Sleep functions will continue to work and will not need to be removed to make the .vbs work in Macro Scheduler.

January 29, 2010

Running Macro Scheduler Macros over the Web Via PHP

Filed under: Automation,General,Scripting,Web/Tech — Marcus Tettmar @ 9:31 am

Here’s a quick and simple proof of concept for running Macro Scheduler macros via the web and having their output displayed in the user’s browser:

Running Macro Scheduler Macros Over the Web Via PHP

The screenshot shows the PHP script, Macro Scheduler script and Internet Explorer being used to run the macro.

1) If you don’t already have a Windows based web server with PHP running, download and install WAMPServer. It’s easy.

2) Create a simple PHP script which takes an EXE name as a parameter and any parameters you want to pass to it. The following script will run EXEs that are in the c:\wamp\ folder, passing in any parameters provided and will dispay the EXEs output.

<?php
$exe = $_GET['exe'];

$dir = "c:\\wamp\\";

$parms = "";
foreach($_GET as $key=>$val) {
  $parms .= "/$key=$val ";
}

echo shell_exec("\"$dir$exe\" $parms");
?>

3) PHP’s safemode must be disabled for this script to work.

4) Create a Macro Scheduler macro and use SOWrite or SOWriteLn to output information. Compile it with the “Create Console App” option checked. Compile the EXE (or copy it) to the c:\wamp\ folder.

5) Now the macro can be executed via the web using http://servername/runmacro.php?exe=my.exe&parm1=value&etc=… which could be a link or entered into the browser directly.

6) Consider adding further security to the script to prevent anyone running any EXE on your server, or putting it in a password protected folder. I’ll leave that to you.

Macro Scheduler Enterprise comes with the msNet Remote Controller which includes a CGI module for running Macro Scheduler macros via web servers.

January 28, 2010

Force DBQuery to Read CSV Columns as Text

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

In More on Reading and Writing CSV Files and various other posts I have demonstrated how CSV data can be read via a SQL SELECT statement using DBQuery.

In order to do this we used an ADO connection string in the DBConnect line:

Let>ConStr=Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\My Documents;Extended Properties='text;HDR=NO;FMT=Delimited'
DBConnect>ConStr,dbH

“Proper” CSV files use the double quote character to delimit strings. But there are many CSV files that do not contain these delimiters. When string delimiters aren’t used this should normally mean that the field is numeric, but that may not always be the case. So ADO sometimes has to take a guess as to whether a column is a string or a number. By default it does this by looking at the first 8 rows of data. This may not always be enough.

Watch what happens if we try to read in this file, which contains IP addresses:

abc.pluto.server.com,18.140.1.2
zxy.saturn.server.com,18.120.2.1
fyg.pluto.server.com,18.5.6.2

We’ll read it in with:

DBQuery>dbH,SELECT * FROM servers.csv,fields,num_recs,num_fields

Something weird happens. Look in the watch list and you’ll see the IP addresses have become:

18.1401
18.1202
18.562

ADO has decided that the IP addresses are numbers. It didn’t see any quote marks and after analysing the rows decided they are meant to be numbers. Bonus points go to anyone who can tell me why it has transformed the numbers in that way.

As mentioned before, ADO looks at the first 8 rows. If more of those 8 are more obviously strings, or contain string delimiters, it will treat them as strings. Try delimiting just one row of the above three. You’ll still get numbers. Delimit two and the problem is solved. Where the data type is mixed it will choose the type of the majority.

But we can’t go editing the CSV files to correct them.

What we can do is use a Schema.ini file. Using a Schema.ini file we can tell ADO what data types should be used for each column. So for our Servers.csv example above we could make a Schema.ini file as follows:

[Servers.csv]
Col1=ServerName Text
Col2=IPAddress Text

This file should be in the same folder as the CSV file.

Now, when we run our query we get the correct values, because we’ve forced ADO to treat the columns as text. Another advantage of this is that we have given our columns names, which is useful because our file doesn’t have a header column. This means we could set the Fieldnames parameter of our DBQuery line to 1 to return our array using the field names.

For more information on Schema.ini options for text files see:
http://msdn.microsoft.com/en-us/library/ms709353(VS.85).aspx

Most of the time you’ll probably be working with CSV files that you know about, so manually creating a schema.ini file once is no issue. But you could have the macro create it for you using WriteLn and/or EditIniFile.

What if your macro needs to read in a CSV file and you don’t already know how many fields there are, but you want to force everything to text? Well, how about doing this:

//Create schema.ini file
DBQuery>dbH,select * from servers.csv,fields,num_recs,num_fields,0
WriteLn>%SCRIPT_DIR%\schema.ini,res,[servers.csv]
Let>k=0
Repeat>k
  Let>k=k+1
  EditIniFile>%SCRIPT_DIR%\schema.ini,servers.csv,Col%k%,Col%k% Text
Until>k=num_fields

//now requery using schema.ini file
DBQuery>dbH,select * from servers.csv,fields,num_recs,num_fields,1
...

So this code uses a DBQuery to get the column count, and creates a schema.ini with each column called Coln where n is the column number and setting it to Text.


Side note: There’s another option called MaxScanRows which is supposed to help by telling ADO how many rows to scan, so that instead of looking at only 8 rows you can tell it to look at more, or less. According to the docs setting it to zero will cause it to scan all rows. Given that in our IP address experiment it took the IP addresses as numbers and we only had 3 which is less than the default 8 rows, I would have expected that setting MaxScanRows to 0 would make no difference. In fact it causes the IP addresses to come back as Text. So it seems to solve our initial problem., but I’m not sure why. Googling MaxScanRows reveals a number of forum and news group posts where others have had problems and there seems to be some confusion over exactly what it does. If we use MaxScanRows without ColNameHeader it also causes ADO to see the first line as a header line. And then setting ColNameHeader to false, while ensuring the first line is not seen as a header, brings back the original problem, where the IP addresses are converted to numbers. All seems a bit strange. Hence my preference for explicitly setting the data type of each column.

January 26, 2010

Get Auto-Generated ID Created By INSERT SQL

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

If you have a database table with an auto-generated numerical index field, you may need to retrieve the value of this field after an INSERT statement.

In Microsoft Access such a field uses an “AutoNumber” data type. In MySQL it’s known as an “auto_increment” field.

We often see these types of fields where a relationship exists between two tables, for example between a “customers” table and “customer_orders” table. The “customers” table may have an AutoNumber field which the system automatically increments when a record is inserted, and in the “customer_orders” table you’ll see a “CustomerID” field which uses this same value to map one or more orders to one customer.

It’s a convenient way to have the database itself automatically create a unique identifier.

If you ever need to use Macro Scheduler to transfer data into such a database you can use the built-in database functions to handle the INSERTS. But when it comes to inserting the data into the second table you’re going to need a way to get the ID that was automatically generated for the first.

Some database technologies give you a function to do just that. MySQL has a function called LAST_INSERT_ID() which you can call with a SELECT statement:

DBExec>dbID,INSERT into customers (name,address1,address2) VALUES ("Mr Customer","..",".."),res 
DBQuery>dbID,SELECT LAST_INSERT_ID(),last_id,nr,nf,0

This will return the ID in LAST_ID_1_1 and you can then use it in your next INSERT for the detail records.

See: MySQL: last_insert_id

Microsoft Access does the same with a function called @@identity:

DBExec>dbID,INSERT into customers (name,address1,address2) VALUES ("Mr Customer","..",".."),res 
DBQuery>dbID,SELECT @@identity,last_id,nr,nf,0

See: Retrieving Identity or Autonumber Values

Your particular flavour of database might have something similar. If not you could take a risk and do this:

DBQuery>mdbH,SELECT TOP 1 ID FROM customers ORDER BY ID DESC,last_id,nr,nf,0

This will return the largest ID – the latest one. But if you’re working on a database that has many users updating it simultaneously there’s a danger you could retrieve the ID generated by someone else’s INSERT. If it’s just you, then it’s probably OK, but you’ve been warned.

For more information on Macro Scheduler’s database functions see:
Using Macro Scheduler’s Database Functions

January 11, 2010

Remove Tags From HTML with RegEx

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

A quick and easy way to remove HTML tags from a string:

Let>Html=

Hello World

Test link Let>pattern=<(.|\n)*?> RegEx>pattern,Html,0,matches,numMatches,1,,plainText MessageModal>plainText

« Newer PostsOlder Posts »