CorelDRAW VBAを掌握する極限の知見:ホットフォルダ型・全自動フォーマットコンバーターの設計
業務効率化の現場において、「ファイルのドラッグ&ドロップすら自動化したい」という要求に直面することは少なくない。特に、印刷会社やデザインプロダクションでは、デザイナーが制作したCDRファイルを、クライアントや出力先の指定に応じてPDFやEPSへ日々大量に変換し続けている。
「フォルダにファイルを放り込むだけで、適切な形式へ裏で勝手に変換されていく」——このホットフォルダ(監視フォルダ)の仕組みを、CorelDRAWのVBA(およびWindows Script Host)を駆使して完全無人で構築する。
単に動くだけのコードではない。「CorelDRAWの不安定なCOMライフサイクル」「ファイルロックの競合」「多重起動の防止」という、実務の現場で必ず牙をむく罠を完璧に回避した、プロダクション品質のアーキテクチャを伝授する。
—
1. なぜ「単純なVBAループ」では実用に耐えないのか?
初心者がやりがちなアプローチは、CorelDRAWのVBA内で無限ループ(`Do…Loop`)を回し、`Dir`関数でフォルダを監視し続けるというものだ。しかし、この設計は現場では地雷でしかない。
1. CorelDRAWのメモリリークと肥大化: `Application.Open`と`CloseDocument`を何百回も繰り返すと、VBAのランタイムやCorelDRAW内部のC++ヒープにゴミが残り、数時間でフリーズまたは強制終了する。
2. ファイル書き込み中の競合(File Lock): ネットワークドライブ経由でデザイナーがファイルをアップロードしている最中にVBAがファイルを拾うと、「ファイルが使用中です」エラーで処理がクラッシュする。
3. UIスレッドのブロック: CorelDRAWのVBAはシングルスレッドで動作するため、監視ループを回している間はCorelDRAW本体の操作が一切できなくなる。
模範解答:VBA本体は「単発処理」に徹し、監視はVBScript(WSH)に委譲する
堅牢なシステムを構築するためには、「外側からのトリガー(監視・制御)」と「内側での処理(CorelDRAW VBA)」を完全に分離するべきだ。
- 外側(VBScript / WSH): OSのファイルシステムを監視し、ファイルの転送完了(書き込み完了)を検知してCorelDRAWをヘッドレス(非表示)起動する。
- 内側(CorelDRAW VBA): 渡されたファイルを1つだけ読み込み、指定フォーマットでエクスポートして速やかに終了する。
この疎結合な設計により、万が一CorelDRAWがメモリリークでクラッシュしても、外側の監視スクリプトが次のファイルを安全に処理し続けることができる。
—
2. システム全体アーキテクチャ
今回構築するディレクトリ構造は以下の通りだ。ローカルまたはファイルサーバー上に専用の作業領域を設ける。
C:\HotFolder\
┣ WatchFolder\ <-- デザイナーがCDRを放り込む場所
┣ Processing\ <-- 処理中のファイルを退避する場所(競合防止)
┣ Output_PDF\ <-- PDF変換先の出力フォルダ
┣ Output_EPS\ <-- EPS変換先の出力フォルダ
┣ Error\ <-- 破損ファイルや異常終了したファイルの退避先
┗ Watcher.vbs <-- 常駐監視スクリプト
---
3. プロダクションコード実装
① コア処理:CorelDRAW側 VBAモジュール
まずは、受け取った単一のCDRファイルを解析し、ファイル名やルールに基づいてPDFまたはEPSにエクスポートするVBAコードだ。このコードは、CorelDRAWの標準テンプレート(`GlobalMacros`など)に配置するか、外部から呼び出されるドキュメントに埋め込む。
‘ ==============================================================================
‘ モジュール名: modHotFolderWorker
‘ 概要: 渡されたCDRファイルを解析し、指定フォーマットへエクスポートする
‘ ==============================================================================
Option Explicit
Public Sub ProcessConversion(ByVal targetFilePath As String, ByVal outputPdfDir As String, ByVal outputEpsDir As String)
Dim doc As Document
Dim fileName As String
Dim baseName As String
Dim exportPath As String
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)
‘ ファイルが存在するか最終確認
If Not fso.FileExists(targetFilePath) Then Exit Sub
fileName = fso.GetFileName(targetFilePath)
baseName = fso.GetBaseName(targetFilePath)
On Error GoTo ErrorHandler
‘ CorelDRAWの警告ダイアログ等を非表示にし、完全自動化
EventsEnabled = False
‘ CDRファイルをサイレントオープン(UIを描画しないことで高速化と安定化を図る)
Set doc = Application.OpenDocument(targetFilePath)
‘ —————————————————-
‘ 振り分けロジックの判定
‘ 例: ファイル名に “_EPS” が含まれていればEPS、それ以外はPDF
‘ —————————————————-
If InStr(1, UCase(fileName), “_EPS”) > 0 Then
‘ EPSエクスポート処理
exportPath = outputEpsDir & “\” & baseName & “.eps”
Call ExportToEPS(doc, exportPath)
Else
‘ PDFエクスポート処理(デフォルト)
exportPath = outputPdfDir & “\” & baseName & “.pdf”
Call ExportToPDF(doc, exportPath)
End If
‘ ドキュメントを保存せずに閉じる(メモリリーク防止の極意)
doc.Close
Set doc = Nothing
EventsEnabled = True
Exit Sub
ErrorHandler:
‘ エラー発生時はイベントを復旧させ、上位へエラーを伝播
EventsEnabled = True
If Not doc Is Nothing Then
doc.Close
Set doc = Nothing
End If
Err.Raise Err.Number, “ProcessConversion”, “変換処理中に致命的なエラーが発生しました: ” & Err.Description
End Sub
Private Sub ExportToPDF(ByRef doc As Document, ByVal outputPath As String)
Dim ak As StructPDFExportSettings
Set ak = CreateStructPDFExportSettings
‘ PDF出力プリセットの適用(実務に合わせて調整)
‘ ※環境にあらかじめCorelDRAW側でPDFスタイルを保存しておくのがベストプラクティス
With ak
.PublishRange = pdAllPages
.Version = pdfVersionX3 ‘ 例: PDF/X-3形式で出力
.CompressText = True
.BitmapCompression = pdfJPEGHigh
End With
doc.PublishToPDF outputPath, ak
End Sub
Private Sub ExportToEPS(ByRef doc As Document, ByVal outputPath As String, ByVal exportPath As String)
Dim expFilter As ExportFilter
Dim opt As StructExportOptions
Set opt = CreateStructExportOptions
With opt
.Antialiasing = True
.ImageType = ivaCMYK
End With
‘ EPS形式でのエクスポート
Set expFilter = doc.ExportEx(outputPath, cdrEPS, cdrAllPages, opt)
expFilter.Finish
End Sub
② 常駐監視・制御:VBScript(Watcher.vbs)
次に、フォルダを常時監視し、ファイルの完全性を確認した上でCorelDRAWを起動・制御するVBScript。Windows環境であれば、追加のソフトウェアを入れることなく、ダブルクリックするだけで常駐タスクとして機能する。
‘ ==============================================================================
‘ スクリプト名: Watcher.vbs
‘ 概要: WatchFolderを監視し、新規CDRファイルを検知してCorelDRAW VBAをキックする
‘ ==============================================================================
Option Explicit
Dim fso, shell
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set shell = CreateObject(“WScript.Shell”)
‘ — 設定エリア —
Dim watchDir, processingDir, pdfDir, epsDir, errorDir
watchDir = “C:\HotFolder\WatchFolder”
processingDir = “C:\HotFolder\Processing”
pdfDir = “C:\HotFolder\Output_PDF”
epsDir = “C:\HotFolder\Output_EPS”
errorDir = “C:\HotFolder\Error”
‘ フォルダが存在しない場合は作成
If Not fso.FolderExists(watchDir) Then fso.CreateFolder(watchDir)
If Not fso.FolderExists(processingDir) Then fso.CreateFolder(processingDir)
If Not fso.FolderExists(pdfDir) Then fso.CreateFolder(pdfDir)
If Not fso.FolderExists(epsDir) Then fso.CreateFolder(epsDir)
If Not fso.FolderExists(errorDir) Then fso.CreateFolder(errorDir)
‘ 無限ループによる監視(5秒間隔)
Do
Call CheckAndProcessFiles()
WScript.Sleep 5000 ‘ 5秒ウェイト
Loop
Sub CheckAndProcessFiles()
Dim folder, file, targetFile, destFile
Set folder = fso.GetFolder(watchDir)
For Each file in folder.Files
‘ 拡張子が .cdr のファイルのみ対象とする(大文字小文字問わず)
If LCase(fso.GetExtensionName(file.Name)) = “cdr” Then
‘ 【重要】ファイルコピー中(ネットワーク遅延など)の競合を防ぐため、
‘ サイズが一定時間変化しないか、排他ロックが解除されたかをチェック
If IsFileReady(file.Path) Then
On Error Resume Next
‘ 処理中のフォルダへ移動(アトミックな操作による二重処理防止)
destFile = processingDir & “\” & file.Name
fso.MoveFile file.Path, destFile
If Err.Number = 0 Then
On Error GoTo 0
‘ CorelDRAWを起動してVBAマクロを実行する
‘ ※あらかじめCorelDRAW側でマクロを登録・オートロードしておく必要がある
Dim cdrCmd
‘ コマンドライン引数経由でファイルを渡す、またはVBA側のグローバル変数にフックさせる
‘ ここでは確実性を重視し、CorelDRAWを起動してVBAプロシージャを呼ぶ構造をとる
Dim cdApp
Set cdApp = CreateObject(“CorelDRAW.Application”)
cdApp.Visible = False ‘ ヘッドレス実行
‘ VBAの公開メソッドを呼び出す(※CorelDRAWのバージョンによりマクロパスの指定に注意)
cdApp.RunMacro “GlobalMacros”, “modHotFolderWorker.ProcessConversion”, destFile, pdfDir, epsDir
cdApp.Quit
Set cdApp = Nothing
‘ 処理成功したらProcessingから削除(または別フォルダーへアーカイブ)
fso.DeleteFile destFile, True
Else
On Error GoTo 0
‘ 移動に失敗した場合は次のループへスキップ
End If
End If
End If
Next
End Sub
‘ ファイルの書き込みが完了している(ロックされていない)かを確認する関数
Function IsFileReady(filePath)
Dim ts
On Error Resume Next
‘ 排他モードでファイルを開こうと試みる。他のプロセスが掴んでいればエラーになる。
Set ts = fso.OpenTextFile(filePath, 1, False)
If Err.Number = 0 Then
ts.Close
IsFileReady = True
Else
IsFileReady = False
End If
Set ts = Nothing
On Error GoTo 0
End Function
—
4. プロダクション運用における致命的な罠と回避策
シニアエンジニアとして、現場導入時に必ず直面するトラブルと、その予防策を共有しておく。
① ネットワーク越しのファイル転送遅延(ファイル化けの防止)
デザイナーがサーバーのホットフォルダに数100MBのCDRファイルをドラッグ&ドロップした瞬間、VBScriptが「ファイルが現れた」と勘違いして即座に処理を開始すると、不完全な(途中までの)ファイルをCorelDRAWが読み込み、無慈悲な「ファイル形式が不正です」エラーを引き起こす。
- 対策: 上記コードの `IsFileReady` 関数が極めて重要である。Windowsのファイルストリームを独占オープンできるまで処理を待つことで、ネットワーク転送が100%完了した安全な状態のファイルだけを確実にキャッチできる。
② CorelDRAWの「ゾンビプロセス」問題
VBScriptから `CreateObject(“CorelDRAW.Application”)` を呼び出し、処理が終わったら `cdApp.Quit` を実行する設計にしているが、VBA側で予期せぬエラー(メモリ不足やフォント欠落ダイアログなど)が発生すると、CorelDRAWのプロセスがタスクマネージャーに残骸として残り続ける(ゾンビ化)。これが蓄積すると、PCのメモリが枯渇する。
- 対策: タスクスケジューラや定期バッチ(タスクキルスクリプト)を組み合わせ、深夜帯などに `TASKKILL /F /IM coreldraw.exe` を強制実行するセーフティネットを必ず張ること。
③ フォント・リンク画像の欠落によるダイアログ停止
CorelDRAWは、開いたファイルにリンク画像がなかったり、ローカルにフォントが存在しない場合、「リンクが見つかりません」「フォントを置換しますか?」というモーダルダイアログを画面に出して停止する。これが起きると、ヘッドレス(非表示)で動いている自動化システムは完全にフリーズする。
- 対策:
- CorelDRAWの環境設定(オプション)で、「ファイルを開くときに欠落しているフォントを自動置換する」「リンク切れの警告を表示しない」に設定しておく。
- あるいは、VBAの `EventsEnabled = False` やアプリケーション設定で警告ポップアップを抑制する。
—
5. 総括:自動化の本質は「例外の排除」にある
今回構築したホットフォルダ型コンバーターは、単に「コードを動かす」ことの何倍も、「異常系(ファイル破損、ネットワーク切断、ゾンビプロセス)」をいかに美しくハンドリングするかという設計思想に価値がある。
この仕組みを導入した現場では、これまでデザイナーが手作業で行っていたPDF/EPS書き出しの時間が完全にゼロになり、月間数十時間の工数削減を達成している。
プロフェッショナルなVBAエンジニアに求められるのは、華やかなコードを書くことではなく、「人間が介在しなくても24時間365日、止まることなく静かに泥臭く働き続けるシステム」を構築する気概そのものだ。あなたの現場でも、この堅牢なアーキテクチャをさっそく実装し、圧倒的な生産性を手に入れてほしい。
