Enhancement Suggestions
What would you like to see in the next version of Macro Scheduler? As always, we’d like your input. You can post suggestions for new features and functions in the Enhancement Suggestions forum.
Macro Recording and Automating Windows with Macro Scheduler – Tips & News
What would you like to see in the next version of Macro Scheduler? As always, we’d like your input. You can post suggestions for new features and functions in the Enhancement Suggestions forum.
I’ve added two new scripts to the Scripts & Tips forum.
How to run a process and kill and restart it if it is taking too long:
http://www.mjtnet.com/usergroup/viewtopic.php?t=2574
How to write to the Application Event Log:
http://www.mjtnet.com/usergroup/viewtopic.php?t=2577
Internet Explorer 7 Beta 2 went public today. Finally IE has tabs! Download it here. ZDNet have a review here. This beta version is likely to have bugs and may not display some sites properly. Microsoft want site designers to test it out fully before it is shipped later this year with Vista. I’ve tested WebRecorder with IE7 and am pleased to note that there are no issues and web activity is recorded and played back correctly.
Recently I wrote about why it’s good to automate and how automation can help you learn software and improve its design. There are other good reasons for automating beyond the obvious benefits of saving time and money.
Documentation: Automation scripts are the ultimate way to document a process. A script that automates a process describes how to carry it out properly. Businesses need to document all their manual processes so that other people can carry out the task. By scripting the process it is being described at the same time. As well as saving time by automating it, it is also now easy for someone else to see how the process is carried out.
Contingency: Contingency goes hand in hand with documentation. If only one person in the organisation knows how to carry out a task there will be problems if and when that person is sick, on vacation, or leaves the company. Not all absences are planned. By documenting a process the business is ensuring that someone else can carry it out should the usual task owner be unavailable. Automation takes that one stage further. If the process is scripted and automated it is easy for someone else to take on ownership of the task in the future. The task will continue to run and the script itself describes how the task works.
We released the first 8.x maintenance release today. This fixes a few small bugs. You will find full details here:
http://www.mjtnet.com/usergroup/viewtopic.php?t=2568
Nothing much to do with Macro Scheduler this except that it finds me sitting in an office in Geneva today. 100 meters beneath me, under the ground, is a circular tunnel 35m wide, 55m tall and 27 km long. It goes right underneath houses and offices in the city of Geneva and surrounding areas. Sandwiched between Lake Geneva and the mountains is the largest particle accelerator in the world, run by CERN, where Tim Berners Lee invented the World Wide Web. Next year they will accelerate protons around this tunnel and smash them together to create conditions similar to those that existed just after the Big Bang. They’re looking to prove the existence of a particle called the Higgs Boson, which is believed to provide matter its mass.
If you think you’ve created long scripts in Macro Scheduler you should see the software they’re creating at CERN to configure and measure the results from the particle accelerator. A friend of mine is debugging this C++ code right now and he says it takes 30-40 minutes to compile! That’s a lot of code. Think about that next time you’re debugging a script! 🙂
I was interviewed yesterday for Channel9’s New MicroISV Show. It will be aired in 5-6 weeks.
MicroISV is a new term to describe small software companies like MJT Net Ltd. ISV stands for Independent Software Vendor. The show is aimed at developers and small software companies and will give an insight into the benefits and challenges faced by small companies developing for the Windows platform.
This is something that comes up often, so I thought I’d mention it here. Every so often we get asked how to put a date into a filename. Say you want to rename or save a file with the date in the filename formatted to reportsYYYYMMDD.txt e.g.:
reports20061801.txt
Well the simplest way to do this is to use the basic date functions Year, Month and Day. These each return the current year, month and day numbers. We also need to embed the variables into the filename. We can create the filename like this:
Year>the_year
Month>the_month
Day>the_day
Let>filename=reports%the_year%%the_month%%the_day%.txt
See how we embed the variables by putting % symbols around them. The % symbols tell Macro Scheduler to find the variable within them and to use the value assigned to that variable. So on 18th January 2006 we get:
the_year=2006
the_month=01
the_day=18
And filename becomes:
filename=reports20060118.txt
Say we wanted to rename the reports.txt file to a reports20060118.txt. Let’s also say that the file is in the c:\data folder. We would do this:
MoveFile>c:\data\reports.txt,c:\data\%filename%
Or we could have said:
Let>filename=c:\data\reports%the_year%%the_month%%the_day%.txt
MoveFile>c:\data\reports.txt,filename
You might not be renaming a file, but sending the filename to an application. Most applications use the standard ‘Save As’ dialog. Once this has opened you can send the full path and filename directly to that box and hit the Enter key to perform the save. So after sending the keystrokes required to open the Save As dialog (often File/Save As) we’d do:
WaitWindowOpen>Save As
Send>c:\data\reports%the_year%%the_month%%the_day%.txt
Press Enter
The Year command returns the year in full 4 digit form. Suppose you only wanted the last two digits (06 in this case). Well we can use the MidStr command to extract the last two digits:
Year>the_year
MidStr>the_year,3,2,the_year
This says: Starting from the third character in the_year take two characters and return the result in the_year. In this case because the_year has previously been declared as a variable (by the Year command) it is seen as a variable. The result of the MidStr command is also the_year so it over writes the_year with the new value. We could have made a new variables:
MidStr>the_year,3,2,YY
Here we end up with a new variable, YY, which contains 06.
To understand this better, paste the following code into the Script Editor. Then open the Watch List (Debug/Show Watch List). Now place the cursor on the first line and hit F8. Each time you hit F8 the script will advance to the next line. You will see the new variables being created in the watch list to the right. And you will see their values changing as you advance through the script.
Year>the_year
Month>the_month
Day>the_day
Let>filename=reports%the_year%%the_month%%the_day%.txtMidStr>the_year,3,2,YY
Let>newfile=outcome%YY%.dat
You might want to use a previous or future date. For more advanced date manipulation I recommend using the VBScript date functions.
Let’s say we want to use yesterday’s date in the filename, instead of today’s. To determine past or future dates based on today’s date use the VBScript function DateAdd. DateAdd takes an interval type, a number and a date. To add one day to the current date do:
DateAdd(“d”,1,Date)
To subtract one day from the current date we use:
DateAdd(“d”,-1,Date)
So to create a dated filename based on yesterday’s date we can do this:
VBSTART
VBEND
VBEval>DateAdd(“d”,-1,Date),yesterday
VBEval>Year(“%yesterday%”),yyyy
VBEval>Month(“%yesterday%”),mm
VBEval>Day(“%yesterday%”),dd
Let>filename=reports%yyyy%%mm%%dd%.txt
Here we use VBScript’s version of the Year, Month and Day functions which operate on a given date. First we subtract one from the current date to get yesterday’s date and we use that in the Year, Month and Day functions to extract the relevant parts and then we can construct our filename.
See the VBScript Documentation for more info on using VBScript functions.
I’ve added some scripts to the Scripts & Tips forum:
A script to Monitor Startup Programs. Useful for detecting rogue apps like spyware etc
Is Drive Ready. A function to determine whether the drive is ready or not.
Automatically Create a System Restore Point. Useful at the start of a script that installs software or makes critical changes to the system.
Backup the Registry. Well worth scheduling to run regularly, or run manually before installing software.
Create a New Outlook Contact. Demonstrates how you can automatically add new contacts to Outlook. Could be used for importing data from another source, or could be integrated with a script that automatically parses order notification emails etc.
Cosmo asked in his comment on How to Start Writing an Automation Script how he could set the position of a desktop shortcut. This is an interesting question that hasn’t come up before and it took me a while to realise how it could be done. You may wonder why you’d even want to do it. Well if you’re automating software installations for your end-user or customer machines you may want to make sure the desktop icons are always in the same place. You may want to put a link to your support site in the top right of the screen, for example, so that your customer can always find it.
The solution wasn’t immediately obvious. You can move icons around with the mouse, but trying to automate that would be a bit of a nightmare and you can’t drag icons with the keyboard. Even then how do you know what position it’s at? So how do you do it? Well I realised that the desktop icons are actually elements of a hidden ListView control belonging to the desktop window. So we need to manipulate this ListView control. Macro Scheduler 8.0 has a function called GetListItem which will return the index of a list item by its caption. So immediately we can find the index of a desktop icon with just this line:
GetListItem>Program Manager,SysListView32,0,RealPlayer,0,0,0,Result,Handle
This line returns the index of the “RealPlayer” shortcut. Note that the main window title is Program Manager and the object class name is SysListView32. You can see this in the View System Windows tool (under the Tools menu in Macro Scheduler). Conveniently, GetListItem also returns the Handle of the listview object. We need this for the next bit.
We need to go a level deeper to figure out how to position the item. We get down and dirty with the Win32 API. The Win32API is a heap of functions deep within Windows. There’s a message called LVI_SETITEMPOSITION which is sent to a ListView control when it needs to be positioned. Messages always have two parameters, known as wParam and lParam. In this case wParam is the index of the ListView item, which we got from the GetListItem command, and lParam is a POINT structure. A POINT structure specifies an X and Y coordinate. So we can send the X and Y coordinate of where we want the shortcut to end up, to the ListView control by way of the LVI_SETITEMPOSITION command.
To send the LVI_SETITEMPOSITION message we need to use the Win32 API function SendMessage. First we need to convert the X and Y coordinates into an integer value. This involves a bit of wizardry using a couple of VBScript functions which are in the full script. So this allows us to do this:
Let>xpos=100 Let>ypos=500 VBEval>MAKELPARAM(%xpos%,%ypos%),lparam //Reposition Let>LVI_SETITEMPOSITION=4111 LibFunc>user32,SendMessageA,r,Handle,LVI_SETITEMPOSITION,Result,lparam
So using the VBscript function MAKELPARAM (it’s in the full script) we convert the target x,y coordinates to an lParam value which we can send to the ListView with the message. We declare the LVI_SETITEMPOSITION message (message 4111 in Windows – LVI_SETITEMPOSITION is just constant name) and then use the LibFunc command to run the SendMessageA Win32 API function which sends the message. We send it to the ListView control using the handle returned by GetListItem and we send the index, also returned by GetListItem, and our lparam which contains the new x,y coordinates.
So here’s the full script:
//Functions needed for working with windows messages VBSTART Function LoWord(wInt) LoWord = wInt AND &HFFFF& End Function Function HiWord(wInt) HiWord = wInt &H10000 AND &HFFFF& End Function Function MAKELPARAM(wLow, wHigh) MAKELPARAM = LoWord(wLow) Or (&H10000 * LoWord(wHigh)) End Function VBEND //Refresh icon view SetFocus>Program Manager Press F5 //Get index of RealPlayer shortcut on desktop GetListItem>Program Manager,SysListView32,0,RealPlayer,0,0,0,Result,Handle //Set position of icon. //If Align to Grid is on this will slot icon in where it fits best. //If Align to Grid is off it will place icon at this absolute position. Let>xpos=100 Let>ypos=500 VBEval>MAKELPARAM(%xpos%,%ypos%),lparam //Reposition Let>LVI_SETITEMPOSITION=4111 LibFunc>user32,SendMessageA,r,Handle,LVI_SETITEMPOSITION,Result,lparam
Apologies for the way the script is formatted. HTML doesn’t lend itself well to showing script code the way it was intended. But you can download the full script file at the end of the article.
Note the VBScript at the top which creates an LParam value out of two integers, in this case the x,y values. Besides declaring the VBScript functions, the very first thing the script does is focus the desktop and hit F5 to force a refresh. This ensures that the icons are in their correct places so that the GetListItem command returns the correct value. Note that the desktop window title is “Program Manager”. So we can use that to focus the desktop window.
If “Align to Grid” is enabled the icon will snap to the position in the list nearest the x,y position we provide. If Align to Grid is off it will use that absolute x,y position. I should also say that the x,y coordinates are the top left position of the shortcut. I’ve included some code to toggle Align to Grid in the downloadable script file.
Windows message names are constants. Macro Scheduler doesn’t have these variables pre-defined so to use Windows messages you’ll need to find out their integer values. If you have a development environment such as C++ you’ll find them declared in winuser.h. If you don’t, I’ve uploaded a text file with a large number here.
So there you are. I hope this is useful.
Download the Script File
AllApi.Net API List Windows 32 API Functions – this site is aimed at users of Visual Basic but I find it a handy reference of API functions and the examples can easily be translated to LibFunc calls.