 |
|
|
|
 |
Writing application event procedures
|
Or how to intercept events affecting any open document, such as the user changing focus from one document to another
Article contributed by Dave Rado, with acknowledgements to Bill Coan
You can respond to certain application-level events using Auto macros
see: Running a macro automatically when Word starts or quits.
However, to respond to other application events you need to create an application
object declared WithEvents
i.e. declared in such a way that it will respond to events.
How to set up code that will respond to application events
If you open a template, press Alt+F11, and in the Project window of the VBA environment, double-click on
Microsoft Word Objects,
you'll see a built-in Class Module called ThisDocument.
If you open this, you can use the list boxes on the toolbar to help you create
document event procedures.
So it would make sense for there to be another built-in class module called ThisApplication;
but Microsoft, in their wisdom, felt this would be too user-friendly, so you have to create
your own ... Help is very unhelpful on the topic there isn't even
a definition in Help of what a Class is! but if you're
interested, Bill Coan covered the topic at
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnword2k2/html/odc_wdappevnt.asp.
In essence, though, a Class is simply a container object which allows you to
create properties, which are objects in their own right, and then create properties and
methods for those objects.
Note that the big picture view of what we're about to do is this: |
|
We want to respond to events. |
|
We need an application variable (declared with WithEvents) to receive the
events. |
|
We need a class module to serve as a container for the application
variable. |
So here's how to create an application event procedure:
1. |
Create an Addin; that is, a .dot file stored in Word's startup directory so
that it is global. |
2. |
Open the Addin, and in the VB Editor, select Insert + Class Module. Rename
the Class Module from Class1 to ThisApplication. Note: The
Class Module and all the variables in this article can be called whatever you
like; but I have tried to make all the names as meaningful as possible. I like ThisApplication
because it shows that it is functionally analogous to the built-in ThisDocument
class module. But note that your ThisApplication
object is simply a container. It doesn't actually represent an
application. It represents all the properties of the Class Object, whatever we
define those properties to be. |
3. |
Insert the following code in the Class Module: Option Explicit
Public WithEvents oApp As
Word.Application This specifies that oApp is
an object variable which will be used to respond to the events triggered by the ActiveX
object Word.Application. By declaring it publicly, you have
made oApp a property of
the class object ThisApplication.
At this point you are simply declaring what type
of object oApp is (its type being a Word Application object), and declaring
the fact it will respond to events. You are not actually assigning the oApp
variable to the Word application yet
that comes later. So the oApp object doesn't actually exist yet
(and no area of memory has been set aside for it yet). The WithEvents keyword can only be used in Class
Modules and can only refer to ActiveX
i.e. OLE-compliant
objects. |
4. |
Now select Insert + Module.
In the Module, insert the following code:
Option Explicit
Dim oAppClass As New ThisApplication
Where ThisApplication
is the name of your Class Module. The statement creates an object variable oAppClass
which references (is a pointer to) the class object ThisApplication which you
created earlier.
Using the keyword New in the declaration creates a new instance
of the class object that is, it loads an instance of the class into memory
and makes the variable oAppClass point to the newly created instance.
From now
on, you can refer to this new instance of the class by using the oAppClass
variable.
Now add the following code in the same Module:
Public Sub AutoExec()
Set oAppClass.oApp = Word.Application
End Sub
The oApp object is a property of the class object oAppClass,
because you declared it as a public variable in the Class Module in step 3.
The above code
creates an instance of the oApp object (loads it into memory), and
makes it actually refer to the Word.Application object. In effect it makes
the oApp object exist.
To put it another way, you have now assigned the actual Active-X
Word Application to the variable, whereas previously you had only declared what
type of variable it was going to be.
By calling your procedure AutoExec, you make it run automatically when your
Addin loads and your Addin will automatically load when Word loads.
|
5. |
Now run the AutoExec macro, by clicking in it and pressing F5, to initialise
the oApp object.
|
6. |
Switch to your ThisApplication Class Module. You'll see two list boxes on the
toolbar. If you pull down the one on the left, and
change it from (General) to
oApp, a procedure
called oApp_Quit() will be created. If you then pull down the list
box on the right, you'll see several other application events to choose from
(and you can delete the oApp_Quit() procedure later, if you don't want it):
|
a)
|
In Word 97, you only have the choice of Quit and DocumentChange.
|
|
b)
|
In Word 2000, you have the choice
of: |
|
Quit |
|
DocumentChange |
|
DocumentBeforeClose |
|
DocumentBeforePrint |
|
DocumentBeforeSave |
|
DocumentOpen |
|
NewDocument |
|
WindowActivate |
|
WindowBeforeDoubleClick |
|
WindowBeforeRightClick |
|
WindowDeactivate |
|
WindowSelectionChange |
|
Note that (rather confusingly) these are all Application events (even
though some of them refer to documents doing things) as distinct from Document events such as
Document_Close.
Because it is an Application event, for instance, a procedure called
oApp_DocumentBeforeClose will fire when any document closes;
whereas because it is a Document event, a Document_Close procedure will only
fire when documents based on the template that the Document_Close procedure is
stored in are closed.
|
7. |
Having inserted the event procedure you want using the listboxes, add your
code, and you're done.
|
Note: If you want to monitor application events affecting documents
based on a specific
template, you can either store the event code in a global Addin as described
above and test for which template is in use by using ActiveDocument.AttachedTemplate;
or you can store the event code in the ThisDocument
Class Module of the relevant template.
For an example of the latter, see: How can I prevent users from editing the header of a document in Word 2000 or higher?
Summary of set-up procedure
oApp_Quit
An oApp_Quit event procedure works in exactly the same way as an AutoExit
macro it fires when Word quits. Unfortunately, both the AutoExit macro and
the oApp_Quit procedure fire after any Do you want to save changes
dialogs have appeared.
There is no event of the Application object analogous to an AutoExec macro,
however.
oApp_DocumentChange
The DocumentChange event triggers whenever you open/close/create a
document and whenever you change focus from one document to another. If the
event code is stored in an Addin, it will be global. In Word 2000, there are
separate events you can use for each of these oApp_NewDocument for
when a new document is created, etc. But in
Word 97, you can use oApp_DocumentChange to simulate them. Even in
Word 2000, simulating them sometimes works better than using the proper events. For more details,
see: How to create global event procedures similar to
AutoOpen, AutoNew and AutoClose, without using Normal.dot. oApp_DocumentBeforeClose, oApp_DocumentOpen, oApp_NewDocument,
oApp_ WindowActivate, oApp_WindowDeactivate
All of these combined at least in theory replace (and build on)
the functionality of oApp_DocumentChange.
The oApp_DocumentBeforeClose, oApp_DocumentOpen, oApp_NewDocument event
procedures are covered in the article: How to create global event procedures similar to
AutoOpen, AutoNew and AutoClose, without using Normal.dot.
The oApp_ WindowActivate, oApp_WindowDeactivate events are self-explanatory. It's safest
to use the list boxes on the toolbar to insert the event procedures, as the
syntax is complicated. oApp_DocumentBeforePrint, oApp_DocumentBeforeSave
These are discussed in the article: Intercepting events like Save and Print.
oApp_WindowBeforeDoubleClick, oApp_WindowBeforeRightClick, oApp_WindowSelectionChange
Again, these are self-explanatory, and it's safest to use the list boxes on the
toolbar to insert the event procedures, to ensure that you get the syntax right. Using
the WindowBeforeDoubleClick and WindowBeforeRightClick events seem to have a
significant performance hit on Word; but the WindowSelectionChange events seems
to work well (subject, that is, to the code you put in it).
|





|