【実務・中級編】【上級】AcadApplication.MenuBarにカスタムメニューを動的に追加し、VBAツールを標準機能化 – AutoCAD VBA解析バイブル

スポンサーリンク

【AutoCAD VBA】CUI地獄からの脱却:`MenuBar`をプログラムで完全掌握し、自作ツールを標準機能化する極意

業務効率化のために血汗を流して作り上げたVBAマクロ。しかし、いざそれを現場の設計者へ配布する段階で、こんな絶望感を味わったことはないか?

  • 「CUIファイル(カスタマイズファイル)を書き換えて、ワークスペースを再読み込みしてください」とマニュアルに書いたのに、全端末で手順がバラバラに失敗する。
  • AutoCADのバージョンアップやパッチ適用のたびに、苦労して追加したカスタムメニューが吹き飛ぶ。
  • 複数人での運用において、誰かがCUIファイルをロックしてしまい、社内共有フォルダでの運用が破綻する。

断言しよう。配布のたびにユーザーの手動設定を強いる時点で、その自動化ツールは「欠陥品」だ。
真のプロフェッショナルであれば、AutoCADが起動した瞬間、あるいはアドインが読み込まれた瞬間に、コードベースでUIを動的に構築し、環境に依存しない完全な「プラグ&プレイ」を実現すべきである。

今回は、`AcadApplication.MenuBar`を徹底的にハックし、CUIファイルの一切の改変なしに自作VBAツールを標準機能の如くメニューバーへ降臨させる、極限のプロダクションコードを伝授する。

1. AutoCAD UIアーキテクチャの核心:なぜMenuBarなのか?

多くの初心者は「リボン(Ribbon)」や「ツールバー」をプログラムから制御しようとして泥沼にハマる。AutoCADのモダンなリボン制御は、XML(CUIx)のパースや厳密なリソースIDの管理が必要であり、VBAから直接触るにはあまりにもオーバーヘッドが大きすぎる。

一方、古風ではあるが`MenuBar`オブジェクトは、AutoCADのメインウィンドウ(`AcadApplication`)の直下に存在し、COMインターフェースを通じて最もダイレクトかつノーリスクで操作できるUIレイヤーだ。

メニューバー操作における3大鉄則

1. 二重登録の完全阻止(冪等性の担保)
AutoCAD VBAのマクロは、起動時や初期化コードが複数回走ることが多積する。同じメニュー名が重複生成されるバグは、プロとして絶対に避けなければならない。
2. メニューの生存期間(Life Cycle)の理解
MenuBarに追加したアイテムはセッション単位で保持される。ドキュメントを閉じても消えないが、AutoCADを終了すれば消える。この特性を利用したクリーンアップ設計が求められる。
3. マクロパスの動的解決(ハードコーディングの排除)
「`C:\Macro\tool.dvb!Module1.Main`」のような固定パスは、ユーザーのインストール先が「Dドライブ」や「デスクトップ」に変わった瞬間に死ぬ。必ず自ファイルのカレントパスを動的に取得してバインドしろ。

2. 【プロダクションコード】動的メニュー構築モジュール

以下のコードは、実務の現場でそのまま組み込める堅牢性を備えた標準モジュール(`.bas`)の全容である。エラーハンドリング、二重登録チェック、動的パス解決のすべてを高次元で網羅している。

Option Explicit

‘ ==============================================================================
‘ モジュール名: CUIlessMenuManager
‘ 概要: CUIファイルを一切汚さず、起動時にMenuBarへカスタムメニューを動的追加する
‘ ==============================================================================

Private Const MENU_TITLE As String = “業務効率化ツール(&B)”
Private Const MACRO_NAME As String = “図面一括処理”

Public Sub InitializeCustomMenu()
Dim acadApp As AcadApplication
Dim currMenuBar As AcadMenuBar
Dim newMenu As AcadPopupMenu
Dim menuItem As AcadPopupMenuItem
Dim macroString As String
Dim i As Long
Dim isAlreadyExists As Boolean

On Error GoTo ErrorHandler

Set acadApp = ThisDrawing.Application
Set currMenuBar = acadApp.MenuBar

‘ ————————————————————————–
| 1. 冪等性の担保:すでに同名のメニューが存在するかチェックし、あれば一度削除する
‘ ————————————————————————–
isAlreadyExists = False
For i = 0 To currMenuBar.Count – 1
If currMenuBar.Item(i).Name = MENU_TITLE Then
isAlreadyExists = True
Exit For
End If
Next i

If isAlreadyExists Then
‘ 既存メニューが存在する場合は安全のため一度削除して再構築する
‘ ※インデックス指定での削除が必要な点に注意
Dim targetMenu As AcadPopupMenu
Set targetMenu = currMenuBar.Item(i)
targetMenu.RemoveFromMenuBar
End If

