Document_New event on launching Word - vba

I have a VBA addin which I want to run every time someone opens a document. It's working fine for opening existing documents (AutoOpen) and creating new documents from the File > New menu (AutoNew) but when I just open Word up for the first time, neither of these events are firing. The only event I can seem to hook into is the AutoExec event and this is not great as the document doesn't exist yet so ActiveWindow is null.
Can anyone help?
Sub AutoNew
MsgBox "New"
End Sub
Sub AutoOpen
MsgBox "Open"
End Sub
Sub AutoExec
MsgBox "Exec"
End Sub

I would start with DocumentOpen and NewDocument. An additional level of complexity exists if you need to support ProtectedView documents; Word triggers a different event. I've found that if I try to check for that event (and it doesn't occur) it raises an error. I didn't had much luck and eventually it wasn't worth the time I was spending. I've posted an example below of some code that opens the Style Pane when a document is opened or a new one created (assuming the add-in is loading) and expands the style margin in draft view if not already expanded.
In my UI module:
Dim X As New clsAppEvent 'This is in the declarations
Public Sub OnRibbonLoad(objRibbon As IRibbonUI)
Do While Documents.Count = 0
DoEvents
Loop ' I find this useful as sometimes it seems my ribbon loads before the document.
Call Register_Event_Handler
' Other stuff
End Sub
Private Sub Register_Event_Handler()
Set X.App = Word.Application
End Sub
Then, in a class module I call clsAppEvent:
Option Explicit
Public WithEvents App As Word.Application
Private Sub App_DocumentOpen(ByVal Doc As Document)
App.TaskPanes(wdTaskPaneFormatting).visible = True
End Sub
Private Sub App_NewDocument(ByVal Doc As Document)
App.TaskPanes(wdTaskPaneFormatting).visible = True
End Sub
Private Sub App_WindowActivate(ByVal Doc As Document, ByVal Wn As Window)
If Wn.StyleAreaWidth <= 0 Then
Wn.StyleAreaWidth = 60
End If
End Sub
Other than the caveats I've noted above, the one problem I've had is if a user has Auto code in their Normal template as well. This has only come up once so I haven't investigated it.
I wish I could find the site where I learned about this (and from which the Register_Event_Handler was derived. If I find it I'll add a comment.

Related

Is there a VBA event triggered when a Word document is closed?

I'm trying to use Normal.dotm as a macro storage object analogous to the Personal.xlsb object within Excel.
The built-in Document_Close() event seems like it cannot be triggered unless it's included within a specific document's ThisDocument object.
I've also tried to use this Application_Quit() event like so but to no avail:
Private Sub Application_Quit()
Msgbox "closing word"
End Sub
Is it possible to listen for closing of the word application like it is in excel with Auto_Close(), etc?
Attempt for #BigBen based on this documentation
Class Module "Event Class Module"
Public WithEvents App As Word.Application
Normal Module "Module 1"
Dim X As New Class1
Sub Register_Event_Handler()
Set X.App = Word.Application
End Sub
Private Sub App_Quit()
MsgBox "closing word"
End Sub
There are two basic ways to capture when any Word document closes:
Use a macro named AutoClose in any module of Normal.dotm (or any template loaded as an add-in). This is the "old-fashioned" way that comes from the WordBasic (Word 2.0 and 6.0) days.
Note that if any other document (or template) has AutoClose that this will over-ride the macro running a "more general" level. In other words, the document- (or template-) specific code takes priority.
Sub AutoClose()
MsgBox "The document " & ActiveDocument.FullName & " is closing."
End Sub
Work with an application-level event. This requires both a class module and a "plain" module. The event code is in the class module; the code to initialize the class must be in a "plain" module.
This event's name is DocumentBeforeClose and can be cancelled, both by the user and by code (see the Cancel parameter in the event signature).
In contrast to AutoClose, if more than one document or template has the event running all will fire - there is no priority or "override".
Class module named clsEvents
Public WithEvents app As Word.Application
Private Sub app_DocumentBeforeClose(ByVal Doc As Document, Cancel As Boolean)
MsgBox "The document " & Doc.FullName & " is being closed."
End Sub
Module
Public myEvents As New clsEvents
Public Sub StartEvents()
Set myEvents.app = Word.Application
End Sub
Public Sub EndEvents()
Set myEvents.app = Nothing
End Sub
Note that if both types of event are present the AutoClose fires after DocumentBeforeClose.
Note also that there is a document-specific event that will fire only for that document: Document_Close. This event must be in the ThisDocument class module of that document.
Private Sub Document_Close()
End Sub
Here are some codes I used to raise an event when the protected Word document is being closed. The purpose is to send a message box BEFORE the preview document is CLOSED. User is able to abort the closing event, modify the document and close the document again. The simpler Word document Document_Close() event handler does not support CANCEL = TRUE.
Step 1. Add following code into a CLASS (codes must be in class module). I named the class as 'EventClassModule', I made a public declaration 'App', these names are referenced in the module.
Public WithEvents App As Word.Application
Private Sub App_DocumentBeforeClose(ByVal Doc As Document, Cancel As Boolean)
If vbYes = MsgBox("Do you need to modify the certificate?", vbYesNo) Then
If ActiveDocument.ProtectionType <> wdNoProtection Then
ActiveDocument.Unprotect
End If
Cancel = True
End If
End Sub
Step 2: Add following code into a module. The class name 'EventClassModule' and the public declaration 'App' are referenced here. The code 'Set X.App = Word.Application' will point to the Word application object, and the event procedures in the class module will run when the events occur.
Dim X As New EventClassModule
Sub abc()
Set X.App = Word.Application
Dim Doc As Word.Document
Set Doc = ActiveDocument
If Doc.ProtectionType <> wdNoProtection Then
Doc.Unprotect
End If
ActiveDocument.Range.Text = Time
Doc.Protect wdAllowOnlyReading
End Sub

Document_Open() does not work in other files

I am writing a VBA project containing 1 module (m1) and 1 userform (uf).
In "ThisDocument" I am calling a public sub from "m1" that initializes a collection I then refer to in the userform. This works perfectly fine until I deploy this project to other files.
I save the file as a .dotm in the %Appdata%/Microsoft/word/startup folder so I can use the project in all of my word files. But as soon as I try to use my project in other files the userform opens itself as designed but the collection is empty.
What could be the problem here?
Manually calling the initialization method from the userform works fine.
'----------------------------------------------ThisDocument
Private Sub Document_Open()
initBetaCollection
End Sub
'----------------------------------------------m1
Option Explicit
Public beta As Collection
Sub initBetaCollection()
Set beta = New Collection
beta.Add Array("0041", "A"), Key:="0041"
'...
End Sub
'----------------------------------------------uf
Option Explicit
Private Sub txtSearch_Change()
Dim arr As Variant
Dim search As String
'Defining the textinput as "search"
search = txtSearch.Value
For Each arr In beta
If search <> "" Then 'No empty search field
If arr(1) Like "*" & search & "*" Then 'Match found
lbResults.AddItem arr(0)
End If
End If
Next
End Sub
I get the: Run Time Error '424' object required
The problem with using Document_Open in the ThisDocument class or a macro named AutoOpen in a regular module is that both execute specifically for this document (or documents created from the template), only.
In order to have an application-level event, that fires for all documents opened, it's necessary to work with application-level events.
For this, first a class module is required. In the class module, the following code is needed:
'Class module named: Class1
Public WithEvents app As Word.Application
Private Sub app_DocumentOpen(ByVal Doc As Document)
'MsgBox Doc.FullName & ": on Open"
'Code here that should fire when a document is opened
'If something needs to be done with this document, use
'the Doc parameter passed to the event, don't try to use ActiveDocument
End Sub
Then, in a regular module, an AutoExec macro can be used to initialize the class with event handling. (AutoExec: fires when Word starts and loads a template with a macro of this name.)
Option Explicit
Dim theApp As New Class1
Sub AutoExec()
'MsgBox "AutoExec"
Set theApp.app = Word.Application
End Sub
'Sub AutoOpen()
' MsgBox "Open in AutoOpen" - fires only for this document
'End Sub

How to detect if user tried to click on save/save as option or pressed ctrl-S in Microsoft word using VBA code?

I want to detect when user press ctrl-S or click on Save option of Microsoft word using VBA excel macro code.
I found related links about Save changes while closing and Detecting if a document is getting close but I not able to find some example code for detecting saving of word document.
Any help would greatly appreciated.
Thanks
Unfortunately (or fortunately) Word does not work like excel and there the keybinding follows different logic. Thus, in Word, you should try something like this, to bind Ctrl + S. The idea is that on openning of the file you tell the application to bind Ctrl + S to the SaveMe Sub.
Option Explicit
Private Sub Document_Open()
With Application
.CustomizationContext = ThisDocument
.KeyBindings.Add KeyCode:=BuildKeyCode(wdKeyControl, wdKeyS), KeyCategory:=wdKeyCategoryCommand, Command:="SaveMe"
End With
End Sub
Public Sub SaveMe()
MsgBox "User Saved"
End Sub
Put the code in ThisDocument:
Until now, it works this way only for Ctrl+S. If you go for the Save through the menu, it will not follow this logic. This is what you should do then:
For the general solution, follow these instructions:
I. Create a clsWord and put the following code inside:
Option Explicit
Public WithEvents appWord As Word.Application
Private Sub appWord_DocumentBeforeSave(ByVal Doc As Document, SaveAsUI As Boolean, Cancel As Boolean)
Call SaveMe
End Sub
II. Change the code in ThisDocument to this:
Option Explicit
Dim myWord As New clsWord
Private Sub Document_Open()
With Application
.CustomizationContext = ThisDocument
.KeyBindings.Add KeyCode:=BuildKeyCode(wdKeyControl, wdKeyS), _
KeyCategory:=wdKeyCategoryCommand, Command:="SaveMe"
End With
Set myWord.appWord = Word.Application
End Sub
III. In a module:
Option Explicit
Public Sub SaveMe()
MsgBox "User Saved"
End Sub
Parts of the ideas are taken from the MSDN here - https://msdn.microsoft.com/en-us/library/office/ff838299.aspx But the code there was not complete :)

DocumentBeforeSave & UserForm autoopen don't work together

Using App_DocumentBeforeSave (in Class1), and Document_New with Call Register_Event_Handler in ThisDocument, I cannot use my usual code to open up a Userform (Autoopen, AutoNew).
How should I place code to allow both DocumentBeforeSave code as well as Userform initiation code?
Sorry for not being more clear. In the template with the working code for changes to a document BeforeSave:
In Microsoft Word Project ThisDocument:
Private Sub Document_Open()
Call Register_Event_Handler
End Sub
Private Sub Document_New()
Call Register_Event_Handler
End Sub
In Modules, Module1:
Dim X As New Class1
Public Sub Register_Event_Handler()
Set X.App = Word.Application
End Sub
In Class Modules, Class1:
Public WithEvents App As Word.Application
Private Sub App_DocumentBeforeSave(ByVal Doc As Document, SaveAsUI As Boolean, Cancel As Boolean)
‘
‘ Then follows my clean up code in this Sub, which also Calls Subs, which are also placed in Class1 under this Sub.
All this works as intended. However, I wrote the code above for all of the Templates we use to generate medical reports, many of which also bring up UserForms upon opening. However, all my templates with UserForms have this code in In Microsoft Word Project ThisDocument to open the Userform whenever the document or template opens:
Sub Autoopen()
Options.ButtonFieldClicks = 1
MACROS.Show
With MACROS
.Top = Application.Top
.LEFT = Application.LEFT
End With
End Sub
Private Sub Document_New()
Options.ButtonFieldClicks = 1
MACROS.Show
With MACROS
.Top = Application.Top
.LEFT = Application.LEFT
End With
End Sub
I cannot get the Userform opening code to work with the initializing code for the DocumentBeforeSave – for one thing they both use Sub Document_New(). I tried changing the Userform opening code to Sub AutoNew(), which still didn’t function.
The Userforms without the DocumentBeforeSave code open fine, and the DocumentBeforeSave code works OK without the Userform code. How do I get both to work in the same project? BTW - the error that occurs: it won't save the project/document.
Thank you.
AutoOpen, AutoNew and AutoSave belong in a "plain vanilla" module. It looks like you've tried putting them in a class, which won't work...

Create macro that updates fields before save

I'm new to VBA and am trying to write a macro that will execute a field update before the user saves the document. My first attempt was going to be intercepting the Save command like this:
Sub FileSave()
'
' FileSave Macro
' Saves the active document or template, and updates fields
'
Fields.Update
ActiveDocument.Save
End Sub
But one guide recommended not doing that and instead using DocumentBeforeSave(), so this is my new attempt:
Private Sub oApp_DocumentBeforeSave(ByVal Doc As Document, _
SaveAsUI As Boolean, Cancel As Boolean)
Fields.Update
End Sub
The first example gives me the following error:
"Runtime error '424': Object required"
The second example doesn't update the fields. I've tried the second code in both the ThisDocument object, and as a new module class. Nevertheless, the fields are still not updating when I save. On a side note, they work with this.
Private Sub Document_Close()
Fields.Update
Save
End Sub
It seems like a simple task but it just doesn't seem to work.
In your ThisDocument code module, add an Application object using the WithEvents keyword so that you can respond to its events:
Dim WithEvents TheApp As Word.Application
Add an event handler for Document_Open() that assigns your variable to the active Application object:
Private Sub Document_Open()
Set TheApp = ThisDocument.Application
End Sub
Add an event handler for Application_DocumentBeforeSave(). Within this event use the Doc object that's passed to it to update your document:
Private Sub TheApp_DocumentBeforeSave(ByVal Doc As Document, SaveAsUI As Boolean, Cancel As Boolean)
Doc.Fields.Update
End Sub
Save your document as a "Macro-Enabled Document (*.docm)".
Close the document and reopen it.
That should be it. If you want to make sure your code is working properly, add a breakpoint or a MsgBox() before your Doc.Fields.Update statement to make sure the event handler is getting called and check your values before and after the update.