【AutoCAD VBA極限攻略】図面に「魂」を宿せ。DictionariesとXRecordsで実現する、堅牢な非可視メタデータ埋め込み術
単なる「CADオペレーター」と、CADのオブジェクトモデルを支配する「システムエンジニア」の境界線はどこにあるか。それは、CAD図面を単なる「線の集まり(絵)」として扱うか、それとも「自己完結した構造化データベース」として扱うかにある。
実務において、「プロジェクトID」「設計担当者」「検図ステータス」「BOM連携用キー」といった管理情報を図面に持たせたいという要求は極めて多い。これらを「図面枠の属性ブロック」や「MText」に持たせるのは素人のアプローチだ。なぜなら、それらはユーザーが容易に削除・改変できてしまい、システムとしての堅牢性を著しく損なうからだ。
本稿では、図面データベースの最深部に非可視データとしてメタデータを埋め込む、「辞書(Dictionaries)」と「拡張レコード(XRecords)」の極限の活用術を伝授する。
—
1. なぜ「XData」でも「属性ブロック」でもなく「XRecord」なのか?
メタデータの保持手法を検討する際、多くの開発者が安易にXData(拡張データ)や属性ブロックを選択し、後に破綻する。まずは、それぞれの技術特性を正しく理解し、なぜXRecordがエンタープライズ用途において絶対的な正解であるのかを論理的に解説する。
| 評価軸 | 属性ブロック | XData(拡張データ) | XRecord(拡張レコード) |
| :— | :— | :— | :— |
| 可視性 | 図面上に表示(非表示も可だが操作可能) | 完全非可視 | 完全非可視 |
| ユーザーによる破壊 | 容易に削除・編集が可能 | エンティティ削除時に消失 | NODに紐づくため、意図しない削除はほぼ不可能 |
| データ容量制限 | 実質制限なし | 1エンティティあたり 16KB | 実質制限なし(メモリが許す限り) |
| データ構造 | フラットな文字列のみ | DXFグループコードのフラット配列 | オブジェクト指向的・ネスト構造が可能 |
| 他システム連携 | 属性抽出が必要で遅い | アクセスにRegAppの登録が必要 | 名前付き辞書(NOD)経由で超高速アクセス |
XDataの限界とXRecordの優位性
XDataは、特定の図形(ラインやサークル)に付随する「16KB以下の軽量な一時データ」を想定して設計されている。そのため、プロジェクト全体を統括するような、構造化された大容量メタデータの保持には全く向いていない。
一方、XRecord(拡張レコード)は、図面全体のルート辞書であるNOD(Named Object Dictionary:名前付きオブジェクト辞書)の配下に独自のカスタム辞書を作成し、その中に無制限に近い容量で、任意のDXFグループコード(型定義)を持ったデータを格納できる。
このアプローチこそが、図面を一つの「独立したリレーショナルデータベースのテーブル」のように機能させる鍵となる。
—
2. AutoCADオブジェクトモデルにおける「辞書の階層構造」
XRecordを攻略するには、AutoCADの内部データベース(オブジェクトモデル)の階層構造を脳内に描けなければならない。
[AcadDocument (図面)]
|
+– [Dictionaries (Named Object Dictionary: NOD)]
|
+– [AcadDictionary (カスタム辞書: 例 “MyCompanyProjectDict”)]
|
+– [AcadXRecord (拡張レコード: 例 “ProjectMetadata”)]
|
+– [DXF Group Codes & Values (データ実体)]
(1000: “PRJ-2026-001”) -> プロジェクトID
(1000: “Arch. Kenzo”) -> 設計担当者
(1071: 20260330) -> 最終更新日(整数)
(1040: 125000.0) -> 予算(実数)
図面のルートには `Dictionaries` というコレクションが存在する。これはAutoCAD用語でNOD(Named Object Dictionary)と呼ばれる。我々開発者は、このNOD直下に「自社専用のカスタム辞書」を1つ定義し、その中に用途に応じた「XRecord」を格納していく。
ここで重要なのが、データ実体を定義する「DXFグループコード」だ。XRecordは、任意の型と値のペアの配列としてデータを保持する。
主要なDXFグループコード
- 1000: 文字列(String)。最大255バイト(現在のバージョンでは実質制限なしだが、互換性のために小分けにすることもある)。
- 1040: 倍精度浮動小数点(Double)。座標値や金額などに使用。
- 1071: 32ビット符号付き整数(Long)。フラグや日付、IDなどに使用。
—
3. 【プロダクション品質】メタデータ制御用VBAソースコード
実務でそのまま利用できる、極めて堅牢に設計されたラッパークラス(または標準モジュール)の実装コードを示す。
このコードは、以下の実務的要件をすべてクリアしている。
1. 既存データの存在チェックと自動初期化
2. データの型安全性の確保
3. エラートラップとリソース解放の徹底
標準モジュール `Mod_XRecordManager`
Option Explicit
‘ — DXFグループコードの定数定義 —
Private Const DXF_STRING As Integer = 1000
Private Const DXF_DOUBLE As Integer = 1040
Private Const DXF_LONG As Integer = 1071
‘ — カスタム辞書およびXRecordのキー名 —
Private Const CUSTOM_DICT_NAME As String = “MyCompanyCorporateDict”
Private Const METADATA_XRECORD_NAME As String = “ProjectMetadata”
”
‘ @brief 図面のNODにカスタムメタデータを書き込む(新規作成・上書き対応)
‘ @param[in] projectID プロジェクトの一意キー
‘ @param[in] designer 担当者名
‘ @param[in] budget 予算額(数値)
‘ @param[in] updateDate 更新日(整数型 YYYYMMDD)
‘ @return Boolean 処理の成否
”
Public Function WriteProjectMetadata( _
ByVal projectID As String, _
ByVal designer As String, _
ByVal budget As Double, _
ByVal updateDate As Long) As Boolean
On Error GoTo ErrorHandler
WriteProjectMetadata = False
Dim doc As AcadDocument
Set doc = ThisDrawing
‘ 1. ルートのNamed Object Dictionary (NOD) を取得
Dim nod As AcadDictionaries
Set nod = doc.Dictionaries
‘ 2. カスタム辞書の取得または新規作成
Dim customDict As AcadDictionary
Set customDict = GetOrCreateDictionary(nod, CUSTOM_DICT_NAME)
If customDict Is Nothing Then Err.Raise vbObjectError + 1001, , “カスタム辞書の作成に失敗しました。”
‘ 3. 既存のXRecordがあれば削除(上書き処理をシンプルにするため、一度破棄する)
On Error Resume Next
customDict.Remove METADATA_XRECORD_NAME
On Error GoTo ErrorHandler
‘ 4. XRecordを新規作成
Dim xRec As AcadXRecord
Set xRec = customDict.AddXRecord(METADATA_XRECORD_NAME)
‘ 5. データの配列化(DXFグループコードと値のペア)
‘ ※VBAの仕様上、グループコードはInteger型、値はVariant型の動的配列にする必要がある
Dim dxfCodes(0 To 3) As Integer
Dim dxfValues(0 To 3) As Variant
dxfCodes(0) = DXF_STRING: dxfValues(0) = projectID
dxfCodes(1) = DXF_STRING: dxfValues(1) = designer
dxfCodes(2) = DXF_DOUBLE: dxfValues(2) = budget
dxfCodes(3) = DXF_LONG: dxfValues(3) = updateDate
‘ 6. XRecordへデータを流し込む
xRec.SetXRecordData dxfCodes, dxfValues
WriteProjectMetadata = True
Exit Function
ErrorHandler:
MsgBox “メタデータ書き込みエラー: ” & Err.Description, vbCritical, “システムエラー”
End Function
”
‘ @brief 図面からカスタムメタデータを読み込む
‘ @param[out] projectID
‘ @param[out] designer
‘ @param[out] budget
‘ @param[out] updateDate
‘ @return Boolean データの読み込みに成功した場合はTrue
”
Public Function ReadProjectMetadata( _
ByRef projectID As String, _
ByRef designer As String, _
ByRef budget As Double, _
ByRef updateDate As Long) As Boolean
On Error GoTo ErrorHandler
ReadProjectMetadata = False
Dim doc As AcadDocument
Set doc = ThisDrawing
‘ 1. NODの存在確認
Dim nod As AcadDictionaries
Set nod = doc.Dictionaries
‘ 2. カスタム辞書の存在確認
Dim customDict As AcadDictionary
On Error Resume Next
Set customDict = nod.Item(CUSTOM_DICT_NAME)
On Error GoTo ErrorHandler
If customDict Is Nothing Then
‘ 辞書自体が存在しない場合は、未登録とみなして正常終了
Exit Function
End If
‘ 3. XRecordの取得
Dim xRec As AcadXRecord
On Error Resume Next
Set xRec = customDict.GetObject(METADATA_XRECORD_NAME)
On Error GoTo ErrorHandler
If xRec Is Nothing Then
Exit Function
End If
‘ 4. XRecordデータの抽出
Dim rawCodes As Variant
Dim rawValues As Variant
xRec.GetXRecordData rawCodes, rawValues
‘ 5. データの展開と型保証
‘ ※配列が空でないか、要素数が一致しているかを厳密にチェック
If VarType(rawCodes) = vbEmpty Or VarType(rawValues) = vbEmpty Then Exit Function
If UBound(rawCodes) < 3 Then Err.Raise vbObjectError + 1002, , "XRecordのデータ構造が不正です。データが破損している可能性があります。" End If ' 取得したVariant配列から適切な型にキャストしながら代入 projectID = CStr(rawValues(0)) designer = CStr(rawValues(1)) budget = CDbl(rawValues(2)) updateDate = CLng(rawValues(3)) ReadProjectMetadata = True Exit Function ErrorHandler: MsgBox "メタデータ読み込みエラー: " & Err.Description, vbCritical, "システムエラー" End Function '' ' @brief 辞書の存在チェックを行い、存在しなければ新規作成して返すヘルパー関数 '' Private Function GetOrCreateDictionary( _ ByRef nod As AcadDictionaries, _ ByVal dictName As String) As AcadDictionary Dim targetDict As AcadDictionary On Error Resume Next Set targetDict = nod.Item(dictName) On Error GoTo 0 If targetDict Is Nothing Then On Error GoTo CreateError Set targetDict = nod.Add(dictName) On Error GoTo 0 End If Set GetOrCreateDictionary = targetDict Exit Function CreateError: Set GetOrCreateDictionary = Nothing End Function ---
テスト用エントリポイント
上記のマネージャーを検証するためのクライアントコード。実務での運用を想定し、書き込み後に即座に読み込みを行って検証する。
Public Sub Test_MetadataStorage()
Dim pID As String: pID = “PRJ-2026-X99”
Dim desc As String: desc = “チーフアーキテクト 鈴木”
Dim cost As Double: cost = 4500000.5
Dim uDate As Long: uDate = 20260330
‘ 1. メタデータの書き込み
Debug.Print “=== メタデータ書き込み開始 ===”
If WriteProjectMetadata(pID, desc, cost, uDate) Then
Debug.Print “書き込み成功!”
Else
Debug.Print “書き込み失敗…”
Exit Sub
End If
‘ 2. メタデータの読み込み(変数を初期化して検証)
Dim r_pID As String
Dim r_desc As String
Dim r_cost As Double
Dim r_uDate As Long
Debug.Print “=== メタデータ読み込み開始 ===”
If ReadProjectMetadata(r_pID, r_desc, r_cost, r_uDate) Then
Debug.Print “読み込み成功!”
Debug.Print “—————————–”
Debug.Print “プロジェクトID: ” & r_pID
Debug.Print “設計担当者 : ” & r_desc
Debug.Print “予算額 : ” & Format$(r_cost, “#,
0.00″)
Debug.Print “更新日 : ” & r_uDate
Debug.Print “—————————–”
Else
Debug.Print “メタデータは存在しません。”
End If
End Sub
—
4. 徹底解説:コードの急所とAPI仕様の裏側
上記のコードには、一般的な技術情報サイトには書かれていない、AutoCAD APIの致命的な「罠」を回避するための設計が施されている。
急所1:`GetXRecordData` の引数は「空のVariant」で渡さなければならない
VBAから `AcadXRecord.GetXRecordData` を呼び出す際、引数に型を厳密に指定した動的配列(例: `Dim codes() As Integer`)を渡すと、AutoCADのCOMインターフェースは高確率で実行時エラー(型が一致しません)を吐いてクラッシュする。
API内部で安全に配列を再確保させるため、受け取り側は必ず `Dim rawCodes As Variant` として宣言し、完全に空のVariant型として渡すのが鉄則だ。
急所2:上書き時の「Remove」処理
既存のXRecordに対して直接 `SetXRecordData` を再実行して上書きすることも可能だが、配列の要素数が減少した場合などに、古いデータがメモリ内に残留するバグの原因となる。
そのため、本プロダクションコードでは、書き込み前に一度 `customDict.Remove METADATA_XRECORD_NAME` を実行し、安全に既存のレコードを物理削除してから再作成している。これにより、データ構造の変更(スキーマ変更)にも柔軟に対応できる。
—
5. 実務運用におけるトラップと回避策
このシステムを実務(マルチユーザー環境、PDM連携など)に投入する際、設計者が必ず直面する「3つの壁」とその解決策を示す。
壁①:`WBLOCK`(ブロック書き出し)によるメタデータの喪失
図面の一部を別の図面として書き出す `WBLOCK` コマンドを実行した際、デフォルトの設定ではNOD内のカスタム辞書はコピーされない。
- 対策:
図面全体を保存する `SAVEAS` ではNODは完全に維持されるため、社内運用ルールとしては「`WBLOCK` による図面切り出し」ではなく「ファイルをコピーして不要オブジェクトを削除する」アプローチを推奨するか、`WBLOCK` 実行後にメタデータを再同期するアドインをVBA側でフック(`AcadDocument.BeginLISP` などのイベント監視)する必要がある。
壁②:外部システム(RDB/ERP)との同期設計
図面内のメタデータと、社内の基幹データベース(SQL Server / Oracle等)のデータが乖離するリスク。
- 対策:
図面内には「プライマリキー(プロジェクトID等)のみ」を保持させ、その他の詳細情報(予算や担当者名など)は、図面を開いた瞬間にVBAが外部DBに問い合わせて動的に取得・表示する設計が最も美しい。
図面内にすべてのデータを持たせすぎると、DB側のマスターデータが更新された際に、すべての図面を開いて書き直さなければならなくなる(マスタ二重持ちの弊害)。
壁③:図面破損時のデータ復旧
AutoCADの `AUDIT`(監査)や `RECOVER`(修復)コマンドを実行した際、不正なポインタ参照を持つカスタム辞書は自動的に消去されることがある。
- 対策:
本稿のコードのように、`ReadProjectMetadata` が `False`(データなし)を返した場合は、速やかに「新規登録ダイアログ」を立ち上げるか、ファイル名等から自動的にメタデータを再生成してNODを再構築する「自己修復ロジック」をVBA側に実装しておくこと。
—
結論:図面をインテリジェントなアセットに変革せよ
本稿で解説した「DictionariesとXRecords」を活用したメタデータの埋め込みは、AutoCAD VBAのスキルの中でも極めて秘匿性が高く、かつ実用性の高い領域である。
図面に「非可視の構造化データ」を持たせることで、CADは単なる製図ツールから、「エンタープライズシステムの一端を担うインテリジェントなデータ端末」へと進化する。この設計手法をマスターし、既存のレガシーなCAD業務自動化ツールを、次世代の堅牢なCADシステムへと引き上げてほしい。
