Word add-in development in Visual Studio: Application and base objects
Microsoft Word has tons of objects and is a bit underrated when it comes to building Office solutions. My opinion is this is due to the attention Outlook and Excel receive… and rightfully so. But Word is just as powerful as its siblings, if not more so.
In this article (the first in a series of Word development topics), I’ll cover Microsoft Word application and base objects. And, as is our tradition, I’ll provide relevant code samples for Word 2013 – 2000 you can copy and paste into your solutions. You have my permission (otherwise it would be stealing).
- Application – The Word application itself. The mother ship… without her we don’t have Word.
- Document – A Word document… I know, almost needs no explanation.
- Selection – The currently selected content in a document. This one is tricky because it can also be the insertion point.
As you can see in the diagram to the right (which I lifted straight off MSDN), everything else resides beneath these three guys.
Today, we will focus on these three and save all the other hangers-on for another day.
Learning to work with the base objects is the 20% that empowers you to do 80% of what’s needed to make things happen. I’m going to do this in alphabetical order today. Let’s get to the code samples.
The Application object
This sample shows how to change some Word application-level settings. Add-in Express provides the WordApp within our AddinModule for easy access to the Word application.
Public Sub SetMyWordApplicationPreferences() WordApp.DisplayRecentFiles = True WordApp.RecentFiles.Maximum = 1 WordApp.DisplayScreenTips = False WordApp.DisplayScrollBars = True WordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone WordApp.WindowState = Word.WdWindowState.wdWindowStateMaximize WordApp.ActiveWindow.View.ReadingLayout = False End Sub
This routine clears Word just a little bit of distractions and prepares the serious writer for some serious writing. It reduces the recent files list to a single file, turns off screen tips and alerts. It also maximizes the Word window and turns off the reading layout. Ahh… now I’m ready to… ready to do some serious writing.
Microsoft Word exists for users to author documents. It stands to reason, therefore, that the majority of the samples today are document focused.
Word has a documents collection that provides access to all open documents. Using the documents collection, you can do what you want with them (assuming the API supports it that is).
Public Sub EnumerateDocumentsAndCloseWithoutSaving() Dim docs As Word.Documents = Nothing docs = WordApp.Documents For i As Integer = docs.Count To 1 Step -1 docs(i).Close(Word.WdSaveOptions.wdDoNotSaveChanges) Next Marshal.ReleaseComObject(docs) End Sub
Here, I wanted to close all the documents and not save them.
Create a new Word document
To create a new word document, you need to add a new document to the Documents collection.
Public Sub CreateNewDocument(docName As String) Dim newDoc As Word.Document = Nothing newDoc = WordApp.Documents.Add() newDoc.SaveAs2(docName) Marshal.ReleaseComObject(newDoc) End Sub
In the above sample, I go the extra trouble of saving the document using the passed docName.
Create a new document from a template
To create new document based on a template, you do the same thing as we just did except you provide the path to the document template.
Public Sub CreateNewDocumentFromTemplate(templatePath As String) Dim newDoc As Word.Document = Nothing newDoc = WordApp.Documents.Add(templatePath) Marshal.ReleaseComObject(newDoc) End Sub
It’s easy but your users will believe it to be magic. And it is.
Open an existing document
To open a document you can call the Open method of the Documents collection and specify the path to the file you want to open.
Public Sub OpenDocument(docPath As String) Dim doc As Word.Document = Nothing doc = WordApp.Documents.Open(docPath) 'or 'doc = WordApp.Documents.Add(docPath) Marshal.ReleaseComObject(doc) End Sub
You can also just add it to the documents collection.
There is always a selection in Word. Either there is selected content or there is an insertion point (meaning, no content is selected and we are ready to add content. This object provides quick access to the content that is the current focus of the user’s attention.
Private Sub ChangeSelectionFontAndCountWords() Dim selection As Word.Selection = Nothing selection = WordApp.Selection selection.Font.Name = "Arial" selection.Font.Size = 16 MessageBox.Show( _ selection.Words.Count, "Selection Word Count", _ MessageBoxButtons.OK, MessageBoxIcon.Information) Marshal.ReleaseComObject(selection) End Sub
This method changes the font and size of the text in the Selection object. It then displays the Word count in a message box.
Working with the base objects and bending them to your will is one thing. Responding to events when they try to sneak away is another. When you combine the two, well, you are close to building some useful solutions.
Don’t let the name of this event fool you. This event is a Word application event that executes when Microsoft Word creates a new document. It is the place for any setup logic you want to execute against a new document.
Private Sub adxWordEvents_NewDocument(sender As Object, hostObj As Object) _ Handles adxWordEvents.NewDocument Dim doc As Word.Document = Nothing doc = TryCast(hostObj, Word.Document) doc.BuiltInDocumentProperties("Author") = "Me" End Sub
This hostObj is the newly created document. By casting to a Document, I then access the built-in properties and set the Author property.
I really like to see the Navigation Pane when I work with documents. If it is not visible, I immediately click the View tab and enable it. But that’s silly. Why not have some code to do it for me?
Private Sub adxWordEvents_DocumentOpen(sender As Object, hostObj As Object) _ Handles adxWordEvents.DocumentOpen WordApp.ActiveWindow.DocumentMap = True End Sub
This DocumentOpen event executes anytime Word opens a document. Thus, it is the event to respond to and automatically display the navigation pane (aka the DocumentMap)
Does anyone besides accountants and lawyers print documents these days? Heck, anytime I think about printing a document I receive, I feel guilty because lots of people have email signatures that include the phrase “Think before you print.” The DocumentBeforePrint is a good event for doing some last minute checking with the user as it executes right before sending the document to the printer.
Private Sub adxWordEvents_DocumentBeforePrint(sender As Object, _ e As ADXHostBeforeActionEventArgs) _ Handles adxWordEvents.DocumentBeforePrint 'At least think about being green before printing If MessageBox.Show( _ "Do you really want to print the document and contribute to the killing of a few _ trees?", "Think Before You Print", MessageBoxButtons.YesNo) = DialogResult.No Then e.Cancel = True End If End Sub
If the user clicks No, the method sets Cancel=True to cancel the print job. Otherwise, the print continues and a few trees are killed. Oh well, they’ll grow back I suppose. Another good use of this event is to automatically route print jobs to different printers depending on the logic of your choosing.
This event executes right before Word closes the document. It’s a good event for cleaning up the document.
Private Sub adxWordEvents_DocumentBeforeClose(sender As Object, _ e As ADXHostBeforeActionEventArgs) Handles adxWordEvents.DocumentBeforeClose Dim doc As Word.Document = Nothing doc = TryCast(e.HostObject, Word.Document) If doc.Comments.Count > 1 Then If MessageBox.Show( _ "This documents contains comments, do you really want to close it?", _ "Respond to Comments?", MessageBoxButtons.YesNo) = DialogResult.No Then e.Cancel = True End If End If End Sub
In this example, I reference the HostObject of the passed ADXHostBeforeActionEventArgs object. I do it because HostObject is the document that’s closing. After I recast it as a Document, I check for comments and alert the user to them and give them a chance to reconsider.
The Quit event is the place for doing some clean-up.
Private Sub adxWordEvents_Quit(sender As Object, e As EventArgs) _ Handles adxWordEvents.Quit 'Clear the recent docs list While WordApp.RecentFiles.Count > 0 WordApp.RecentFiles.Item(1).Delete() End While End Sub
Continuing my theme of removing distractions, this sample removes all recent files. The NSA can’t track this! Notice that I do not up the count in the loop and always access WordApp.RecentFiles.Item(1). The reason is that each Delete action lowers the count in the RecentFiles collection. Thus, by calling Item(1) each time, I can safely delete each item.
Okay, there you go… that’s Word Application and Base Objects 101. This is enough information and samples to get you started. But, it’s also enough to make you thirst for more. You will not thirst for long as we have a whole series of Beginning Word Development topics set for this month.
This sample Outlook add-in was developed using Add-in Express for Office and .net:
You may also be interested in:
- Creating add-ins for Microsoft Word and Excel(C#, VB.NET)
- Sample Word addin (C#, VB.NET) with source code
Word add-in development in Visual Studio for beginners:
- Part 2: Customizing Word UI – What is and isn’t customizable
- Part 3: Customizing Word main menu, context menus and Backstage view
- Part 4: Creating custom Word ribbons and toolbars
- Part 5: Building custom task panes for Word 2013 – 2003
- Part 6: Working with Word document content objects
- Part 7: Working with Word document designs, styles and printing
- Part 8: Working with multiple Microsoft Word documents
- Part 9: Using custom XML parts in Word add-ins
- Part 10: Working with Word document properties, bookmarks, content controls and quick parts
- Part 11: Populating Word documents with data from external sources
- Part 12: Working with Microsoft Word templates