【CorelDRAW VBA】ActiveDocumentの罠を回避せよ!複数ファイルを安全に操る「参照保持」の極意
こんにちは!CorelDRAWを使ったデザイン業務や製版データの作成、日々のルーティン作業の自動化に挑戦している皆さん。一歩進んだVBAの世界へようこそ。
「マクロの記録」を使って自動化の第一歩を踏み出した方が、次に必ずと言っていいほどぶつかる大きな壁があります。
それは、「複数のファイル(ドキュメント)を開いた状態でマクロを実行すると、意図しないファイルに対して処理が行われてしまう、あるいはエラーで止まってしまう」という問題です。
「さっきまでは上手く動いていたのに、別のファイルを開きながら実行したら、大事な元データが書き換えられてしまった……」
そんな悲しい事故を防ぎ、CorelDRAWのポテンシャルを100%引き出すための鍵が、今回解説する`Application.ActiveDocument` と `Documents` コレクションの使い分けです。
ここをクリアすれば、CorelDRAW VBAの基本はバッチリですよ。先輩エンジニアと一緒に、この仕組みを根本から楽しく紐解いていきましょう!
—
1. なぜ「ActiveDocument」だけに頼ると危険なのか?
CorelDRAW VBAを学び始めたばかりのとき、コードにはよく `ActiveDocument` という言葉が登場します。これは文字通り「今、ユーザーが目の前で操作している(一番手前にある)ドキュメント」を指します。
直感的で分かりやすいのですが、ここにプログラミング特有の罠が潜んでいます。
アクティブなドキュメントは「移り気な主役」
マクロの実行中、以下のような操作が行われると、CorelDRAWにとっての「アクティブ(主役)」は一瞬で切り替わってしまいます。
- マクロが新しくドキュメントを開いた(`Documents.Open`)
- マクロが新しいドキュメントを作成した(`CreateDocument`)
- ユーザーがマクロ実行中に、別のグラフィックウィンドウをカチッとクリックした
‘ — 危険なコードの例 —
Sub DangerMacro()
‘ 今開いているドキュメント(Document A)を処理したい
ActiveDocument.Unit = cdrMillimeter
‘ 新しいドキュメント(Document B)を開く
Documents.Open “C:\Temp\template.cdr”
‘ 【罠!】ここでのActiveDocumentは、新しく開いた「Document B」に切り替わっている!
‘ 本来 Document A に描きたかった四角形が、Document B に描かれてしまう。
ActiveDocument.ActiveLayer.CreateRectangle 0, 0, 100, 100
End Sub
このように、`ActiveDocument` は「その瞬間、たまたま一番手前にいるファイル」に過ぎません。処理の途中で主役が移り変わると、マクロは迷子になり、最悪の場合、ユーザーの大切なデザインデータを破壊してしまうのです。
—
2. メモリの視点で見る「Documents」と「Document」
この問題を根本から解決するために、CorelDRAWがメモリの中でドキュメントをどう管理しているか、イメージ図で理解しましょう。
ドキュメント管理の構造図
[ CorelDRAW Application ]
│
└── [ Documents コレクション ] (開いているすべてのファイルの束)
│
├── [ Document (1) ] ── (例: “flyer.cdr” / 固有のメモリ番地: &H101)
├── [ Document (2) ] ── (例: “banner.cdr” / 固有のメモリ番地: &H102)
└── [ Document (3) ] ── (例: “untitled.cdr” / 固有のメモリ番地: &H103)
- `Documents` コレクション:現在CorelDRAWで開かれているすべてのドキュメントを束ねた「本棚」のような存在です。
- `Document` オブジェクト:本棚に並ぶ「本(ファイル)」そのものです。それぞれがメモリ上で固有の住所(参照)を持っています。
プロが書く安全なコードでは、`ActiveDocument` という「曖昧な状態」に頼るのではなく、「この本棚(Documents)から、この本(Document型変数)を直接掴んで離さない!」というアプローチを取ります。
これを「オブジェクト参照の保持」と呼びます。
—
3. プロが実践する「安全なマルチドキュメント操作」3つの黄金律
では、具体的にどのようにコードを書けば安全なのでしょうか? 押さえておくべき3つの黄金律を紹介します。
黄金律①:変数への代入(Set)を徹底する
ドキュメントを開いた瞬間、または作成した瞬間に、そのドキュメントを変数に「ガッチリとホールド」します。
Dim sourceDoc As Document
‘ 開くと同時に、変数 sourceDoc にこのファイルを固定する
Set sourceDoc = Documents.Open(“C:\Data\source.cdr”)
‘ 以降、どれだけ画面が切り替わろうとも、sourceDoc は絶対に揺らがない!
sourceDoc.Unit = cdrMillimeter
黄金律②:インデックス番号(1, 2, 3…)で指定しない
`Documents.Item(1)` のように数字でドキュメントを指定するのは避けましょう。なぜなら、ユーザーがファイルを手動で閉じたり、新しく開いたりすると、このインデックス番号は動的にズレてしまうからです。
指定する場合は、必ず上記のようにオブジェクト変数に格納するか、以下のようにファイル名(Name)を使って指定します。
Dim targetDoc As Document
On Error Resume Next ‘ エラーを一時的に無視して確認
Set targetDoc = Documents(“flyer.cdr”)
On Error GoTo 0 ‘ エラーハンドリングを元に戻す
If targetDoc Is Nothing Then
MsgBox “指定したファイルが開かれていません!”, vbExclamation
End If
黄金律③:処理の前に「絶対的な原点」を確保する
マクロがスタートした瞬間の「スタートライン(最初に開いていたファイル)」を、最初に変数に退避させておくのが鉄則です。
Dim startDoc As Document
Set startDoc = ActiveDocument ‘ スタート時点のActiveDocumentを「固定」する
—
4. 【実践コード】複数ファイルを安全に渡り歩く実用マクロ
ここでは、実務でよくある「開いているすべてのドキュメントを順番にチェックし、そのサイズ(幅と高さ)を一覧として、新しく作成したドキュメント(レポート用)に書き出す」というシナリオを実装してみましょう。
このコードを読めば、複数のファイル間をいかに安全に行き来するかが完璧に理解できます。
Sub SecureMultiDocumentProcessing()
Dim reportDoc As Document
Dim currentDoc As Document
Dim reportText As String
Dim yPosition As Double
‘ 1. 事前準備:開いているドキュメントがあるかチェック
If Documents.Count = 0 Then
MsgBox “処理対象のドキュメントが開かれていません。”, vbInformation, “終了”
Exit Sub
End If
‘ 2. レポート用のテキストのヘッダーを作成
reportText = “【CorelDRAW ドキュメントサイズ一覧レポート】” & vbCrLf
reportText = reportText & “実行日時: ” & Now & vbCrLf & “—————————————-” & vbCrLf
‘ 3. 開いているすべてのドキュメントを安全に走査(ループ処理)
‘ Documentsコレクションの中を、1つずつ「currentDoc」という変数に代入して処理します
For Each currentDoc In Documents
‘ 自身の名前、幅、高さを取得(単位をミリメートルに一時変更して測定)
Dim originalUnit As cdrUnit
originalUnit = currentDoc.Unit ‘ 元の単位を記憶
currentDoc.Unit = cdrMillimeter ‘ 単位をミリメートルに統一
‘ 情報をテキストに蓄積
reportText = reportText & “ファイル名: ” & currentDoc.Name & vbCrLf
reportText = reportText & ” サイズ: ” & currentDoc.ActivePage.SizeWidth & “mm x ” & _
currentDoc.ActivePage.SizeHeight & “mm” & vbCrLf
currentDoc.Unit = originalUnit ‘ 単位を元に戻す
Next currentDoc
‘ 4. 新しいドキュメント(レポート出力先)を作成
‘ この瞬間に、画面上のActiveDocumentは「新規ドキュメント」に移りますが、
‘ 私たちは変数を使ってコントロールしているため、一切影響を受けません。
Set reportDoc = CreateDocument()
reportDoc.Unit = cdrMillimeter
‘ 5. レポートドキュメントに結果を書き出す
‘ 画面の切り替えを伴うことなく、直接「reportDoc」のレイヤーを指定してテキストを描画
Dim artText As Shape
Set artText = reportDoc.ActiveLayer.CreateParagraphText(10, 280, 200, 10, reportText)
‘ フォントやサイズを調整
artText.Text.FontProperties.Name = “MS Gothic”
artText.Text.FontProperties.Size = 12
MsgBox “すべてのドキュメント情報の集約が完了しました!”, vbInformation, “完了”
End Sub
このコードが「極めて安全」な理由
1. `For Each currentDoc In Documents` を使用することで、インデックス番号のズレを完全に無視し、メモリ上の実体を直接指し示しながらループしています。
2. 新しく作成したドキュメントを `Set reportDoc = CreateDocument()` で変数に格納しているため、新ファイルが作られた瞬間にフォーカスが移っても、マクロが混乱しません。
3. すべての描画・設定処理が `currentDoc` や `reportDoc` といった変数経由で直接指示されているため、ユーザーが処理の途中で画面をクリックしても、処理対象がブレることはありません。
—
5. まとめ:ここをクリアすれば基本はバッチリ!
今回の最重要ポイントを振り返りましょう。
1. `ActiveDocument` は「今、たまたま一番手前にあるファイル」を指すため、処理の途中で主役が変わりやすい。
2. 複数のファイルを扱うときは、必ず `Dim doc As Document` で変数を用意し、`Set doc = …` で参照を固定する。
3. `Documents` コレクションを `For Each` で回す手法は、安全な複数ファイル処理の王道パターンである。
この「参照を保持する」という概念は、CorelDRAW VBAのみならず、Excel VBAやIllustratorのスクリプトなど、すべてのOffice・DTP自動化における超重要コンセプトです。
これが自然にできるようになれば、あなたはもう「マクロの記録」を卒業した、立派なVBAエンジニアです。自信を持って、より複雑で頑丈な自動化ツール作りに挑戦してくださいね!
何か分からないことや、思い通りに動かないコードがあれば、いつでも頼れる先輩としてサポートします。ハッピー・コーディング!
