【テクニカル・上級編】【実務中級】On Error Resume Nextの正しい使い所とErrオブジェクトを活用した安全なエラーロギング機構 – CorelDRAW VBA解析バイブル

スポンサーリンク

CorelDRAW VBAを掌握する極限の知見

【実務中級】On Error Resume Nextの正しい使い所とErrオブジェクトを活用した安全なエラーロギング機構

VBA(Visual Basic for Applications)の歴史は長く、そのシンプルさゆえに多くのエンジニアが「適当なエラー処理」でその場凌ぎのコードを書いてきた。特にCorelDRAWの自動化において、無秩序な `On Error Resume Next` の乱用は、デバッグを不可能にし、メモリリークやサイレントバグの温床となる。

本稿では、CorelDRAW VBAのオブジェクトモデルの特性、COMのライフサイクル、そしてWindows APIや外部ファイルシステムとの連携を視野に入れ、「攻めと守りを完全に分離したエラーハンドリング設計」の極限の知見を公開する。

1. なぜ `On Error Resume Next` は「諸刃の剣」なのか

VBA初学者は、「エラーでプログラムを止めないため」にコードの先頭に `On Error Resume Next` を置きたがる。しかし、これはエンジニアリングの観点から言えば「計器の故障ランプをペンキで塗りつぶす行為」に等しい。

CorelDRAWのVBA環境において、`On Error Resume Next` を有効にすると、以下の致命的な問題が発生する。

1. Errオブジェクトの持続: 一度エラーが発生すると、明示的にクリア(`Err.Clear`)するか、別のエラーが発生するまで `Err` プロパティ(`Number`, `Description` 等)は過去の値を保持し続ける。
2. COMオブジェクトの無効化(ゾンビ化): 存在しないシェイプのプロパティにアクセスした際、エラーを無視して後続処理を進めると、VBA内部でCOMポインタの整合性が崩れ、最悪の場合CorelDRAW本体が強制終了(クラッシュ)する。
3. 根本原因の隠蔽: 構文エラーや型ミスマッチといった致命的なバグさえも握り潰され、意図しないレイヤーやドキュメントに対して破壊的な処理が実行されてしまう。

許される唯一の使い所

`On Error Resume Next` を使ってよいのは、「エラーが発生することが仕様上許容されており、直ちにフォールバック処理へ移行する、あるいは単一のプロパティ存在確認を行う瞬間のみ」である。それ以外の範囲で漫然と放置してはならない。

2. シニアエンジニアが実装するべき「安全なエラーロギング機構」

実務で求められるのは、「エラーで止まらないこと」ではなく、「エラーが発生した瞬間に正確なコンテキスト(どのドキュメントの、どのレイヤーの、どのシェイプで起きたか)を記録し、安全に処理を継続または離脱すること」である。

以下のコードは、CorelDRAWのドキュメント走査中に発生しうる例外を捕捉し、タイムスタンプ付きのテキストログとしてファイルシステムに書き出す、実務レベルのエラーロギングクラス(またはモジュール)の設計パターンである。

Option Explicit

‘ ==============================================================================
‘ モジュール名: MdlErrorLogger
‘ 概要: CorelDRAW VBA専用 安全なエラーハンドリング&ロギング機構
‘ ==============================================================================

Private Const LOG_FILE_NAME As String = “\CorelDraw_Automation_Error.log”

‘ ——————————————————————————
‘ 処理の安全性を担保しつつ、例外をフックしてログに残すラッパー関数
‘ ——————————————————————————
Public Sub ExecuteSafely(ByVal processName As String, ByVal targetName As String)
On Error GoTo ErrorHandler

‘ — 【シミュレーション】意図的な危険領域の実行 —
‘ 例: 存在しないレイヤー名へのアクセスや、不正な変形処理
Call RiskyCorelDrawOperation(targetName)

Exit Sub

ErrorHandler:
‘ 1. エラー情報の退避(他の処理でErrが上書きされるのを防ぐ)
Dim errNum As Long: errNum = Err.Number
Dim errDesc As String: errDesc = Err.Description
Dim errSource As String: errSource = Err.Source

‘ 2. ログへの書き込み実行
Call WriteErrorLog(processName, targetName, errNum, errDesc, errSource)

‘ 3. Errオブジェクトの即座クリア(後続への汚染防止)
Err.Clear

‘ 4. 必要に応じた処理の継続(Resume Nextの局所的適用)
Resume Next
End Sub

