【テクニカル・上級編】【上級プロフェッショナル】AcadApplicationオブジェクトを活用した、複数図面の図面プロパティ(カスタムプロパティ含む)の一括更新 – AutoCAD VBA解析バイブル

スポンサーリンク

AutoCAD VBAを掌握する極限の知見:複数図面の図面プロパティ一括更新の極意

AutoCAD VBAの領域において、単一図面の自動化はチュートリアルに過ぎない。真にプロフェッショナルなエンジニアが直面するのは、数百、数千に及ぶレガシー図面群の統御、すなわち「マルチドキュメント環境におけるトランザクションとリソースの完全掌握」である。

今回は、`AcadApplication`オブジェクトとDocumentsコレクションを駆使し、複数図面の標準プロパティおよびカスタムプロパティをノーウインドウ(あるいは最適化されたバックグラウンド処理)で一括更新する、エンタープライズグレードのソリューションを提示する。

レガシーなVBAの限界を突破し、メモリリークを根絶するための知見をここに公開する。

1. アーキテクチャの設計思想:なぜ通常のVBAコードでは破綻するのか?

多くの初学者は、複数の図面を開閉する際に以下のような愚を犯す。
1. `Workbooks.Open`のノリで`Documents.Open`を連発する。
2. エラーハンドリングを怠り、CADプロセスの裏でCOMコンポーネントがゾンビ化する。
3. `SummaryInfo`(概要情報)オブジェクトのライフサイクルを無視し、メモリリークを引き起こす。

AutoCADのCOMインターフェースは強靭だが、同時に極めてデリケートである。特にカスタムプロパティ(CustomProperty)の操作には、内部の安全なインデックス管理と、変更後の確実な同期が求められる。

これを解決するための鉄則は以下の3点だ。

  • 完全なオブジェクトの解放(`Set obj = Nothing`)の徹底
  • バックグラウンド処理による描画負荷の排除(可能な限りの`Visible = False`活用とドキュメントコンテキストの制御)
  • 堅牢なトランザクションとエラー回復メカニズム

2. 実装コード:エンタープライズ仕様・一括プロパティ更新エンジン

以下のコードは、指定したフォルダ内のすべてのDWGファイルに対し、標準プロパティ(タイトル、作成者等)およびカスタムプロパティを一括で書き換え、上書き保存して閉じるプロフェッショナル向けのマクロである。

Option Explicit

‘ —————————————————————————
‘ 処理名: BatchUpdateDrawingProperties
‘ 概要 : 指定フォルダ内の全DWGファイルの図面プロパティを一括更新する
‘ —————————————————————————
Public Sub BatchUpdateDrawingProperties()
Dim targetFolder As String
targetFolder = “C:\CAD_Data\TargetDrawings\” ‘ 対象フォルダパス(環境に合わせて変更)

If Dir(targetFolder, vbDirectory) = “” Then
MsgBox “指定されたフォルダが存在しません。”, vbCritical, “致命的エラー”
Exit Sub
End If

Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)

Dim targetFiles As Object
Set targetFiles = fso.GetFolder(targetFolder).Files

Dim appAcad As AcadApplication
Set appAcad = ThisDrawing.Application ‘ 現在のセッションを利用、またはCreateObject(“AutoCAD.Application”)

‘ 最速化のため、アラートや画面更新を抑制(CADの仕様上完全に消えない場合もあるが負荷軽減に寄与)
Dim oldSDI As Variant
oldSDI = appAcad.GetSystemVariable(“SDI”)

Dim fileItem As Object
Dim docTarget As AcadDocument
Dim summaryInfo As AcadSummaryInfo

On Error GoTo ErrorHandler

‘ MDI環境での効率的なループ処理
For Each fileItem In targetFiles
If UCase(fso.GetExtensionName(fileItem.Name)) = “DWG” Then

Debug.Print “処理中: ” & fileItem.Name

‘ ドキュメントを開く(非表示起動はAutoCADの制限があるため、最小化または通常オープン後に処理)
Set docTarget = appAcad.Documents.Open(fileItem.Path, False)

‘ SummaryInfoオブジェクトの取得(極めて重要:ドキュメント毎にインスタンスを取得する)
Set summaryInfo = docTarget.SummaryInfo

‘ 1. 標準プロパティの更新
summaryInfo.Title = “2026年度 共通インフラ設計”
summaryInfo.Author = “BIM/CAD Automation System”
summaryInfo.Subject = “自動一括更新完了”

