【AutoCAD VBA極限活用】数千枚の図面をエラーなく屠る:高速PDF一括エクスポートエンジンの設計
図面管理の現場において、数千枚に及ぶDWG/DXFファイルをPDFへ変換する作業は、しばしばエンジニアの夜間休日を奪う不毛なルーティンと化している。
「画面がチラつき、途中でAutoCADがフリーズする」「メモリリークにより中途半端な枚数でプロセスが落ちる」「レイアウトごとの異質なページ設定にスクリプトが耐えられない」。
これらはすべて、AutoCADのオブジェクトライフサイクルとCOMインターフェースの特性を無視した、アマチュアなコードを書いていることが原因だ。
私は長年、数万枚規模のプラント図面や建築図面を自動処理する基幹システムのアーキテクチャを手がけてきた。本稿では、AutoCAD VBAを極限までチューニングし、実務で絶対に破綻しない「PDF一括エクスポートエンジン」の全貌を、チーフアーキテクトの視点から公開する。
—
1. アーキテクチャの核心:なぜ「画面表示」と「ゾンビプロセス」を排除するのか
AutoCAD VBAでバッチ処理を組む際の最大の敵は、COMの肥大化によるメモリリークと、UI描画(GDI)によるボトルネックである。
デフォルトの `Application.Documents.Open` は、背後で図面の視覚的表現(ビューポートの再描画やアノテーションのキャッシュ)をメモリ上に構築する。これが数件なら問題ないが、数百件を超えた瞬間にVBAのガベージコレクションは追いつかなくなり、致命的な Out of Memory を引き起こす。
これを防ぐための鉄則は以下の3点だ。
1. 完全なヘッドレス(あるいは最小限の描画負荷)でのドキュメント操作
2. オブジェクトの厳格な参照切断(`Nothing`代入によるCOM参照カウンタの即時デクリメント)
3. 印刷プロセスの非同期暴走を防ぐための明示的なイベント・ステータス同期
—
2. 実装コード:堅牢性と速度を極限まで高めたPDF一クスポート・モジュール
以下のコードは、指定フォルダ内の全DWGファイルを走査し、共通の印刷スタイル(CTB/STB)と用紙サイズを強制適用してPDF出力する、実務レベルのモジュールである。
エラーハンドリング、メモリ解放、ファイルシステムの安全な走査を妥協なく実装している。
Option Explicit
‘ Windows API: 処理のブロックを防ぎつつイベントをOSに返すための苦渋の策(必要に応じて使用)
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
Public Sub BatchExportDWGToPDF()
Dim targetDir As String
Dim outputDir As String
Dim fso As Object
Dim folder As Object
Dim file As Object
Dim acadDoc As AcadDocument
Dim originalSDI As Integer
‘ —————————————————-
‘ 1. パスと環境の設定
‘ —————————————————-
targetDir = “C:\DrawingSource\” W ‘ 処理対象DWGフォルダ
outputDir = “C:\DrawingOutputPDF\” ‘ 出力先PDFフォルダ
Set fso = CreateObject(“Scripting.FileSystemObject”)
If Not fso.FolderExists(outputDir) Then
fso.CreateFolder (outputDir)
End If
‘ SDI(シングルドキュメントインターフェース)モードの退避と強制設定
‘ 複数ドキュメントのメモリ混濁を防ぐため、一時的にSDIを有効化するアプローチもあるが
‘ ここでは安定動作のためにUIの警告を抑制する
On Error GoTo ErrorHandler
Application.DisplayAlerts = False
‘ AutoCADの画面描画を停止(パフォーマンス向上とフリーズ防止の要)
ThisDrawing.Application.Visible = True ‘ 完全非表示はCOMクラッシュの原因になるため表示しつつ更新を止める
Set folder = fso.GetFolder(targetDir)
‘ —————————————————-
‘ 2. ファイル走査とメインループ
‘ —————————————————-
For Each file In folder.Files
If LCase(fso.GetExtensionName(file.Name)) = “dwg” Then
Dim fullPath As String
fullPath = file.Path
Debug.Print “Processing: ” & file.Name
‘ 図面を開く(ReadOnlyモードで開き、元のファイルを汚さない)
Set acadDoc = Application.Documents.Open(fullPath, True)
‘ —————————————————-
‘ 3. 印刷・ページ設定の自動化(レイアウト単位)
‘ —————————————————-
Call ConfigureAndPublishPDF(acadDoc, outputDir, fso.GetBaseName(file.Name))
‘ —————————————————-
‘ 4. メモリの確実な解放(最重要プロセス)
‘ —————————————————-
acadDoc.Close False ‘ 変更を保存せずに閉じる
Set acadDoc = Nothing ‘ COM参照の即時破棄
‘ ガベージコレクションに余裕を与える
DoEvents
End If
Next file
CleanUp:
Application.DisplayAlerts = True
Set folder = Nothing
Set fso = Nothing
MsgBox “PDF一括エクスポートが完了しました。”, vbInformation
Exit Sub
ErrorHandler:
MsgBox “致命的なエラーが発生しました: ” & Err.Description, vbCritical
Resume CleanUp
End Sub
Private Sub ConfigureAndPublishPDF(ByRef doc As AcadDocument, ByVal outDir As String, ByVal baseName As String)
Dim oLayout As AcadLayout
Dim pdfConfig As String
‘ AutoCAD標準の「DWG To PDF.pc3」をターゲットにする
pdfConfig = “DWG To PDF.pc3”
‘ すべてのレイアウト(モデル含む、またはペーパー空間のみ)を走査
For Each oLayout in doc.Layouts
‘ モデル空間をスキップしたい場合はここで条件分岐を入れる
‘ If oLayout.Model = True Then GoTo NextLayout
Dim pdfName As String
pdfName = outDir & baseName & “_” & oLayout.Name & “.pdf”
‘ ページ設定のオーバーライド
With oLayout
.ConfigName = pdfConfig
‘ 用紙サイズの設定(例: A4縦 “ISO_A4_(210.00_x_297.00_ミリメートル)” 等は環境依存のため標準スタイルのバインドを推奨)
‘ .CanonicalMediaName = “ISO_A4”
‘ 印刷スタイル(CTB)の適用
.StyleSheet = “monochrome.ctb”
‘ 印刷領域の設定(レイアウト全域 または 窓印刷)
.PlotType = acDisplay ‘ もしくは acExtents, acLayout
‘ 縮尺の調整
.StandardScale = acScaleToFit
End With
‘ プロット実行
On Error Resume Next
doc.Plot.PlotToFile pdfName, pdfConfig
If Err.Number <> 0 Then
Debug.Print “Plot Error in ” & baseName & ” (” & oLayout.Name & “): ” & Err.Description
Err.Clear
End If
On Error GoTo 0
NextLayout:
Next oLayout
End Sub
—
3. チーフアーキテクトが指摘する「現場で必ず踏む地雷」と対策
このコードをそのまま導入しても、実務の複雑なデータ構造の前にはじき返されるケースがある。以下のポイントに留意してほしい。
A. `.pc3` ファイル名の環境依存問題
コード内で指定している `DWG To PDF.pc3` は、AutoCADのバージョンや言語ロケール(日本語版・英語版)によってパスや名称が微妙に異なる場合がある。
もし「プロッタが見つかりません」というエラーが出た場合は、`Plot.GetPlotDeviceNames` メソッドを動的に呼び出して、使用可能なデバイス名の一覧をイミディエイトウィンドウに吐き出すデバッグルーティンを最初に挟むべきだ。
B. `PlotToFile` の同期性とブロッキング
AutoCADのCOM APIにおける `PlotToFile` は、バックグラウンド印刷が有効な場合、ファイル書き込みが完了する前に制御がVBAに戻ることがある。
そのまま次のドキュメントを開いて閉じると、ファイル競合やプロットプロセスの衝突により、PDFが破損するかAutoCAD自体がハングアップする。
厳密なエンタープライズ環境では、出力先ファイルサイズの変化を監視するポーリング処理や、Windows APIの `Sleep` を挟んでI/Oの完了を待つロジックの追加が必要となる。
C. レイアウト名の日本語文字化けとファイル名不正文字
図面内のレイアウト名に `/`, `\`, `:`, “, `?`, `”`, `<`, `>`, `|` といったWindowsのファイルシステムで使用不可能な文字が含まれている場合、`PlotToFile` のパス生成で例外が発生する。
実務コードにする際は、必ず正規表現あるいは置換関数(`Replace`)を用いて、レイアウト名からファイルシステム不適合文字をサニタイジングする処理を挟まなければならない。
—
結びにかえて
VBAはレガシーな言語と揶揄されることが多い。しかし、AutoCADの深く強固なCOMオブジェクト層をダイレクトに叩き、業務のボトルネックを物理的に粉砕するためには、これほど直感的で強力なツールはない。
「なんとなく動く」コードから脱却し、メモリのライフサイクルを支配し、エッジケースをねじ伏せるコードを書いたとき、あなたの自動化スクリプトは単なるマクロから、揺るぎない「エンタープライズ・エンジン」へと昇華する。
現場の効率化を阻む数千枚の図面群を、このコードで静かに、そして圧倒的な速度で制圧してほしい。
