TL;DR — To Word, a document is one long run of characters, and a Word
Rangeis just a start and an end position in it. You do not visit cells; you describe a stretch of text and act on it. The working pattern from Excel is: keep the layout in a Word template with placeholders such as{{Client}}, open a copy, replace the placeholders with worksheet values, save, close, quit. Three things break this pattern:Dim r As Rangein Excel means Excel's Range, soSet r = doc.Contentfails with a type mismatch; an unqualifiedActiveDocumentorSelectioncreates a hidden link to Word that fails with error 462 on the second run; and Find and Replace refuses replacement text longer than 255 characters. Qualify every Word object through your own variables and all three go away.
Sub QuickLetter()
Dim wd As Object, doc As Object
Set wd = CreateObject("Word.Application") ' a new, hidden Word
Set doc = wd.Documents.Add(ThisWorkbook.Path & "\Letter.dotx")
doc.Content.Find.Execute FindText:="{{Client}}", _
ReplaceWith:=Range("B2").Value, Replace:=2 ' 2 = wdReplaceAll
doc.SaveAs2 ThisWorkbook.Path & "\Letter_out.docx"
doc.Close
wd.Quit
End Sub
This is the second article in a three-part cluster on driving other Office apps from Excel. The
PowerPoint guide covers a deck, made of shapes on slides. Here, Word: a stream of
text. The References guide explains how VBA learns the other program's vocabulary,
which is exactly where the Range clash below comes from. The rule for all three: every object belongs
to one application, so say which one.
What you'll learn
- The mental model: a document is a run of text and a Range is a pair of positions
- How to start Word, open a template and close everything cleanly
- How to replace placeholders, including text longer than 255 characters
- The
Rangeclash between Excel and Word, and how to avoid it - Why an unqualified
ActiveDocumentcauses error 462 and a leftover WINWORD.EXE - How to paste an Excel table, save as DOCX and export to PDF
The mental model: a run of text, not a grid
Excel addresses a value by row and column. Word has no rows and columns, except inside tables. A Word
document is a sequence of characters, paragraphs marks included, and almost everything is a Range: a start
position and an end position in that sequence.
| You want | Word expression |
|---|---|
| the whole body text | doc.Content |
| one paragraph | doc.Paragraphs(3).Range |
| a marked spot in a template | doc.Bookmarks("Total").Range |
| the end of the document | doc.Content collapsed to its end |
You act on a range by setting its .Text, formatting its .Font, or searching it with .Find. When you
change the text, the positions after it shift, which is why code that remembers character numbers breaks and
code that searches for markers does not.
So the division of work is the same as with PowerPoint: Excel holds the data, Word holds the layout. Design the letter, contract or report in Word, as a template the business can edit, and let the macro put values into it.
Starting Word and finishing cleanly
Unlike PowerPoint, Word starts a new, invisible copy for CreateObject, which the
CreateObject guide describes. That copy is yours, so quitting it is safe. The danger
is the opposite one: if the macro stops on an error before wd.Quit, the invisible Word keeps running, and
the next time the template is opened Word complains that it is locked. Put the clean-up where an error still
reaches it:
Sub MakeLetter()
Const wdExportFormatPDF As Long = 17
Dim wd As Object, doc As Object
On Error GoTo CleanUp
Set wd = CreateObject("Word.Application")
Set doc = wd.Documents.Add(Template:=ThisWorkbook.Path & "\Letter.dotx")
ReplaceTag doc, "{{Client}}", Range("B2").Value
ReplaceTag doc, "{{Amount}}", Format(Range("B3").Value, "#,##0.00")
ReplaceTag doc, "{{Terms}}", Range("B4").Value ' may be a long paragraph
doc.SaveAs2 ThisWorkbook.Path & "\Letter_" & Range("B2").Value & ".docx"
doc.ExportAsFixedFormat OutputFileName:=ThisWorkbook.Path & "\Letter.pdf", _
ExportFormat:=wdExportFormatPDF
CleanUp:
If Not doc Is Nothing Then doc.Close SaveChanges:=False
If Not wd Is Nothing Then wd.Quit
Set doc = Nothing
Set wd = Nothing
If Err.Number <> 0 Then MsgBox "Letter failed: " & Err.Description
End Sub
Documents.Add with a template path creates a new, untitled document based on the .dotx, so the template
itself is never changed. The On Error guide explains the jump to CleanUp. If you want
to watch Word while you develop, add wd.Visible = True after creating it.
Replacing placeholders, and the 255-character wall
Find.Execute with Replace:=2 (wdReplaceAll) is the quick way to swap a placeholder, and for names,
dates and amounts it is all you need. But give it a paragraph of contract terms and it stops with error 5854,
String parameter too long: the replacement text is limited to 255 characters.
The robust version finds each placeholder and writes the text into the found range directly, which has no length limit:
Sub ReplaceTag(doc As Object, ByVal tag As String, ByVal newText As String)
Const wdFindStop As Long = 0
Const wdCollapseEnd As Long = 0
Dim r As Object ' a Word range, NOT Excel's Range
Set r = doc.Content
With r.Find
.ClearFormatting
.Text = tag
.MatchCase = True
.Wrap = wdFindStop
Do While .Execute
r.Text = newText ' r is now the found placeholder
r.Collapse wdCollapseEnd ' continue after what we wrote
Loop
End With
End Sub
When Execute succeeds, the range r moves to the text it found, so setting r.Text replaces exactly the
placeholder. Collapsing to the end lets the loop continue from there, so a value that happens to contain the
tag is not replaced again. Curly-brace tags are easy for the template author to see and impossible to confuse
with real text. Word's content controls and bookmarks work too, but plain tags are the ones non-developers can
maintain.
The Range clash: Excel's Range is not Word's Range
Both programs have an object called Range, and also Shape, Font, Border and Selection. Inside
Excel's VBA, an unqualified Range always means Excel's, because Excel's library sits above Word's in the
priority list. So this fails, even with a reference to Word set:
Dim r As Range ' Excel.Range
Set r = doc.Content ' Run-time error 13: Type mismatch
The fix is to say which application you mean: Dim r As Word.Range with a reference, or Dim r As Object
without one, as in ReplaceTag above. The References guide shows the priority list
that decides what an unqualified name means. The habit is simple: in Excel code, any variable that holds a
Word object is either Word.Something or Object, never a bare name.
Error 462: the hidden link from an unqualified ActiveDocument
The second clash is quieter. With a reference to the Word library set, Excel lets you write Word's global names without any prefix:
Set wd = New Word.Application
wd.Documents.Add
ActiveDocument.Content.Text = "Hello" ' unqualified - works the first time
wd.Quit
The first run works. The second run stops with run-time error 462, The remote server machine does not exist
or is unavailable, or Task Manager shows a WINWORD.EXE that never goes away. The unqualified
ActiveDocument did not go through your wd variable; VBA made its own hidden connection to Word for it.
wd.Quit closed Word, but the hidden connection still points at the closed copy, and it is only cleared when
the VBA project resets.
The rule: reach every Word object through a variable you created. Write wd.ActiveDocument, or better,
keep the document in doc and never use ActiveDocument or Selection at all. Late binding helps here: with
no reference set, an unqualified ActiveDocument is simply an undeclared variable, and
Option Explicit stops it at compile time.
Pasting an Excel table into the document
A table you have already formatted in Excel can go into Word as a real Word table at a bookmark the template author placed:
Sub PasteTable(doc As Object)
Dim target As Object
ThisWorkbook.Worksheets("Summary").Range("A1:D12").Copy
Set target = doc.Bookmarks("SalesTable").Range
target.PasteExcelTable LinkedToExcel:=False, WordFormatting:=False, RTF:=False
Application.CutCopyMode = False
End Sub
LinkedToExcel:=False makes a plain copy, which is right for a letter or report that will be sent. A linked
table breaks as soon as the document leaves your PC. WordFormatting:=False keeps the Excel look; set it to
True to adopt the document's table style instead. For a range that should look exactly like the sheet and
never be edited, CopyPicture and a picture paste, as in the PowerPoint guide, is the
alternative.
Inside Word itself: the same object model
If you searched for Word VBA because you want a macro inside Word, everything above still applies, minus the
bridge. In Word's own VBA editor, ActiveDocument, Range and Selection mean Word's objects, and there is
no wd variable to qualify through. The run-of-text model, the Find loop and the 255-character limit are the
same. What changes is direction: from Word, Excel becomes the foreign program, and the same rules apply to
Excel's Range.
The judgment call: Word for the layout, Excel for the loop
For one letter, either program can do the job. For two hundred, the design decision matters. My rule:
the loop and the data stay in Excel, the layout stays in a Word template, and the macro never formats
text it could have left to the template. Start Word once, create one document per row from the same
.dotx, close each after saving, and quit at the end. That is a mail merge you control, with file names,
PDF output and error handling of your choosing. Word's built-in mail merge is fine for printing one long
merged document; as soon as you need one file per row, the macro wins.
How ExcelMaster helps
Word automation bugs hide in the space between the two programs: a type mismatch on a line that looks right, a WINWORD.EXE that never quits, a contract clause that is too long to replace.
ExcelMaster lets you describe the result, such as "one letter per customer from my template, saved as PDF with the customer name". It writes the macro with every Word object qualified, a placeholder loop with no length limit, and clean-up that runs even when a row fails.
Frequently asked questions
How do I open a Word document from Excel VBA?
Create Word with CreateObject("Word.Application"), then call wd.Documents.Open with the file path, or
wd.Documents.Add with a template path to get a new document based on it. Keep the result in a variable and
work only through that variable.
Why do I get error 462 when automating Word from Excel?
Your code used a Word object without qualifying it, usually ActiveDocument or Selection, so VBA made a
hidden connection to Word. After Quit, that connection points at a closed program. Reach every Word object
through your own wd or doc variable.
Why does Dim r As Range give a type mismatch with Word?
In Excel's VBA, Range means Excel's Range. A Word range is a different type, so assigning
doc.Content to it fails. Declare it as Word.Range with a reference to Word, or as Object without one.
How do I replace text longer than 255 characters in Word with VBA?
Find the placeholder with Range.Find.Execute, then set the found range's .Text to the long value. The
255-character limit only applies to the ReplaceWith argument of Find and Replace, not to Range.Text.
How do I save a Word document as PDF from Excel VBA?
Call doc.ExportAsFixedFormat with an output file name and ExportFormat:=17, which is wdExportFormatPDF.
The document stays open, so close it and quit Word afterwards.
Tested in
Tested in: Excel 365 and Word 365 (Windows 11), VBA 7.1 — last verified 2026-10-02.
Related guides: VBA PowerPoint · VBA References · VBA CreateObject · VBA Outlook · VBA On Error · VBA Option Explicit · VBA Replace · VBA Save as PDF
