Excel VBA操作Word时Runtime Error 438报错求助
Hey there! Let's break down this Runtime Error 438 issue you're hitting with your Excel VBA code.
Why the Error Happens
The error pops up because you're trying to call the SaveAs2 method on the Documents collection (wordapp.documents), but this method only belongs to a single Document object. The Documents collection is just a group of all open Word documents—it doesn't have a SaveAs2 method of its own.
The Quick Fix
You need to assign the opened Word document to a dedicated object variable, then call SaveAs2 on that specific document. Here's how to adjust your code:
- Declare a
Documentvariable at the start of your sub:Dim doc As Object ' Using late binding since you're relying on CreateObject - When opening the document, assign it to this variable:
Set doc = wordapp.documents.Open("C:\temp\SLATemp.docx") - Replace your problematic save line with:
doc.SaveAs2 "C:\temp\SLATemp1.docx"
Bonus: Optimize Your Code (For Better Reliability & Readability)
As a VBA newbie, your replacement logic works, but relying on Selection can be fragile (it depends on cursor position) and repetitive. Here are two key improvements to make your code cleaner:
1. Use Document.Content.Find Instead of Selection
This lets you perform find/replace operations directly on the document content without messing with the selection. For bulk replacements, you can use this pattern:
With doc.Content.Find .ClearFormatting .Replacement.ClearFormatting .Text = "<<ClientName>>" .Replacement.Text = ThisWorkbook.Sheets("Dashboard").Range("C9").Value .Execute Replace:=wdReplaceAll ' Define wdReplaceAll as 2 if using late binding End With
2. Create a Reusable Replacement Sub
Since you're repeating the same find/replace pattern multiple times, wrap it in a sub to eliminate redundant code. Add this to your module:
Sub ReplacePlaceholder(doc As Object, placeholder As String, replacementValue As Variant) Const wdReplaceAll As Long = 2 With doc.Content.Find .ClearFormatting .Replacement.ClearFormatting .Text = placeholder .Replacement.Text = replacementValue .Execute Replace:=wdReplaceAll End With End Sub
Then call it like this in your main sub:
ReplacePlaceholder doc, "<<ClientName>>", ThisWorkbook.Sheets("Dashboard").Range("C9").Value ReplacePlaceholder doc, "<<inrate>>", ThisWorkbook.Sheets("SLA Costing").Range("J20").Value ' ... repeat for all your placeholders
Full Modified Code
Here's your code updated with the fix and optimization:
Sub SLAProposal() Dim wordapp As Object Dim doc As Object ' Initialize Word and open document Set wordapp = CreateObject("Word.Application") Set doc = wordapp.documents.Open("C:\temp\SLATemp.docx") wordapp.Visible = True ' Call reusable replacement sub for each placeholder ReplacePlaceholder doc, "<<ClientName>>", ThisWorkbook.Sheets("Dashboard").Range("C9").Value ReplacePlaceholder doc, "<<inrate>>", ThisWorkbook.Sheets("SLA Costing").Range("J20").Value ReplacePlaceholder doc, "<<afterrate>>", ThisWorkbook.Sheets("SLA Costing").Range("K20").Value ReplacePlaceholder doc, "<<otherrate>>", ThisWorkbook.Sheets("SLA Costing").Range("L20").Value ReplacePlaceholder doc, "<<agreement>>", ThisWorkbook.Sheets("SLA Costing").Range("J7").Value ReplacePlaceholder doc, "<<hours>>", ThisWorkbook.Sheets("SLA Costing").Range("J5").Value ReplacePlaceholder doc, "<<retainer>>", ThisWorkbook.Sheets("SLA Costing").Range("J13").Value ReplacePlaceholder doc, "<<servicedescription>>", ThisWorkbook.Sheets("SLA Costing").Range("K17").Value ReplacePlaceholder doc, "<<hoursval>>", ThisWorkbook.Sheets("SLA Costing").Range("J14").Value ReplacePlaceholder doc, "<<addons>>", ThisWorkbook.Sheets("SLA Costing").Range("J15").Value ReplacePlaceholder doc, "<<total>>", ThisWorkbook.Sheets("SLA Costing").Range("J17").Value ReplacePlaceholder doc, "<<month>>", ThisWorkbook.Sheets("Lookup Table").Range("P1").Value ReplacePlaceholder doc, "<<year>>", ThisWorkbook.Sheets("Lookup Table").Range("P2").Value ReplacePlaceholder doc, "<<maxusers>>", ThisWorkbook.Sheets("SLA Costing").Range("K21").Value ' Save the modified document doc.SaveAs2 "C:\temp\SLATemp1.docx" ' Optional cleanup (good practice to release objects) ' wordapp.Quit ' Set doc = Nothing ' Set wordapp = Nothing End Sub Sub ReplacePlaceholder(doc As Object, placeholder As String, replacementValue As Variant) Const wdReplaceAll As Long = 2 With doc.Content.Find .ClearFormatting .Replacement.ClearFormatting .Text = placeholder .Replacement.Text = replacementValue .Execute Replace:=wdReplaceAll End With End Sub
内容的提问来源于stack exchange,提问作者Steven Nel

