Word VBAを掌握する極限の知見:カスタム文書プロパティによる版管理の完全自動化
開発プロジェクトのリーダーである私たちが、クライアントや他部署へ納品する仕様書、契約書、あるいは社内ニッチな申請書。その「版管理(バージョンコントロール)」はどう行われているだろうか。
ファイル名に `_v1.0.docx` とハードコーディングする。プロパティの「コメント」欄に履歴を手入力する。
――もしあなたが未だにそんな前近代的な手法をとっているなら、今すぐその手を止めてほしい。ファイル名による版管理は、リンク切れ、上書きミス、外部システム連携時のパースエラーの温床であり、プロフェッショナルなエンジニアリングの観点から見れば「技術的負債」でしかない。
Word文書の本質は、ただの「文字の塊」ではない。XML構造化されたコンテナであり、その内部にはメタデータ(文書プロパティ)を安全に保持する領域が標準で備わっている。
今回は、Word VBAの `CustomDocumentProperties` を完全に手なづけ、版管理を完全自動化する「堅牢かつ美しい」実務ソリューションを伝授しよう。
—
1. なぜ「ビルトイン」ではなく「カスタム」プロパティなのか?
Wordには、作成者やタイトルといった「ビルトインプロパティ(BuiltInDocumentProperties)」が存在する。しかし、これらはOfficeのUIから容易にユーザー上書きされてしまい、かつスキーマが固定されているため拡張性がない。
一方、`Document.CustomDocumentProperties` コレクションは、開発者が任意の型(文字列、数値、日付、真偽値)のメタデータを自由に定義・埋め込みできる強力なストレージである。
- 外部システム(Power Automate、Python、C#製バッチ等)からの直接読み取りが可能:Wordファイルを解凍せずとも、OOXML(Open XML)の `custom.xml` をパースすれば、VBAを起動せずにメタデータを抽出できる。
- UI汚染の防止:ユーザーが通常見えない(あるいは編集しにくい)領域にデータを隠蔽できるため、版数の改ざんや誤消去を防げる。
—
2. 実務で直面する「罠」と堅牢な設計アプローチ
VBAでカスタムプロパティを扱う際、アマチュアプログラマーが必ず踏む地雷がある。それは「存在しないプロパティを取得しようとした際の実行時エラー(Error 5: プロシージャの呼び出し、または引数が不正です)」だ。
‘ 【悪手】エラーハンドリングなしの直叩き
Dim ver As String
ver = ActiveDocument.CustomDocumentProperties(“AppVersion”).Value
‘ ↑初回実行時やプロパティ未定義時に容赦なくクラッシュする
プロフェッショナルなコードは、例外を恐れるのではなく、例外が発生しない防御的設計(Defensive Design)を行う。カスタムプロパティの有無を動的に判定し、なければ安全に生成する「Getter/Setterパターン」の関数カプセル化が必須となる。
—
3. 【プロダクションコード】版管理自動化モジュール
以下のコードは、実務の現場でそのままコピー&ペーストして即座に稼働させられる、エンタープライズグレードのVBAモジュールである。
文書の保存(`BeforeSave` イベント等、あるいは明示的なプロシージャ)のタイミングで呼び出すことで、版数のインクリメントとメタデータの同期を完全に自動化する。
Option Explicit
‘ ==============================================================================
‘ 模块名: ModVersionController
‘ 用途: カスタムプロパティを用いた文書の版管理およびメタデータ自動付与
‘ ==============================================================================
Private Const PROP_VERSION As String = “DocumentVersion”
Private Const PROP_LAST_UPDATER As String = “LastUpdater”
Private Const PROP_UPDATED_DATE As String = “LastUpdatedDate”
Public Sub SynchronizeDocumentVersion(Optional ByVal IsMajorUpdate As Boolean = False)
On Error GoTo ErrorHandler
Dim doc As Document
Set doc = ActiveDocument
‘ 1. ドキュメントが保存済みかチェック(新規未保存ファイル対策)
If doc.Path = “” Then
MsgBox “文書が一度も保存されていません。一度保存してから実行してください。”, vbExclamation, “版管理システム”
Exit Sub
End If
‘ 2. プロパティの取得または初期化
Dim currentVer As String
currentVer = GetCustomProperty(doc, PROP_VERSION, “1.0”)
‘ 3. 版数のインクリメントロジック
Dim newVer As String
newVer = CalculateNextVersion(currentVer, IsMajorUpdate)
‘ 4. カスタムプロパティへの書き込み(アトミックな更新)
SetCustomProperty doc, PROP_VERSION, newVer
SetCustomProperty doc, PROP_LAST_UPDATER, Environ$(“USERNAME”) ‘ Windowsログオン名
SetCustomProperty doc, PROP_UPDATED_DATE, Format$(Now, “yyyy-mm-dd hh:nn:ss”)
‘ 5. 文書のフッターや表紙のバージョン表記フィールドを強制更新(必要に応じて)
‘ ※文書内の特定のブックマーク「BM_VERSION」にバージョンを同期させる例
Call UpdateBookmarkText(doc, “BM_VERSION”, “Ver. ” & newVer)
MsgBox “版管理の更新に成功しました。” & vbCrLf & _
“新バージョン: Ver. ” & newVer & vbCrLf & _
“更新者: ” & Environ$(“USERNAME”), vbInformation, “版管理システム”
Exit Sub
ErrorHandler:
MsgBox “版管理の同期中に重大なエラーが発生しました。” & vbCrLf & _
“Error ” & Err.Number & “: ” & Err.Description, vbCritical, “システムエラー”
End Sub
‘ ==============================================================================
‘ 堅牢なプロパティ取得 (Getter)
‘ ==============================================================================
Private Function GetCustomProperty(ByVal doc As Document, ByVal propName As String, ByVal defaultValue As String) As String
Dim prop As DocumentProperty
On Error Resume Next
Set prop = doc.CustomDocumentProperties(propName)
On Error GoTo 0
If prop Is Nothing Then
GetCustomProperty = defaultValue
Else
GetCustomProperty = CStr(prop.Value)
End If
End Function
‘ ==============================================================================
‘ 堅牢なプロパティ設定 (Setter – 存在しない場合は新規作成、存在する場合は上書き)
‘ ==============================================================================
Private Sub SetCustomProperty(ByVal doc As Document, ByVal propName As String, ByVal propValue As String)
Dim prop As DocumentProperty
Dim exists As Boolean
exists = False
On Error Resume Next
Set prop = doc.CustomDocumentProperties(propName)
If Err.Number = 0 Then exists = True
On Error GoTo 0
If exists Then
prop.Value = propValue
Else
‘ 文字列型(msoPropertyTypeString)として新規追加
doc.CustomDocumentProperties.Add _
Name:=propName, _
LinkToContent:=False, _
Type:=msoPropertyTypeString, _
Value:=propValue
End If
End Sub
‘ ==============================================================================
‘ バージョン数値の繰り上げ計算ロジック (例: 1.0 -> 1.1 / メジャーなら 2.0)
‘ ==============================================================================
Private Function CalculateNextVersion(ByVal currentVer As String, ByVal isMajor As Boolean) As String
Dim parts() As String
parts = Split(currentVer, “.”)
Dim majorNum As Long
Dim minorNum As Long
If UBound(parts) >= 1 Then
majorNum = Val(parts(0))
minorNum = Val(parts(1))
Else
majorNum = 1
minorNum = 0
End If
If isMajor Then
majorNum = majorNum + 1
minorNum = 0
Else
minorNum = minorNum + 1
End If
CalculateNextVersion = majorNum & “.” & minorNum
End Function
‘ ==============================================================================
‘ 文書内ブックマークへの同期処理
‘ ==============================================================================
Private Sub UpdateBookmarkText(ByVal doc As Document, ByVal bmName As String, ByVal textValue As String)
If doc.Bookmarks.Exists(bmName) Then
Dim rng As Range
Set rng = doc.Bookmarks(bmName).Range
rng.Text = textValue
‘ ブックマーク範囲を再定義して維持
doc.Bookmarks.Add bmName, rng
End If
End Sub
—
4. 外部システム(Python等)との連携を見据えたアーキテクチャ
この仕組みの真価は、VBA単体で完結しないところにある。
例えば、社内のCI/CDパイプラインや文書管理サーバー(Python製バッチなど)が、Wordファイル(`.docx`)を受け取ったとする。
`.docx` は実態がZIPアーカイブであるため、内部の `docProps/custom.xml` を読み込むだけで、VBAを一切実行せずに以下のメタデータを一瞬で抽出できる。
これにより、「誰が、いつ、何版の文書を提出したか」をデータベースに自動登録するインデックスサーバーをわずか数十行のPythonスクリプトで構築可能になる。ファイル名に依存しない、完全なメタデータ駆動型のドキュメント管理エコシステムが完成するのだ。
—
総括
プログラミングにおける「自動化」とは、単に手作業の手間を減らすことではない。「ヒューマンエラーが入り込む余地をシステム的に根絶し、データの信頼性を担保すること」に他ならない。
今回解説した `CustomDocumentProperties` を活用した版管理の自動化は、あなたのチームのドキュメントワークフローを次のステージへと引き上げる確かな武器となる。
属人化した手作業の運用からは今すぐ脱却し、コードによる洗練された統制を実装してほしい。
