Controlling When VBScript Events Are Handled

Written by Nilpo in Windows Scripting | 8 Comments

“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 M.

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!

Tags

Like the read? Share it!

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

Leave a Reply

Contact

Wanna say hello?
Drop us a line!

You'll find us here

1 Microsoft Way,
Redmond,
WA 98052, United States