【入門編】【上級プロ向け】COMオートメーションのメモリリークとゾンビプロセスの完全撲滅!巨大なCDRファイルを安全に連続バッチ処理する堅牢なエラーハンドリング – CorelDRAW VBA解析バイブル

スポンサーリンク

こんにちは!CorelDRAW VBAの自動化の世界へようこそ。
マクロの記録ボタンを押して「動いた!すごい!」と感動したのも束の間、いざ数百ファイルもある巨大なCDRファイルのバッチ処理(一括処理)を組んでみると……。

  • 「処理の途中でCorelDRAWがフリーズする」
  • 「タスクマネージャーを見ると、見えないCorelDRAWのプロセス(ゾンビプロセス)が何重にも残っている!」
  • 「メモリリークを起こしてPCが重くなり、最終的に強制終了するしかない」

……そんな悪夢に頭を抱えていませんか?

大丈夫、安心してください。ここをクリアすれば、あなたもCorelDRAW VBAを完全に手懐けた「真の自動化エンジニア」です。今日は、プロの現場でも不可欠な「巨大CDRファイルを安全に連続バッチ処理するための、メモリ管理と徹底的なエラーハンドリング」の本質を、優しく、そして深く伝授します。

なぜCorelDRAW VBAは「ゾンビプロセス」を生むのか?

まず、敵を知ることから始めましょう。
VBAを書いていると、私たちはついつい次のようなコードを書きがちです。

‘ 【やってはいけないアンチパターンの例】
Sub BadBatchProcess()
Dim doc As Document
Set doc = OpenDocument(“C:\Data\HugeFile.cdr”)

‘ 何らかの処理…
doc.Pages(1).CreateRectangle 0, 0, 100, 100

doc.Save
doc.Close
‘ 変数解放をサボる
End Sub

一見、問題なく閉じて終了するように見えますよね? しかし、CorelDRAWのCOMオートメーションの裏側では、「オブジェクトの参照カウント」という仕組みが働いています。

ループ内で `Shape` や `ShapeRange`、`Layer`、`Page` などを生成・取得した際、VBA側がそのメモリへの参照を握りしめたままにしていると、ドキュメントやアプリケーションを閉じたつもりでも、Windowsのメモリ上にCorelDRAWのプロセスが幽霊(ゾンビ)のように残り続けます。

これが、バッチ処理を重ねるごとにメモリが食いつぶされ、PCが悲鳴を上げる根本原因です。

ゾンビ撲滅の3大鉄則

巨大なCDRファイルを何百個、何千個と安全に処理し続けるためには、以下の3つの鉄則をコードに組み込む必要があります。

1. すべてのオブジェクト参照を、使い終わったら即座に `Nothing` 代入する
2. ループの「外」と「内」でスコープ(生存期間)を明確に分ける
3. `On Error Goto` を用いて、予期せぬエラー時でも必ず後処理(クリーンアップ)を通す

これらを完璧に満たす、実務レベルの「堅牢なバッチ処理テンプレート」を次の章で公開します。

【実践】メモリリークを完全封鎖する堅牢バッチ処理コード

以下のコードは、指定したフォルダ内にあるすべてのCDRファイルを開き、何らかの処理(ここでは例としてシェールの追加と保存)を行ったあと、完全にメモリを解放して閉じるプロシージャです。

そのままコピペして、パスをご自身の環境に合わせて書き換えればすぐにテストできます。

Option Explicit

‘ ==============================================================================
‘ 巨大CDRファイル安全バッチ処理エンジン
‘ ==============================================================================
Sub SafeBatchProcessMaster()
Dim targetFolder As String
Dim fileName As String
Dim fso As Object
Dim totalFiles As Long
Dim processedCount As Long

‘ 処理対象のフォルダパス(環境に合わせて変更してください)
targetFolder = “C:\MyCDRFiles\”

‘ フォルダの存在チェック
Set fso = CreateObject(“Scripting.FileSystemObject”)
If Not fso.FolderExists(targetFolder) Then
MsgBox “指定されたフォルダが存在しません: ” & targetFolder, vbCritical
Set fso = Nothing
Exit Sub
End If

‘ フォルダ内の最初のCDRファイルを検索
fileName = Dir(targetFolder & “.cdr”)

If fileName = “” Then
MsgBox “処理対象のCDRファイルが見つかりません。”, vbExclamation
Set fso = Nothing
Exit Sub
End If

‘ 処理開始
processedCount = 0
Do While fileName <> “”
‘ 1ファイルごとの処理をサブルーチンに分離し、エラーハンドリングを強固にする
If ProcessSingleFile(targetFolder & fileName) Then
processedCount = processedCount + 1
End If

