Excel の一覧から Word の文書を差し込み作成し、PDF で保存する
Excel の送付先一覧をもとに、Word テンプレートのブックマークや置換用の文字列へ値を入れて1件ずつ文書を作り、PDF で保存するマクロです。Word を確実に終了させる書き方も解説します。
どんな場面で使うか
案内状、契約更新のお知らせ、受講証明書など、文面は同じで宛名や金額だけが変わる文書を毎月何十通も作る作業があります。Word の差し込み印刷機能でも作れますが、「1件ずつ別の PDF ファイルにしたい」「ファイル名に顧客コードを付けたい」といった要望には手作業が残りがちです。
このマクロは、Excel の一覧を1行ずつ読み、Word のテンプレートから新しい文書を作って値を差し込み、PDF として保存します。レイアウトの調整は Word 側で行い、データは Excel 側で管理する、という役割分担ができるのが利点です。
テンプレートの準備
差し込む位置の指定方法は2通りあります。1つは Word の「挿入」→「ブックマーク」で位置に名前を付ける方法、もう1つは本文に「{顧客名}」のような目印の文字列を書いておき、置換する方法です。ブックマークは見た目に影響せず位置を正確に指定でき、置換は同じ値を文書内の複数箇所に入れたいときに便利です。この記事では両方を使います。
一覧は「送付先」シートとし、次の列構成を例にします(説明用の架空の構成です)。テンプレートはマクロのブックと同じフォルダに置きます。
- A列:顧客コード
- B列:顧客名
- C列:担当者名
- D列:契約更新日
- E列:更新後の月額
コード
Word は CreateObject で起動するため、参照設定は不要です。そのかわり Word 側の定数(wdReplaceAll など)は使えないので、数値で指定しています。エラーが起きても Word が裏で起動したまま残らないよう、後始末の処理を必ず通る構成にしています。
Sub CreateWordDocs()
Const TEMPLATE_FILE As String = "更新案内_テンプレート.docx"
Dim ws As Worksheet, data As Variant, lastRow As Long, i As Long
Dim wdApp As Object, wdDoc As Object
Dim outDir As String, pdfPath As String, created As Long, msg As String
Set ws = ThisWorkbook.Worksheets("送付先")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
If lastRow < 2 Then MsgBox "データがありません": Exit Sub
data = ws.Range("A2:E" & lastRow).Value
outDir = ThisWorkbook.Path & "\PDF出力\"
If Dir(outDir, vbDirectory) = "" Then MkDir outDir
On Error GoTo ErrHandler
Set wdApp = CreateObject("Word.Application")
wdApp.Visible = False
For i = 1 To UBound(data, 1)
If Trim(CStr(data(i, 1))) <> "" Then
' テンプレートを直接開かず、テンプレートをもとに新規文書を作る
Set wdDoc = wdApp.Documents.Add(Template:=ThisWorkbook.Path & "\" & TEMPLATE_FILE)
SetBookmarkText wdDoc, "CustName", CStr(data(i, 2))
SetBookmarkText wdDoc, "StaffName", CStr(data(i, 3))
ReplaceAllText wdDoc, "{更新日}", Format(data(i, 4), "yyyy年m月d日")
ReplaceAllText wdDoc, "{月額}", Format(data(i, 5), "#,##0")
pdfPath = outDir & data(i, 1) & "_" & data(i, 2) & ".pdf"
wdDoc.ExportAsFixedFormat OutputFileName:=pdfPath, ExportFormat:=17 ' 17 = PDF
wdDoc.Close SaveChanges:=False
Set wdDoc = Nothing
created = created + 1
End If
Next i
Cleanup:
On Error Resume Next
If Not wdDoc Is Nothing Then wdDoc.Close SaveChanges:=False
If Not wdApp Is Nothing Then wdApp.Quit
Set wdDoc = Nothing
Set wdApp = Nothing
On Error GoTo 0
If msg <> "" Then
MsgBox created & " 件作成したところでエラーが発生しました:" & msg
Else
MsgBox created & " 件の PDF を作成しました"
End If
Exit Sub
ErrHandler:
msg = Err.Description
Resume Cleanup
End Sub
' ブックマークの位置に文字を入れる(入れたあともブックマークを残す)
Private Sub SetBookmarkText(ByVal doc As Object, ByVal bmName As String, ByVal txt As String)
Dim rng As Object
If doc.Bookmarks.Exists(bmName) Then
Set rng = doc.Bookmarks(bmName).Range
rng.Text = txt
doc.Bookmarks.Add bmName, rng
End If
End Sub
' 文書全体の目印の文字列をすべて置き換える
Private Sub ReplaceAllText(ByVal doc As Object, ByVal findText As String, ByVal newText As String)
With doc.Content.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = findText
.Replacement.Text = newText
.MatchWildcards = False
.Execute Replace:=2 ' 2 = すべて置換
End With
End Subコードのポイント
Documents.Add の引数にテンプレートのパスを渡すと、テンプレートを複製した新しい文書が作られます。Documents.Open でテンプレートを直接開いて書き換えると、誤って上書き保存したときに原本が壊れるため、この書き方が安全です。
ブックマークの範囲に文字を入れると、元のブックマークは消えてしまいます。SetBookmarkText では入れた文字の範囲に同じ名前のブックマークを付け直しているので、あとから同じ文書に再度差し込む処理を加えても動きます。
後始末は「Cleanup」の部分にまとめ、正常に終わったときもエラーのときも必ずここを通るようにしています。エラー処理の中で Resume Cleanup を使うと、エラー処理の状態が解除されてから後始末に進むため、後始末の途中でもう一度エラーが起きてもマクロが止まりません。
つまずきやすい点
Word を Quit せずにマクロが止まると、画面には見えない Word がタスクマネージャーに残り、次回の実行でテンプレートが「使用中」になるなどの不具合の原因になります。開発中に何度も止めた場合は、タスクマネージャーで WINWORD.EXE が残っていないか確認してください。
- 置換後の文字列は255文字までという制限があるため、長い文章はブックマークで差し込む
- ファイル名に使えない記号(\ / : * ? < > | など)が顧客名に含まれると保存に失敗する
- ブックマーク名は英字で始める必要があり、空白は使えない
- 参照設定を使わないので wdFormatPDF などの Word の定数名は書けない(数値で指定する)
※Word がインストールされている Windows 環境を前提としています。作成した文書を送付する前に、数件を開いて差し込み結果を確認してください。