“Hey, Windows Guru. How can I make it so that my VBScript event routines are only executed after a certain point in my script?”
Sam, you’ve asked an awesome question that you probably won’t find much documentation for. However, I have a really cool solution for you.
As you probably know, VBScript event routines are executed asynchronously. That means that the VBScript engine is going to execute an event routine any time it receives an event notification while your script continues to run. That’s usually fine for most applications, but as you’ve mentioned, what do you do if you don’t want that event routine to execute after a certain point in your script?
Let’s take a minute to make sure everyone is up to speed on how events work in VBScript. In VBScript, objects can issue events whenever certain based on changes to that object or its environment. These events are hard coded into the object’s code and made available to programmers. For instance, Microsoft’s Word automation object can notify a script whenever a new document is created. Likewise, Internet Explorer’s automation object can notify you whenever a file download is complete.
In order to handle events in VBScript, you must first connect to the object that you wish to receive events from. To do this you must use the CreateObject or ConnectObject method from the WScript object. You will typically use the first.
Set objWord = WScript.CreateObject("Word.Application", "wd_") Sub wd_DocumentChange MsgBox "The current document has been changed." End Sub |
This should look fairly standard to you. I’ve just created an object referent to the Word automation object. This effectively creates a running copy of the Word application. Notice that I’ve specifically used the WScript version of the CreateObject method rather than VBScript’s own native method to create the Word object. This allows me to use a second parameter to supply an alias for this object. This alias will be used to reference this object’s events. The alias follows the same naming rules as a variable reference and should end with an underscore.
Next, you create a subroutine named after the event you wish to monitor. In this case, I’m monitoring the DocumentChange event which will notify the script any time that changes occur within the current Word document. The event routine must be named specifically in the form of alias_eventname.
Once this object is created, any event routines attached to that alias will execute for their specified events. Let’s assume for a moment that we don’t actually want that to happen. What if we want to create the Word object and then start monitoring events later?
Set objWord = CreateObject("Word.Application") objWord.Visible = False objWord.DisplayAlerts = False objWord.Documents.Add Set objDoc = objWord.ActiveDocument objDoc.Content = "This is some text." |
To do this, let’s revert to the common method of creating the Word object without an alias instead. This allows us to work with the Word application without handling any events. In this case, we’re creating a new document and then adding some text.
Here’s where it might come in handy to control when our events are handled. If we work of our previous examples and monitor document changes, we probably don’t want to know when our script is doing the changing. So now that we’ve added our text, let’s go ahead and create an event alias so that our event routine will begin working.
WScript.ConnectObject objWord, "wd_" |
Remember that the ConnectObject method can be used to reference objects that already exist. Since we already created a reference to the Word object, we can use the ConnectObject method to add an alias to our existing object reference. Remember to use the WScript objects version of this method or you’ll get an error for having an extra parameter.
By adding an alias to our existing reference, we’ve effectively turned event handling on for that object.
Ok, this very simple, but it may seem like a lot to take in. Let’s take a look at a complete script so you can see better what the flow of the script will look like.
Const wdDoNotSaveChanges = 0 Set objWord = CreateObject("Word.Application") objWord.Visible = False objWord.DisplayAlerts = False objWord.Documents.Add Set objDoc = objWord.ActiveDocument objDoc.Content = "This is some text." WScript.ConnectObject objWord, "wd_" 'The event routine is now activated. Set objSelection = objWord.Selection 'Creating a selection should result in a DocumentChange event objDoc.Close objWord.Quit wdDoNotSaveChanges Sub wd_DocumentChange MsgBox "The current document has been changed." End Sub |
This script demonstrates how you can enable an event routine later in a script by adding an alias to an object reference rather than at the time of its creation. So then, what if you wanted to turn that event routine back off again?
Set objWordAlias = WScript.ConnectObject(objWord, "wd_") ' Create an event alias on WScript.DisconnectObject objWordAlias ' Destroy the event alias without disconnecting the original object reference |
To turn off an event alias, you can use the DisconnectObject method. In this case, you’ll want to supply an object name when creating the alias so that only the alias reference is disconnected.
Hope that helps!
8 Comments
Using the example for WScript.ConnectObject objWord, “wd_”, I was able to trap the wd_DocumentChange event but unable to trp the WD_BeforeDucumentPrint event, using Vista32 and Word 2007. Several events including ws_OnQuit I am unable to catch, If you have a moment.
Thank you
Harold
Not all events may be exposed through the scripting interface. Can you post the code you are trying so I can try it myself?
””””””””””””””
‘ Attempting to trap the
‘ objWd_DocumentBeforePrint
‘ Event
””””””””””””””
‘
Dim sTo,sFrom,objWD,objDoc
‘
sTo = “John Jones” & vbcrlf & “1313 Miller St.”
sTo = sTo & vbcrlf & “Dover, De 19901”
sFrom = “Mike Jones” & vbcrlf & “3333 Miller St.”
sFrom = sFrom & vbcrlf & “Wilmington, De 19954”
‘
‘
Set objWD = WScript.CreateObject(“Word.Application”,”objWD_”)
Set objDoc = objWD.Documents.Add
Set Env = objWD.ActiveDocument.Envelope
Env.Insert ,sTo,,,sFrom
objWD.windowstate = 2
objWD.PrintPreview = true
WScript.ConnectObject objWD, “objWD_”
WScript.ConnectObject objDoc, “objDoc_”
objWD.Visible = True
objWD.windowstate = 0
Do While objWD.Visible
WScript.Sleep 200
If objWD.PrintPreview = False Then Exit Do
Loop
Do while objWD.BackgroundPrintingStatus > 0
WScript.Sleep 100
Loop
‘
objWD.windowstate = 2
WScript.Sleep 25
objWD.Quit 0
Set objDoc = Nothing
Set objWD = Nothing
””’ Object Events ””””
Sub objWD_DocumentChange
‘ Event Caught
MsgBox “The current document has been changed.”
End Sub
Sub objWD_DocumentBeforePrint
Cancel = True
Msgbox “BeforeDucumentPrint”,,”objWD_BeforeDucumentPrint”
Env.PrintOut
End Sub
Sub objWD_OnQuit
Msgbox “objWD_Quit”
WScript.Quit
End Sub
Thank you so much for assistance.
Harold
Harold:
See http://msdn.microsoft.com/en-us/library/aa211873(office.11).aspx.
Try the sub header:
Sub objWD_DocumentBeforePrint(ByVal oDoc, ByRef Cancel)
instead of your header.
As for the quit event, shouldn’t it be:
Sub objWD_Quit
instead of using “OnQuit”?
Oops, forgot the tracking as I’m interested in knowing if you succeed. 🙂
I did remove the “On” in Wd_OnQuit. I can receive the Quit event.
I can not catch the “BeforeDucumentPrint” event. It does appear if the event needs to pass params, I can not catch it.
hi sir,
i want that for particular internet base application , whenever i pressed any button so that a script run for particular that application, suppose a apllication name is “abc” and there is to buttons “btn1” and “btn2” and this application is created so many before years so now i want the acces of mouse whenever it clicks on a particular pixels on the application “abc” then my scripts run,,
@ Harold Little:
Hope you’ve already resolved this issue, but if not…
1) Add “Option Explicit” — I resisted this practice at first because I hated the extra work including each & every variable in a declaration line, but as my scripts become increasingly complex, it helps A LOT in debugging.
2) I haven’t tested your code, but it seems some instances of your sub are spelled “ducument” rather than “document”–spelling error may be causing your trap to fail, and since you’re not using Option Explicit as above, WSH is creating a new variable space allotment which is not returning a value as you expect it to.
Best wishes!
Dan