【上級プロフェッショナル向け】図面保存イベント(BeginSave)をフックしたカスタムメタデータの自動埋め込み
AutoCAD VBAの領域において、単なる「マクロによる自動作図」の時代は終わった。現代の企業間連携、特にBIM/CIMワークフローや厳格な品質管理(ISO 9001等)が求められる現場において、図面ファイルの「トレーサビリティ(追跡可能性)」は生命線である。
「誰が、いつ、どの端末で、どのバージョンで保存したか」
この情報を、ユーザーの善意や手動操作に依存することなく、図面ファイルのDNAレベルに刻み込むアーキテクチャをいかに構築するか。
今回は、AutoCAD VBAのイベントハンドリングの極限領域である `BeginSave` イベントをフックし、図面カスタムプロパティへメタデータを自動埋め込みするプロフェッショナル・ソリューションを解説する。
—
1. AutoCAD VBAイベントハンドリングの暗黙の罠
多くのアマチュア開発者は、`ThisDrawing` モジュールにそのまま `DocumentEvents_BeginSave` を記述して満足する。しかし、大規模な設計環境や複数図面を同時に開くマルチドキュメント環境(SDI=0)において、このアプローチはメモリリークやイベントのデッドロックを引き起こす。
真のチーフアーキテクトが考慮すべき設計要件は以下の3点である。
1. アプリケーションレベルの監視: 個別図面ではなく、AutoCADセッション全体(`AcadApplication`)でイベントを捕捉する。
2. Win32 APIによる環境情報の確実な取得: AutoCAD内部変数(`LOGINNAME`など)は容易に偽装・変更されるため、OSレベルのドメイン認証情報を直接叩く。
3. トランザクションとオブジェクトの厳密なライフサイクル管理: COMオブジェクトの解放漏れによるメモリ肥大化を完全に防ぐ。
—
2. 実装アーキテクチャの全体像
このシステムは、以下の2つのコンポーネントで構成される。
- クラスモジュール (`CAppEventMonitor`): アプリケーションイベントをフックし、保存イベントを検知する。
- 標準モジュール (`mMain`): イベント監視の初期化と、メタデータ書込ロジックの実装。
—
3. 実装コード(コピペ即運用可能・本番仕様)
クラスモジュール: `CAppEventMonitor`
Option Explicit
‘ アプリケーションレベルのイベントをフックするための宣言
Public WithEvents AppEvents As AcadApplication
Private Sub AppEvents_BeginSave(ByVal DocumentName As String)
On Error GoTo ErrorHandler
‘ デバッグ用出力(イミディエイトウィンドウ)
Debug.Print “[BeginSave Hook] Target: ” & DocumentName
‘ メタデータ自動埋め込みプロシージャの呼び出し
Call InjectTraceabilityMetadata(ActiveDocument)
Exit Sub
ErrorHandler:
MsgBox “メタデータの自動埋め込みに失敗しました: ” & Err.Description, vbCritical, “Traceability Engine”
End Sub
標準モジュール: `mMain`
Option Explicit
‘ グローバル変数としてクラスインスタンスを保持し、イベントのスコープを維持する
Private oAppMonitor As CAppEnvironmentMonitor
‘ Windows APIを使用して、偽装不可能なOSレベルのユーザー名を取得
Private Declare PtrSafe Function GetUserName Lib “advapi32.dll” Alias “GetUserNameA” ( _
ByVal lpBuffer As String, _
nSize As Long) As Long
Public Sub InitializeTraceabilitySystem()
‘ すでに初期化されている場合は二重起動を防ぐ
If oAppMonitor Is Nothing Then
Set oAppMonitor = New CAppEnvironmentMonitor
Set oAppMonitor.AppEvents = ThisDrawing.Application
MsgBox “AutoCAD トレーサビリティ・エンジンが正常にロードされました。”, vbInformation, “System Ready”
Else
MsgBox “システムはすでに稼働中です。”, vbExclamation, “Notice”
End If
End Sub
Public Sub TerminateTraceabilitySystem()
‘ 明示的なオブジェクトの解放(メモリ最適化の極意)
Set oAppMonitor = Nothing
MsgBox “トレーサビリティ・エンジンをアンロードしました。”, vbInformation, “System Shutdown”
End Sub
Private Sub InjectTraceabilityMetadata(ByRef targetDoc As AcadDocument)
Dim oInfoSets As AcadCustomDatabaseProperty
Dim userName As String
Dim machineName As String
On Error GoTo CleanUp
‘ OSレベルのユーザー名取得
userName = GetOSUserName()
‘ 環境変数からマシン名取得
machineName = Environ(“COMPUTERNAME”)
‘ 図面データベースのカスタムプロパティコレクションを取得
‘ ※AutoCADのバージョン互換性を考慮し、エラーハンドリングを挟む
Set oInfoSets = targetDoc.SummaryInfo
‘ カスタムプロパティへの書き込み(存在しない場合は自動生成される)
‘ キー名: LastEditedByOS
Call oInfoSets.AddCustomKeyValue(“LastEditedByOS”, userName & ” (” & machineName & “)”)
‘ キー名: LastSaveTimestamp
Call oInfoSets.AddCustomKeyValue(“LastSaveTimestamp”, Format(Now, “yyyy-mm-dd hh:nn:ss”))
‘ キー名: AutoCADVersion
Call oInfoSets.AddCustomKeyValue(“AutoCADVersion”, targetDoc.Application.Version)
CleanUp:
‘ COMオブジェクトの参照を確実に解放(メモリリークの根絶)
Set oInfoSets = Nothing
If Err.Number <> 0 Then
Debug.Print “[Error in InjectMetadata] ” & Err.Description
End If
End Sub
Private Function GetOSUserName() As String
Dim lpBuffer As String 255
Dim nSize As Long
nSize = Len(lpBuffer)
If GetUserName(lpBuffer, nSize) <> 0 Then
GetOSUserName = Left$(lpBuffer, nSize – 1)
Else
GetOSUserName = “Unknown_User”
End If
End Function
—
4. チーフアーキテクトが解説する技術的ポイント
1. `BeginSave` と `EndSave` の選択思想
今回はあえて `BeginSave`(保存処理が走る直前)をフックしている。これにより、書き込んだカスタムメタデータも「今回の保存ストリームに確実に包含される」ことになる。
`EndSave` を使うと、メタデータを書き込んだ瞬間に「未保存の変更(Modifiedフラグ)」が再び立ってしまい、ユーザーが終了しようとした際に無限セーブプロンプトの罠に陥るリスクがある。`BeginSave` 内でのメタデータ追加は、AutoCADの内部セーブシーケンスに巧みに割り込む高度なテクニックである。
2. メモリ最適化とCOMオブジェクトの寿命
VBAの裏側では、COM(Component Object Model)の参照カウンタが動作している。`targetDoc.SummaryInfo` のようなプロパティアクセスを行うたびに、COMオブジェクトへの参照がヒープ上に生成される。
これを放置すると、大容量図面の編集・保存を繰り返すうちにAutoCADプロセス全体のメモリフットプリントが肥大化し、最悪の場合「致命的なエラー (Fatal Error)」による強制終了を引き起こす。
コード中の `Set oInfoSets = Nothing` は、単なる作法ではなく「防衛プログラミングの必須要件」である。
3. レガシー環境とバージョン互換性
上記のコードは、32bit/64bit環境が混在する過渡期から最新のAutoCAD環境までを見据え、`Declare PtrSafe` を採用している。これにより、古い図面管理資産を引き継いだ現代のエンタープライズ環境においても、環境差異によるクラッシュを完全に排除している。
—
5. 運用への組み込み(自動起動の設定)
このシステムを実務でシームレスに稼働させるためには、ユーザーの手動による `InitializeTraceabilitySystem` の呼び出しを排除する必要がある。
1. 上記コードを `acad.dvb`(自動ロード用プロジェクト)に組み込む。
2. `acad.lsp` または `acaddoc.lsp` に以下のコードを記述し、図面オープン時に自動で初期化プロシージャが走るようブリッジを架ける。
(defun S::STARTUP ()
(vl-load-com)
(vl-vbarun “InitializeTraceabilitySystem”)
(princ “\n[System] Traceability Engine Activated.”)
(princ)
)
総括
VBAは、しばしば「おもちゃの言語」と揶揄されることがある。しかし、APIの深部を理解し、メモリ管理とイベントライフサイクルを完全に掌握したエンジニアが書いたVBAコードは、C#やC++で書かれたアドインと同等の堅牢性と実用性を発揮する。
手動保存の背後で静かに、しかし確実に対象ファイルのメタデータを書き換えるこの仕組みは、あなたの組織の図面管理品質を次のステージへと引き上げるだろう。
