AutoCAD VBAを掌握する極限の知見
バッチ処理の暗殺者:DWG「読み取り専用」ダイアログを制圧する極意
AutoCAD VBAによる大規模な図面ファイルのバッチ処理、あるいは外部システム連携において、最も厄介な障害の1つが「この図面は現在別のユーザー(またはプロセス)によって編集のために開かれています。『読み取り専用』で開きますか?」というダイアログボックスだ。
このモーダルダイアログが出現した瞬間、VBAの実行スレッドは完全に凍結し、無人であるはずの夜間バッチ処理は朝まで完全停止する。開発者であれば誰もが一度は直面し、そして頭を抱えたことがある問題だろう。
本稿では、この悪名高いダイアログを如何にして完全に無力化し、完全自動化されたパイプラインを構築するか、その極限の知見をコードとシステムアーキテクチャの双方向から解き明かす。
—
1. なぜ「通常のアプローチ」では失敗するのか
多くの初学者や中級者は、AutoCADの `Documents.Open` メソッドの引数を調整したり、`FILEDIA` システム変数を `0`(オフ)にしたりすることで、このダイアログを回避しようとする。
しかし、`FILEDIA` を 0 にしても、この「読み取り専用」確認ダイアログは消えない。
なぜなら、これはファイルダイアログ(ファイル選択UI)ではなく、排他制御(File Locking)に起因する安全装置としての警告メッセージだからだ。AutoCADの内部エンジン(ObjectARX)レベルで安全性が担保されない限り、このメッセージは容赦なく画面に割り込んでくる。
ここで、泥臭くも極めて確実なアプローチが必要となる。「システム変数による制御」と「Windows API / SendKeysによるUI介入」のハイブリッド戦術である。
—
2. アーキテクチャの全体像:防御と介入の二段構え
完全自動化を実現するためには、以下の2つの防壁を突破する必要がある。
1. AutoCAD自体の警告抑制(システム変数): `DEMANDLOAD` や `XCLIPFRAME` のようなマイナーなものではなく、ファイルオープン時のバックグラウンド動作を制御する。
2. UIスレッドへの強制介入(SendKeys / Windows API): どうしてもポップアップしてしまったモーダルダイアログに対し、ミリ秒単位のタイミングで「はい(Read-Only)」のキー入力を送り込む。
—
3. 実装コード:完全自動オープン・エンジン
以下に、実務の現場で即座に機能する堅牢なVBAコードを提供する。オブジェクトのライフサイクル管理とエラーハンドリングを極限まで高めた実装だ。
Option Explicit
‘ Windows API: ウィンドウのアクティブ化と制御用(高度な制御が必要な場合വ拡張)
If VBA7 Then
Declare PtrSafe Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)
Else
Declare Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)
End If
/
- 指定されたDWGファイルを、排他制御を無視して強烈に自動オープンする
- @param {String} fullPath – 対象DWGファイルの絶対パス
- @return {AcadDocument} – 開かれたドキュメントオブジェクト
/
Public Function ForceOpenDWG(ByVal fullPath As String) As AcadDocument
Dim targetDoc As AcadDocument
Dim fso As Object
‘ 1. ファイルの存在確認(ランタイムエラーの予防)
Set fso = CreateObject(“Scripting.FileSystemObject”)
If Not fso.FileExists(fullPath) Then
Err.Raise vbObjectError + 1000, “ForceOpenDWG”, “指定されたファイルが存在しません: ” & fullPath
End If
On Error GoTo ErrorHandler
‘ 2. AutoCADの警告ダイアログ等を一時的に抑制
‘ SECURELOAD: 悪意のあるコードの実行を防ぐ安全装置だがバッチでは邪魔になる場合がある (0:オフ, 1:警告, 2:ロード)
Dim originalSecureLoad As Integer
originalSecureLoad = ThisDrawing.GetVariable(“SECURELOAD”)
ThisDrawing.SetVariable “SECURELOAD”, 0
‘ 3. キーボードバッファへ「読み取り専用で開く」ための割り込みを予約
‘ ダイアログが出現した瞬間に「Enter」または「Y」が押されるようにSendKeysを先行投入
‘ 構文: “{ENTER}” は「はい」がデフォルトフォーカスされているダイアログに対して極めて有効
Application.SendKeys “{ENTER}”, True
‘ 4. ドキュメントのオープン実行
‘ 既に誰かが開いている場合、ここで内部的にモーダルダイアログがポップアップするが、
‘ 直前に仕込んだ SendKeys がダイアログを即座に踏み潰す。
Set targetDoc = ThisDrawing.Application.Documents.Open(fullPath, ReadOnly:=False)
‘ 5. システム変数の復元
ThisDrawing.SetVariable “SECURELOAD”, originalSecureLoad
‘ 6. オブジェクトの返却
Set ForceOpenDWG = targetDoc
‘ クリーンアップ
Set fso = Nothing
Exit Function
ErrorHandler:
‘ 異常終了時もシステム変数の復元を確実に実行
On Error Resume Next
ThisDrawing.SetVariable “SECURELOAD”, originalSecureLoad
Set fso = Nothing
‘ エラーを上位へ伝播
Err.Raise Err.Number, “ForceOpenDWG [” & fullPath & “]”, Err.Description
End Function
—
4. チーフアーキテクトが教える:実運用における「罠」と最適化
上記の `SendKeys` アプローチは極めて強力だが、WindowsのメッセージループやAutoCADの描画スレッドの負荷状況によっては、キー入力のタイミングがズレるというリスクを常に孕んでいる。
シニアエンジニアとして、この手法をプロダクション環境(24時間稼働のバッチサーバー等)に導入する際の重要な知見を共有する。
① `SendKeys` の同期的実行とウェイトの調整
`Application.SendKeys(text, wait)` の第二引数に `True` を指定することで、キー送信が対象アプリケーションに処理されるまでVBAの実行を同期的に待たせることができる。しかし、AutoCADの重いDWG読み込みプロセスにおいては、これだけでは不十分な場合がある。
ダイアログの描画遅延が見られる環境では、ファイルオープンの直前ではなく、FileSystemObject等でファイルのロック状態を事前に検知し、ロックされている場合のみSendKeysを多重に仕込むという条件分岐を入れるのが、アーキテクチャとしてより洗練されている。
② メモリリークとCOMオブジェクトの解放
バッチ処理で何百ものDWGを順次オープン・クローズしていくと、AutoCAD VBA特有のCOMメモリリーク(Heap Fragmentation)が発生する。
`Documents.Open` で開いた `AcadDocument` は、処理が終了したら必ず以下のように明示的にメモリから破棄しなさい。
targetDoc.Close SaveChanges:=False
Set targetDoc = Nothing
‘ ガベージコレクションの強制(VBA単体では完全ではないが、COM参照カウンタを落とす)
DoEvents
③ マルチスレッド・並列処理の幻想
「AutoCADを複数起動して同時に処理させれば高速化するのでは?」という発想に行き着くが、AutoCADのCOMインターフェースはスレッドセーフではない。複数インスタンスの制御は、ライセンス数やCPUコアの負荷を考慮すると、かえってシステム全体の安定性を著しく損なう。「シングルインスタンスで、極限まで最適化されたシーケンシャル処理」こそが、AutoCAD自動化における真のベストプラクティスである。
—
5. 結論
「読み取り専用」ダイアログという、開発者の心を折りにかかる些細な障害。
しかし、システム変数の挙動を熟知し、WindowsのUIメッセージループの隙間を `SendKeys` で縫い刺すこのテクニックを習得すれば、あなたのバッチシステムは、深夜の無人環境でも一度たりとも止まることのない「鉄の意志」を手に入れる。
妥協のないコードとアーキテクチャで、レガシーなCAD環境を完全に従えよ。
