【Visio VBA極限解説】Document.CustomDocumentPropertiesを支配せよ:図面メタデータの自動統御と一括管理
開発現場でこんな絶望を味わったことはないか?
「どのバージョンの図面が最新か分からない」
「手動でプロパティを更新し忘れたせいで、古い仕様書のまま製造ラインが動きかけた」
「何百枚もある図面ファイルを1つずつ開いて作成部署や版数を確認する地獄の作業…」
Visioを単なるお絵かきツールだと思っているうちは、図面の管理にエンジニアの貴重な時間が奪われ続ける。
Visioには、図面ファイル(`.vsdx`)そのものにデータを埋め込み、一元管理するための強力な機構が備わっている。それが `Document.CustomDocumentProperties` だ。
今回は、このドキュメントレベルのカスタムプロパティをVBAで完全に掌握し、ファイルオープン時や保存時にメタデータ(版数・作成部署・更新日時)を自動同期・統御する「プロダクションコード」を授ける。
—
1. なぜ「Shape」ではなく「Document」なのか?
初心者がやりがしなミスが、図面内の特定のシェイプにバージョン情報を持たせることだ。
「タイトルブロック(表題欄)のシェイプのテキストを読み書きすればいいや」と考えてはならない。
シェイプは削除されたり、レイアウト変更で消失したり、別ページにコピーされたりするリスクがある。
図面の「メタデータ(誰が、いつ、何版作ったのか)」は、シェイプという流動的な存在に依存させてはならず、ドキュメント自体の不変の領域に持たせるべきだ。
ここで登場するのが `Document.CustomDocumentProperties` コレクションである。これはExcelの「ブックのプロパティ」やWordの「ドキュメント情報面板」に相当し、図面ファイルそのものに付随する。ファイル一覧を取得する外部ツール(PowerShellやC#アプリなど)からも、Visioの図面を開くことなく高速に読み取れるという圧倒的なアドバンテージを持つ。
—
2. 堅牢なメタデータ管理クラスの設計思想
実務で使えるコードを書くうえで、以下の「プロの鉄則」を厳守する。
1. 存在チェックと動的追加(Get or Create)
カスタムプロパティは、初回実行時には存在しない。そのため「存在すれば更新、なければ新規追加」というロジックをカプセル化する必要がある。エラーハンドリングに頼るな、ロジックで防げ。
2. イベントドリブンな自動化
ユーザーに「メタデータを更新してください」と頼ってはいけない。`ThisDocument` モジュールを使い、保存時(`BeforeSave`)やオープン時に自動発火させる。
3. トランザクション的思考
メタデータの書き込み失敗が図面の保存そのものを阻害してはならない。適切なエラーハンドリングでシステムをクラッシュから守る。
—
3. 実装コード:一撃で図面メタデータを統御するプロダクションコード
以下のコードを、VisioのVBAエディタにおける対象図面の `ThisDocument` モジュール にそのまま貼り付けろ。
【ThisDocument モジュール】
Option Explicit
‘ =================================================================
‘ 変更履歴・メタデータ自動管理エンジン
‘ アーキテクト設計:Document.CustomDocumentProperties 統御モジュール
‘ =================================================================
‘ ドキュメントが開かれた時のイベント
Private Sub Document_DocumentOpened(ByVal Doc As Visio.Document)
On Error GoTo ErrorHandler
‘ 閲覧時はアクセスログや最終閲覧日を更新するなどの処理をここに記述
Debug.Print “図面オープン: ” & Doc.Name & ” (版数: ” & GetMeta(Doc, “DrawingVersion”) & “)”
Exit Sub
ErrorHandler:
Debug.Print “DocumentOpened Error: ” & Err.Description
End Sub
‘ ドキュメント保存時のイベント(メタデータの自動更新)
Private Sub Document_BeforeSave(ByVal Doc As Visio.Document)
On Error GoTo ErrorHandler
‘ 読み取り専用ファイルの場合は処理をスキップ
If Doc.ReadOnly Then Exit Sub
‘ 1. 更新日時の自動スタンプ
Call SetMeta(Doc, “LastUpdatedDate”, Format(Now, “yyyy-mm-dd hh:nn:ss”))
‘ 2. 保存ユーザーの自動記録(環境変数等から取得も可能)
Call SetMeta(Doc, “LastUpdatedBy”, Environ(“USERNAME”))
‘ 3. 版数の整合性チェック(必要に応じてインクリメントロジックをここに組み込む)
If Not ExistsMeta(Doc, “DrawingVersion”) Then
Call SetMeta(Doc, “DrawingVersion”, “Rev.01”) ‘ 初期値
End If
Debug.Print “メタデータ自動同期完了: ” & Doc.Name
Exit Sub
ErrorHandler:
MsgBox “メタデータの自動保存処理に失敗しました: ” & Err.Description, vbCritical, “メタデータ管理システム”
End Sub
‘ =================================================================
‘ コア・ユーティリティ関数群(カプセル化)
‘ =================================================================
/
- 指定したカスタムプロパティの値を取得する(存在しない場合は空文字を返す)
/
Public Function GetMeta(ByVal Doc As Visio.Document, ByVal PropName As String) As String
On Error GoTo NotFound
Dim prop As Object
Set prop = Doc.CustomDocumentProperties(PropName)
GetMeta = CStr(prop.Value)
Exit Function
NotFound:
GetMeta = “”
End Function
/
- 指定したカスタムプロパティが存在するか判定する
/
Public Function ExistsMeta(ByVal Doc As Visio.Document, ByVal PropName As String) As Boolean
On Error GoTo NotExist
Dim dummy As Variant
dummy = Doc.CustomDocumentProperties(PropName).Value
ExistsMeta = True
Exit Function
NotExist:
ExistsMeta = False
End Function
/
- カスタムプロパティを設定する(存在しない場合は新規作成、存在する場合は値を更新)
/
Public Sub SetMeta(ByVal Doc As Visio.Document, ByVal PropName As String, ByVal PropValue As String)
On Error GoTo CreateNew
‘ 既存のプロパティの値を更新
Doc.CustomDocumentProperties(PropName).Value = PropValue
Exit Sub
CreateNew:
‘ 存在しない場合は新規追加 (msoPropertyTypeString = 4)
On Error GoTo AddError
Doc.CustomDocumentProperties.Add Name:=PropName, _
LinkToSource:=False, _
Type:=4, _
Value:=PropValue
Exit Sub
AddError:
Err.Raise Err.Number, “SetMeta”, “プロパティの追加に失敗しました: ” & PropName & ” / ” & Err.Description
End Sub
—
4. コードの急所:なぜこの実装が「プロ」なのか?
① 型安全性の担保 (`msoPropertyTypeString = 4`)
`CustomDocumentProperties.Add` メソッドの引数 `Type` には、Officeドキュメント共通のプロパティ型を指定する。文字列(String)を明確に指定するためにマジックナンバーの `4` (`msoPropertyTypeString`) を用いている。これにより、勝手に数値型や日付型に変換されて後続の外部プログラム(C#やPowerShell)でパースエラーが起きる事故を未然に防いでいる。
② エラーハンドリングによる「二段構え」
VBAの `On Error Resume Next` を安易に乱発する素人が多いが、あれはバグの温床だ。
上記のコードでは `On Error GoTo NotFound` や `CreateNew` というラベルを明確に切り、「存在チェックの代わりにエラーをハンドリングしてロジックに昇華させる」という洗練されたアプローチをとっている。これにより、無駄なループやオブジェクト走査が発生せず、パフォーマンスが極限まで高められている。
—
5. 発展:外部システム(PowerShell)からの超高速メタデータ一括抽出
このアーキテクチャの真骨頂は、Visioを起動せずにメタデータを吸い出せることにある。
以下のPowerShellスクリプトを使えば、社内サーバーにある数千枚の `.vsdx` ファイルから、図面を開くことなく「版数」と「作成部署」が一瞬でCSVに出力される。
指定フォルダ内のVisioファイルからカスタムプロパティを爆速抽出するPowerShell
$folderPath = “C:\VisioDrawings”
$outputCsv = “C:\VisioDrawings\Metadata_Report.csv”
$results = foreach ($file in Get-ChildItem -Path $folderPath -Filter “.vsdx”) {
$word = $null
$doc = $null
try {
# Visioオブジェクトは重いため、COM経由でバックグラウンドロード
$visio = New-Object -ComObject Visio.Application
$visio.Visible = $false
$doc = $visio.Documents.Open($file.FullName)
$version = “N/A”
$dept = “N/A”
# カスタムプロパティの安全な取得
foreach ($prop in $doc.CustomDocumentProperties) {
if ($prop.Name -eq “DrawingVersion”) { $version = $prop.Value }
if ($prop.Name -eq “Department”) { $dept = $prop.Value }
}
[PSCustomObject]@{
FileName = $file.Name
Version = $version
Department = $dept
Path = $file.FullName
}
}
catch {
Write-Warning “読込失敗: $($file.Name)”
}
finally {
if ($doc) { $doc.Close(0) } # 変更を保存せずに閉じる
if ($visio) { $visio.Quit() }
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($visio) | Out-Null
}
}
$results | Export-Csv -Path $outputCsv -NoTypeInformation -Encoding UTF8
Write-Host “レポート出力完了: $outputCsv” -ForegroundColor Green
—
総括
図面管理の自動化において、最もコストがかかるのは「属人化した手動入力のリカバリー」と「ファイルの総当たりチェック」だ。
今回紹介した `Document.CustomDocumentProperties` を軸にしたメタデータ自動統御の仕組みを導入すれば、人間の手でバージョンを書き換える必要は二度となくなる。保存するだけでシステムが勝手に最新状態を刻み込み、外部連携の基盤までシームレスに繋がる。
泥臭い手作業の自動化から卒業し、真に価値のあるアーキテクチャ設計に時間を投資せよ。これこそが、プロの業務自動化エンジニアの仕事である。
