Publisher 2003: Using the NewDocument and DocumentOpen Events

I got an email the other day from a user who asked if the NewDocument event in Publisher actually worked. It does, but it is a little more complicated than you'd think. Read on.

To enable event handling within a typical application, you create a new class module, and declare an Application object with events:

Public WithEvents App As Publisher.Application

Then, write your event handlers:

Private Sub App_NewDocument(ByVal Doc As Document)

  MsgBox "You've created a new publication", , "New Pub Created"

End Sub

Finally, initialize the your object with the Application object:

Dim pub As New Class1

Sub Register_Event_Handler()

  Set pub.App = Publisher.Application

End Sub

Which is exactly what the user was doing. But whenever he created a new document, either through the user interface or programmatically, his NewDocument event handler was never invoked. The NewDocument event didn't seem to be firing.

Actually, it was; he just hadn't hooked up his event handler to the right Publisher.Application object.

Publisher is a single document interface (SDI) application; each document you have open resides in a separate instance of Publisher. Which means if you have an instance of Publisher that already contains an open document, and you open another document, you're actually launching another instance of Publisher first. That second instance of Publisher then opens the document, even though it looks like you're launching the document directly from the first instance.

That's why his NewDocument event handler never fired. His code was watching the first instance of Publisher; but with a document already open in the first instance, any commands to create a new document actually launched another instance of Publisher, which is where the NewDocument event was raised.

The same is true of the DocumentOpen event; if the instance of Publisher already contains an open document, then an additional instance launches, and the DocumentOpen event is raised in that second instance.

The only time either event would occur in an existing instance of Publisher is if Publisher was open, but didn't have a document open. Which means you can't write VBA code in a document to have it watch it's own application instance for those events. By simple fact that the document containing the VBA code was open, additional instances of Publisher would be launched for any open or new document commands.

You can, of course, use the DocumentOpen and NewDocument events from:

· Another instance of Publisher

· A Publisher add-in

· Another application

So let's create an example for the first bullet point, another instance of Publisher. The example below creates a new instance of Publisher, and initializes code to respond to events raised within that instance.

First, create a new class module, and declare an Application object with events, as you would normally:

Public WithEvents App As Publisher.Application

Then, write handler procedures for all the application events to which you want to respond:

Private Sub App_DocumentBeforeClose(ByVal Doc As Document, Cancel As Boolean)

  MsgBox "You are about to close: " & Doc.Name

End Sub

 

Private Sub App_DocumentOpen(ByVal Doc As Document)

  MsgBox "You have opened: " & Doc.Name, , "Document Open"

End Sub

 

Private Sub App_NewDocument(ByVal Doc As Document)

  MsgBox "You've created a new publication", , "New Pub Created"

End Sub

 

Private Sub App_WindowPageChange(ByVal Vw As View)

  MsgBox "Hey", , "Window Page Change Event"

End Sub

However, in the procedure that initializes your application object, set your variable to the application instance launched when Publisher opens a new document, not the application instance that contains the document with the VBA project.

For example, the following code creates a new document, and initializes the pub.App variable with the resulting new instance of Publisher. The event handlers now fire when events are raised in that application instance. Calling the NewDocument method, as the next line of code does, actually results in two events: the DocumentBeforeClose event for the new document open in the previous line, and then the NewDocument event for the new document that replaces it.

Dim pub As New Class1

Sub InitializeNewPubInstance()

  Set pub.App = NewDocument.Application

  pub.App.NewDocument

End Sub

You could also create a new instance of Publisher using the New VB keyword. However, instances of Publisher launched this way are not visible by default; this enables you to launch Publisher and automate it without displaying it to the user. So you have to explicitly specify the application be visible, like so:

Sub NewDocTest()

  Set pub.App = New Publisher.Application

  pub.App.ActiveWindow.Visible = True

  pub.App.NewDocument

End Sub

Now you event handler can respond to events the user raises in that Publisher instance, including DocumentOpen and NewDocument events. The event handlers I wrote simply pop up message boxes, but you get the idea. Just remember, those message boxes will appear in the Publisher instance running the code, not the Publisher instance actually raising the events.

One last piece of house-keeping. We want to release the pub.App variable if and when the user closes that instance of Publisher. So let's create a procedure that does that, and place it in the ThisDocument project:

Public Sub FreeApp()

  Set pub.App = Nothing

End Sub

And then call that procedure from the Quit event handler:

Private Sub App_Quit()

  ThisDocument.FreeApp

End Sub

On a related note, did you know it's impossible to programmatically arrive at a Publisher instance that doesn't have a document open? The New keyword launches a new instance of Publisher, with a new blank publication open. The Document.Close method closes the current publication, but then opens a new blank publication in it's place. There is no way to launch Publisher without also opening a publication. Likewise, there is no way to programmatically close the current publication without either also closing Publisher, or getting a new publication in its place. To get an instance of Publisher without an open publication, you have to go through the user interface.