word 2003 vba bug? DocumentBeforePrint execute twice? - vba

Is this a Word 2003 VBA bug? DocumentBeforePrint executes multiple times?
I reference
http://msdn.microsoft.com/en-us/library/office/aa211873(v=office.11).aspx
http://msdn.microsoft.com/en-us/library/office/aa211915(v=office.11).aspx
DocumentBeforeClose syntax
I make a test.dot with macro DocumentBeforePrint.
'ref http://msdn.microsoft.com/en-us/library/office/aa211915(v=office.11).aspx
Dim X As New EventClassModule
Sub Register_Event_Handler()
Set X.appWord = Word.Application
End Sub
Private Sub Document_New()
Call Register_Event_Handler
End Sub
Private Sub Document_Open()
Call Register_Event_Handler
End Sub
'ref http://msdn.microsoft.com/en-us/library/office/aa211873(v=office.11).aspx
Public WithEvents appWord As Word.Application
Private Sub appWord_DocumentBeforePrint _
(ByVal Doc As Document, _
Cancel As Boolean)
MsgBox "WORKING!"
End Sub
When I press Ctrl+P, the macro executes.
There is a bug. When I double click test.dot to generate two word files (a.doc/b.doc).
Press Ctrl+P,the DocumentBeforePrint will execute twice.
If I generate 3 word files, Press Ctrl+P, the Macro will execute three times.
What's wrong? I just want to execude once.

