This post is the second in a series about controlling other applications from Excel using VBA. In the first part we looked at the basics of how to reference other applications using Early Binding or Late Binding. In this post, we will look at how we can automate Word from Excel even though we don’t know any VBA code for Word… yet. The process we will use for this is as follows:
- Enable the Word Developer menu
- Record a Word macro
- Add the code to Excel VBA and amend
- Record macros in Excel if necessary
- Repeat the previous steps until macro complete
I am not an Excel VBA expert (I’m more of an Excel VBA tinkerer), and I am certainly not a Word VBA expert. The process I am about to show you may not create the most efficient code, but I know this process works, because I have used it myself to automate lots tasks using Microsoft Word.
Enable the Word Developer menu
If you have enabled the Excel Developer menu it is the same process in Word.
In Word: File -> Options -> Customize Ribbon
Then tick the Developer Ribbon option, OK.
Record a Word Macro
The key to the success of this method is taking small sections of code and building up a complex macro bit by bit. Using the Word Macro Recorder is again, similar to the Excel Macro recorder.
Click on: Developer -> Record Macro
For the example in this post, we will create a macro which will open a new Word document, then copy a chart from Excel and paste it into that Word document. We will tackle this one stage at a time. Firstly, lets create the macro to open a new word document.
Click – Developer -> Record Macro. The Record Macro window will open.
Make a note of the “Store macro in” option, as we will need to know where to find the recorded code later. Normal.dotm is fine for now. Click OK – the Macro Recorder is now running.
Open a new Word Document – File -> New -> Blank Document
Stop the Macro from recording – Developer -> Stop Recording
We can now view the code for opening a new Word Document in the Visual Basic Editor. Click: Developer -> Visual Basic.
Find the location of your recorded code in the Visual Basic Editor. In this example: Normal -> Modules -> NewMacros.
Your code should look like the following. It may be slightly different, but not significantly.
Sub Macro1() ' ' Macro1 Macro ' ' Documents.Add Template:="Normal", NewTemplate:=False, DocumentType:=0 Windows("Document1").Activate Windows("Document2").Activate End Sub
Add the code to Excel VBA and amend
Let’s head back to the Excel VBA Editor and use the Early Binding method to control to Microsoft Word. In the Visual Basic Editor click Tools -> References select Microsoft Word x.xx Object Library. Then click OK.
As we are using Early Binding we need to declare the Application as a variable as follows:
Dim WordApp As Word.Application Set WordApp = New Word.Application
Now copy and paste the code from the Word VBA Editor into the Excel VBA Editor.
The Word VBA code started with Documents.Add, all we have to do is add our application variable to the front of that line of code. Now becomes WordApp.Documents.Add . . .
Often, Selecting and Activating Objects is not required in VBA code, so I have not copied those statements into the code below.
Sub CreateWordDocument() 'Connect using Early Binding. 'Remember to set the reference to the Word Object Library 'In VBE Editor Tools -> References -> Microsoft Word x.xx Object Library Dim WordApp As Word.Application Set WordApp = New Word.Application WordApp.Documents.Add Template:="Normal", NewTemplate:=False, DocumentType:=0 WordApp.Visible = True 'New Apps will be hidden by default, so make visible Set WordApp = Nothing 'release the memory End Sub
A point to note, when an application is opened with VBA, it is normally opened in the background. To make the Word document visible I have added the following code:
WordApp.Visible = True
Record macros in Excel (if necessary)
If we want to copy Excel content into a Word document, we will need to copy that content using Excel VBA. We can use the Macro Recorder in Excel to obtain the VBA code for copying, then we can use the Word Macro Recorder to obtain the VBA code for pasting.
Macro Recording from Excel – selecting a worksheet and copying chart
Sheets("Sheet1").Select ActiveSheet.ChartObjects("Chart 1").Activate ActiveChart.ChartArea.Copy
Macro Recording from Word – pasting a chart into a document
Selection.PasteSpecial Link:=False, DataType:=wdPasteEnhancedMetafile, _ Placement:=wdInLine, DisplayAsIcon:=False
We can add both Macro recordings into our Excel macro. Remember to add WordApp. at the start of each statement of Word VBA code.
Sub CreateWordDocument() 'Connect using Early Binding. 'Remember to set the reference to the Word Object Library 'In VBE Editor Tools -> References -> Microsoft Word x.xx Object Library Dim WordApp As Word.Application Set WordApp = New Word.Application WordApp.Documents.Add Template:="Normal", NewTemplate:=False, DocumentType:=0 WordApp.Visible = True 'New Apps will be hidden by default, so make visible 'code copied from Excel Macro recorder Sheets("Sheet1").Select Selection.ChartObjects("Chart 1").ChartArea.Copy 'code copied from Word Macro recorder with WordApp. added to the front. WordApp.Selection.PasteSpecial Link:=False, DataType:=wdPasteEnhancedMetafile, _ Placement:=wdInLine, DisplayAsIcon:=False Set WordApp = Nothing 'release the memory End Sub
This code is not particularly efficient; it contains a few unnecessary sections code. However… it works!
Repeat the previous steps until macro complete
By repeating the same steps above; recording short actions, then transferring the code into Excel, we can slowly build up much more complex Macros. The key is to keep the actions short, if you do too many actions with the Macro Recorder, code starts to look long and scary.
If you’ve you tried to use the Macro Recorder before you will know that this is not as easy as it seems. And this simple tutorial may make you think it is easy, when it’s not. Sometimes, it can be quite frustrating trying to find out where the issues and errors are. The key to success is recording very short actions, such as those below and copying them into the Visual Basic Editor.
'Pressing the Enter Key to move to a new line in Word WordApp.Selection.TypeParagraph 'Turn on/off Bold Text WordApp.Selection.Font.Bold = wdToggle 'Change Font Size WordApp.Selection.Font.Size = 16 'Type some text WordApp.Selection.TypeText Text:="Here is some text"
You will soon build up a standard library of code that you can use to control Word for most basic tasks.
In recorded VBA code from Word, the word “Selection” in the code often refers to the document itself. It is possible to make the code a little bit more efficient by declaring the document as a variable. If we were opening a specific document, we could include this at the start, just below the declaration of the application.
'Declare a specific document as a variable Dim WordDocument As Object Set WordDocument = WordApp.Documents.Open(sourceFileName)
Or, if we created a new document we could include the following below the declaration of the application variable.
'Delcare a new document as a variable Dim WordDocument As Object Set WordDocument = WordApp.Documents.Add Template:="Normal", _ NewTemplate:=False, DocumentType:=0
If we have created the document as a variable we can then reference the specific document. This code:
WordApp.Selection.TypeParagraph
Would become this code:
WordDocument.TypeParagraph
Or this code:
WordApp.Selection.TypeText Text:="Here is some text"
Would become this code:
WordDocument.TypeText Text:="Here is some text"
This method is much better, as it doesn’t rely on the Selection of the user being in the right place.
Conclusion
We have seen in this post that it is possible to create complex Macros to automate Word from Excel using VBA. By understanding how to declare variables for the application and documents we can create much more robust macros, even without knowing a lot of VBA code.
Related Posts:
- 5 quick ways to embed a Word document in Excel
- Controlling Powerpoint from Excel using VBA
- Edit links in Word using VBA
- How to link Excel to Word
About the author
Hey, I’m Mark, and I run Excel Off The Grid.
My parents tell me that at the age of 7 I declared I was going to become a qualified accountant. I was either psychic or had no imagination, as that is exactly what happened. However, it wasn’t until I was 35 that my journey really began.
In 2015, I started a new job, for which I was regularly working after 10pm. As a result, I rarely saw my children during the week. So, I started searching for the secrets to automating Excel. I discovered that by building a small number of simple tools, I could combine them together in different ways to automate nearly all my regular tasks. This meant I could work less hours (and I got pay raises!). Today, I teach these techniques to other professionals in our training program so they too can spend less time at work (and more time with their children and doing the things they love).
Do you need help adapting this post to your needs?
I’m guessing the examples in this post don’t exactly match your situation. We all use Excel differently, so it’s impossible to write a post that will meet everybody’s needs. By taking the time to understand the techniques and principles in this post (and elsewhere on this site), you should be able to adapt it to your needs.
But, if you’re still struggling you should:
- Read other blogs, or watch YouTube videos on the same topic. You will benefit much more by discovering your own solutions.
- Ask the ‘Excel Ninja’ in your office. It’s amazing what things other people know.
- Ask a question in a forum like Mr Excel, or the Microsoft Answers Community. Remember, the people on these forums are generally giving their time for free. So take care to craft your question, make sure it’s clear and concise. List all the things you’ve tried, and provide screenshots, code segments and example workbooks.
- Use Excel Rescue, who are my consultancy partner. They help by providing solutions to smaller Excel problems.
What next?
Don’t go yet, there is plenty more to learn on Excel Off The Grid. Check out the latest posts:
Since most users install the full Microsoft Office suite of tools, they have Word and Excel installed on the same computer. You might need to automate Word functionality along with your Excel application. You can automate Word functionality from your Excel VBA code. In this article, we’ll show you how to automate Word functionality from your Excel spreadsheets.
Initializing Word Variables
Before you can use Word in your applications, you need to add it to your references. References are used in programming languages to allow the local application to use the third-party application’s DLLs. Dynamic link libraries (DLLs) are a part of the Windows operating system and any Microsoft application to allow other developers to code for the application. In this case, you want to use Word DLLs, so you must add the reference to your Excel VB application.
In your VBE, you’ll see the Tools menu item. This menu is where you can add references. Click «Tools» and then click «References.» A dialog window opens with a list of available third-party applications. You might be surprised at how many applications you have to choose from. If it’s installed on the local desktop, then you will probably see it in the list. You can use numerous applications in your VBA code, and all you need to do is add a reference to it from this dialog window to get started.
Scroll down to the check box labeled Microsoft Word Object Library. You’ll also see a version number, but this just indicates the version for the DLLs you’ll be using.
Click «OK» and the VBE includes the reference in your project.
With the Word DLLs referenced, you can now use VB code to work with Word automation. First, just like the other code we’ve worked with, we want to create a subroutine. Let’s create a subroutine named WordDoc().
Sub WordDoc()
End Sub
With the subroutine set up, we can now create and initialize Word variables. Take a look at the following code that sets up and defines Word variables.
Sub WordDoc()
Dim word As Word.Application
Dim doc As Word.Document
End Sub
In the above code, we have two variables. You need both of them to work with Word applications. The first one initializes the Word application itself. You need an application variable to work with its DLLs. Next, we created a Word variable for the document component. You need this variable to create, edit and manipulate documents. Just remember that both of these variables are needed when you want to work with Word documents.
With the variables created, we can now assign objects to the variables. Let’s add the variable objects.
Sub WordDoc()
Dim word As Word.Application
Dim doc As Word.Document
Set word = New Word.Application
word.Visible = True
Set doc = word.Documents.Add
End Sub
We added three lines of code. The first one is the instantiation of the Word application class. You know this is an instantiation line of code because it uses the «New» statement.
The next statement makes the Word application visible. When you initialize Word, you can create documents in the background without the application being visible to the user. In this example, we make it visible to the user, so it can be manipulated or edited later. After we make the Word application visible, we now want to add a document to it. In this example, we call the Documents.Add method to add a new document to the open window.
The above code initializes the Word variables, but it essentially adds a new document as well. Once we create the Word document, we can write data to it. We’ll cover opening and writing content to a Word document in the next section.
Opening and Editing Word Documents
Since we’re working with Word documents, you should allow users to open a document manually or auto-open it for them. You can open a file automatically in code, but some applications require that you show the user an open dialog window and let them choose the file that they want to use. In this section, we’ll show you both methods and then show you how to add content to the file.
We need the same variables from the previous section, so let’s copy the code from the first section to our new EditDoc subroutine.
Sub WordDoc()
Dim word As Word.Application
Dim doc As Word.Document
Set word = New Word.Application
word.Visible = True
End Sub
Notice that we took away the «Add» function. We don’t want to add a new document to the application. We want to open an existing document. We know that there are two ways to do this. Let’s first open it in the code without prompting the user for a name.
Sub WordDoc()
Dim word As Word.Application
Dim doc As Word.Document
Set word = New Word.Application
word.Visible = True
word.documents.Open («C:\doc.docx»)
End Sub
In the above code, we use the word variable to open the document in the existing application instance. We open the doc.docx file and add it to our instance.
In many cases, you need to prompt the user to open the file on their hard drive. You don’t need to write your own open dialog window. Microsoft Windows provides you with the tools to open a dialog window. The operating system on the user’s local computer is used to draw and prompt the user. When you open a dialog window, the code’s execution stops until the user chooses a file or clicks the Cancel button.
Let’s remove the auto-open code and add the choice for the user to select a Word document from a dialog window.
Sub WordDoc()
Dim word As Word.Application
Dim doc As Word.Document
Set word = New Word.Application
word.Visible = True
choice = Application.FileDialog(msoFileDialogOpen).Show
End Sub
We added the code that shows a dialog window to the user’s interface. The «Show» command actually displays it to the user. Had we not used the Show method, the user would not see the window. Since the window is an internal Windows function, we use the Application class. Whatever file the user chooses is assigned an integer value and stored in the «choice» variable.
At this point, a file was chosen but it’s not opened yet. We need to add the code to actually open the document in the current Word application instance. Let’s take a look at the code.
Sub WordDoc()
Dim word As Word.Application
Dim doc As Word.Document
Set word = New Word.Application
word.Visible = True
choice = Application.FileDialog(msoFileDialogOpen).Show
If choice <> 0 Then
strPath = Application.FileDialog( _
msoFileDialogOpen).SelectedItems(1)
word.documents.Open (strPath)
End If
End Sub
We added an If statement that first identified that the user chose a file. If the user clicks «Cancel,» then this code would not run and the subroutine would end without doing anything more. If the user clicks a file, it’s given a number to identify it from the other files. The next execution falls in the If statement.
We first assign the path of the file to a string variable. This string variable contains the drive letter and the full path including the directory tree. Notice we use the static value of 1 in the SelectedItems function. This is to indicate that the first file should be retrieved. Users can also choose multiple files at a time. In this example, we only choose the first file since we only want to allow one file to open in the application.
Once the path is assigned to the string variable, we can now open it. The Open method using the word application variable is used. Once this line of code executes, the file is opened and added to the Word application window.
Writing Data to a Word Document
The Word document is now open and activated, so now we can write information to it. Since the focus of this article is to work with Excel data, we’ll show you how to write data from an Excel spreadsheet to the Word document. We can use the existing subroutine that we’ve worked with and add some functionality to it to take data from the spreadsheet cells and send it to the word document.
First, copy the existing subroutine from the previous section.
Sub WordDoc()
Dim word As Word.Application
Dim doc As Word.Document
Set word = New Word.Application
word.Visible = True
choice = Application.FileDialog(msoFileDialogOpen).Show
If choice <> 0 Then
strPath = Application.FileDialog( _
msoFileDialogOpen).SelectedItems(1)
word.documents.Open (strPath)
End If
End Sub
Now, we need to loop through each cell and add data to Word. The following code adds two variables for the loop and the loop to retrieve data.
Sub WordDoc()
Dim word As Word.Application
Dim doc As Word.Document
Set word = New Word.Application
word.Visible = True
choice = Application.FileDialog(msoFileDialogOpen).Show
If choice <> 0 Then
strPath = Application.FileDialog( _
msoFileDialogOpen).SelectedItems(1)
word.documents.Open (strPath)
End If
Dim j As Integer
Dim input As String
For j = 1 To 5
doc.Activate
input = Cells(j + 1, 1)
word.Selection.TypeText Text:= input
word.Selection.TypeParagraph
Next j
End Sub
We created a j variable used for the loop, and the input string variable will be used to store data from the cells we capture.
Note that we first call the Activate function on the doc variable to ensure that the Word document is set to receive data. We then loop through the first 5 rows and assign the input to a property named TypeText. The TypeParagraph property adds a carriage return and line feed to the document.
Once you work with Word documents, you can offer users a way to work with Excel and then export data to Word for reports and other word processing functionality. This coding can be useful when you have users that prefer to send a backup or archive of data to Word for future reports and printouts.
Handling Errors
When you write real-world applications, you must account for unforeseen logic or input errors. These errors cause bugs in your application. If you don’t account for these errors, your application crashes and the Excel file closes. You can imagine that users would be very frustrated with this behavior since they lose any unsaved data. Fortunately, Visual Basic has error handling functionality that lets you send a message to the user, trap the error, and avoid crashing the application. This section discusses error handling and how you can work it into your code.
The On Error Resume Next Statement
The first and most common error handling statement is the On Error Resume Next statement. This statement has two parts.
The On Error statement is used to capture the error when it occurs. If you’re familiar with other languages such as C#, you’ll recognize the try-catch statement. The On Error statement is similar to a try-catch block.
When an error occurs, the On Error statement captures the event and holds it until you tell the compiler what to do with the bug. If you don’t have this statement available, your program crashes.
You must place the On Error statement at the top of your code or where you suspect a bug or error could be thrown. Let’s take a look at some code that uses the On Error Resume Next statement.
On Error Resume Next
j = 1 / 0
If Err.Number <> 0 Then
j = 1
End If
If you recall from basic math rules, you can’t divide any number by 0. We have an On Error Resume Next statement at the top of our code, and then we attempt to divide by 0 and assign the result to a variable. We know this causes an error to our code, so the On Error statement captures it instead of allowing the program to crash. At this point, the Resume Next statement is used. The On Error statement captures the error, and any statement following it tells the compiler what to do next. The Resume Next statement tells the compiler to ignore the error and just continue to the next block of code.
In this example, we identify if an error was captured in the next statement. If the result is 0, no error was captured. In this example, we know that an error occurred, so we then assign the j variable a value of 1.
The On Error Resume Next statement is useful in short blocks of code. The statement has two issues, though. The first one is that the next line of code after any statement must identify if there was an error from the previous statement. This can make your code tedious and complicated.
The next issue is that it forces your code to ignore errors, so you never know if there are any bugs or errors. If we eliminated the If statement in the previous example, the code would execute normally and continue execution without any warning. This can create logic bugs and unintended issues with your application.
The On Error Resume Next statement should be used rarely and only when you know that resuming to the next code statement won’t cause any significant issues with your application.
The On Error Goto Statement
The alternative to the On Error Resume Next statement is to use the On Error Goto statement. Instead of ignoring an error and moving to the next line of code, the Goto statement tells the compiler to jump to a location that specifies how you want to handle the error. This statement makes it much easier to handle errors, because you know the error occurs and control the next block of code that executes.
Let’s take a look at an example using the divide-by-zero code we used in the previous section.
Sub ErrorSample()
On Error Goto ErrHandler
j = 1 / 0
j = 1
MsgBox j
Exit Sub
ErrHandler:
MsgBox «You have an error in your code!»
End Sub
We’ve created an ErrorSample subroutine to demonstrate the way On Error Goto works. We used the same division code, which again throws an error.
Instead of moving to the next line of code, the On Error statement captures the bug and then sends the next execution directive to the label indicated in the Goto statement. In this example, we used the name ErrHandler, but you can give your labels any name. The name you choose for the Goto statement must match the name of the label.
The label code syntax is its name and then a colon. After this colon, the error handling statements are executed. We just used a message box to send a message to the user. In this example, we tell the user that there was an error in the application. Once the error handler runs, no other code in the subroutine runs.
You can test this code by executing the subroutine. Instead of assigning the j variable with the value of 1, the j variable contains no value and the message «You have an error in your code» displays. If no error occurs, the j variable is assigned the value of one and a message box displays the value of j. Of course, we purposely throw an error in this code, so the proper code will never run and the error handler always executes.
This type of error handling is the most popular in VB, so it will be a majority of your error handling code.
You can have multiple labels and error handling statements. Let’ stake a look at some code that uses two error handling blocks.
Sub ErrorSample()
On Error Goto ErrHandler
j = 1 / 0
j = 1
MsgBox j
Exit Sub
ErrHandler:
On Error Goto ErrHandler2
Debug.Print 1/0 ‘this also throws an error
ErrHandler2:
MsgBox «You have an error in your code!»
End Sub
In the code above, we use two labels. The first one catches the original error. We then have another division statement in the error handler. Since this code also throws an error, we need another error handler. This error handler then tells the user that there is a bug in the code.
When you receive an error in your code, the best way to manage it is to use the debugger to step through the code and watch the way the compiler executes each statement. As soon as an error is found, the execution flow jumps to the error handler assigned to the subroutine.
The Resume Statement
We saw the Resume Next statement in the first section, but the Resume statement doesn’t require «Next» to function. The Resume statement simply tells the compiler to resume to the next statement for execution. This statement can be controlled within your error handling blocks.
In the previous sections, we showed you error handlers that displayed a message to the user but then exited the subroutine with no follow-up statements. In many cases, once you trap the error, you want to continue with the rest of the subroutine statements.
For instance, your code could throw an error during a calculation. If the calculation fails you want to tell the user but then use an alternative value or resort to the previous value. Prematurely ending the subroutine could be an issue with some functions.
Luckily, the Visual Basic language has the Resume statement that lets you handle an error and then go back to the subroutines main statements.
Let’s take a look at an example.
Sub ErrorSample()
On Error Goto ErrHandler
Worksheets(«NewSheet»).Activate
Exit Sub
ErrHandler:
If Err.Number = 9 Then
Worksheets.Add.Name = «NewSheet»
Resume
End If
End Sub
In the code above, we work with a new worksheet. We first try to activate the worksheet. If the worksheet does not exist, then the Activate function will throw an error. Without capturing the error, your program would crash and the user would be forced to re-open Excel.
Since we capture the error, the program doesn’t crash. Instead, program execution falls to the ErrHandler label. The error returned is an integer value of 9. You need to look up these values or run through your code using the debugger to identify the right integer value for different errors.
If the error is number 9, then we create a new worksheet and use the Resume statement. The Resume statement tells the error handler to return to the statement that caused the error. In this example, the Activate method for a worksheet named «NewSheet» caused the error. Code execution returns to this line of code. Now that NewSheet does indeed exist, the subroutine is able to activate the worksheet and continue functioning.
This type of error handling is the best way to handle bugs if you’re able to work with it. You won’t always be able to automatically fix the error and return to code execution, but it’s the most convenient for your users.
Error handling is an important factor for good user experiences. These handlers stop your application from crashing, and they allow your users to work with your VBA code without losing any data that they haven’t saved. It’s also a convenient way to trap bugs that would otherwise cause critical logic bugs. Every subroutine should have an error handler label assigned to it even if you don’t think it will throw an error. A common developer mistake is thinking that sections of code could never throw an error. Always write subroutines with error handlers regardless if you think they could never throw an error.
Using Excel VBA to create Microsoft Word documents
In these examples, we generate Microsoft Word Documents with various formatting features using
the Microsoft Excel VBA scripting language. These techniques can have many useful applications.
For instance if you have a list of data like a price or product list in Excel that you want to present
in a formatted Word Document, these techniques can prove useful.
In these examples, we assume the reader has at least basic knowledge of VBA, so we will not
go over basics of creating and running scripts. This code has been tested on Microsoft Word and Excel
2007. Some changes may be required for other versions of Word and Excel.
Writing to Word
Inserting a Table of Contents
Inserting Tabs
Inserting Tables
Inserting Bullet List
more on Inserting Tables
Multiple Features
Function that demonstrates VBA writing to a Microsoft Word document
The following code illustrates the use of VBA Word.Application object and related properties.
In this example, we create a new Word Document add some text.
'In Tools > References, add reference to "Microsoft Word XX.X Object Library" before running. 'Early Binding Dim wdApp As Word.Application Set wdApp = New Word.Application 'Alternatively, we can use Late Binding 'Dim wdApp As Object 'Set wdApp = CreateObject("word.Application") With wdApp .Visible = True .Activate .Documents.Add With .Selection .ParagraphFormat.Alignment = wdAlignParagraphCenter .Font.Bold = True .Font.Name = "arial" .Font.Size = 14 .TypeText ("My Heading") .TypeParagraph End With End With
Some VBA Vocabulary
ParagraphFormat
Represents all the formatting for a paragraph.
output in MS Word:
Inserting a Table of Contents into Word Document using Excel VBA
In this example, we generate a Table of Contents into a Word Document using Excel VBA
Sub sAddTableOfContents() Dim wdApp As Word.Application Set wdApp = New Word.Application 'Alternatively, we can use Late Binding 'Dim wdApp As Object 'Set wdApp = CreateObject("word.Application") Dim wdDoc As Word.Document Set wdDoc = wdApp.Documents.Add ' Note we define a Word.range, as the default range wouled be an Excel range! Dim myWordRange As Word.range Dim Counter As Integer wdApp.Visible = True wdApp.Activate 'Insert Some Headers With wdApp For Counter = 1 To 5 .Selection.TypeParagraph .Selection.Style = "Heading 1" .Selection.TypeText "A Heading Level 1" .Selection.TypeParagraph .Selection.TypeText "Some details" Next End With ' We want to put table of contents at the top of the page Set myWordRange = wdApp.ActiveDocument.range(0, 0) wdApp.ActiveDocument.TablesOfContents.Add _ range:=myWordRange, _ UseFields:=False, _ UseHeadingStyles:=True, _ LowerHeadingLevel:=3, _ UpperHeadingLevel:=1 End Sub
Some VBA Vocabulary
ActiveDocument.TablesOfContents.Add
The TablesOfContents property to return the TablesOfContents collection.
Use the Add method to add a table of contents to a document.
Some TablesOfContents Parameters
Range
The range where you want the table of contents to appear. The table of contents replaces the range, if the range isn’t collapsed.
UseHeadingStyles
True to use built-in heading styles to create the table of contents. The default value is True.
UpperHeadingLevel
The starting heading level for the table of contents. Corresponds to the starting value used with the o switch for a Table of Contents (TOC) field. The default value is 1.
LowerHeadingLevel
The ending heading level for the table of contents. Corresponds to the ending value used with the o switch for a Table of Contents (TOC) field. The default value is 9.
output Word Table in MS Word:
Write Microsoft Word Tabs
A function that writes tabbed content to a Microsoft Word Document. Note in each iteration, we change the
value of the leader character (characters that are inserted in the otherwise blank area created by the tab).
Public Sub sWriteMicrosoftTabs() 'In Tools > References, add reference to "Microsoft Word XX.X Object Library" before running. 'Early Binding Dim wdApp As Word.Application Set wdApp = New Word.Application 'Alternatively, we can use Late Binding 'Dim wdApp As Object 'Set wdApp = CreateObject("word.Application") With wdApp .Visible = True .Activate .Documents.Add For Counter = 1 To 3 .Selection.TypeText Text:=Counter & " - Tab 1 " ' position to 2.5 inches .Selection.Paragraphs.TabStops.Add Position:=Application.InchesToPoints(2.5), _ Leader:=Counter, Alignment:=wdAlignTabLeft .Selection.TypeText Text:=vbTab & " - Tab 2 " ' position to 5 inches .Selection.Paragraphs.TabStops.Add Position:=Application.InchesToPoints(5), _ Leader:=Counter, Alignment:=wdAlignTabLeft .Selection.TypeText Text:=vbTab & " - Tab 3 " .Selection.TypeParagraph Next Counter End With End Sub
Some VBA Vocabulary
.TabStops.Add
Use the TabStops property to return the TabStops collection. In the example above,
nprogram adds a tab stop positioned at 0, 2.5 and 5 inches.
output in MS Word:
Write Microsoft Word Tables
In this example, we generate a Microsoft Table using Excel VBA
Sub sWriteMSWordTable () 'In Tools > References, add reference to "Microsoft Word XX.X Object Library" before running. 'Early Binding Dim wdApp As Word.Application Set wdApp = New Word.Application 'Alternatively, we can use Late Binding 'Dim wdApp As Object 'Set wdApp = CreateObject("word.Application") With wdApp .Visible = True .Activate .Documents.Add With .Selection .Tables.Add _ Range:=wdApp.Selection.Range, _ NumRows:=1, NumColumns:=3, _ DefaultTableBehavior:=wdWord9TableBehavior, _ AutoFitBehavior:=wdAutoFitContent For counter = 1 To 12 .TypeText Text:="Cell " & counter If counter <> 12 Then .MoveRight Unit:=wdCell End If Next End With End With End Sub
Some VBA vocabulary
Table.Add
Table object that represents a new, blank table added to a document.
Table.Add properties
Range
The range where you want the table to appear. The table replaces the range, if the range isn’t collapsed.
NumRows
The number of rows you want to include in the table.
NumColumns
The number of columns you want to include in the table.
DefaultTableBehavior
Sets a value that specifies whether Microsoft Word automatically resizes cells in tables to fit the cells� contents (AutoFit). Can be either of the following constants: wdWord8TableBehavior (AutoFit disabled) or wdWord9TableBehavior (AutoFit enabled). The default constant is wdWord8TableBehavior.
AutoFitBehavior
Sets the AutoFit rules for how Word sizes tables. Can be one of the WdAutoFitBehavior constants.
output in MS Word:
Write Microsoft Word bullet list
In this example, we write with bullet list and outline numbers with Excel VBA
'In Tools > References, add reference to "Microsoft Word XX.X Object Library" before running. 'Early Binding Dim wdApp As Word.Application Set wdApp = New Word.Application 'Alternatively, we can use Late Binding 'Dim wdApp As Object 'Set wdApp = CreateObject("word.Application") With wdApp .Visible = True .Activate .Documents.Add ' turn on bullets .ListGalleries(wdBulletGallery).ListTemplates(1).Name = "" .Selection.Range.ListFormat.ApplyListTemplate ListTemplate:=.ListGalleries(wdBulletGallery).ListTemplates(1), _ continuepreviouslist:=False, applyto:=wdListApplyToWholeList, defaultlistbehavior:=wdWord9ListBehavior With .Selection .ParagraphFormat.Alignment = wdAlignParagraphLeft .Font.Bold = False .Font.Name = "Century Gothic" .Font.Size = 12 .TypeText ("some details") .TypeParagraph .TypeText ("some details") .TypeParagraph End With ' turn off bullets .Selection.Range.ListFormat.RemoveNumbers wdBulletGallery With .Selection .ParagraphFormat.Alignment = wdAlignParagraphLeft .TypeText ("some details") .TypeParagraph .TypeText ("some details") .TypeParagraph End With ' turn on outline numbers .ListGalleries(wdOutlineNumberGallery).ListTemplates(1).Name = "" .Selection.Range.ListFormat.ApplyListTemplate ListTemplate:=.ListGalleries(wdOutlineNumberGallery).ListTemplates(1), _ continuepreviouslist:=False, applyto:=wdListApplyToWholeList, defaultlistbehavior:=wdWord9ListBehavior With .Selection .ParagraphFormat.Alignment = wdAlignParagraphLeft .TypeText ("some details") .TypeParagraph .TypeText ("some details") End With End With
output in MS Word:
Another example of Writing Tables to Microsoft Word
In this example we will create a word document with 20 paragraphs. Each paragraph will have a header with a header style element
'In Tools > References, add reference to "Microsoft Word XX.X Object Library" before running. Dim wdApp As Word.Application Dim wdDoc As Word.Document Set wdApp = New Word.Application wdApp.Visible = True Dim x As Integer Dim y As Integer wdApp.Visible = True wdApp.Activate wdApp.Documents.Add wdApp.ActiveDocument.Tables.Add Range:=wdApp.Selection.Range, NumRows:=2, NumColumns:= _ 2, DefaultTableBehavior:=wdWord9TableBehavior, AutoFitBehavior:= _ wdAutoFitFixed With wdApp.Selection.Tables(1) If .Style <> "Table Grid" Then .Style = "Table Grid" End If .ApplyStyleHeadingRows = True .ApplyStyleLastRow = False .ApplyStyleFirstColumn = True .ApplyStyleLastColumn = False .ApplyStyleRowBands = True .ApplyStyleColumnBands = False End With With wdApp.Selection For x = 1 To 2 ' set style name .Style = "Heading 1" .TypeText "Subject" & x .TypeParagraph .Style = "No Spacing" For y = 1 To 20 .TypeText "paragraph text " Next y .TypeParagraph Next x ' new paragraph .TypeParagraph ' toggle bold on .Font.Bold = wdToggle .TypeText Text:="show some text in bold" .TypeParagraph 'toggle bold off .Font.Bold = wdToggle .TypeText "show some text in regular front weight" .TypeParagraph End With
Some VBA vocabulary
TypeText
Inserts specified text at the beginning of the current selection. The selection is turned into an insertion point at the end of the inserted text.
If Options.ReplaceSelection = True then the original selection will be replaced. This behaves exactly the same as typing some text at the keyboard.
TypeParagraph
Insert a new blank paragraph. The selection is turned into an insertion point after the inserted paragraph mark. If Options.ReplaceSelection = True then the original selection will be replaced. This behaves exactly the same as pressing the Enter key.
output in MS Word:
Generating a Word table with VBA
'In Tools > References, add reference to "Microsoft Word XX.X Object Library" before running. Dim wdApp As Word.Application Dim wdDoc As Word.Document Dim r As Integer Set wdApp = CreateObject("Word.Application") wdApp.Visible = True Set wdDoc = wdApp.Documents.Add wdApp.Activate Dim wdTbl As Word.Table Set wdTbl = wdDoc.Tables.Add(Range:=wdDoc.Range, NumRows:=5, NumColumns:=1) With wdTbl .Borders(wdBorderTop).LineStyle = wdLineStyleSingle .Borders(wdBorderLeft).LineStyle = wdLineStyleSingle .Borders(wdBorderBottom).LineStyle = wdLineStyleSingle .Borders(wdBorderRight).LineStyle = wdLineStyleSingle .Borders(wdBorderHorizontal).LineStyle = wdLineStyleSingle .Borders(wdBorderVertical).LineStyle = wdLineStyleSingle For r = 1 To 5 .Cell(r, 1).Range.Text = ActiveSheet.Cells(r, 1).Value Next r End With
output in MS Word:
Option Explicit Dim wdApp As Word.Application Sub extractToWord() 'In Tools > References, add reference to "Microsoft Word 12 Object Library" before running. Dim lastCell Dim rng As Range Dim row As Range Dim cell As Range Dim arrayOfColumns arrayOfColumns = Array("", "", "", "", "", "", "", "", "", "", "", "", "", "", "") Dim thisRow As Range Dim thisCell As Range Dim myStyle As String ' get last cell in column B lastCell = getLastCell() Set rng = Range("B2:H" & lastCell) 'iterate through rows For Each thisRow In rng.Rows 'iterate through cells in row row For Each thisCell In thisRow.Cells If thisCell.Value = arrayOfColumns(thisCell.Column) Or thisCell.Value = "" Then ' do nothing ''frWriteLine thisCell.Value, "Normal" ''frWriteLine arrayOfColumns(thisCell.Column), "Normal" If thisCell.Value = arrayOfColumns(thisCell.Column) Or thisCell.Value = "" Then End If Else myStyle = "Normal" Select Case thisCell.Column Case 2 myStyle = "Heading 1" Case 3 myStyle = "Heading 2" Case 4 myStyle = "Heading 3" Case Is > 5 myStyle = "Normal" End Select frWriteLine thisCell.Value, myStyle End If arrayOfColumns(thisCell.Column) = thisCell.Value Next thisCell Next thisRow End Sub Public Function getLastCell() As Integer Dim lastRowNumber As Long Dim lastRowString As String Dim lastRowAddress As String With ActiveSheet getLastCell = .Cells(.Rows.Count, 2).End(xlUp).row End With End Function Public Function frWriteLine(someData As Variant, myStyle As String) If wdApp Is Nothing Then Set wdApp = New Word.Application With wdApp .Visible = True .Activate .Documents.Add End With End If With wdApp With .Selection .ParagraphFormat.Alignment = wdAlignParagraphCenter .Style = myStyle .TypeText (someData) .TypeParagraph End With End With End Function
output in MS Word:
In this article, we will see how to access the various word objects using VBA in Excel and insert data from Excel to Word. This has many practical applications such as when you have to fill out a form multiple times with data from Excel or when you have to create a Word document with the same structure but different data each time and so on.
Before we go through individual controls, first let us have a look at how to access a Word document in Excel.
Step 1: Get the name and path of the Word Document that you need to modify. We will use the GetOpenFilename command for that.
fileName = Application.GetOpenFilename(, , "Select the word Document")Step 2: Check to see if Word is already running on the system.
Set oApp = GetObject(, "Word.Application")If Word is not running already, then start it
If Err.Number &amp;amp;amp;amp;amp;lt;&amp;amp;amp;amp;amp;gt; 0 Then Set oApp = CreateObject("Word.Application") End If
Step 3: Assign the selected Word file to a Word object so that we can access it.Set oDoc = oApp.Documents.Open(fileName) oApp.Visible = TrueNow that we know how to access to the Word document, let us see how to access the various controls in Word. In each of the below examples, we will need to add the above code.
Example 1: Bookmarks
In this example, we will see how to insert data from Excel after a bookmark in Word. Let us assume you have a bookmark named “Table1” in Word, where you be inserting a table from Excel. So, for simplicity, we will name that range in Excel as “Table1”.
Step 1: Access the bookmark
Set oBkMrk = oApp.ActiveDocument.Bookmarks("Table1")Step 2: Get the location where you want to insert the data
Set objRange = oBkMrk.Range.Characters.last ‘Position of the last character of the bookmark objRange.Start = objRange.Start + 1 ‘We need to start pasting from the next character
Step 3: Copy the table and paste it at that locationRange(“Table1”).Copy objRange.PasteExcelTable False, False, FalseThe PasteExcelTable method takes 3 arguments: LinkedToExcel, WordFormatting, RTF. We have set them all to False. Once you run the code, the Word Document will look like this
Example 2: Text boxes
In Word, the only way to assign a name to a shape is by using VBA (in contrast to Excel where this can be done using the formula bar). Secondly, Word does not force shapes to have unique names. So, accessing a text box by its name is not a very good option. The approach we will follow is referring to shapes by their index position.
Note: We are referring to text box created using drawing controls (Insert tab)
In this example we will loop through all the text boxes in Word and modify their text.Step 1: So, first loop through all the shapes in the Word document using the .Shapes collection
Step 2: Check if the shape is a textbox
Step 3: Manipulate the .TextFrame.TextRange.Text property, to copy text from Excel.Dim str As String Dim i As Integer i = 1 For Each shp In oDoc.Shapes If shp.Type = msoTextBox Then str = ThisWorkbook.Sheets("Sheet1").Cells(i, 1).Value shp.TextFrame.TextRange.Text = str i = i + 1 End If NextHere the excel values we are using are in column A, and i is used as the counter to directly access column A rows from the Excel. This is how the output will look:
Example 3: Content control Text box from Developer tab
For this we will be using the Title property of a textbox to access it. The title can be set using the properties option of a textbox from the Developer Tab. The code is very similar to that in example 2
For Each cc In oDoc.ContentControls If cc.Title = "Text1" Then cc.Range.Text = "Hello World!" Exit For End If Next ccFor multiple textboxes, you can match the title of the text box to the corresponding range in Excel and easily loop through.
Example 4: Headers and Footers
This code will add Headers and Footers on all the pages of Section 1 of the Word Document. The text can easily be taken from an Excel file.
With oDoc.Sections(1) .Headers.Item(1).Range.Text = "Header text" .Footers.Item(1).Range.Text = "Footer text" End WithHere is how the header and footer will look like.
And here’s all the above code put together for easy reference:Sub copyToWord() Dim oApp As Object 'Word.Application Dim oDoc As Object 'Word.Document Dim sDocName As String Dim path As String Dim fileName As String Dim noOfFields As Integer Dim varName As String Dim wb fileName = Application.GetOpenFilename(, , "Select the word Document") Set wb = ThisWorkbook On Error Resume Next Set oApp = GetObject(, "Word.Application") 'See if word is already running If Err.Number &amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; 0 Then 'Word isn't running so start it Set oApp = CreateObject("Word.Application") End If On Error GoTo Error_Handler_Exit Set oDoc = oApp.Documents.Open(fileName) oApp.Visible = True 'Bookmarks Set oBkMrk = oApp.ActiveDocument.Bookmarks("Table1") Set objRange = oBkMrk.Range.Characters.last objRange.Start = objRange.Start + 1 Range("Table1").Copy objRange.PasteExcelTable False, False, False 'Textbox Dim str As String Dim i i = 1 For Each shp In oDoc.Shapes If shp.Type = msoTextBox Then str = ThisWorkbook.Sheets("Sheet1").Cells(i, 1).Value shp.TextFrame.TextRange.Text = str i = i + 1 End If Next 'Textbox Content Control For Each cc In oDoc.ContentControls If cc.Title = "Text1" Then cc.Range.Text = "Hello World!" Exit For End If Next cc 'Headers and Footers With oDoc.Sections(1) .Headers.Item(1).Range.Text = "Header goes here" .Footers.Item(1).Range.Text = "Footer goes here" End With oDoc.Save Error_Handler_Exit: On Error Resume Next Set oDoc = Nothing Set oApp = Nothing Exit Sub Error_Handler: MsgBox "The following error has occured." &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; vbCrLf &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; vbCrLf &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; _ "Error Number: " &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; Err.Number &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; vbCrLf &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; _ "Error Source: UpdateDoc" &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; vbCrLf &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; _ "Error Description: " &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; Err.Description, _ vbCritical, "An Error has Occured!" Resume Error_Handler_Exit End Sub
Sub ExcelRangeToWord()
‘PURPOSE: Copy/Paste An Excel Table Into a New Word Document
‘NOTE: Must have Word Object Library Active in Order to Run _
(VBE > Tools > References > Microsoft Word 12.0 Object Library)
‘SOURCE: www.TheSpreadsheetGuru.com
Dim tbl As Excel.Range
Dim WordApp As Word.Application
Dim myDoc As Word.Document
Dim WordTable As Word.Table
‘Optimize Code
Application.ScreenUpdating = False
Application.EnableEvents = False
‘Copy Range from Excel
Set tbl = ThisWorkbook.Worksheets(Sheet1.Name).ListObjects(«Table1»).Range
‘Create an Instance of MS Word
On Error Resume Next
‘Is MS Word already opened?
Set WordApp = GetObject(class:=»Word.Application»)
‘Clear the error between errors
Err.Clear
‘If MS Word is not already open then open MS Word
If WordApp Is Nothing Then Set WordApp = CreateObject(class:=»Word.Application»)
‘Handle if the Word Application is not found
If Err.Number = 429 Then
MsgBox «Microsoft Word could not be found, aborting.»
GoTo EndRoutine
End If
On Error GoTo 0
‘Make MS Word Visible and Active
WordApp.Visible = True
WordApp.Activate
‘Create a New Document
Set myDoc = WordApp.Documents.Add
‘Copy Excel Table Range
tbl.Copy
‘Paste Table into MS Word
myDoc.Paragraphs(1).Range.PasteExcelTable _
LinkedToExcel:=False, _
WordFormatting:=False, _
RTF:=False
‘Autofit Table so it fits inside Word Document
Set WordTable = myDoc.Tables(1)
WordTable.AutoFitBehavior (wdAutoFitWindow)
EndRoutine:
‘Optimize Code
Application.ScreenUpdating = True
Application.EnableEvents = True
‘Clear The Clipboard
Application.CutCopyMode = False
End Sub
In this part of the code we are determining if Microsoft Word is open or not. If Word is already open, we can set a variable equal to the entire program by using GetObject. If MS Word is not currently running we can use CreateObject to run an instance of Word and then set a variable equal to that specific instance of MS Word.
When using CreateObject, the target application will start running but it is not visible on screen. Therefore we need to turn the Visible setting on (equal to true). Also, VBA with Word is a little bit different than with Excel in that it is much more dependent on its window showing on screen. Therefore a second command must be written to Activate Microsoft Word.
Copy From Excel, Paste Onto Document
Now that you have a new document created, you can command Excel to paste your table into MS Word. Near the beginning of the code, there was a line that allowed you to specify the exact table you wanted to copy. The variable tbl was used to remember this table range and to allow you to reference the range later on in the code.
Guru Tip: It is a good idea to place code that may need to be manually changed at some point in the future near the beginning of the subroutine. This prevents you from having to scroll through your code and pinpoint the exact place where you spelled out which range you wanted to copy or which worksheet you wanted to pull data from. This can save you a bunch of time and prevent confusion!
Word has a special method called PasteExcelTable, which (as you can guess) allows you paste in an Excel table. There are three variables you can tweak to get you table looking and functioning just the way you want.
-
LinkedToExcel — True links the pasted table to the original Excel file so that changes made to the Excel file are reflected in Microsoft Word.
-
WordFormatting — True formats the table using the formatting in the Word document. False formats the table according to the original Excel file.
-
RTF — True pastes the Excel table using Rich Text Format (RTF). False pastes the Excel table as HTML.
Now for the last step! Depending on how large your table is, it may be spilling outside of your document page. In order to prevent this from happening you can go ahead and use AutoFitBehavior to resize the table to fit perfectly inside your Word document.
About The Author
Hey there! I’m Chris and I run TheSpreadsheetGuru website in my spare time. By day, I’m actually a finance professional who relies on Microsoft Excel quite heavily in the corporate world. I love taking the things I learn in the “real world” and sharing them with everyone here on this site so that you too can become a spreadsheet guru at your company.
Through my years in the corporate world, I’ve been able to pick up on opportunities to make working with Excel better and have built a variety of Excel add-ins, from inserting tickmark symbols to automating copy/pasting from Excel to PowerPoint. If you’d like to keep up to date with the latest Excel news and directly get emailed the most meaningful Excel tips I’ve learned over the years, you can sign up for my free newsletters. I hope I was able to provide you with some value today and I hope to see you back here soon!
— Chris
Founder, TheSpreadsheetGuru.com