【上級】VBAからAutoCADのメニューバーとツールバーを動的にカスタマイズ!AcadMenuGroupとAcadToolbarの操作
AutoCAD VBAによる業務自動化の領域において、マクロの記述や図形エンティティの直接操作(`AcadModelSpace`の網羅など)はもはや初級・中級の通過点に過ぎない。真に「システム化されたアドイン」を構築するステージにおいて、避けて通れないのがAutoCADのユーザーインターフェース(UI)の動的制御である。
エンドユーザーに「Altキーを押してVBAマネージャーを開き、モジュールを選んで実行してください」などと指示するシステムは、アーキテクチャの敗北であり、保守性の観点からも悪手である。
本稿では、`AcadMenuGroup`および`AcadToolbar`(さらにはCUIx時代におけるメニューバー操作の罠)を駆使し、VBAの起動と同時にカスタムメニューとツールバーをプログラム側から完全自動構築・配置する極限の知見を公開する。
—
1. 現代AutoCADにおけるUIカスタマイズの現実とCUIxの壁
まず、大前提として認識しなければならない技術的負債がある。
AutoCADはバージョン2006以降、従来の`.mns` / `.mnu`といったメニューファイルから、XMLベースの`.cuix`ファイルによるCUI(カスタマイズユーザーインターフェース)アーキテクチャへ移行した。
VBAから操作する `AcadMenuGroups` コレクションは、内部的にこのCUIXのメモリ上へのロード状態をラップしている。
ここでシニアエンジニアが陥りがちな罠が、「すでに存在するグループ名への重複追加による例外」と「AutoCAD終了時のメモリリーク・ゾンビプロセスの発生」である。
UIを動的に操作するコードは、何度ロード・アンロードを繰り返しても「冪等性(いどんせい)」が担保されていなければならない。
—
2. 実装アーキテクチャ:動的メニュー・ツールバー構築の全体像
以下のコードは、指定した名前のメニューグループとツールバーが存在しない場合は新規作成し、すでに存在する場合は一度クリーンアップ(または安全に再利用)した上で、独自のVBAマクロを紐付けたボタンを動的に配置する実用的なプロシージャである。
Option Explicit
‘ ==============================================================================
‘ 模範的アーキテクチャ: 起動時自動UI構築モジュール
‘ ==============================================================================
Public Sub InitializeCustomUI()
On Error GoTo ErrorHandler
Dim currMenuGroup As AcadMenuGroup
Dim targetGroupName As String
targetGroupName = “MyEnterpriseTools”
‘ 1. AcadMenuGroups コレクションから既存グループの有無を走査(安全性の確保)
Dim i As Long
Dim groupExists As Boolean
groupExists = False
For i = 0 To ThisDrawing.Application.MenuGroups.Count – 1
If ThisDrawing.Application.MenuGroups(i).Name = targetGroupName Then
Set currMenuGroup = ThisDrawing.Application.MenuGroups(i)
groupExists = True
Exit For
End If
Next i
‘ 2. 存在しない場合は新規作成(※CUIXのロードパスに注意)
If Not groupExists Then
‘ 注意: 通常はエンタープライズCUIやメインCUIに統合するのが安全だが、
‘ 動的生成の場合は新規メニューグループとしてメモリ上にロードする
Set currMenuGroup = ThisDrawing.Application.MenuGroups.Load(targetGroupName)
End If
‘ 3. 既存の同名ツールバーをパージ(ゾンビ要素の排除)
Call PurgeExistingToolbar(currMenuGroup, “Enterprise Utilities”)
‘ 4. ツールバーの新規作成とボタン(ポップアップメニュー含む)のバインド
Dim customToolbar As AcadToolbar
Set customToolbar = currMenuGroup.Toolbars.Add(“Enterprise Utilities”)
Dim btnMacro1 As String
Dim btnMacro2 As String
‘ AutoCADコマンドラインへマクロを安全に送り込むための構文
‘ ^C^C_-vbarun “ModuleName.MacroName”
btnMacro1 = “^C^C_-vbarun “”C:\\Autodesk\\Macros\\BatchPlot.dvb!ModMain.RunBatchPlot”” ”
btnMacro2 = “^C^C_-vbarun “”C:\\Autodesk\\Macros\\LayerAudit.dvb!ModMain.RunLayerAudit”” ”
Dim toolButton1 As AcadToolbarItem
Dim toolButton2 As AcadToolbarItem
‘ ツールバーアイテムの追加 (index, name, helpstring, macro)
Set toolButton1 = customToolbar.AddToolbarButton(0, “一括印刷”, “図面を一括でPDF/紙出力します”, btnMacro1)
Set toolButton2 = customToolbar.AddToolbarButton(1, “画層監査”, “指定画層の不整合を自動修復します”, btnMacro2)
‘ アイコンの割り当て(通常はリソースDLLやBMPの絶対パスを指定)
‘ toolButton1.SetBitmaps “icon_normal_16.bmp”, “icon_hot_16.bmp”
‘ 5. 画面上の可視化
customToolbar.Visible = True
‘ 6. メニューバー(上部のプルダウン)への統合
Call RegisterPullDownMenu(currMenuGroup)
MsgBox “カスタムUIの初期化が正常に完了しました。”, vbInformation, “System Architect”
Exit Sub
ErrorHandler:
MsgBox “UI初期化エラー: ” & Err.Description, vbCritical, “Critical Error”
‘ 実運用ではここでログ出力基盤へエラートレースを流すこと
End Sub
‘ ==============================================================================
‘ ヘルパー関数: 既存ツールバーの安全な削除
‘ ==============================================================================
Private Sub PurgeExistingToolbar(ByRef mg As AcadMenuGroup, ByVal tbName As String)
On Error Resume Next
Dim tb As AcadToolbar
Set tb = mg.Toolbars.Item(tbName)
If Not tb Is Nothing Then
tb.Delete
End If
On Error GoTo 0
End Sub
‘ ==============================================================================
‘ ヘルパー関数: プルダウンメニューの登録
‘ ==============================================================================
Private Sub RegisterPullDownMenu(ByRef mg As AcadMenuGroup)
On Error Resume Next
Dim menuBar As AcadMenuBar
Set menuBar = ThisDrawing.Application.MenuBar
Dim popMenus As AcadPopupMenus
Set popMenus = mg.Menus
If popMenus.Count > 0 Then
Dim targetMenu As AcadPopupMenu
Set targetMenu = popMenus.Item(0)
‘ すでにメニューバーにアタッチされているか確認して重複を防ぐ
‘ ※厳密な重複チェックはメニューバーのインデックス走査が必要
targetMenu.InsertInMenuBar menuBar.Count + 1
End If
On Error GoTo 0
End Sub
—
3. チーフアーキテクトが指摘する「メモリ管理」と「ライフサイクル」の罠
上記のコードは一見して完結しているように見えるが、AutoCAD VBAの内部アーキテクチャ(COMインターフェースの参照カウンティング)を理解している者から見れば、いくつかの「地雷」が潜んでいる。
A. COMオブジェクトの解放漏れとメモリリーク
VBAは自動ガベージコレクションを備えているが、AutoCADのCOMオブジェクト(特に `AcadApplication`, `AcadDocument`, `AcadMenuGroup` の階层)は、明示的に変数に `Nothing` を代入して参照を切断しない限り、AutoCADプロセスのメモリ空間内にCOM RCW (Runtime Callable Wrapper) の残骸が残り続ける。
これが蓄積すると、図面を閉じたり開いたりするうちにAutoCADがメモリ不足や突然のクラッシュ(Fatal Error)を引き起こす原因となる。
B. グローバル名前空間の汚染とマクロパスの脆弱性
ハードコードされたパス(`C:\\Autodesk\\Macros\\…`)は、クライアントPCの環境が異なるだけで完全に破綻する。
真に堅牢なシステムを構築する場合、`ThisDrawing.Path` や Windows環境変数(`Environ(“APPDATA”)` など)から動的にパスを解決し、VBAプロジェクト(.dvb)自体をAutoCADの自動ロード機構(`acad.fas` や `Startup Suite` / `Appload`)と同期させる必要がある。
—
4. 現場で使える極限の知見:VB.NET (Add-in) への移行ブリッジ
ここまでVBAによるUIカスタマイズを解説したが、率直に言って、AutoCAD 2021以降の環境において、VBAによるUIカスタマイズはレガシー領域の維持管理という側面が強い。
もしあなたが真のエンタープライズ環境の自動化を志すなら、VBAから.NET API(C# / VB.NET)へのブリッジを検討すべきだ。
しかし、既存のVBA資産を生かしつつUIだけをモダンに保ちたい場合、「VBAマクロを叩くCOMラッパーとしてのC# Plug-in」を記述し、AutoCADの `ExtensionLoader` を経由してロードするのが最も手堅いソリューションとなる。
—
5. 総括
AutoCADのUIをVBAから動的に支配することは、単なる「ショートカットの作成」ではない。それは、CADという巨大なデスクトップアプリケーションのライフサイクルに、自作の自動化ロジックをシームレスに組み込み、エンドユーザーの「迷い」をゼロにするためのエンジニアリングそのものである。
今回提示した「冪等性を考慮したグループ走査」「安全なパージ処理」「COMオブジェクトの厳格なライフサイクル管理」の思想は、VBAに限らず、あらゆるCADプログラミングの根底を支える黄金律である。
レガシーな技術であっても、そこに最高峰のアーキテクチャを持ち込むことで、システムは美しく、そして強靭に稼働し続ける。
