CorelDRAW VBAを掌握する:数千のCDRファイルを「落とさず」完遂するメモリ管理の極意
現場のエンジニア諸君。CorelDRAW VBAで数百、数千ものバッチ処理を回していて、「最初は快調だが、後半になるにつれて極端に遅くなり、最終的にプロセスがクラッシュする」という悪夢に遭遇したことはないか?
CorelDRAWのCOMオブジェクトは、VBAの「自動メモリ管理」を過信すると即座に牙を剥く。特に`Document`, `Layer`, `Shape`といった重厚なオブジェクトをループ内で生成し続けると、参照カウントが正しくデクリメントされず、メモリリークが爆発的に進行する。
今日は、プロフェッショナルとして「一晩中走らせても絶対に落ちない」堅牢なバッチ処理アーキテクチャを伝授する。
—
1. なぜ「なんとなく」書いたコードは死ぬのか
VBAのガーベジコレクションは、COMオブジェクトの寿命を正確に制御できない。特にCorelDRAWの内部オブジェクトは、COMマーシャリングを通じてホストプロセス(CorelDRW.exe)に依存している。
- 参照のスタック: ループ内で `doc = app.OpenDocument(…)` を呼び出し、明示的に `Nothing` にしても、内部的な参照が残ることがある。
- ドキュメントの残留: `doc.Close` を呼んでも、Undoバッファやメモリ上のキャッシュが解放されないケースがある。
- イベントの干渉: 大量処理中にイベントハンドラが干渉し、処理待ちのキューが溢れる。
これらを解決するための「鉄則」を叩き込む。
—
2. 堅牢なバッチ処理の設計指針
Rule 1: セッション・ステートの強制リセット
`Application.Optimization = True` は必須だが、それ以上に「処理単位ごとのクリーンアップ」が重要だ。ドキュメントを閉じるだけでなく、`DoEvents`を挟むことでWindowsのメッセージキューをクリアし、COM参照の確定を待つ時間を確保する。
Rule 2: オブジェクトの寿命を最小化する
グローバル変数にDocumentオブジェクトを持たせてはいけない。すべての処理は「手続き単位」で完結させ、ローカル変数としてスコープアウトさせる。
Rule 3: 異常系への徹底的な備え
ファイルが破損している場合、`OpenDocument`は容赦なく例外を投げる。これをキャッチできなければ、バッチ全体が停止する。必ず `On Error GoTo` を活用し、スタックをクリーンに保つ仕組みを作る。
—
3. 実装:メモリリークを排除したバッチテンプレート
以下は、数千個のファイルを安全に処理するための「プロフェッショナル・テンプレート」だ。
Option Explicit
‘ メモリ管理を意識した堅牢なバッチ処理の核
Public Sub BatchProcessFiles(ByVal folderPath As String)
Dim fso As Object
Dim file As Object
Dim doc As Document
Set fso = CreateObject(“Scripting.FileSystemObject”)
‘ 最適化をオン(描画更新を停止しメモリ消費を抑える)
Application.Optimization = True
On Error Resume Next
For Each file In fso.GetFolder(folderPath).Files
If LCase(fso.GetExtensionName(file.Path)) = “cdr” Then
‘ 1. ファイルを開く
Set doc = Application.OpenDocument(file.Path)
‘ 2. 実務処理の実行(関数化してスコープを閉じる)
If Not doc Is Nothing Then
ProcessSingleDocument doc
‘ 3. 明示的なドキュメント解放
doc.Close
Set doc = Nothing
End If
‘ 4. OSへのメモリ解放要求とキューのクリア
DoEvents
‘ 必要に応じて一定数ごとにGCを促す(プロセス再起動の判断材料)
Debug.Print “Processed: ” & file.Name
End If
Next
Application.Optimization = False
MsgBox “全工程が完了しました。”
End Sub
Private Sub ProcessSingleDocument(ByRef doc As Document)
‘ ここに具体的なベクター操作を記述する
‘ 重いオブジェクトの参照はすべてこのスコープ内で完結させること
Dim sr As ShapeRange
Set sr = doc.ActivePage.Shapes.All
‘ 例: エクスポート処理
‘ doc.Export …
‘ ここでもオブジェクトを明示的にNothingにしていく
Set sr = Nothing
End Sub
—
4. プロの現場でさらに一歩進むために
もし、扱うファイルが極めて巨大で、上記の方法でもメモリが漸増する場合は、「プロセス分離戦略」をとるべきだ。
1. コントローラー役のVBAを作る: 全ファイルをリスト化する。
2. ワーカースクリプト: 1ファイルだけ処理して終了する小さなスクリプトを用意する。
3. Shell実行: コントローラーから `Shell(“CorelDRW.exe /runscript …”)` のように、処理ごとにCorelDRAWを再起動する。
これは一見非効率に見えるが、「メモリリークによるフリーズ」という最大のリスクを物理的に遮断できるため、数万点規模のアーカイブ変換案件では最も信頼性の高い手法となる。
—
最後に:エンジニアとしての矜持
「動けばいい」コードを書くのは素人だ。業務自動化エンジニアの価値は、「どれだけ安定して、計算通りの時間で完走させられるか」という予測可能性にある。
CorelDRAWのVBAは確かに古い技術だが、APIの奥底を理解し、COMの挙動を制御下におけば、これほど強力な武器はない。この記事を読んだ諸君には、ぜひ「落ちない自動化」を実現し、無駄な残業時間をゼロにしてほしい。
健闘を祈る。
