【テクニカル・上級編】【上級】AcadDocumentのBeginCommandイベントを捕捉し、特定の禁止コマンド実行を自動キャンセル – AutoCAD VBA解析バイブル

スポンサーリンク

AutoCAD VBAを掌握する極限の知見:BeginCommandイベントによる鉄壁のコマンドインターセプトと社内統制

AutoCAD VBAの領域において、多くの開発者は「マクロの自動記録」や「図形の一括生成」といった表層的なレイヤーにとどまっている。しかし、真のアーキテクトが目指すのは、AutoCADという巨大なCADエンジンのイベントライフサイクルを掌握し、その振る舞いをコードで完全制御することだ。

図面規格の厳格化が求められるエンタープライズ環境において、最も厄介なのは「ユーザーの自由奔放な操作」である。特に`EXPLODE`(分解)や`OVERKILL`といった、データの整合性を破壊しかねないコマンドの実行をいかにして未然に防ぐか。

今回は、`AcadDocument`の`BeginCommand`イベントをフックし、特定の禁止コマンドの実行をリアルタイムで検知・強制キャンセルする、プロダクション品質の社内統制ツールの実装手法を解説する。

1. AutoCADイベントモデルの深層と落とし穴

AutoCADのVBA環境において、イベントを捕捉するには`WithEvents`キーワードを使用する。しかし、ここで多くのエンジニアがハマる致命的な罠がある。

  • イベントの有効化タイミング: 図面が開かれた瞬間、あるいはアドインがロードされた瞬間に`AcadApplication`や`AcadDocument`への参照が正しく結びついていなければならない。
  • モーダルダイアログとCOMのブロック: イベントハンドラ内でAutoCADの標準コマンドやモーダルなUIを不適切に呼び出すと、COMの呼び出しがデッドロックを引き起こす。
  • エラーハンドリングの欠如: イベント内で未処理のエラーが発生した場合、AutoCAD自体が不安定化するか、最悪の場合は強制終了する。

`BeginCommand`イベントは、ユーザーがコマンド名を入力し、実際にそれが実行される直前に発火する。この瞬間にコマンド名を文字列として取得できるため、ブラックリスト方式によるインターセプト(横取り)が可能となる。

2. 実装アーキテクチャ

このソリューションは、以下の2つのコンポーネントで構成する。

1. Class モジュール (`C_CommandMonitor.cls`): `AcadDocument`のイベントを監視し、コマンド名を評価する心臓部。
2. 標準モジュール (`M_Main.bas`): クラスのインスタンス化とライフサイクル管理を行うエントリーポイント。

3. 実装コード:鉄壁のインターセプト・エンジン

以下のコードは、実務の現場でそのまま稼働させうる堅牢性を持たせたものである。メモリリークを防ぐためのオブジェクト参照の管理と、厳密な文字列評価を実装している。

クラスモジュール: `C_CommandMonitor.cls`

Option Explicit

‘ WithEventsを使用してAcadDocumentのイベントを捕捉
Public WithEvents TargetDoc As AcadDocument

‘ 禁止するコマンドのリスト(大文字・小文字を区別せずに比較するためすべて大文字で定義)
Private Const FORBIDDEN_COMMANDS As String = “EXPLODE,PURGE,OVERKILL”

Private Sub TargetDoc_BeginCommand(ByVal CommandName As String)
On Error GoTo ErrorHandler

Dim upperCmd As String
upperCmd = UCase$(Trim$(CommandName))

‘ デバッグ用(必要に応じてコメントアウト)
‘ Debug.Print “Executing Command: ” & upperCmd

‘ 禁止コマンドリストに合致するか判定
If IsCommandForbidden(upperCmd, FORBIDDEN_COMMANDS) Then
‘ 【極限の知見】
‘ BeginCommand内では直接コマンドの中断関数を呼べないため、
‘ AutoCADのSendCommandメソッドを利用して強制的にCANCELを送信し、
‘ さらにVBA側からユーザーへ警告をポップアップする。

‘ 1. コマンドをキャンセルするためのエスケープキー相当の動作を送信
TargetDoc.SendCommand CStr(Chr(3) & Chr(3)) ‘ ^C^C