‘ 2. カスタムプロパティの更新(存在する場合は値変更、なければ追加)
Call UpsertCustomProperty(summaryInfo, “ProjectNo”, “PRJ-9988-AX”)
Call UpsertCustomProperty(summaryInfo, “CheckStatus”, “Approved”)

‘ 変更を確実に反映して保存
docTarget.Save

‘ オブジェクトの明示的解放(メモリリーク防止の絶対防壁)
docTarget.Close False
Set summaryInfo = Nothing
Set docTarget = Nothing

End If
Next fileItem

MsgBox “すべての図面プロパティの一括更新が正常に完了しました。”, vbInformation, “完了”
GoTo Cleanup

ErrorHandler:
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“説明: ” & Err.Description, vbCritical, “エラー”

Cleanup:
‘ 参照の解放
Set summaryInfo = Nothing
Set docTarget = Nothing
Set appAcad = Nothing
Set fso = Nothing
Set targetFiles = Nothing
End Sub

‘ —————————————————————————
‘ 補助関数: カスタムプロパティの更新・追加(Upsert)ロジック
‘ —————————————————————————
Private Sub UpsertCustomProperty(ByRef sumInfo As AcadSummaryInfo, ByVal propName As String, ByVal propValue As String)
Dim numKeys As Long
Dim i As Long
Dim key As String
Dim val As String
Dim found As Boolean

found = False
sumInfo.NumCustomKeys numKeys

‘ 既存のカスタムプロパティを走査
For i = 0 To numKeys – 1
sumInfo.GetCustomByIndex i, key, val
If StrComp(key, propName, vbTextCompare) = 0 Then
‘ 存在する場合は値を更新
sumInfo.SetCustomByIndex i, key, propValue
found = True
Exit For
End If
Next i

‘ 存在しない場合は新規追加
If Not found Then
sumInfo.AddCustomProperty propName, propValue
End If
End Sub

3. チーフアーキテクトが解説するコードの急所

① `SummaryInfo` オブジェクトの動的ライフサイクル

`AcadDocument.SummaryInfo` は、ドキュメントインスタンスに強くバインドされている。ループ内で使い回すことは絶対に避けてほしい。図面を切り替える(あるいは閉じる)たびに `summaryInfo` 変数は `Nothing` に初期化し、新しいドキュメントから再取得しなければ、ポインタの指し示す先が消失し致命的なCOM例外(Error 462: リモートサーバーが見つからないか、またはサーバーによって使用が拒否されました)を引き起こす。

② カスタムプロパティの「Upsert」アルゴリズム

AutoCADの標準COMラッパーには「キー名で直接カスタムプロパティを指定して取得・変更するメソッド」が存在しない(※一部バージョンを除く)。そのため、`NumCustomKeys` で総数を取得し、`GetCustomByIndex` でインデックスを総なめしてキー名を比較するという泥臭いアプローチが必要になる。
上記の `UpsertCustomProperty` 関数はこのボイラープレートをカプセル化し、実務でそのまま使える堅牢性を持たせてある。

③ メモリ最適化とCOMプロセスのゾンビ化防止

VBAにおける最大の敵は「見えないメモリリーク」である。AutoCADを外部から制御する場合や、内部マクロであっても `Documents.Open` を多用すると、解放されなかったドキュメントオブジェクトがCOMの参照カウントを保持し続け、AutoCAD終了後もバックグラウンドプロセス(`acad.exe`)がタスクマネージャーに残留する現象が発生する。
これを防ぐため、ループの最後では必ず以下の順序でオブジェクトを断ち切る。

docTarget.Close False
Set summaryInfo = Nothing
Set docTarget = Nothing

この「下位オブジェクトから順に `Nothing` を代入する」という規律こそが、何万回ものループを走らせても安定稼働するシステムを構築唯一の道である。

4. さらなる高みへ:システム間連携への布石

このVBAスクリプトは、単なる「手間の削減」にとどまらない。
例えば、社内の基幹システム(ERPやPLM)から出力されたCSVやJSON形式のメタデータ読み込み部とこのVBAを結合すれば、「設計変更が発生した際に、夜間バッチで数千枚の図面属性を自動同期する完全自律型CAD管理パイプライン」のコアエンジンへと昇華させることができる。

レガシーと侮るなかれ。VBAの本質とAutoCADのオブジェクトモデルの深淵を理解していれば、現代のモダンな開発言語に匹敵する堅牢な自動化インフラを構築することが可能なのだ。

現場の泥臭い課題を、極限のコードで鮮やかに解決せよ。

タイトルとURLをコピーしました