‘ 次のファイルへ
fileName = Dir()
Loop

Set fso = Nothing
MsgBox “バッチ処理が正常に完了しました。処理ファイル数: ” & processedCount, vbInformation
End Sub

‘ ==============================================================================
‘ 単一ファイルの安全処理関数(個別のエラーとメモリ解放を担保)
‘ ==============================================================================
Private Function ProcessSingleFile(ByVal filePath As String) As Boolean
Dim targetDoc As Document
Dim currentLayer As Layer
Dim newShape As Shape
Dim success As Boolean

success = False

‘ 【重要】エラーが発生しても必ず後処理(クリーンアップ)へジャンプする仕組み
On Error GoTo ErrorHandler

‘ 1. ドキュメントを開く(UI表示を抑制して高速化&安定化を図る場合は Application.OpenDocumentEx を使用)
Set targetDoc = Application.OpenDocument(filePath)

‘ 2. 処理対象のレイヤーを取得
Set currentLayer = targetDoc.ActivePage.ActiveLayer

‘ — ここに実際の業務ロジックを記述 —
‘ 例:アクティブレイヤーに赤い四角形を配置する
Set newShape = currentLayer.CreateRectangle(0, 0, 50, 50)
newShape.Fill.UniformColor.RGBAssign 255, 0, 0
‘ ————————————

‘ 3. 上書き保存して閉じる
targetDoc.Save
targetDoc.Close

‘ 正常終了フラグ
success = True

CleanUp:
‘ ==========================================================================
‘ 【極めて重要】オブジェクト変数の徹底的な破棄(Nothing代入)
‘ 生成した順とは逆に、内側(子)から外側(親)へ向かって解放するのが定石です
‘ ==========================================================================
On Error Resume Next ‘ 解放時の予期せぬエラーで止まらないようにする

If Not newShape Is Nothing Then Set newShape = Nothing
If Not currentLayer Is Nothing Then Set currentLayer = Nothing

If Not targetDoc Is Nothing Then
‘ 万が一閉じられていない場合の保険
targetDoc.Close
Set targetDoc = Nothing
End If

On Error GoTo 0 ‘ エラー監視を復元

ProcessSingleFile = success
Exit Function

ErrorHandler:
‘ エラーログの出力やイミディエイトウィンドウへの通知
Debug.Print “エラー発生ファイル: ” & filePath & ” / 錯誤内容: ” & Err.Description
success = False
Resume CleanUp
End Function

コードのここがスゴい!プロの技を解説

1. `On Error GoTo` と `CleanUp` ラベルのコンビネーション

VBAで最も恐ろしいのは、処理の途中でエラー(例えば「ファイルが壊れている」「メモリが足りない」など)が発生したときに、コードが途中で止まってしまい、`Document` オブジェクトがメモリに残ったままになることです。
上記のコードでは、エラーが起きても必ず `CleanUp:` ラベルに処理がジャンプするよう設計されています。これにより、どんな例外が起きようとも確実にメモリが掃除されるようになっています。

2. 子オブジェクトから順に `Nothing` を代入する美学

VBAのメモリ管理において、親を先に消すのではなく、ドキュメント内で生成した細かいパーツ(ShapeやLayer)を先に `Nothing` にし、最後に大元の `Document` を `Nothing` にするのが鉄則です。この順番を守ることで、COMの参照カウントが綺麗にゼロになります。

3. ループのスコープ分離

ファイルを開いて閉じる処理を別の関数(`ProcessSingleFile`)に切り出している点にも注目してください。
VBAでは、プロシージャ(SubやFunction)が終了した瞬間、その中で宣言されたローカル変数のメモリは自動的に解放されるという特性があります。
ループの中で直接ドキュメントを扱い続けるよりも、1ファイルごとに別関数へ閉じ込める方が、圧倒的にメモリリークを防ぎやすくなります。

まとめ:ここをクリアすれば、CorelDRAW VBAは怖くない!

今回ご紹介した「徹底的な `Nothing` による解放」と「エラーハンドリングによるクリーンアップの保証」を身につければ、もうタスクマネージャーのゾンビプロセスに怯える必要はありません。

何百、何千という巨大なCDRファイルも、夜間に安心して一晩中バッチ処理にかけられるようになります。ぜひ、あなたの開発現場のコードにもこの仕組みを取り入れてみてください。

「ここをもっとこうしたい」「こんな複雑なオブジェクトの解放はどう書けばいい?」といった疑問があれば、いつでも先輩エンジニアの私に尋ねてくださいね。応援しています!

タイトルとURLをコピーしました