‘ 2. 警告の通知
MsgBox “【社内統制システム】” & vbCrLf & _
“コマンド ‘” & upperCmd & ” getId’ の実行は、図面規格統制により禁止されています。” & vbCrLf & _
“操作は強制中断されました。”, _
vbCritical + vbOKOnly, “AutoCAD Security Manager”

End If

Exit Sub

ErrorHandler:
‘ 予期せぬエラーでAutoCAD本体を巻き添えにしないための防御策
MsgBox “CommandMonitor Error: ” & Err.Description, vbCritical, “Critical Error”
End Sub

‘ 補助関数:コマンドが禁止リストに含まれているか判定
Private Function IsCommandForbidden(ByVal cmd As String, ByVal list As String) As Boolean
Dim arr() As String
Dim i As Long

arr = Split(list, “,”)
For i = LBound(arr) To UBound(arr)
If cmd = Trim$(arr(i)) Then
IsCommandForbidden = True
Exit Function
End If
Next i

IsCommandForbidden = False
End Function

Private Sub Class_Terminate()
‘ オブジェクト破棄時のクリーンアップ
Set TargetDoc = Nothing
End Sub

標準モジュール: `M_Main.bas`

Option Explicit

‘ グローバル変数としてクラスインスタンスを保持し、スコープの消滅(ガベージコレクション)を防ぐ
Private g_Monitor As C_CommandMonitor

‘ AutoCAD起動時、またはアドイン手動ロード時に実行するエントリポイント
Public Sub InitializeCommandMonitor()
On Error GoTo ErrorHandler

‘ 既に監視中の場合は一度破棄
If Not g_Monitor Is Nothing Then
Set g_Monitor = Nothing
End If

‘ アクティブドキュメントが存在するか確認
If AcadApplication.Documents.Count = 0 Then
MsgBox “監視対象となるアクティブな図面が存在しません。”, vbExclamation
Exit Sub
End If

‘ クラスのインスタンス化とイベント紐付け
Set g_Monitor = New C_CommandMonitor
Set g_Monitor.TargetDoc = AcadApplication.ActiveDocument

MsgBox “AutoCAD 統制モニターが正常に有効化されました。”, vbInformation, “System Ready”
Exit Sub

ErrorHandler:
MsgBox “初期化に失敗しました: ” & Err.Description, vbCritical
End Sub

‘ 監視を停止するプロシージャ
Public Sub TerminateCommandMonitor()
Set g_Monitor = Nothing
MsgBox “AutoCAD 統制モニターを無効化しました。”, vbInformation, “System Stopped”
End Sub

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

1. ガベージコレクションとスコープの維持
VBAにおいて、プロシージャ内でローカル変数としてイベントクラスを宣言すると、プロシージャ終了時にメモリから解放され、イベントが一切発火しなくなる。これを防ぐために、標準モジュールレベルの変数(`g_Monitor`)でインスタンスを強固に保持し続ける必要がある。
2. `SendCommand “^C^C”` による強制割り込み
`BeginCommand`イベントの最中、オブジェクトモデル側から直接現在のコマンドをキルするメソッドは用意されていない。そのため、COMインターフェースを介して強制的にキーボード入力(Ctrl+Cに相当する `Chr(3)`)をストリームに流し込み、AutoCADのコマンドスタックを強制クリアするアプローチをとる。これが最も確実かつ副作用の少ない手法である。
3. 文字列評価の堅牢性
ユーザーが小文字や全角スペース混じりでコマンドを入力するケースを想定し、`UCase$` および `Trim$` による正規化を徹底している。

5. レガシー環境とエンタープライズ運用への提言

VBAによるこのソリューションは迅速な導入が可能である反面、マクロが無効化されたり、ユーザーがVBEからコードを改ざんできるリスクが残る。本当の意味での厳格な社内統制を目指すのであれば、ゆくゆくは ObjectARX (C++) または .NET API (C#) によるManaged Add-inへの移行を視野に入れるべきだ。

しかし、急進的なアーキテクチャの変更が難しいレガシーな現場において、本稿で示したVBAによるイベントフックは、低コストで最大の防御効果を発揮する強力な一手となる。

AutoCADの挙動のすべてをコードの統制下に置き、データの品質と信頼性を担保すること――それこそが、現場を支えるエンジニアの矜持である。

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