【実務・中級編】【上級】AcadApplicationのイベントハンドリング:図面保存やコマンド終了をトリガーに外部DBを自動更新する高度な連携 – AutoCAD VBA解析バイブル

スポンサーリンク

【上級】AcadApplicationのイベントハンドリング:図面保存やコマンド終了をトリガーに外部DBを自動更新する高度な連携

こんにちは。オートデスク製品のカスタマイズと大規模な業務自動化を統括するチーフアーキテクトだ。
これまで数多くの製造業やゼネコンの設計現場を見てきたが、未だに「図面を保存したら手動でエクセルに集計する」「設計変更の履歴を誰も追えない」といった前近代的なワークフローを放置している現場が後を絶たない。

設計者が図面を描き、保存する。その瞬間、バックグラウンドで外部データベース(SQL Server等)へ自動的にメタデータや変更履歴が同期される――。
これこそが、ヒューマンエラーを根絶し、真のBIM/CIMデータ連携を実現するプロフェッショナルなアーキテクチャだ。

今回は、AutoCAD VBAにおける`WithEvents`を用いた`AcadApplication`のイベント監視を極限まで解説する。単に動くだけのコードではない。「なぜその設計でなければならないのか」「実務で必ず直面する罠をどう回避するか」という、現場の生き血を吸った知見をすべて授けよう。

1. なぜ「ドキュメント側」ではなく「アプリケーション側」なのか?

多くの初学者が犯す設計ミスは、各図面(`AcadDocument`)のモジュール内でイベントを捉えようとすることだ。
しかし、実務の現場を考えてみてほしい。設計者は日々何十枚もの図面を開き、閉じ、新しく作成する。その都度イベント用のコードを各図面に埋め込むなど、保守性の観点から「悪夢」でしかない。

図面のライフサイクルを超越して常に監視を行うためには、`AcadApplication`(アプリケーションレベル)のイベントを捉えなければならない。

アプリケーションイベントの生命線

  • `BeginSave`: 図面がストレージに書き込まれる直前に発火。メタデータのハッシュやプロパティをDBに刻むのに最適。
  • `EndCommand`: 特定のコマンド(例: `SAVE`, `QSAVE`, `EXPORT`など)が完了した瞬間に発火。
  • `AppActivate` / `DocumentActivate`: 複数図面間を行き来する際のコンテキスト管理。

これらを「クラスモジュール」で一元管理することこそが、堅牢なAutoCAD自動化の唯一の正解である。

2. アーキテクチャの全体像

堅牢な連携システムを構築するため、以下の3つの要素で構成する。

1. 標準モジュール (`modMain`): アプリケーションの起動時にイベント監視クラスをインスタンス化し、グローバル領域に保持する。
2. クラスモジュール (`CAppEvents`): `WithEvents`キーワードを使い、`AcadApplication`のイベントをフックする。
3. データベース連携レイヤー: ADO(ActiveX Data Objects)を用いてSQL Serverへ非同期に近い形でトランザクションを流し込む。

3. プロダクションコード実装例

ここからが本題だ。コピペでそのまま現場のテスト環境に投入できるレベルの、エラーハンドリングを網羅したコードを提示する。

① クラスモジュール: `CAppEvents`

このクラスがAutoCADの脈動を常に監視する心臓部となる。

Option Explicit

‘ WithEventsを使用してAcadApplicationのイベントをフック
Public WithEvents アプリ As AcadApplication

‘ クラス初期化時にアプリケーション参照をバインド
Private Sub Class_Initialize()
Set アプリ = ThisDrawing.Application
End Sub

‘ ==========================================
‘ イベント1: 図面保存開始イベント (BeginSave)
‘ ==========================================
Private Sub アプリ_BeginSave(ByVal ドキュメント名 As String)
On Error GoTo ErrorHandler

Dim activeDoc As AcadDocument
Set activeDoc = アプリ.ActiveDocument

‘ デバッグ出力(イミディエイトウィンドウ)
Debug.Print “[Event] 保存開始: ” & ドキュメント名

‘ 外部データベースへログとメタデータを送信するプロシージャを呼出
Call SyncDrawingMetadataToDB(activeDoc, “BEGIN_SAVE”)

Exit Sub
ErrorHandler:
‘ イベント内でエラーが発生してもAutoCAD本体をクラッシュさせてはならない
MsgBox “DB同期エラー (BeginSave): ” & Err.Description, vbCritical, “API連携エラー”
End Sub

‘ ==========================================
‘ イベント2: コマンド終了イベント (EndCommand)
‘ ==========================================
Private Sub アプリ_EndCommand(ByVal コマンド名 As String)
On Error GoTo ErrorHandler

‘ 例えば特定のコマンド(例: 属性書き出しやブロック置換など)の終了をトリガーにする場合
If コマンド名 = “QSAVE” Or コマンド名 = “SAVEAS” Then
Debug.Print “[Event] コマンド完了による保存検知: ” & コマンド名
‘ 必要に応じた追加処理を記述
End If

Exit Sub
ErrorHandler:
Debug.Print “[Error] EndCommand Handler: ” & Err.Description
End Sub

‘ ==========================================
‘ データベース同期ロジック (ADOによるSQL Server連携)
‘ ==========================================
Private Sub SyncDrawingMetadataToDB(ByVal doc As AcadDocument, ByVal actionType As String)
Dim conn As Object
Dim cmd As Object
Dim connStr As String
Dim drawingName As String
Dim drawingPath As String
Dim userMachine As String

‘ 接続文字列の構築(SQL Server Authenticationの例)
connStr = “Provider=SQLOLEDB;Server=192.168.1.50;Database=DesignMetadataDB;Uid=db_user;Pwd=SecurePassword123;”

On Error GoTo DBError

