I have created a VSTO addin for Word 2016
On a tab in Word I have a number of buttons, but I only want to show some buttons if the name of the document or another property is a certain value.
But I cannot get it to fire when a document is opened.
Am I missing something?
Imports Microsoft.Office.Interop.Word
Public Class ThisAddIn
Dim wordApp = System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application")
Private Sub ThisAddIn_Startup() Handles Me.Startup
End Sub
Private Sub ThisAddIn_Shutdown() Handles Me.Shutdown
End Sub
Private Sub Application_DocumentOpen(Doc As Document) Handles Application.DocumentOpen
MsgBox("opened")
If wordApp.ActiveDocument.BuiltInDocumentProperties("Title").Value = "Posting Slip - Client Receipt" Then
PostClientReceipt.Visible = True
End If
End Sub
End Class
First of all, there is no need to get the Word Application running instance in the following way from your VSTO Word add-in:
Dim wordApp = System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application")
Instead, you can use the Application property of the add-in class. For example:
Globals.ThisAddIn.Application
Second, the DocumentOpen event is fired before the add-in is loaded when you double click the file. Since Word 2010, the Word startup behavior is changed, VSTO runtime waits for Word to be ready before firing the ThisAddIn_Startup event. In this scenario by that time the DocumentOpen and WindowActivate events are already fired.
You may find the DocumentOpen and WindowActivate events do not fire on Word 2010 thread helpful.
As a possible workaround at startup you may check for any opened document and call the DocumentOpen event handler programmatically.
Related
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
I want to perform some text replacements that are just too complicated for Automatic replacement feature of Microsoft outlook. Microsoft has rather extensive documentation on Microsoft Outlook VBA scripting hosted on GitHub.
I started by pressing Alt+F11 which opened Visual Basic Editor. This is what I see in the project explorer:
Please note that I am not VBA programmer, so what I did afterwards probably looks stupid. I figured out that OutlookOutlook namespace represents all Outlook classes, so I just picked one of the classes that sounds like a text field:
Dim WithEvents textField As Outlook.OlkTextBox
And I created a dummy event that should fire before change in text field:
Private Sub textField_BeforeUpdate(Cancel As Boolean)
MsgBox "Nope!"
Cancel = True
End Sub
Of course, when start outlook and edit message, the script doesn't get executed. So I suppose that for starter, I need to get a refference to actual text editor. How do I do that?
My question basically is, how to get this code execute when I try to edit any outlook message:
MsgBox "Nope!"
Cancel = True
Try the write event.
Private WithEvents myItem As MailItem
Private Sub Application_Startup()
Set myItem = ActiveInspector.CurrentItem
End Sub
Private Sub myItem_Write(Cancel As Boolean)
MsgBox "Nope!"
Cancel = True
End Sub
I've got a simple test .pptm file to try to debug the failure of the AfterShapeSizeChange event in PowerPoint 2013 (15.0.4659.1001) on Windows 7 x64.
In a standard module:
Public EH As New ClassEH
' Run to initialise PowerPoint application events
Sub InitApp()
Set EH.App = PowerPoint.Application
End Sub
In a class module with name ClassEH:
Public WithEvents App As PowerPoint.Application
Private Sub App_WindowSelectionChange(ByVal Sel As Selection)
Debug.Print "App_WindowSelectionChange"
End Sub
Private Sub App_AfterShapeSizeChange(ByVal shp As Shape)
Debug.Print "App_AfterShapeSizeChange"
End Sub
After running InitApp, the WindowSelectionChange event is firing as expected with a selection change but the AfterShapeSizeChange event is not firing after changing the size of a shape on the slide.
This event was added in PowerPoint 2013 as per this MSDN article:
http://msdn.microsoft.com/en-us/library/office/jj227375(v=office.15).aspx
Any ideas?
The shape size change fires OK here Jamie. I have 2013 Pro (msi version)
What is the best way within a MailMerge Application Event to access a Document object which has been created by opening a macro-enabled template?
More specifically, I'm writing code for a macro-enabled template Template.dotm. When that template is opened, it creates a new document, usually called Document1, with a reference to Template.dotm.
Here's the ThisDocument module of Template.dotm.
Dim objEventHandler As clsEventHandler
Private Sub Document_New()
Set objEventHandler = New clsEventHandler
Set objEventHandler.AppWithEvents = Word.Application
End Sub
Private Sub Document_Close()
Set objEventHandler = Nothing
End Sub
And here's my event handler class.
Public WithEvents AppWithEvents As Word.Application
Private Sub AppWithEvents_MailMergeBeforeRecordMerge(ByVal Doc As Document, Cancel As Boolean)
'code needs to reference "Document1"
End Sub
Within the MailMergeBeforeRecordMerge procedure, I want to access Document1. This question comes close to addressing this, but not quite.
What doesn't work:
ThisDocument refers to Template.dotm.
ActiveDocument refers to the mailmerge result file.
ActiveDocument.AttachedTemplate might be the way to go, but I haven't figure out how to resolve a Document object from a Template object.
In a pinch, I might loop through open documents and identify it by filename, but I don't know what other documents a user may have open when this is run, so I'd prefer a less breakable strategy.
Many, many thanks for any advice.
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.