CorelDRAW VBAを掌握する極限の知見:選択未完了(No Selection)を完封するガード節設計と堅牢な例外処理
CorelDRAW VBAで業務効率化ツールや自動化マクロを構築する際、「ユーザーがオブジェクトを選択していない状態でボタンを押した」という事態は、日常茶飯事にして最大のクラッシュ要因です。
素人エンジニアは `On Error Resume Next` でこの問題を握り潰し、結果として原因不明の挙動不審や、データ不整合という最悪のバグを本番環境に撒き散らします。プロフェッショナルなアーキテクトは、COMオブジェクトのライフサイクルと評価コストを理解した上で、「ガード節(Guard Clause)」による厳密な事前判定を設計します。
本稿では、CorelDRAWの内部オブジェクトモデルに深く切り込み、非選択時の実行時エラー(Runtime Error)を100%遮断する堅牢なコーディング・パターンを伝授します。
—
1. なぜ未選択時のアクセスは致命的なのか?(内部メカニズムの解剖)
CorelDRAWのVBA環境において、`ActiveDocument.ActiveShape` や `ActiveSelection` は、単なる変数ではありません。これらはCorelDRAW本体(C++コアエンジン)へのCOM(Component Object Model)ブリッジを介して、リアルタイムにUI上の描画オブジェクトをクエリする動的プロパティです。
1.1 `Err 91` または COM例外の発生構造
選択オブジェクトが存在しない状態で以下のようなコードを実行した場合、何が起きているのでしょうか。
‘ ❌ 致命的なアンチパターン:非選択時に即死するコード
Sub BadExample()
‘ ActiveShapeがNothingを返すため、.Fillにアクセスした瞬間にErr 91が発生する
ActiveDocument.ActiveShape.Fill.ApplyUniformFill CreateRGBColor(255, 0, 0)
End Sub
1. CorelDRAWエンジンは「現在選択中の描画要素」を探すが、空であるため内部的に `NULL` (VBAでは `Nothing`) を返す。
2. VBA側は `Nothing` に対して `.Fill` プロパティのドット演算を行おうとする。
3. VBAインタープリタが `Object variable or With block variable not set (エラー 91)` をスローし、マクロが強制終了する。
1.2 `On Error Resume Next` という麻薬の危険性
エラーを防ぐために以下のようなコードを書く人間がいますが、これは開発者としての敗北です。
‘ ❌ 絶対に書いてはいけない:エラーの隠蔽
Sub DangerousExample()
On Error Resume Next
ActiveDocument.ActiveShape.Fill.ApplyUniformFill CreateRGBColor(255, 0, 0)
‘ 何が起きても処理が先へ進んでしまい、以降のロジックで予期せぬ破壊的変更が起きる
Call HeavyDatabaseUpdateProcess()
End Sub
エラーを無視すると、後続の「選択オブジェクトが存在することを前提とした処理」や「外部データベース/ファイル出力処理」が、空のデータや不正な状態のまま実行されることになります。エラーは「隠す」のではなく、「早期に検知して安全に脱出(Early Exit)」しなければなりません。
—
2. 正しいオブジェクトモデルの選択:`ActiveShape` vs `ActiveSelectionRange`
CorelDRAW VBAのオブジェクトモデルには、選択状態を取得するためのアプローチが複数存在します。それぞれの特性とパフォーマンスの重みを理解してください。
| プロパティ / メソッド | 返り値の型 | 特徴と評価 |
| :— | :— | :— |
| `ActiveDocument.ActiveShape` | `Shape` | 単一選択専用。未選択時は `Nothing` を返す。複数選択時でも1つのShape(Primary Selection)しか参照できないため、判定としては不完全。 |
| `ActiveDocument.Selection` | `Selection` | 旧互換用のプロパティ。COMオブジェクトのオーバーヘッドが大きく、近代的なコードでは非推奨。 |
| `ActiveSelectionRange` | `ShapeRange` | 決定版。選択されているオブジェクトのコレクション(配列的オブジェクト)を返す。未選択時は要素数0の空の `ShapeRange` が安全に返る。 |
プロダクション環境で採用すべきは、例外なく `ActiveSelectionRange` (または `ActiveDocument.SelectionRange`) です。未選択時であっても `Nothing` ではなく「要素数0(Count = 0)の `ShapeRange` オブジェクト」を安全に生成してくれるため、型安全な判定が可能になります。
—
3. ガード節(Guard Clause)による多重防御設計
現場で耐えうる堅牢なツールを作成するには、単に「選択されているか」だけでなく、以下の3つのバリアを構築する必要があります。
1. ドキュメント存在チェック: そもそもファイルが開かれているか? (`ActiveDocument Is Nothing`)
2. 選択数チェック: 指定した必要数(1つ以上、または特定個数)のシェイプが選択されているか? (`ShapeRange.Count`)
3. 編集可能性チェック: 選択されたオブジェクトのレイヤーがロックされていないか?(ロック状態のシェイプを変更しようとすると別の例外が発生する)
これらを1つの共通バリデーション関数に集約するのが、スマートなアーキテクチャです。
—
4. プロダクション適用コード例
そのまま実務に投入できる、堅牢に設計されたVBAモジュールの完全なサンプルです。
構成
- `Module_Main`: 業務ロジックの呼び出しと、エラーログ制御。
- `Module_SelectionGuard`: 選択状態の判定、ロックチェック、およびユーザーガイドを担う共通モジュール。
Option Explicit
‘ ==============================================================================
‘ モジュール名: Module_Main
‘ 概要: 業務ロジックを実行するメイン処理
‘ ==============================================================================
Public Sub ProcessSelectedShapes()
‘ 1. ガード節による安全性の確保
‘ 少なくとも1つの可変(編集可能)なシェイプが選択されているか検証
Dim targetRange As ShapeRange
Set targetRange = SafeGetSelection(RequiredMinCount:=1, RequireEditable:=True)
‘ 検証失敗(未選択、または編集不可)の場合は安全に処理を抜ける
If targetRange Is Nothing Then Exit Sub
‘ 2. 描画最適化(パフォーマンスの最大化)
‘ CorelDRAWの描画更新とUndo履歴の統合を行う
On Error GoTo ErrorHandler
CorelDRAW.Optimization = True
ActiveDocument.BeginCommandGroup “Apply Corporate Red Fill”
‘ 3. メインの業務ロジック実行(安全が保障された状態)
Dim targetShape As Shape
For Each targetShape In targetRange
‘ 例: 選択された全オブジェクトを特定の色に変更
targetShape.Fill.ApplyUniformFill CreateRGBColor(230, 0, 18)
Next targetShape
CleanUp:
‘ 4. 後処理(確実な状態復元)
ActiveDocument.EndCommandGroup
CorelDRAW.Optimization = False
CorelDRAW.Refresh
Exit Sub
ErrorHandler:
‘ 予期せぬ実行時エラーのログとユーザー通知
MsgBox “処理中にエラーが発生しました。” & vbCrLf & _
“エラー内容: ” & Err.Description & ” (Code: ” & Err.Number & “)”, _
vbCritical, “システムエラー”
Resume CleanUp
End Sub
Option Explicit
‘ ==============================================================================
‘ モジュール名: Module_SelectionGuard
‘ 概要: CorelDRAW VBA 選択判定用ガードエンジン
‘ ==============================================================================
”’
”’
”’ 必要な最小選択数(デフォルト: 1)
”’ ロック済みレイヤーのシェイプを除外・警告するか
”’
Public Function SafeGetSelection( _
Optional ByVal RequiredMinCount As Long = 1, _
Optional ByVal RequireEditable As Boolean = True _
) As ShapeRange
‘ — 第1バリア: ドキュメントの存在確認 —
If ActiveDocument Is Nothing Then
MsgBox “作業中のドキュメントが存在しません。ファイルを開いてから実行してください。”, _
vbExclamation, “実行不能”
Set SafeGetSelection = Nothing
Exit Function
End If
‘ — 第2バリア: 選択シェイプ範囲の取得 —
‘ ActiveSelectionRange は非選択時でも安全にCount=0のShapeRangeを返す
Dim currentSelection As ShapeRange
Set currentSelection = ActiveDocument.ActiveSelectionRange
‘ 選択数が足りない場合のガード
If currentSelection.Count < RequiredMinCount Then
ShowUserInstructionMessage RequiredMinCount, currentSelection.Count
Set SafeGetSelection = Nothing
Exit Function
End If
' --- 第3バリア: 編集可能性(ロック状態)の検証 ---
If RequireEditable Then
Dim editableSelection As New ShapeRange
Dim s As Shape
For Each s In currentSelection
' シェイプ自体、または所属レイヤーがロックされているか判定
If Not s.Layer.Locked And Not s.Locked Then
editableSelection.Add s
End If
Next s
' ロックされていないシェイプが指定数に満たない場合
If editableSelection.Count < RequiredMinCount Then
MsgBox "選択されたオブジェクト(またはレイヤー)がロックされています。" & vbCrLf & _
"ロックを解除してから再度実行してください。", _
vbWarning, "編集不可"
Set SafeGetSelection = Nothing
Exit Function
End If
' フィルタリング後のSafeなShapeRangeをセット
Set SafeGetSelection = editableSelection
Else
Set SafeGetSelection = currentSelection
End If
End Function
'''
”’
Private Sub ShowUserInstructionMessage(ByVal required As Long, ByVal actual As Long)
Dim msg As String
If actual = 0 Then
msg = “オブジェクトが選択されていません。” & vbCrLf & _
“対象のオブジェクトを選択してから、再度マクロを実行してください。”
Else
msg = “選択されたオブジェクトの数が足りません。” & vbCrLf & _
“必要数: ” & required & ” 個以上” & vbCrLf & _
“現在数: ” & actual & ” 個”
End If
MsgBox msg, vbInformation, “操作ガイド”
End Sub
—
5. アーキテクトが教える「エンタープライズ対応」の深掘りポイント
このコード設計には、単なる「エラー回避」を超えた、業務システム構築上の重要思想が組み込まれています。
① `CorelDRAW.Optimization` の安全な巻き戻し
CorelDRAWの再描画を停止して処理速度を10倍以上に高める `CorelDRAW.Optimization = True` ですが、処理の途中で未選択エラーで落ちると、「CorelDRAWの画面が一切更新されなくなる」 という最悪のハングアップ状態に陥ります。ガード節(`SafeGetSelection`)を `Optimization = True` に設定する前に配置することで、この事故を根本から防止しています。
② ロック状態の二重検証(Layer & Shape)
CorelDRAWには「オブジェクト単位のロック(`Shape.Locked`)」と「レイヤー単位のロック(`Layer.Locked`)」の2種類が存在します。未選択チェックを通過しても、ロックされたオブジェクトに対して幾何学的な変更(移動・回転・色変更)をかけるとCOMエラーが飛んできます。ガード節内でこれらをフィルタリングしておくことが、本番環境での絶対的な安定性をもたらします。
③ 外部DBやファイル出力との連携時の鉄則
もしこのマクロが「選択オブジェクトのサイズを測り、CSV出力する」「基幹システム(DB)にデータを飛ばす」ツールである場合、ガード節を通過しなかった際はトランザクションを発生させないことが極めて重要です。`SafeGetSelection` が `Nothing` を返した段階で即座に離脱することで、無駄なファイルアクセスや不整合なDBレコードの作成を完璧に遮断できます。
—
結論:例外処理の質が、ツールの品質を決める
CorelDRAW VBAにおいて、「動くコード」を書くことは難しくありません。しかし、「素人がどんな操作をしても絶対にクラッシュせず、適切なガイドを出して終了するツール」を書くには、徹底した防御的プログラミングが必要です。
今回提示した `SafeGetSelection` モジュールをあなたの共通ライブラリ(VBAプロジェクトの標準モジュール)に組み込み、すべてのマクロの入口に配置してください。これだけで、現場から寄せられる「マクロが止まった」「エラーが出る」という問い合わせの8割を撲滅できます。
