実行時エラー「オブジェクト変数または With ブロック変数が見つかりません」を根絶するNothing判定の実装パターン
CorelDRAW VBAの開発現場において、ランタイムエラー「オブジェクト変数または With ブロック変数が見つかりません(実行時エラー 91)」ほど、エンジニアの精神を摩耗させるエラーはない。
このエラーの本質は、VBAランタイムがメモリ上に実体を持たない(= `Nothing` である)オブジェクトに対してメソッドの実行やプロパティの参照を試みた際、アクセストラップを踏み抜くことにある。特にCorelDRAWのCOMオブジェクトモデルは、ドキュメントの閉じ忘れ、選択解除、レイヤー構造の動的変更など、不確定要素が絡み合うため、甘い参照取得はシステム全体のクラッシュへと直結する。
本稿では、レガシーなVBAの限界を見据え、`Nothing` 判定のイディオム、メモリの適正管理、そして実務で即座に使える堅牢なエラーハンドリングの極限パターンを提示する。
—
1. CorelDRAWオブジェクトモデルにおける「存在しない」リスク
CorelDRAW VBAで最も頻発するエラー91の発生源は、以下のような「暗黙の前提」に基づいたコードである。
‘ 【アンチパターン】存在しないアクティブドキュメントを強引に操作する
Sub BadExample()
‘ ドキュメントが開かれていない場合、ここでエラー91が発生する
ActiveDocument.ActiveLayer.CreateRectangle 0, 0, 100, 100
End Sub
`ActiveDocument` や `ActiveShape` といったグローバルヘルパープロパティは、対象が存在しない場合に `Nothing` を返す。これをそのままドット繋ぎ(メソッドチェーン)で叩くことは、C言語でNULLポインタをデリファレンスするに等しい愚行である。
—
2. 厳格な `Is Nothing` 判定とフォールバックの設計
堅牢なコードの第一歩は、取得したオブジェクトが確実に実体を持っているかを `Is` 演算子で検証することだ。
以下のコードは、アクティブな選択図形(`Shape`)安全に取得し、存在しない場合のフォールバック(処理の回避または新規作成)を実装した実用的なモジュールである。
Public Sub ProcessSelectedShape()
Dim srTarget As ShapeRange
Dim shTarget As Shape
‘ 1. 安全なオブジェクトの取得
On Error Resume Next
Set srTarget = ActiveSelectionRange
On Error GoTo 0
‘ 2. コレクション自体の存在確認
If srTarget Is Nothing Then
MsgBox “ドキュメントが開かれていないか、選択範囲が不正です。”, vbCritical
Exit Sub
End If
‘ 3. 要素数の確認(コレクションが空の場合のケア)
If srTarget.Count = 0 Then
MsgBox “処理対象の図形が選択されていません。”, vbExclamation
Exit Sub
End If
‘ 4. 先頭シェイプの取得とNothing判定
Set shTarget = srTarget.Shapes(1)
If shTarget Is Nothing Then
MsgBox “指定されたシェイプの参照に失敗しました。”, vbCritical
GoTo CleanUp
End If
‘ — メイン処理 —
shTarget.Outline.Color.RGBAX 255, 0, 0, 0 ‘ 赤枠に変更
CleanUp:
‘ 5. メモリの明示的解放(後述)
Set shTarget = Nothing
Set srTarget = Nothing
End Sub
—
3. 領域階層(Document / Page / Layer)を安全に巡回するパターン
CorelDRAWのドキュメント構造は階層が深い。特定のレイヤー名が存在するかどうかを動的に判断し、存在しない場合は新規作成する(Fail-Safeな初期化処理)のイディオムを以下に示す。
Public Function GetOrCreateLayer(ByVal targetPage As Page, ByVal layerName As String) As Layer
Dim lyr As Layer
Dim foundLayer As Layer
Set foundLayer = Nothing
‘ ページオブジェクト自体の生存確認
If targetPage Is Nothing Then
Set GetOrCreateLayer = Nothing
Exit Function
End If
‘ レイヤーコレクションの走査
For Each lyr In targetPage.Layers
If lyr.Name = layerName Then
Set foundLayer = lyr
Exit For
End If
Next lyr
‘ 該当レイヤーが存在しない場合は新規作成
If foundLayer Is Nothing Then
Set foundLayer = targetPage.CreateLayer(layerName)
‘ 作成直後の成否判定
If foundLayer Is Nothing Then
Err.Raise 9999, “GetOrCreateLayer”, “レイヤーの生成に失敗しました: ” & layerName
End If
End If
Set GetOrCreateLayer = foundLayer
‘ ループ変数およびローカル参照のクリーンアップ
Set lyr = Nothing
Set foundLayer = Nothing
End Function
—
4. メモリ最適化:オブジェクト変数の明示的解放 (`Set … = Nothing`)
VBAのガベージコレクションは参照カウント方式に基づいている。ローカル変数はプロシージャ終了時に自動解放されるが、複雑なオブジェクト階層や長寿命のモジュールレベル変数、あるいは大規模な一括処理(数百個のシェイプ生成など)においては、明示的な `Nothing` による参照の切断を行わなければ、CorelDRAWプロセス内にメモリリークが蓄積する。
特に、CorelDRAW VBAと外部COM(Excelや独自アドイン等)を連携させるシステム間連携の現場では、このリークがCOMコンポーネントのフリーズやハングアップの主原因となる。
厳格なメモリ解放の作法
Sub HeavyProcessOptimization()
Dim doc As Document
Dim pag As Page
Dim sh As Shape
Set doc = Application.ActiveDocument
If doc Is Nothing Then Exit Sub
Set pag = doc.ActivePage
If pag Is Nothing Then GoTo FreeDoc
‘ 大量のシェイプを扱うループ
Dim i As Long
For i = 1 to 10000
Set sh = pag.CreateRectangle(i, i, i + 10, i + 10)
‘ シェイプに対する処理…
‘ ループ内でのオブジェクト再割当て時の注意
‘ 連続してインスタンスを掴む場合、前の参照がリークしないようループ内で確実に破棄するか、
‘ コレクション経由で処理を完結させる。
Set sh = Nothing
Next i
FreePag:
Set pag = Nothing
FreeDoc:
Set doc = Nothing ‘ 最後にルートを解放
End Sub
—
5. チーフアーキテクトからの提言:例外を「握りつぶさない」エラーハンドリング
`On Error Resume Next` は、`Nothing` 判定を行うための強力な武器であると同時に、予期せぬ重大なバグを隠蔽する諸刃の剣である。
プロシージャ全体を `On Error Resume Next` で汚染してはならない。「エラーが発生し得る極小のスコープ(APIの呼び出しやCOMオブジェクトのバインド直後)」のみに限定して適用し、即座に `On Error GoTo 0` で通常のエラー監視状態に戻すこと。
‘ 【推奨されるスコープ制御】
Dim targetShape As Shape
On Error Resume Next
Set targetShape = ActivePage.FindShape(Name:=”MyUniqueShape”)
On Error GoTo 0
If targetShape Is Nothing Then
‘ 存在しない場合のフォールバック処理
Call LogMessage(“対象シェイプが見つからないため、新規作成します。”)
Set targetShape = ActivePage.CreateRectangle(0, 0, 50, 50)
targetShape.Name = “MyUniqueShape”
End If
‘ 以降、targetShape は確実に実体を持つため、安全に操作できる
targetShape.Fill.UniformColor.CMYKAssign 0, 100, 100, 0
Set targetShape = Nothing
総括
CorelDRAW VBAにおける堅牢性の担保は、魔法の呪文ではなく、オブジェクトのライフサイクルに対する冷徹なまでの理解と、徹底した `Is Nothing` へのこだわりによってのみ達成される。
エラー91に怯える日々を終わらせ、ミリ秒単位の処理速度と、数昼夜連続稼働しても微動だにしない鉄壁の自動化基盤を構築せよ。
