【AutoCAD VBAを掌握する極限の知見】AcadApplication.WindowState制御によるUI/UXの極限最適化とシステム間連携
Excelなどの外部ホストアプリケーションからAutoCADをCOM(Component Object Model)経由で操作する際、多くの開発者が直面する見落としがちなボトルネックがある。それが「UI描画の競合とフォーカス泥棒(Focus Stealing)」だ。
数千本の図形を一括生成するようなバッチ処理の最中、AutoCADが前面にしゃしゃり出てきたり、図面の再描画(Regen)やビューポートの更新が走るたびにWindowsの画面がチラついたりする現象に悩まされたことはないだろうか。ユーザーがExcel側で進捗を確認したり、他の業務を行おうとした矢先にAutoCADがフォーカスを奪い、キーボード入力を阻害する。これはシステム間連携における典型的な「悪いUI/UX」である。
今回は、`AcadApplication.WindowState` の制御を軸に、バックグラウンド処理の徹底、メモリの最適化、そしてレガシー環境における安全なプロセス管理の極意を、チーフアーキテクトの視点から解説する。
—
1. なぜ `WindowState` の制御が必要なのか?
AutoCADのCOMオブジェクト(`AcadApplication`)をインスタンス化、あるいは `GetObject` で取得した直後、AutoCADはデフォルトでユーザーの前にウィンドウを最大化または通常表示の状態で現す。
Dim acadApp As AcadApplication
Set acadApp = GetObject(, “AutoCAD.Application”)
この状態のまま大容量の図面生成スクリプトを走らせると、以下の弊害が生じる。
1. GDI/Userリソースの無駄な消費: ウィンドウが表示されているだけで、AutoCADはレイアウトの再計算やビューポートの再描画(Render/Viewport Refresh)を強制される。
2. フォーカスの競合: 処理の途中でユーザーがExcelを操作していると、AutoCADのイベントハンドラやモーダルダイアログの割り込みによってキーボードフォーカスが奪われる。
3. 心理的ストレス: ユーザーは「今何が起きているのか」が分からず、固まったように見える画面の前で待たされることになる。
これを解決するのが、処理開始時のウィンドウ最小化(`acMin`)と、処理完了時の復元、あるいは完全な非表示化(`Visible = False`)のテクニックである。
—
2. 実装コード:堅牢なWindowState制御とオブジェクトライフサイクル管理
以下に、実務の現場でそのまま使える、堅牢性を極めたVBAモジュールを提示する。単にウィンドウを隠すだけでなく、エラーハンドリング、画面更新の抑止(`REDUCE_OVERHEAD`)、そしてCOMオブジェクトの適切な解放(Garbage Collectionの強制)までを網羅している。
Option Explicit
‘ AutoCADのWindowState定数(タイプライブラリを参照していない場合のフォールバック)
Const acMin As Long = 2 ‘ 最小化
Const acMax As Long = 3 ‘ 最大化
Const acNorm As Long = 1 ‘ 通常
Public Sub ExecuteBackgroundAutoCADTask()
Dim acadApp As AcadApplication
Dim acadDoc As AcadDocument
Dim isAppStartedByMe As Boolean
Dim originalState As Long
‘ 画面描画と警告の抑制(Excel側のパフォーマンス最適化)
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
.EnableEvents = False
End With
On Error GoTo ErrorHandler
‘ 1. AutoCADインスタンスの取得または生成
On Error Resume Next
Set acadApp = GetObject(, “AutoCAD.Application”)
If acadApp Is Nothing Then
Set acadApp = New AcadApplication
isAppStartedByMe = True
End If
On Error GoTo ErrorHandler
‘ 2. ユーザーの作業を邪魔しないためのUIロック & 最小化
‘ ※完全非表示にする場合は acadApp.Visible = False とするが、
‘ クラッシュ時のゾンビプロセス防止のため WindowState = acMin を推奨する
originalState = acadApp.WindowState
acadApp.WindowState = acMin
‘ AutoCAD側のアラートやスクリプト実行確認をサイレントにする
acadApp.SetSystemVariable “FILEDIA”, 0
acadApp.SetSystemVariable “CMDECHO”, 0
‘ 3. ドキュメントのオープンまたは新規作成
Set acadDoc = acadApp.Documents.Add(“acad.dwt”)
‘ —————————————————-
‘ 4. ここに重たい図形生成処理を記述(例:大量の線分を描画)
‘ —————————————————-
Dim pt1(2) As Double, pt2(2) As Double
Dim i As Long
For i = 1 to 1000
pt1(0) = i: pt1(1) = 0: pt1(2) = 0
pt2(0) = i: pt2(1) = 100: pt2(2) = 0
acadDoc.ModelSpace.AddLine pt1, pt2
Next i
‘ 5. 変更の保存と終了処理
acadDoc.SaveAs “C:\Temp\Output_Sample.dwg”
‘ システム変数を元に戻す
acadApp.SetSystemVariable “FILEDIA”, 1
acadApp.SetSystemVariable “CMDECHO”, 1
CleanUp:
‘ 6. ウィンドウ状態の復元
If Not acadApp Is Nothing Then
acadApp.WindowState = originalState
If isAppStartedByMe Then
acadApp.Quit
End If
End If
‘ 7. オブジェクト参照の完全解放(メモリリーク防止の鉄則)
Set acadDoc = Nothing
Set acadApp = Nothing
‘ Excel側の設定復元
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
.EnableEvents = True
End With
MsgBox “バックグラウンド処理が正常に完了しました。”, vbInformation
Exit Sub
ErrorHandler:
MsgBox “致命的なエラーが発生しました: ” & Err.Description, vbCritical
Resume CleanUp
End Sub
—
3. シニアエンジニアが知るべき「裏側の真実」と落とし穴
上記のコードは一見して完結しているように見えるが、AutoCAD VBAのアーキテクチャを熟知する者であれば、いくつかの「地雷」を踏まないための配慮に気づくだろう。
① `Visible = False` の危険性と `WindowState = acMin` の優位性
「ユーザーに一切画面を見せたくない」という理由で `acadApp.Visible = False` を選択したくなる。しかし、COMオートメーションにおけるAutoCADの非表示実行は、例外発生時にプロセスがメモリ上に残留する(いわゆる「ゾンビプロセス」化する)確率が跳ね上がる。
バックグラウンドで実行しつつも、タスクバーに最小化(`acMin`)として留めておく方が、OSのプロセス管理上も安全であり、万が一の強制終了時にもユーザーがタスクマネージャーから視認・Killしやすいというメリットがある。
② COMオブジェクトの「二段階解放」とメモリ最適化
VBAのガベージコレクションは参照カウンタ方式(Reference Counting)に依存している。
`Set acadDoc = Nothing` と `Set acadApp = Nothing` を行うだけでは不十分なケースがある。特に、`ModelSpace` や `SelectionSet` などの子オブジェクトを明示的に変数に格納してループ内で使用した場合、それらの参照が解放されないままメモリリークを起こす。
大量の図面エンティティを扱うバッチ処理では、「子オブジェクトを変数に格納して使い回さない。必要な時はドキュメント経由で都度呼び出し、即座に解放する」のが鉄則である。
‘ 悪例:ModelSpaceを変数に保持し続けると参照が残りやすい
Dim ms As AcadModelSpace
Set ms = acadDoc.ModelSpace
ms.AddLine … ‘ ずっと保持される
‘ 推奨:必要な瞬間にドキュメントから直接アクセスする
acadDoc.ModelSpace.AddLine …
③ システム変数 `FILEDIA` と `CMDECHO` の制御
バックグラウンド処理中にAutoCADが「ファイルを上書きしますか?」といったダイアログをモーダル表示させると、Excel側からのVBAスレッドが完全にフリーズ(デッドロック)する。
これを防ぐため、処理の冒頭で `FILEDIA` を `0`(ダイアログ非表示、コマンドライン入力モード)に設定し、ファイル保存等の操作を完全にプログラム側で制御することが、無人稼働(ファームオートメーション)の絶対条件となる。
—
総括
AutoCAD VBAによるシステム連携の成否は、「いかにAutoCADを主役にせず、黒子として裏で完璧に働かせるか」にかかっている。
`AcadApplication.WindowState = acMin` によるUIの制御は、単なる見た目の工夫ではない。ユーザーの生産性を阻害せず、Excelという司令塔からのコントロールを確実なものにするための、シニアエンジニア必須の防衛的プログラミング手法なのだ。
レガシーな技術と侮るなかれ。この細部に宿る配慮こそが、現場で止まない「真に安定した業務自動化システム」を構築する唯一の道である。