‘ ——————————————————————————
‘ 実際のCorelDRAW操作(例:アクティブレイヤーの強制取得・操作)
‘ ——————————————————————————
Private Sub RiskyCorelDrawOperation(ByVal targetName As String)
‘ 意図的にエラーを起こすテスト(オブジェクトが存在しない状況を模擬)
Dim sh As Shape
Set sh = ActiveDocument.Pages(1).Layers(targetName).Shapes(1)

‘ オブジェクトがNothingの場合のハンドリング
If sh Is Nothing Then
Err.Raise 9999, “RiskyCorelDrawOperation”, “指定されたシェイプが存在しません。”
End If

‘ プロパティ操作
sh.Outline.Width = 0.5

‘ 【極限の知見】メモリ最適化:Corelオブジェクトの明示的解放
Set sh = Nothing
End Sub

‘ ——————————————————————————
‘ ファイルシステムオブジェクト(FSO)を用いた堅牢なログ出力
‘ ——————————————————————————
Private Sub WriteErrorLog(ByVal proc As String, ByVal target As String, ByVal eNum As Long, ByVal eDesc As String, ByVal eSource As String)
Dim fso As Object
Dim logFile As Object
Dim logPath As String

On Error GoTo LogWriteError ‘ ログ書き込み自体の失敗でループするのを防ぐ

Set fso = CreateObject(“Scripting.FileSystemObject”)
logPath = Environ(“USERPROFILE”) & “\Desktop” & LOG_FILE_NAME

‘ ログファイルが存在しない場合は作成、存在する場合は追記
If Not fso.FileExists(logPath) Then
Set logFile = fso.CreateTextFile(logPath, True)
Else
Set logFile = fso.OpenTextFile(logPath, 8, True) ‘ 8 = ForAppending
End If

‘ フォーマット化されたログの書き込み
logFile.WriteLine “————————————————–”
logFile.WriteLine “Timestamp : ” & Now
logFile.WriteLine “Process : ” & proc
logFile.WriteLine “Target : ” & target
logFile.WriteLine “Err Number: ” & eNum
logFile.WriteLine “Err Source: ” & eSource
logFile.WriteLine “Desc : ” & eDesc
logFile.WriteLine “————————————————–”

logFile.Close

CleanUp:
Set logFile = Nothing
Set fso = Nothing
Exit Sub

LogWriteError:
‘ ログ出力すら失敗した場合は、最低限イミディエイトウィンドウに逃がす
Debug.Print “CRITICAL LOG ERROR: ” & Err.Description
Resume CleanUp
End Sub

3. オブジェクトのライフサイクルとメモリ管理の鉄則

CorelDRAW VBAで最も恐ろしいのは、VBAがガベージコレクション(GC)を持つ近代言語ではないという点だ。`Shape`, `Layer`, `Page`, `Document` といったCOMオブジェクトは、参照カウントによって管理されている。

特に、ループ処理の中でオブジェクト変数に次々と代入を行い、`Set` を解除しないまま処理を終えると、CorelDRAWのプロセス内にメモリリークが蓄積され、数十万点のベクターデータを扱うバッチ処理の途中で「メモリ不足(Out of Memory)」エラーを引き起こす。

局所的な `On Error` とオブジェクト解放のパターン

.net
Public Sub ProcessAllShapesInActivePage()
Dim sr As ShapeRange
Dim i As Long

On Error GoTo SafeExit

Set sr = ActivePage.Shapes.All

For i = 1 to sr.Count
‘ 個別のシェイプ処理でエラーが出る可能性がある場合
On Error Resume Next
sr(i).Fill.UniformColor.RGBAssign 255, 0, 0

If Err.Number <> 0 Then
‘ ログに残して処理を続行
Debug.Print “Shape Index ” & i & ” 処理スキップ: ” & Err.Description
Err.Clear
End If
On Error GoTo SafeExit ‘ エラートラップを通常モードに戻す
Next i

SafeExit:
‘ 【極限の知見】明示的なメモリ解放
‘ コレクションおよびオブジェクト変数は必ずNothingを代入してCOM参照を解放する
Set sr = Nothing
If Err.Number <> 0 Then
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical
End If
End Sub

4. チーフアーキテクトからの提言

実務において、VBAは「おもちゃのスクリプト言語」ではない。印刷現場のプレフライト、巨大なCAD図面のインポート、数千ファイルにおよぶデザインデータのバッチ置換など、企業の基幹システムの一部として稼働するケースが多々ある。

`On Error Resume Next` を免罪符のように使うのではなく、「どこでエラーが起きうるかを予測し、Errオブジェクトから情報を抽出して安全なストレージ(ファイルやDB)に退避させ、COMの参照を確実に断ち切る」こと。この規律をコードベース全体に徹底することこそが、真に堅牢なCorelDRAW自動化アーキテクチャを実現する唯一の道である。

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