AutoCAD VBAを掌握する極限の知見
第1回:タスクバーをハックせよ!`AcadApplication.Caption`によるリアルタイム・バッチ進捗監視の極意
こんにちは。開発プロジェクトの現場を率いるチーフアーキテクトの私だ。
日々、何百枚、何千枚という図面と格闘し、マクロの処理が終わるのを祈るように画面の前で待っていないか?あるいは、AutoCADを最小化して裏でバッチ処理を走らせたはいいものの、今全体の何パーセントが進んでいるのか分からず、イライラしながらタスクマネージャーを覗き込んでいるエンジニアの姿を私は何度も見てきた。
非効率だ。エンジニアなら、機械に働かせている間は優雅にコーヒーでも飲んでいればいい。そのためには「今、何が起きているのか」を視覚的に把握する絶対的な仕組みが必要なのだ。
今回は、AutoCAD VBAの基礎である `AcadApplication` オブジェクトを深く理解し、タイトルバー(=Windowsのタスクバー)を動的に書き換えることで、「最小化状態でもバッチ処理の残り枚数が一目でわかる」実務直結の堅牢なコードを伝授しよう。
—
なぜ、ただの `MsgBox` では実務で使い物にならないのか?
初心者がやりがちな失敗はこれだ。
‘ 【アンチパターン】ループごとにMsgBoxを出す愚行
For i = 1 To 100
‘ 重い処理…
MsgBox i & “枚目の処理が終わりました。”
Next i
笑い話ではない。実際にこれを書いてしまうジュニアプログラマーが後を絶たない。
これでは「バッチ処理」の最大のメリットである完全自動化(Unattended Automation)が完全に死ぬ。100枚の図面を処理するのに、人間が100回「OK」ボタンを押さなければならない地獄絵図だ。
では、プロはどうするか?
画面の描画を抑制し、裏で黙々と処理をさせつつ、進捗状況をWindowsのタスクバー(AutoCADのタイトルバー)にブロードキャストするのだ。これなら、AutoCADを最小化して他のドキュメント(Excelやブラウザ)で作業していても、タスクバーにマウスオーバーするかチラ見するだけで、残りどれだけ時間がかかるかが秒速で把握できる。
—
堅牢なバッチ処理設計の要諦
実務におけるバッチ処理には、以下の3つの鉄則がある。これを破ると、途中でAutoCADがフリーズしたり、メモリリークを起こして深夜の自動処理が全滅する。
1. 画面更新の完全停止 (`ScreenUpdating` 相当の制御)
AutoCADにはExcelのような `Application.ScreenUpdating` は存在しないが、`ActiveDocument.Regen` や不要なオブジェクト選択を排除し、視覚的な再描画コストを極限まで削る必要がある。
2. 元のタイトルバーの完全復元(イディオムの遵守)
マクロが異常終了したり途中でブレークされたりした際、AutoCADのタイトルバーが「処理中…(残り5枚)」のままフリーズするのはプロとして許されない。必ず `On Error` でトラップし、終了時には元の文字列に戻すこと。
3. オブジェクトのライフサイクル管理
ループ内で不要なドキュメントを開閉する際、メモリ解放(Nothing代入)を怠ると、30枚を超えたあたりからCOM例外(Error 462など)でクラッシュする。
—
【プロダクションコード】コピペで即動くバッチ処理エンジン
以下のコードは、指定フォルダ内のすべてのDWGファイルを開き、何らかのバッチ処理(ここでは例としてレイアウト名の取得・ログ出力)を行いつつ、タスクバーの表示を動的に書き換える実戦用のプロシージャだ。
Option Explicit
‘ =================================================================================
‘ 担当者: チーフアーキテクト
‘ 概要: 複数DWGファイルのバッチ処理を行い、進捗をAcadApplication.Captionにリアルタイム表示する
‘ =================================================================================
Public Sub BatchProcessWithCaptionHack()
Dim acadApp As AcadApplication
Dim originalCaption As String
Dim targetFolder As String
Dim fso As Object
Dim folderObj As Object
Dim fileObj As Object
Dim targetFiles As Collection
Dim totalFiles As Long
Dim currentCount As Long
Dim doc As AcadDocument
Dim startTime As Double
startTime = Timer
‘ 1. Applicationオブジェクトの取得とタイトルの退避
Set acadApp = ThisDrawing.Application
originalCaption = acadApp.Caption
‘ エラーハンドリングの準備(異常終了時もタイトルを元に戻すため必須)
On Error GoTo ErrorHandler
‘ 2. 処理対象ファイルの収集(ここではC:\CAD_Work\をターゲットとする)
targetFolder = “C:\CAD_Work\”
Set fso = CreateObject(“Scripting.FileSystemObject”)
If Not fso.FolderExists(targetFolder) Then
MsgBox “指定されたフォルダが存在しません: ” & targetFolder, vbCritical, “パスエラー”
Exit Sub
End If
Set folderObj = fso.GetFolder(targetFolder)
Set targetFiles = New Collection
For Each fileObj In folderObj.Files
If LCase(fso.GetExtensionName(fileObj.Name)) = “dwg” Then
targetFiles.Add fileObj.Path
End If
Next fileObj
totalFiles = targetFiles.Count
If totalFiles = 0 Then
MsgBox “処理対象のDWGファイルがありません。”, vbExclamation, “通知”
Exit Sub
End If
‘ 3. パフォーマンス最適化(警告表示の抑制)
acadApp.Preferences.System.DisplayScreenMenu = False
‘ 4. バッチ処理ループ本番
currentCount = 0
Dim filePath
For Each filePath In targetFiles
currentCount = currentCount + 1
‘ ★ここが今回のキモ:タイトルバーを動的に書き換え、タスクバーに進捗を出す
acadApp.Caption = “【バッチ実行中】 ” & currentCount & ” / ” & totalFiles & ” 枚完了 (残り: ” & (totalFiles – currentCount) & “枚) – ” & fso.GetFileName(filePath)
‘ ドキュメントを開く(非表示モードはAutoCAD VBA単体では制限があるため、ActiveDocumentとして開く)
Set doc = acadApp.Documents.Open(filePath, True) ‘ ReadOnly = True
‘ —————————————————————–
‘ 【ここに実務の個別処理を記述】
‘ 例:すべてのレイアウト名を取得してイミディエイトウィンドウに出力する
Call DoSomething(doc)
‘ —————————————————————–
‘ メモリリークを防ぐため、変更を保存せずに閉じる
doc.Close False
Set doc = Nothing
‘ Windowsに制御を戻し、タスクバーの描画更新を確実に行うためのDoEvents
DoEvents
Next filePath
‘ 5. 正常終了処理
acadApp.Caption = originalCaption
MsgBox “すべてのバッチ処理が完了しました。” & vbCrLf & _
“処理ファイル数: ” & totalFiles & “枚” & vbCrLf & _
“所要時間: ” & Format(Timer – startTime, “0.00”) & ” 秒”, vbInformation, “完了”
Exit Sub
ErrorHandler:
‘ 異常終了時のフォールバック(タイトルの復元とメモリ解放)
acadApp.Caption = originalCaption
If Not doc Is Nothing Then
doc.Close False
Set doc = Nothing
End If
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error No: ” & Err.Number & vbCrLf & _
“Description: ” & Err.Description, vbCritical, “致命的エラー”
End Sub
‘ 個別の図面に対する処理モジュール(スタブ)
Private Sub DoSomething(ByRef targetDoc As AcadDocument)
Dim layoutItem As AcadLayout
For Each layoutItem in targetDoc.Layouts
‘ 何らかのデータ抽出やレイヤー操作など
Debug.Print targetDoc.Name & ” -> Layout: ” & layoutItem.Name
Next layoutItem
End Sub
—
コードの技術的解説とアーキテクトからの助言
1. `AcadApplication.Caption` の動的書き換えと `DoEvents` のシナジー
Windowsのタスクバーは、OSのウィンドウマネージャー(DWM)がアプリケーションのタイトルバー文字列をポーリングまたはイベントキャッチして描画している。
VBAのようなシングルスレッド環境で重いループを回すと、UIスレッドがブロックされ、タスクバーの表示が更新されなくなる。ここで効いてくるのが `DoEvents` だ。
ループの1回ごとに `DoEvents` を挟むことで、Windowsに制御権を一時返却し、タスクバーのキャプション書き換えを確実に画面(およびタスクバーホバー時のプレビュー)に反映させることができる。
2. 徹底的な防御的プログラミング (`On Error` と 復元処理)
バッチ処理の途中で「図面が破損している」「パスがロックされている」などの理由で `Documents.Open` がエラーを吐くことは実務では日常茶飯事だ。
その際、`ErrorHandler` を通さずにマクロがクラッシュすると、AutoCADのタイトルバーが一生「【バッチ実行中】…」のまま固定されてしまう。これはユーザーに無用な混乱を与える。必ずラベルジャンプによる復元処理をセットで実装すること。
—
まとめ
今回の手法は非常にシンプルだが、「長時間のバックグラウンド処理におけるユーザー体験(UX)」を劇的に向上させるプロの常套手段だ。
現場で「まだ終わらないのか?」とイライラしている同僚や上司がいたら、タスクバーに優雅に残枚数を出力するこのマクロを見せてやるといい。
「おっ、やるな」と評価されること間違いなしだ。
次回の極限の知見でも、現場の戦闘力を底上げする圧倒的なノウハウを公開する。期待していてくれ。