‘ ————————————————————————–
| 2. 動的パス解決:現在稼働中の.dvbファイルのフルパスを取得し、マクロ文字列を生成
‘ ————————————————————————–
‘ パスにスペースが含まれている場合を考慮し、シングルクォーテーションで囲む
macroString = “-vbarun ” & Chr(34) & ThisDrawing.Path & “\BimBatchTool.dvb!modMain.RunBatchProcess” & Chr(34) & ” ”

‘ ————————————————————————–
| 3. メニューバーおよびポップアップメニューの生成
‘ ————————————————————————–
‘ メニューバーの末尾(Countの位置)に新しいポップアップメニューを追加
Set newMenu = currMenuBar.Add(MENU_TITLE)

‘ メニュー項目の追加 (インデックスは 0 起算)
‘ 引数: 挿入位置(インデックス), 表示名, 実行するマクロ文字列
Set menuItem = newMenu.AddMenuItem(0, MACRO_NAME, macroString)

‘ 必要であれば区切り線やサブメニューも追加可能
‘ newMenu.AddSeparator 1
‘ Set subItem = newMenu.AddMenuItem(2, “設定…”, “-vbarun …”)

Exit Sub

ErrorHandler:
MsgBox “カスタムメニューの初期化中に致命的なエラーが発生しました。” & vbCrLf & _
“詳細: ” & Err.Description, vbCritical, “AutoCAD VBA Error”
End Sub

Public Sub RemoveCustomMenu()
Dim acadApp As AcadApplication
Dim currMenuBar As AcadMenuBar
Dim i As Long

On Error Resume Next
Set acadApp = ThisDrawing.Application
Set currMenuBar = acadApp.MenuBar

‘ メニューバーを逆順に走査して該当メニューを安全に抹消
For i = currMenuBar.Count – 1 To 0 Step -1
If currMenuBar.Item(i).Name = MENU_TITLE Then
currMenuBar.Item(i).RemoveFromMenuBar
Exit For
End If
Next i
End Sub

3. コードの急所:なぜこの実装でなければならないのか?

A. パスの動的解決とスペース対策

多くの自作ツールが動かなくなる原因の第1位は「ファイルパスのスペース(例: `C:\My Folder\tool.dvb`)」である。AutoCADのコマンドラインは空白を区切り文字として認識するため、パスやマクロ名にスペースが含まれていると、そこでコマンドが途切れてエラーを起こす。
本コードでは、`Chr(34)`(ダブルクォーテーション)でパスを厳重に囲むことで、空白を含むディレクトリパスであっても確実に実行できるよう担保している。

B. 安全なライフサイクル管理(削除と再構築)

開発途中でマクロの構造を変更テストする際、古いメニューが残り続けると「どのメニューがどのコードを叩いているか」分からなくなる。
`RemoveFromMenuBar`メソッドは、メニューバー上の表示を消去するだけであり、メモリ上のオブジェクト参照とは挙動が異なる。そのため、ループ処理で正確に名前を突き止め、存在する場合は一度クリーンアップしてから再構築(Add)するフローが極めて安全である。

4. プロダクション環境への組み込みと「真の自動化」

このモジュールを用意しただけでは、ユーザーが手動で `InitializeCustomMenu` を叩かなければならない矛盾が生じる。これを真の「標準機能化」にするためには、AutoCADの自動ロード機構(acad.fas / acad.lsp / acaddoc.lsp)、あるいはドキュメントオープンイベントと組み合わせる必要がある。

最もスマートなアプローチは、`ThisDrawing`クラスモジュールや、専用のローダー用LISP(またはアプリケーション起動時のイベント)から、DVBのロードと同時に初期化プロシージャを自動キックすることだ。

‘ AcadDocumentのOpenイベント等で自動実行させる場合の例
Private Sub AcadDocument_Open()
‘ 図面が開かれた瞬間にメニューが未登録であれば自動構築する
Call InitializeCustomMenu
End Sub

これさえ仕込んでおけば、ユーザーは社内サーバー等にあるこの`.dvb`ファイルを読み込むだけで、AutoCADの画面上部に一瞬で専用メニューが描画される。CUIファイルの配布や、面倒なワークスペースのカスタマイズ作業は、今日この瞬間から過去のものとなる。

5. チーフアーキテクトからの総括

CUIファイルの迷宮に迷い込む時代は終わった。
COMのオブジェクトモデルを正しく理解し、`AcadApplication.MenuBar`をプログラムの支配下に置くことで、あなたの開発したVBAツールは「単なるマクロの集まり」から、商用アドインに匹敵する「洗練されたAutoCAD標準機能」へと昇華する。

設計の美しさは、そのままコードの堅牢性に直結する。ぜひ、あなたの開発プロジェクトのスタンダードとしてこの設計思想を取り入れてほしい。業務効率化の限界を突破するのは、いつだって妥協のないエンジニアリングだ。

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