CorelDRAW VBAを極める:CAD/Officeデータインポートの自動化と「負の遺産」を制するメモリ最適化術
CorelDRAWのVBAは、単なるマクロの域を超え、複雑なグラフィックエンジンの心臓部を直接叩く強力な武器となる。しかし、DXFやDWGといったCADデータ、あるいはOffice由来のEMFを扱う際、多くのエンジニアが「メモリリーク」と「予期せぬ描画の崩れ」という壁に突き当たる。
本稿では、レガシーな環境を逆手に取り、システム間連携を極限まで安定させるための「真のアーキテクチャ」を提示する。
—
1. インポート処理における「墓場」の回避
外部フォーマットをCorelDRAWに持ち込む際、最も避けるべきは`Application.CorelScript.FileImport`の安易な多用だ。これらは内部的なコンテキストをクリアしないケースが多く、数千枚のバッチ処理では確実にメモリが飽和する。
重要なのは、`ImportFilter`オブジェクトを明示的に制御し、処理が終わるたびにスコープを破棄することだ。
実践コード:メモリを汚染しないインポートルーチン
‘ インポート処理の最適化例
Public Sub OptimizedImport(ByVal filePath As String)
Dim doc As Document
Dim impFilter As ImportFilter
Dim impOptions As StructImportOptions
‘ 1. 文脈の固定:新しいドキュメントを作成せず、メモリを再利用する設計を推奨
Set doc = Application.ActiveDocument
‘ 2. フィルタの明示的生成
Set impOptions = New StructImportOptions
impOptions.MaintainLayers = False
‘ 3. インポート実行
Set impFilter = doc.Layers(1).ImportEx(filePath, cdrDXF, impOptions)
impFilter.Finish
‘ 4. オブジェクトの強制解放
‘ VBAのガベージコレクションを待たず、明示的にNothingを代入し参照カウントを下げる
Set impFilter = Nothing
Set impOptions = Nothing
‘ レガシー環境ではDoEventsを挟み、メッセージキューの処理を強制する
DoEvents
End Sub
—
2. 構造の正規化:CADデータ特有の「ゴミ」を叩く
CADから出力されたDXFは、往々にして「線分の断片化」や「不要なレイヤーの混入」を伴う。これをそのまま保存すれば、後工程のシステムで必ずエラーになる。インポート直後に以下の正規化処理を走らせるのが、シニアエンジニアの流儀である。
正規化の定石
- グループ解除と結合: `Curve.BreakApart`を再帰的に適用し、`Curve.Combine`でノードを整理する。
- 不要な線種の削除: CAD特有の点線設定はCorelDRAW上で描画負荷が高いため、すべてソリッドに変更する。
- 単位の強制置換: `Application.ActiveDocument.Unit`をミリメートルに強制固定し、数値の浮動小数点誤差を丸める。
—
3. Windows APIによる「強制的なプロセス管理」
VBA単体では、インポート時に発生するダイアログや、外部ライブラリのハングアップを制御できない。ここでWindows APIの登場だ。特に`FindWindow`と`SendMessage`を用いて、背後で動くインポートダイアログを強制的に閉じるテクニックは、無人バッチ処理には不可欠である。
If VBA7 Then
Private Declare PtrSafe Function FindWindow Lib “user32” Alias “FindWindowA” (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Private Declare PtrSafe Function SendMessage Lib “user32” Alias “SendMessageA” (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
End If
‘ 処理中に突如現れるダイアログをウィンドウハンドルで捉えて叩く
Public Sub ForceKillDialog(ByVal caption As String)
Dim hWnd As LongPtr
hWnd = FindWindow(vbNullString, caption)
If hWnd <> 0 Then
‘ WM_CLOSE (0x10) を送信
SendMessage hWnd, &H10, 0, 0
End If
End Sub
—
4. 極限の知見:保存とフォーマット変換の戦略
最後に、保存プロセスについて。`doc.SaveAs`をループ内で叩くのは自殺行為だ。
1. 段階的保存: 巨大なファイルを扱う際は、一度ネイティブ(.cdr)で保存し、その後に別プロセスとしてExportを呼び出す。これにより、メモリの解放タイミングを物理的に分離できる。
2. ExportFilterの活用: `ExportFilter`オブジェクトを使用する際、`StructExportOptions`の`Transparency`(透明度)や`Resolution`(解像度)設定は、必ず定数ではなく変数で管理し、処理の都度設定をリセットせよ。
チーフアーキテクトからの助言
CorelDRAW VBAは、もはや「古い言語」ではない。システム間のインターフェースとして、堅牢なパイプラインを構築するための「接着剤」である。メモリを制する者がシステムを制する。
「動けばいい」という考えは捨てろ。「10万回のインポート処理を再起動なしで完遂できるか?」 常にその問いをコードに突きつけることだ。それが、エンジニアとしての品格である。