It appears you have put all the code except the printing code in the ThisDocument code module. This is incorrect. Because you put ^Dim X as NewEventClassModuleinThisDocument`, which is, itself, a class module representing each document, multiple instances were being created. Declaring it in a "plain module" doesn't cause this problem.
You need three modules:
"Plain" module:
Dim X As New EventClassModule
Sub Register_Event_Handler()
Set X.appWord = Word.Application
End Sub
"ThisDocument" module:
Private Sub Document_New()
Register_Event_Handler
End Sub
Private Sub Document_Open()
Register_Event_Handler
End Sub
"EventClassModule"
Public WithEvents appWord As Word.Application
Private Sub appWord_DocumentBeforePrint _
(ByVal Doc As Document, _
Cancel As Boolean)
MsgBox "WORKING!"
End Sub

Related

Template addin crashes Word in Windows 10 /Office 365 only

Windows 8 Machine (works):
Microsoft Office Professional Plus 2013
Windows 10 Machine (doesn't work):
Microsoft Office 365
Template (.dotm file) gets placed in Startup folder for Word.
When I start Word I am presented with a blank screen. Clicking on "File" causes Word to exit immediately with no error message.
The add-in has a module called MainModule and a class called WordApp. AutoExec fires up a loop which calls a dummy function.
MainModule:
'event processor class instance
Dim myWordApp As WordApp
Sub Register_Event_Handler()
Set myWordApp.appWord = Word.Application
End Sub
'gets executed automatically
Sub AutoExec()
Set myWordApp = New WordApp
Call MainProgram
End Sub
Sub MainProgram()
Register_Event_Handler
Do While True
testFunction
DoEvents
Loop
End Sub
'dummy function gets called in loop
Private Sub testFunction()
Dim i As Integer
i = 0
i = i + 1
End Sub
WordApp class:
Public WithEvents appWord As Word.Application
'fires upon closing word
Private Sub appWord_DocumentBeforeClose(ByVal Doc As Document, Cancel As
Boolean)
MsgBox "Closing"
End Sub

Outlook events not firing

I'm trying to send an email based on a calendar reminder going off.
I'm having trouble getting VBA macros to recognize that an Outlook event has occurred.
I put this code in a Class Module:
Public WithEvents myOlApp As Outlook.Application
Sub Initialize_handler()
Set myOlApp = Outlook.Application 'also tried with double quotes around "Outlook.Application"
End Sub
Private Sub myOlApp_Reminder(ByVal Item As Object)
MsgBox ("test")
End Sub
Private Sub myOlApp_NewMail()
MsgBox ("test")
End Sub
When I get a new email or a reminder goes off, nothing happens.
I've tested with this macro in a normal module and it works:
Sub MsgBoxTest()
MsgBox ("test")
End Sub
I have macro settings on "Enable all macros" in the Trust Center.
I've searched google, stackoverflow, a bunch of other websites, and read the documentation on Microsoft.com.
I'm on Outlook 2016 on a PC running Windows 10 Enterprise.
A class module is just a blueprint for an object. A class module doesn't exist all by itself, at runtime a class module is just a type that an object variable can be declared as.
Your code is fine (leaked public field aside).
You're just missing an instance of that class. Keep the class and make ThisOutlookSession create an instance of it:
'[ThisOutlookSession]
Option Explicit
Private AppEvents As AppEventsHandler
Private Sub Application_Startup()
Set AppEvents = New AppEventsHandler
End Sub
Private Sub Application_Quit()
Set AppEvents = Nothing
End Sub
VBA classes fire an Initialize event on creation, and a Terminate event on destruction. Handle them to set your Private WithEvents field:
'[AppEventsHandler] (class module)
Option Explicit
Private WithEvents app As Outlook.Application
Private Sub Class_Initialize()
Set app = Outlook.Application
End Sub
Private Sub Class_Terminate()
Set app = Nothing
End Sub
Private Sub app_NewMail()
'TODO handle app event
End Sub
Private Sub app_Reminder(ByVal Item As Object)
'TODO handle app event
End Sub
'...more handlers...
That's it - now you're handling Outlook.Application events in a dedicated class, without polluting ThisOutlookSession with the nitty-gritty details of every event handler out there.
For this method, often used in documentation, run Initialize_handler manually or run it at startup in the special class module ThisOutlookSession.
Private Sub Application_Startup()
Initialize_handler
End Sub
In order to handle Reminder events, you need to enclose your code in a Sub named "Application_Reminder"
Try this:
Option Explicit
Private Sub Application_Reminder(ByVal Item As Object)
MsgBox "Test"
End Sub

How to schedule an async macro from WORD

I'm facing an annoying issue where I simply want to schedule an asynchronous macro from another instance of Word, which happens to be the same .doc file.
Meaning, in the ThisDocument namespace I have the following code snippet:
Public Sub Document_Open()
Set Obj = New Word.Application
Obj.OnTime Now + TimeValue("00:00:01"), "Module1.Test"
End Sub
I've declared a new object of Word due to the following reasons:
My macro may block user's I\O
The user may close the document before the macro finishes its task
And declared a module named Module1 with a simple MsgBox
Public Sub Test()
MsgBox "hhh"
End Sub
Needless to say, nothing happened, and I'm unable to check what OnTime function returns.
I've also tried the following combinations:
"!Module1.Test"
"c:\\....\\file.doc!Module1.Test"
What am I missing here?
Your newly created Word application, represented by a Word.Application object, doesn't have the document open. Thus there's no "Module1" as far as he's aware. The fact that you want to run code from the same document is immaterial. It's a different instance of Word.
Something like this works:
'''''''' ThisDocument
Option Explicit
Private Sub Document_Open()
Dim res As VbMsgBoxResult
Dim Obj As Word.Application
If Application.Visible Then
res = MsgBox("Hello", vbOKCancel, "Hi!")
Else
Exit Sub
End If
If res = vbOK Then
Set Obj = New Word.Application
Obj.Documents.Open "C:\Users\conio\Desktop\Hello.docm", , True
Obj.OnTime Now + TimeValue("00:00:01"), "Module1.Foo"
End If
End Sub
'''''''' Module1
Public Sub Foo()
If Not Application.Visible Then
MsgBox "Foo"
Application.Quit
End If
End Sub
Maybe you'd want to use a different check to differentiate between the interactive run and the unattended run.

Using Events with the Application Object in MS Word

Ms Word does not want to load my add-in. I want to call a userform on print event. Here is my code:
in module 1
Option Explicit
Private Sub App_DocumentBeforePrint(ByVal Doc As Document, Cancel As Boolean)
'Debug.Print Now & " " & "App_DocumentBeforePrint: " & Wb.FullName
Userform1.Show
End Sub
Sub InitializeApp()
Dim X As New EventClassModule
Set X.App = Word.Application
End Sub
in Document module
Private Sub Document_Open()
Call InitializeApp
End Sub
in EventClassModule
Public WithEvents App As Word.Application
in Userform1 Mode
Option Explicit
Private Sub UserForm1_Initialize()
End Sub
I used this 2 links to help me write this code
1) https://msdn.microsoft.com/en-us/library/bb221264%28v=office.12%29.aspx
2) https://msdn.microsoft.com/en-us/library/gg597509%28v=office.14%29.aspx
Can anyone tell why my code does not work?
As explained in the first link you show, the procedure App_DocumentBeforePrint needs to be in the CLASS module (EventClassModule, in your explanation), not in Module 1.
Other than that, it's not clear what you mean by "my add-in". Usually, I'd think of a template (or COM add-in) when this term is used that's being loaded as an add-in. I'm concerned whether Document_Open is actually being triggered to initialize your events. This event, in the ThisDocument module (in reality, it's a class) will only fire when the document containing this code is opened...
For anybody else who comes across this thread like I did, this is what worked for me:
in module 1
(your module shouldn't contain the event-based sub; also, X needs to be declared as a global variable rather than within the 'InitializeApp' sub)
Option Explicit
Dim X As New EventClassModule
Sub InitializeApp()
Set X.App = Word.Application
End Sub
in Document module
Private Sub Document_Open()
Call InitializeApp
End Sub
in EventClassModule
(your Class Module should contain the event-based sub)
Public WithEvents App As Word.Application
Private Sub App_DocumentBeforePrint(ByVal Doc As Document, Cancel As Boolean)
'''Your procedure here
End Sub

Call UserForm on Save

How do I go about calling a userform in VBA when user clicks on the Save button in MS Word?
You have two options to do that: You can either override the built-in FileSave and FileSaveAs commands, or you can create an event handler for the application's DocumentBeforeSave event (which is a little more work to do).
Overriding the built-in commands can be accomplished by adding the following code to a VBA module (adjust the type of the user form to be displayed accordingly):
' override File -> Save
Public Sub FileSave()
CustomSave
' call ActiveDocument.Save to actually save the document
End Sub
' override File -> Save As...
Public Sub FileSaveAs()
CustomSave
' call ActiveDocument.SaveAs to actually save the document
End Sub
Sub CustomSave()
Dim frm As New frmCustomSave
frm.Show
End Sub
The second option can be implemented by placing the following code under Microsoft Word Objects -> ThisDocument in the VBA editor:
Option Explicit
Private WithEvents wdApp As Word.Application
Private Sub Document_New()
Set wdApp = Word.Application
End Sub
Private Sub Document_Open()
Set wdApp = Word.Application
End Sub
Private Sub wdApp_DocumentBeforeSave(ByVal Doc As Document, SaveAsUI As Boolean, Cancel As Boolean)
Dim frm As New frmCustomSave
frm.Show
End Sub
See Intercepting events like Save and Print for an example that should help.