【上級】AcadDocumentのBeginCommandイベントを捕捉し、特定の禁止コマンド実行を自動キャンセル
開発プロジェクトのリーダーである私から、AutoCAD VBAを極めたいあなたへ一つ問いたい。
「ユーザーが勝手に『EXPLODE(分解)』や『OVERKILL』を実行し、図面のトポロジーやブロック構造を破壊するのを、どうやって防いでいるか?」
標準機能やレイヤーロックだけで防げるなどと考えていないだろうか。実務の現場では、熟練のオペレーターであってもうっかり禁止コマンドを叩いてしまい、データ整合性が崩壊することが多々ある。
今回は、AutoCAD VBAのオブジェクトモデルにおける隠し味、`AcadDocument`のイベントハンドラ(特に `BeginCommand`)を完全に手なづけ、特定のコマンド実行をリアクティブかつ強制的にキャンセルする社内統制ツールの設計思想と実装コードを伝授する。
中途半端な知識で書かれたネット上のコードは、メモリリークを起こしたり、イベントのデッドロックでAutoCADごとフリーズしたりする。
プロのアーキテクトが書くべき「バグの起きない堅牢なコード」の全貌をここに公開しよう。
—
1. なぜ「イベントハンドラ」なのか? アーキテクチャの選定理由
GUIのボタンにマクロを割り当てるアプローチは、リボンやショートカット(コマンドライン直接入力)から実行された場合には無力だ。
全社的な図面標準(CADコンプライアンス)を強制するためには、CADのエンジン自体が発火させるイベントを捕らえる必要がある。
ここで登場するのが `AcadDocument` の `BeginCommand` イベントだ。
コマンド名が文字列として渡されるため、ユーザーが入力した瞬間にそれをフックし、条件に合致すれば「キャンセル信号」を送るという極めてスマートなアプローチが取れる。
しかし、VBAでイベントを扱う際には、以下の地雷原を避けて通ることはできない。
1. WithEvents変数のスコープ切れによるイベントロスト
2. イベントハンドラ内での重い処理(AutoCADのハングアップ誘発)
3. キャンセル処理の競合による予期せぬ挙動
これらを完全にクリアするプロダクションコードを構築する。
—
2. 堅牢な実装:クラスモジュールによるイベント管理
VBAでアプリケーション/ドキュメントイベントを安全に扱うための鉄則は、「イベントを監視する専用のクラスモジュールを切ること」だ。標準モジュールにいきなり `Public WithEvents` は書けない。ここが最初の分かれ道である。
ステップ1:クラスモジュールの作成(名称:`C_CommandInterceptor`)
以下のコードを、新規に挿入したクラスモジュールにそのまま貼り付けてほしい。
Option Explicit
‘ グローバルにイベントをフックするためのWithEvents変数
Public WithEvents TargetDoc As AcadDocument
‘ 禁止するコマンドのリスト(大文字・小文字を区別しないためUCaseで比較する)
Private m_ForbiddenCommands As Variant
Private Initialize_Executed As Boolean
”’
”’
Private Class_Initialize()
‘ ここに社内規定で禁止・制限したいコマンド名を登録する
m_ForbiddenCommands = Array(“EXPLODE”, “OVERKILL”, “PURGE”)
End Class_Initialize
”’
”’
”’ 実行されたコマンドの文字列
Private Sub TargetDoc_BeginCommand(ByVal CommandName As String)
On Error GoTo ErrorHandler
Dim i As Long
Dim upperCmd As String
upperCmd = UCase(Trim(CommandName))
‘ 禁止リストとの突合
For i = LBound(m_ForbiddenCommands) To UBound(m_ForbiddenCommands)
If upperCmd = m_ForbiddenCommands(i) Then
‘ 【極意】AutoCADのコマンド実行を中断させる
‘ VBAからネイティブのキャンセルを直接呼ぶことはできないため、
‘ SendCommandメソッドを利用してESCキーを送信し、コマンドを強制終了させる。
‘ 警告メッセージの提示
MsgBox “【社内統制アラート】” & vbCrLf & _
“コマンド ‘” & upperCmd & “‘ の実行は、図面整合性維持のため禁止されています。”, _
vbCritical + vbOKOnly, “AutoCAD ガバナンスシステム”
‘ コマンドを強制キャンセルするためESCを2回送信
‘ (ダイアログが開いている場合やプロンプト待ちの状態を確実に抜けるため)
ActiveDocument.SendCommand Chr(27) & Chr(27)
Exit For
End If
Next i
Exit Sub
ErrorHandler:
‘ イベントハンドラ内でのエラーはAutoCAD全体のクラッシュに繋がるため確実に握りつぶすかログ化する
Debug.Print “Error in BeginCommand: ” & Err.Description
End Sub
ステップ2:標準モジュールでのライフサイクル管理
クラスのインスタンスを保持し続けなければ、イベントは一瞬で消滅する。標準モジュールでグローバル変数として保持し、図面が開かれたタイミング(あるいは手動マクロ実行時)で結線する。
名称:`M_EventListener`
Option Explicit
‘ イベント監視クラスのインスタンスを保持するグローバル変数
Public InterceptorInstance As C_CommandInterceptor
”’
”’
Public Sub StartCommandMonitor()
‘ すでにインスタンスが存在する場合は二重起動を防ぐ
If Not InterceptorInstance Is Nothing Then
MsgBox “監視システムは既に稼働しています。”, vbInformation
Exit Sub
End If
Set InterceptorInstance = New C_CommandInterceptor
‘ 現在アクティブなドキュメントをイベント監視対象にバインド
Set InterceptorInstance.TargetDoc = ThisDrawing
MsgBox “AutoCAD コマンドガバナンス監視を開始しました。”, vbInformation
End Sub
”’
”’
Public Sub StopCommandMonitor()
If Not InterceptorInstance Is Nothing Then
Set InterceptorInstance.TargetDoc = Nothing
Set InterceptorInstance = Nothing
MsgBox “AutoCAD コマンドガバナンス監視を停止しました。”, vbInformation
Else
MsgBox “監視システムは稼働していません。”, vbInformation
End If
End Sub
—
3. 実務運用における重要な注意点とデータベース連携
このツールを実際の設計部隊に展開する際、現場のエンジニアから必ず出る要望と、アーキテクトとして抑えておくべき注意点を解説する。
1. データベース・外部ログ連携への拡張
単にメッセージを出して止めるだけでは、「なぜ怒られたのか」がログに残らない。プロダクション環境では、`TargetDoc_BeginCommand` 内で社内のSQL ServerやSQLite、あるいは共有フォルダのCSVファイルに対して「誰が・いつ・どの図面で・どの禁止コマンドを叩いたか」のログを非同期(または軽量に)書き込む処理をフックさせると、監査証跡として極めて強力なツールに進化する。
2. 図面オープン時の自動アタッチ(AutoCADの自動ロード)
毎回手動で `StartCommandMonitor` を叩かせるのはUI/UXとして三流だ。
これを解決するには、`acad.lsp` または `acaddoc.lsp` を利用し、図面が開かれた瞬間(`S::STARTUP`)にVBAの特定マクロを自動実行するか、VB.NETのIExtensionApplicationによる完全アドイン化へ移行する布石とするべきだ。VBAだけで完結させる場合は、スタートアップ時に自動実行されるマクロに組み込むのが定石となる。
3. `SendCommand Chr(27)` の挙動の癖
AutoCAD VBAにおいて、コードの実行中に発生したイベント内で `SendCommand` を呼ぶタイミングによっては、コマンドスタックが競合し「コマンドがアクティブな間は実行できません」というエラーを吐くことがある。
今回のコードでは `BeginCommand` の発火直後にESCをねじ込むことで大半のコマンドを即座にハントできるが、より厳密な制御が必要な場合は、VB.NET (`IExtensionApplication` / `CommandEnded`) へのリプレイスを検討すべき境界線だと言える。
—
4. チーフアーキテクトからの総括
今回紹介した `AcadDocument` のイベントハント手法は、AutoCAD VBAのポテンシャルを限界まで引き出すための基本技術だ。
「ユーザーの自由を奪う」のではなく、「図面の品質と資産価値をシステムで担保する」――これこそが、業務自動化エンジニアに求められる真の設計思想である。
コピペで動かすことはゴールではない。このコードをベースに、自社のレギュレーションに合わせたブラックリストの動的読み込み(外部JSON/INIファイル連携など)へ拡張し、真に強靭な設計インフラを構築してほしい。
あなたの開発現場のコード品質が、次の次元へ引き上げられることを期待している。