Set conn = CreateObject(“ADODB.Connection”)
conn.Open connStr

‘ 図面情報の取得
drawingName = doc.Name
On Error Resume Next
drawingPath = doc.Path & “\” & drawingName
If Err.Number <> 0 Then drawingPath = “未保存(新規図面)”
On Error GoTo DBError

userMachine = Environ(“COMPUTERNAME”)

‘ パラメータ化クエリによるSQLインジェクション対策(プロフェッショナルとしての最低限の作法)
Dim sql As String
sql = “INSERT INTO DrawingAuditLogs (DrawingName, DrawingPath, ActionType, ModifiedByMachine, Timestamp) ” & _
“VALUES (?, ?, ?, ?, GETDATE())”

Set cmd = CreateObject(“ADODB.Command”)
Set cmd.ActiveConnection = conn
cmd.CommandText = sql

‘ パラメータの追加
cmd.Parameters.Append cmd.CreateParameter(“p1”, 200, 1, 255, drawingName)
cmd.Parameters.Append cmd.CreateParameter(“p2”, 200, 1, 500, drawingPath)
cmd.Parameters.Append cmd.CreateParameter(“p3”, 200, 1, 50, actionType)
cmd.Parameters.Append cmd.CreateParameter(“p4”, 200, 1, 100, userMachine)

cmd.Execute

conn.Close
Set cmd = Nothing
Set conn = Nothing
Exit Sub

DBError:
‘ ネットワーク切断やDBダウン時にAutoCADの保存自体を阻害してはならないため、
‘ エラーはログに留め、処理を継続させる(あるいはローカルのキューに退避する設計が望ましい)
Debug.Print “[Critical DB Error] ” & Err.Description
If Not conn Is Nothing Then
If conn.State = 1 Then conn.Close
End If
Set conn = Nothing
End Sub

② 標準モジュール: `modMain`

アプリケーション全体でイベントリスナーのインスタンスを生存させるためのモジュール。

Option Explicit

‘ ガベージコレクションによってインスタンスが消滅しないよう、グローバル(Public)変数として保持
Public AppListener As CAppEvents

‘ AutoCAD起動時、あるいは手動実行時にイベント監視を開始するエントリーポイント
Public Sub StartAutoCADEventListener()
If AppListener Is Nothing Then
Set AppListener = New CAppEvents
MsgBox “AutoCAD データベース自動同期システムが正常に稼働を開始しました。”, vbInformation, “システム起動”
Else
MsgBox “すでに監視システムは稼働中です。”, vbExclamation, “確認”
End If
End Sub

‘ 監視を停止する場合
Public Sub StopAutoCADEventListener()
Set AppListener = Nothing
MsgBox “AutoCAD データベース自動同期システムを停止しました。”, vbInformation, “システム停止”
End Sub

4. チーフアーキテクトが教える「現場で絶対に踏んではいけない地雷」

上記のコードは美しく動くが、実務の現場に投入するにあたって、以下の設計上の注意点を理解していなければ痛い目を見る。

1. データベースの応答遅延がAutoCADをフリーズさせる

`BeginSave`イベントの中で重いSQLクエリやリモートサーバーへの通信を行うと、図面の保存処理そのものがブロック(フリーズ)される。設計者が「保存が終わらない!」とイライラする原因になる。

  • 対策: 本番環境では、DBへの書き込みは別スレッド(COMコンポーネントや.NETのバックグラウンドタスク)に非同期で投げるか、一度ローカルのSQLiteやテキストログへ逃がす「ライトバック・キャッシュ方式」を採用すべきだ。VBA単体で行う場合はタイムアウト設定を極限まで短くすること。

2. 変数のスコープ切れ(ガベージコレクションの罠)

標準モジュールで `Dim AppListener As CAppEvents` とプロシージャ内で宣言してしまった場合、プロシージャを抜けた瞬間にインスタンスが消滅し、「イベントが一切発火しない」という不可解なバグに直面する。

  • 対策: 必ず `Public` 変数、あるいはクラスのライフサイクルに紐づくグローバル領域で保持し続けること。

3. 未保存図面のパス取得エラー

新規作成したばかりの図面(まだ一度も名前を付けて保存されていない状態)では、`doc.Path` プロパティにアクセスするとランタイムエラー(エラー番号: 該当なし、オブジェクトまたはアプリケーション定義のエラー)が発生する。

  • 対策: 上記のサンプルコードのように `On Error Resume Next` を適切に挟み、未保存状態のハンドリングを必ず実装すること。

5. さらなる高みへ:VBAから.NET (C#) アドインへの移行判断基準

ここまでVBAによる高度なイベントハンドリングを解説したが、チーフアーキテクトとしての最後の進言をしておこう。

VBAは手軽で強力だが、以下の要件が出てきた瞬間に限界を迎える。

  • JSONやREST APIとの本格的な非同期通信(HTTPリクエスト)
  • SQL Serverとのセキュアなコネクションプーリング
  • 数万枚の図面を一括処理するマルチスレッド処理

もし、あなたが統括するプロジェクトの規模が拡大し、より堅牢なエンタープライズアーキテクチャを求めるのであれば、今回のVBAロジックをベースにしつつ、AutoCAD .NET API (C#) の `IExtensionApplication` と `DocumentCollection.DocumentActivated` を使ったアドイン開発へのリファクタリングを検討してほしい。

しかし、まずは今回のVBAコードをあなたの設計環境に導入してみてほしい。図面を「Ctrl + S」と叩いた瞬間、背後でデータベースのレコードが更新される快感――それこそが、自動化エンジニアの醍醐味だ。

実装でつまずいたか?仕様の壁にぶ当たったか?
コードは嘘をつかない。論理的に組み立てられたシステムは、必ず君の業務を解放する。健闘を祈る。

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