こんにちは!AutoCAD VBAの世界へようこそ。
日々、図面作成の自動化に挑んでいるあなたなら、一度はこんな恐怖の現象に出くわしたことがあるはずです。
「VBAのプログラムを終了したはずなのに、なぜかタスクマネージャーに『acad.exe』が亡霊のように残り続けている……!」
画面は閉じているのに、裏でこっそりメモリを食いつぶし続けるこの現象。通称「ゴーストプロセス」です。これを放置すると、次にマクロを動かしたときに「ファイルがロックされて開けない」「動作が異常に重い、またはフリーズする」といった不可解なバグの温床になります。
今回は、この厄介なゴーストプロセスを完全に根絶し、綺麗すっきりとメモリを解放するための「極限のクリーンアップ術」を伝授しましょう。
ここをクリアすれば、あなたのAutoCAD VBAのスキルは間違いなくプロの領域に到達します。一緒にマスターしていきましょう!
—
1. なぜ「ゴーストプロセス」は生まれるのか?(根本原因の解明)
まずは敵を知ることから始めます。なぜ、VBAを終わらせたのにAutoCAD(acad.exe)が居座るのでしょうか?
原因は、VBAとAutoCADの間にある「参照カウント(COMの仕組み)」にあります。
VBAから外部のAutoCADアプリケーションを操作するとき、メモリ上には以下のような「参照の鎖」が生まれます。
[VBA変数] ──> [AcadApplication] ──> [AcadDocument] ──> [ModelSpace…]
VBA側で `Set acadApp = Nothing` としたり、プログラムを終了したりしても、この鎖の末端(ドキュメントや図形オブジェクト)の解放漏れがわずかでも残っていると、AutoCADは「まだ主人が俺を必要としているな」と勘違いし、メモリ上に居残り続けてしまうのです。これがゴーストの正体です。
—
2. 【基本原則】「下から上へ」解放するオブジェクトの作法
プログラミング初学者がやりがちな最大のミスが、いきなり大元である `AcadApplication` を解放しようとすることです。
❌ 駄目な例:親から先に消そうとする
Set acadApp = Nothing ‘ 子ども(ドキュメントや図形)が残ったまま親を消そうとしても消えない!
正解は、「末端の子どもから親へ、順番に `Nothing` を代入して鎖を断ち切る」ことです。これがオブジェクトのライフサイクル管理の鉄則です。
模範的なクリーンアップのコード例
Sub CleanExitSample()
Dim acadApp As Object
Dim acadDoc As Object
Dim ssetObj As Object
On Error GoTo ErrorHandler
‘ AutoCADのインスタンスを取得(または新規起動)
Set acadApp = GetObject(, “AutoCAD.Application”)
Set acadDoc = acadApp.ActiveDocument
‘ 例として選択セット(末端のオブジェクト)を作成したと仮定
Set ssetObj = acadDoc.SelectionSets.Add(“MyTempSSet”)
‘ — ここで何らかの自動化処理を行う —
MsgBox “処理が完了しました。クリーンアップを開始します。”, vbInformation
‘ ==========================================
‘ 【重要】解放は必ず「末端から親へ」の順序で行う!
‘ ==========================================
‘ 1. 選択セットを削除してメモリから解放
ssetObj.Delete
Set ssetObj = Nothing
‘ 2. ドキュメント変数を解放(※Document.Closeではない点に注意)
Set acadDoc = Nothing
‘ 3. アプリケーション変数を解放
Set acadApp = Nothing
Exit Sub
ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
キシツ(強制解放用)のルーチンへ誘導
‘ ※実際のコードではエラー時も確実にNothingを入れるための工夫が必要です
End Sub
—
3. それでも消えない時:Win32 APIを用いた「強制終了」の切り札
「ちゃんと `Nothing` を入れたはずなのに、たまにacad.exeが残る……」
COMの歴史は長く、時にはAutoCAD本体のバグやアドイン(外部プラグイン)の悪影響で、どれだけ丁寧にコード書いてもプロセスが解放されない「どうしようもない瞬間」が存在します。
そんな時のために、WindowsのAPIを使って、OSレベルでゴーストプロセスを叩き潰す最終手段を用意しておきましょう。
以下のコードをVBAの標準モジュールの一番上に貼り付けてください。
‘ ==========================================
‘ Windows APIの宣言(プロセスの強制終了用)
‘ ==========================================
If VBA7 Then
Private Declare PtrSafe Function OpenProcess Lib “kernel32” (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As LongPtr
Private Declare PtrSafe Function TerminateProcess Lib “kernel32” (ByVal hProcess As LongPtr, ByVal uExitCode As Long) As Long
Private Declare PtrSafe Function CloseHandle Lib “kernel32” (ByVal hObject As LongPtr) As Long
Else
Private Declare Function OpenProcess Lib “kernel32” (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function TerminateProcess Lib “kernel32” (ByVal hProcess As Long, ByVal uExitCode As Long) As Long
Private Declare Function CloseHandle Lib “kernel32” (ByVal hObject As Long) As Long
If
Const PROCESS_TERMINATE = &H1
そして、マクロの終了間際に、取得していたAutoCADのプロセスID(ProcessID)を利用して以下のように強制終了をかけます。
Sub ForceKillAcad(ByVal processId As Long)
Dim hProcess As LongPtr
If processId = 0 Then Exit Sub
‘ プロセスへのアクセス権を取得
hProcess = OpenProcess(PROCESS_TERMINATE, 0, processId)
If hProcess <> 0 Then
‘ 強制終了を実行
TerminateProcess hProcess, 0
‘ ハンドルを閉じる
CloseHandle hProcess
End If
End Sub
AutoCADを起動(または接続)する際に `acadApp.HWND` やプロセスIDをあらかじめ控えておくことで、マクロの最後に「どうしても消えないゴースト」を自ら狩り取ることが可能になります。実務の現場では、この「保険」があるだけで夜も安心して眠れるようになりますよ。
—
4. まとめ:ここをクリアすれば、AutoCAD VBAの基本はバッチリ!
いかがでしたでしょうか? 今回のポイントをギュッとまとめます。
1. ゴーストプロセスの原因は「参照の残りカス」。
2. オブジェクトの解放は必ず「末端(図形・選択セット等)から親(Application)へ」の順番で行う。
3. どうしても消えない頑固なプロセスには、Win32 API(TerminateProcess)という最終兵器を準備しておく。
このメモリ管理の思想を身につければ、単に「動くマクロ」を作るレベルから、大規模な業務運用に耐えうる「堅牢なシステム」を設計できるエンジニアへとステップアップできます。
ここをクリアすれば、AutoCAD VBAの基本はもうバッチリです!
ぜひ、あなたの開発環境でも試してみてくださいね。快適な自動化ライフを応援しています!
