CorelDRAW VBAを掌握する極限の知見:多ページドキュメントの高速走査とアクティブ化のアンチパターン
CorelDRAW VBAによる自動化において、最も多くの開発者が陥る罠が「ページ走査とアクティブ化」のコストを見誤ることだ。数百ページに及ぶカタログ、パッケージ展開図、あるいは可変データのバッチ処理において、愚直に画面を描画させながらページを切り替えているようでは、プロのエンジニアとは言えない。
今回は、`Document` オブジェクトのコレクション走査、パフォーマンスを極限まで引き上げるためのコンテキスト制御、そしてCOMのライフサイクルを支配するメモリ最適化の真髄を解説する。
—
1. なぜ「画面描画とアクティブ化」がパフォーマンスの癌なのか
CorelDRAWのUIスレッドとVBAの実行スレッドは密結合している。`ActiveDocument.Pages(i).Activate` を実行するたびに、CorelDRAWは以下の重処理を同期的に強制される。
1. DOM(Document Object Model)のビューポート再計算
2. プレビューウィンドウの再描画(InvalidateRect)
3. 選択セット(Selection)のクリアと再構築
これを数千回のループで行えば、CPUコアの大部分が無駄なUI描画に費やされる。シニアエンジニアが真っ先に行うべきことは、「UIとデータモデルの完全な切り離し」である。
—
2. 画面描画の完全凍結:`Optimization` プロパティの活用
CorelDRAW VBAには、VBAの `Application.ScreenUpdating` よりも強力な、CorelDRAWネイティブの最適化フラグが存在する。それが `Optimization = True` だ。
これを宣言すると、オブジェクトの生成・変更・ページ移動に伴う画面描画やイベント発火が完全にバイパスされ、メモリ上で直接DOMが操作される。
Sub ProcessMultiPageDocument()
Dim startTime As Double
startTime = Timer
‘ 1. 描画とイベントを完全凍結
Application.Optimization = True
Application.EventsEnabled = False ‘ イベントも抑制して暴走を防ぐ
Dim doc As Document
Set doc = ActiveDocument
Dim originalPage As Page
Set originalPage = doc.ActivePage
On Error GoTo ErrorHandler
Dim p As Page
Dim sh As Shape
‘ 2. ページコレクションの直接走査(Activateを使わない)
For Each p In doc.Pages
‘ ページをアクティブにせずとも、Pageオブジェクト経由で直接操作可能
For Each sh As Shape in p.Shapes
‘ 例:特定のレイヤーにあるテキストを置換するなどの処理
If sh.Type = cdrTextShape Then
‘ 処理ロジック
End If
Next sh
Next p
ErrorHandler:
‘ 3. 必ず環境を復元する
Set originalPage = Nothing
Set doc = Nothing
Application.EventsEnabled = True
Application.Optimization = False
Application.Refresh ‘ 最後に一度だけ強制描画
MsgBox “処理完了: ” & Format(Timer – startTime, “0.00”) & “秒”, vbInformation
End Sub
—
3. 実践:アクティブ化が「どうしても必要」な場合のスマート・コンテキスト制御
どうしても `ActivePage.Activate` を使わざるを得ないサードパーティ製プラグインの呼び出しや、複雑なツール操作を伴う処理が存在する。その場合でも、「描画コストを最小化する作法」がある。
以下のコードは、多ページドキュメントを一括走査しつつ、安全にページを切り替える堅牢な実装パターンだ。
Sub SafePageTraversalWithContext()
Dim doc As Document
Set doc = ActiveDocument
Dim totalPages As Long
totalPages = doc.Pages.Count
Dim i As Long
‘ 最適化の開始
Application.Optimization = True
For i = 1 To totalPages
Dim targetPage As Page
Set targetPage = doc.Pages(i)
‘ ページをアクティブにする(必要な場合のみ)
targetPage.Activate
‘ — ここにページ単位の重い処理を記述 —
ProcessPageContent targetPage
‘ 参照の解放(メモリリーク防止)
Set targetPage = Nothing
Next i
‘ 終了処理
Application.Optimization = False
Application.Refresh
Set doc = Nothing
End Sub
Private Sub ProcessPageContent(ByRef p As Page)
‘ ページオブジェクトを直接叩くことで、無駄な再描画を抑制
Dim lay As Layer
For Each lay In p.Layers
If Not lay.Name = “Guideline” Then
‘ レイヤー単位の処理
End If
Set lay = Nothing
Next lay
End Sub
—
4. COMのライフサイクルとメモリリークの根絶
CorelDRAW VBA(VBA環境全般)における最大の悪夢は、「裏で生き続けるCOM参照(ゾンビプロセス)」である。
特に `For Each` ループや、変数の暗黙的な保持によって、ドキュメントやページ、シェイプの参照がメモリ上に残留し、CorelDRAW終了後もプロセスがタスクマネージャーに残る現象が多発する。
徹底すべき鉄則:
1. オブジェクト変数は必ず `Nothing` で明示的に解放する。
2. ループ変数のスコープを極力狭め、ループ脱出時に即座に破棄する。
3. エラーハンドリング(`On Error GoTo`)内でも確実に参照を解放するクリーンアップブロックを設ける。
レガシーなCorelDRAW(X7, 2019等)の環境であればあるほど、このメモリ管理の甘さがクラッシュ(強制終了)直結する。安定稼働する自動化システムを構築したいのであれば、コードの美しさよりも「リソースの確実な解放」を優先すべきだ。
—
5. チーフアーキテクトからの提言
複数ページのドキュメント制御において、最も重要なのは「CorelDRAWに余計な仕事をさせないこと」だ。
画面を書き換えさせず、イベントを抑制し、メモリをクリーンに保つ。たったこれだけの設計思想の違いで、処理時間は数分から数秒へと劇的に短縮される。
VBAはレガシーな言語と言われるが、その裏で動くCorelDRAWのCOMアーキテクチャの急所を突けば、現在でも極めて強力なエンタープライズ・バッチ処理基盤として機能する。
プロとして、ただ動くだけのコードではなく、リソースを支配した洗練されたコードを書き上げてほしい。
