AutoCAD VBAを掌握する極限の知見:図面メタデータの完全抽出と外部システム連携
AutoCAD VBAは、単なる「図面描画の自動化ツール」ではない。それは、CAD内部の精緻なオブジェクトモデルと、Windowsエコシステムを直結させるための極めて強力なインターフェースである。
多くの開発者は、`AcadDocument`の図形要素(Line, Circle, BlockReferenceなど)を操作することだけに終始しがちだ。しかし、シニアエンジニアやプラントのシステム管理者が真に注目すべきは、図面という「バイナリの殻」に包まれたメタデータの流動性である。
今回は、`AcadDatabase.SummaryInfo`(図面のプロパティ管理オブジェクト)に格納されたカスタムプロパティを抽出し、外部の工程管理システムやERPへシームレスに流し込むための「XML同期パイプライン」の構築手法を解説する。
—
1. AutoCADオブジェクトモデルの深層:SummaryInfoの真実
AutoCADの図面ファイル(.dwg)は、単なる図形の集合体ではない。図面番号、改訂番号、設計者名、そしてユーザーが独自に定義する「カスタムプロパティ」といった属性情報(メタデータ)を内包している。
これらを管理するのが `AcadDatabase.SummaryInfo` である。しかし、このオブジェクトの背後にあるCOMコンポーネントのライフサイクル管理は、VBAランタイムにおいてしばしばメモリリークやCOM例外の温床となる。
メモリ最適化とオブジェクト参照の鉄則
AutoCAD VBAにおける最大の罠は、ドキュメントやデータベースへの参照を安易にチェーン(連続呼び出し)させることだ。
‘ 【悪例】背後で暗黙のCOMオブジェクトが生成され、GC(ガベージコレクタ)に回収されないリスクがある
Dim val As String
val = ThisDrawing.Database.SummaryInfo.GetCustomByKey(“ProjectCode”, val)
厳格なリソース管理が求められる現場では、各階層のオブジェクトを明示的に変数に格納し、スコープの抜け際あるいは処理の完了時に `Nothing` を代入してメモリを解放するライフサイクル管理が不可欠である。
—
2. 実装:カスタムプロパティを構造化XMLへ書き出すVBAエンジン
以下のコードは、アクティブな図面から `SummaryInfo` のカスタムプロパティを全走査し、外部システム(工程管理システム等)がインポート可能な構造化XMLファイルとして出力する、実務仕様のVBAプロシージャである。
エラーハンドリング、DOM(Document Object Model)の適切な利用、そしてメモリの明示的解放を徹底している。
Option Explicit
Public Sub ExportSummaryInfoToXML()
Dim oDoc As AcadDocument
Dim oDb As AcadDatabase
Dim oSumInfo As AcadSummaryInfo
‘ DOM用オブジェクト
Dim xmlDoc As Object ‘ MSXML2.DOMDocument
Dim rootElem As Object
Dim propElem As Object
Dim numProps As Long
Dim i As Long
Dim key As String
Dim val As String
Dim exportPath As String
‘ 1. 安全なドキュメント・データベースの取得
On Error GoTo ErrorHandler
Set oDoc = ThisDrawing
Set oDb = oDoc.Database
Set oSumInfo = oDb.SummaryInfo
‘ 2. MSXML2.DOMDocumentのインスタンス化 (レガシー環境でも安定稼働するバージョン指定)
Set xmlDoc = CreateObject(“MSXML2.DOMDocument.6.0”)
‘ XML宣言とルート要素の作成
Dim pi As Object
Set pi = xmlDoc.createProcessingInstruction(“xml”, “version=’1.0’ encoding=’UTF-8′”)
xmlDoc.AppendChild pi
Set rootElem = xmlDoc.createElement(“DrawingMetadata”)
xmlDoc.AppendChild rootElem
‘ 標準プロパティ(タイトル、図面名など)の付加
Call AddXmlNode(xmlDoc, rootElem, “DrawingName”, oDoc.Name)
Call AddXmlNode(xmlDoc, rootElem, “Author”, oSumInfo.Author)
Call AddXmlNode(xmlDoc, rootElem, “Title”, oSumInfo.Title)
Call AddXmlNode(xmlDoc, rootElem, “Revision”, oSumInfo.RevisionNumber)
‘ 3. カスタムプロパティの全走査と抽出
numProps = oSumInfo.NumCustomKeys
Dim customRoot As Object
Set customRoot = xmlDoc.createElement(“CustomProperties”)
rootElem.AppendChild customRoot
For i = 0 To numProps – 1
‘ キーと値の取得(API仕様に準拠)
oSumInfo.GetCustomByIndex i, key, val
‘ 子要素としてXMLに格納
Set propElem = xmlDoc.createElement(“Property”)
Dim keyAttr As Object
Set keyAttr = xmlDoc.createAttribute(“Name”)
keyAttr.Text = key
propElem.setAttributeNode keyAttr
propElem.Text = val
customRoot.AppendChild propElem
Next i
‘ 4. 出力パスの生成 (図面と同階層にタイムスタンプ付きXMLを吐き出す)
exportPath = GetExportFilePath(oDoc.FullName, “xml”)
‘ ファイル保存
xmlDoc.Save exportPath
MsgBox “図面メタデータのXMLエクスポートが完了しました。” & vbCrLf & “出力先: ” & exportPath, vbInformation, “システム連携モジュール”
CleanUp:
‘ 5. 厳格なオブジェクトの解放 (メモリリーク防止)
Set propElem = Nothing
Set customRoot = Nothing
Set rootElem = Nothing
Set xmlDoc = Nothing
Set oSumInfo = Nothing
Set oDb = Nothing
Set oDoc = Nothing
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“説明: ” & Err.Description, vbCritical, “致命的エラー”
Resume CleanUp
End Sub
‘ —————————————————————–
‘ 補助関数: XMLノード生成の共通化
‘ —————————————————————–
Private Sub AddXmlNode(ByRef doc As Object, ByRef parent As Object, ByVal nodeName As String, ByVal nodeValue As String)
Dim elem As Object
Set elem = doc.createElement(nodeName)
elem.Text = nodeValue
parent.AppendChild elem
Set elem = Nothing
End Sub
‘ —————————————————————–
‘ 補助関数: 出力ファイルパスの動的生成
‘ —————————————————————–
Private Function GetExportFilePath(ByVal dwgPath As String, ByVal ext As String) As FunctionResult
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)
If dwgPath = “” Then
‘ 未保存図面の場合のフォールバック
GetExportFilePath = “C:\Temp\DrawingMeta_” & Format(Now, “yyyymmdd_hhnnss”) & “.” & ext
Else
Dim folderPath As String
Dim baseName As String
folderPath = fso.GetParentFolderName(dwgPath)
baseName = fso.GetBaseName(dwgPath)
GetExportFilePath = folderPath & “\” & baseName & “_” & Format(Now, “yyyymmddhhnnss”) & “.” & ext
End If
Set fso = Nothing
End Function
—
3. シニアアーキテクトが解説する実装の急所
上記のコードベースは、単なるサンプルではない。現場の運用に耐えうるよう、いくつかの高度な設計思想が組み込まれている。
① MSXML2.DOMDocument.6.0 の採用
レガシーなVBAコードでは `MSXML2.DOMDocument` とだけ記述しがちだが、これでは実行環境のIEやWindowsのバージョンによって挙動が異なり、セキュリティ脆弱性のある古いパーサーが選ばれるリスクがある。明示的に `6.0` を指定することで、高速かつ安全な最新のDOMパーサーを強制する。
② 未保存図面(Untitled)への堅牢なフォールバック
設計者が図面を新規作成し、まだ一度も保存していない段階(`FullName` が空文字列)でマクロが実行された場合、ファイルパスの結合処理で致命的なランタイムエラーが発生する。関数 `GetExportFilePath` 内でこれを検知し、一時ディレクトリ (`C:\Temp` 等) へ逃がす実装にすることで、システムの堅牢性を担保している。
③ COMオブジェクトの完全なスコープアウトと解放
VBAのガベージコレクションは非常に脆弱である。特にAutoCADのCOMインターフェースを複数経由する場合、参照カウントが残存し、AutoCAD本体を終了してもプロセス(`acad.exe`)がメモリ上に残り続ける「ゾンビプロセス問題」を引き起こす。
今回のコードでは、プロシージャの出口(`CleanUp` ラベル)で、生成したすべてのオブジェクト変数に `Nothing` を代入し、明示的に参照を断ち切る設計を貫いている。
—
4. 外部工程管理システムとの統合アーキテクチャ
このVBAによって生成されたXMLファイルは、次のようなパイプラインで外部システムと連携される。
1. バッチ / イベントトリガー:
設計者が図面を保存・チェックインしたタイミング、あるいは夜間バッチで、このVBA(または外部からAutoCADをバックグラウンド起動するConsole Runner)をキックする。
2. XMLパース:
外部の工程管理システム(WebアプリやC#/.NET製クライアントアプリケーション)が、出力されたXMLをインポートする。
3. データベース同期:
XML内の `
手動による転記ミスや、進捗管理のタイムラグを完全に排除し、「図面が情報の唯一の源泉(Single Source of Truth)」となる理想的なエンジニアリングチェーンが完成する。
—
総括
AutoCAD VBAはレガシーな技術と揶揄されることもある。しかし、オブジェクトモデルの挙動を熟知し、Windows APIやCOMのライフサイクルをコントロール下に対置できたとき、それは最強の「プラント・製造業向けインテグレーションツール」へと変貌する。
泥臭い現場の課題を、エレガントかつ堅牢なコードで解決することこそ、真のシニアエンジニアの矜持である。
