CorelDRAW VBAを掌握する極限の知見:SQL Server完全同期型ベクターパーツ管理システム
レガシーとモダンが交錯するエンタープライズの現場において、デザインアセットの散逸は永遠の課題だ。「あのロゴの最新版はどこだ」「共有フォルダのどこに社内共通パーツがあるかわからない」――こうした属人化を排除し、デザインプロセスをサプライチェーンの一部として組み込むためには、CorelDRAWと外部リレーショナルデータベース(RDB)を直結させたアセット管理システムの構築が不可欠となる。
本稿では、CorelDRAW VBAとSQL Server(ADO)を完全同期させ、メモリリークを極限まで排除したプロフェッショナル向けベクターパーツ管理システムのアーキテクチャを詳説する。
—
1. アーキテクチャ概略:なぜ「ファイル共有」ではなく「SQL Server」なのか
多くの現場では、共通パーツをネットワーク上の共有フォルダにCDRファイルとして乱雑に配置している。しかし、ファイルサーバーはトランザクションを保証せず、並行書き込みによる破損、タグ検索の欠如、バージョン管理の不徹底を招く。
本システムでは、ベクターデータそのものをバイナリ(VARBINARY(MAX))としてSQL Serverに格納し、メタデータ(パーツ名、カテゴリ、タグ、最終更新者)をリレーショナルに管理する。CorelDRAW側からは、ADO(ActiveX Data Objects)を介して非同期に近い速度でクエリを発行し、必要なパーツのみをオンデマンドでドキュメントへロード、あるいは逆方向の同期(アップサート)を実行する。
—
2. 実装:SQL Server接続とバイナリ・ストリーム処理の極意
VBAにおける最大の罠は、COMオブジェクトのライフサイクル管理の甘さによるメモリリークと、ADOによるバイナリチャンクのメモリ効率の悪さである。以下の実装では、エラーハンドリングを徹底し、メモリの爆発を防ぐための定石を網羅している。
データベース通信モジュール (`modDatabase.bas`)
Option Explicit
‘ 接続文字列の定数化(環境に合わせて変更してください)
Private Const CONNECTION_STRING As String = _
“Provider=SQLOLEDB;Server=db_server_name;Database=VectorAssetsDB;Uid=app_user;Pwd=secure_password;”
Public Function OpenDatabaseConnection() As Object
Dim conn As Object
On Error GoTo ErrorHandler
Set conn = CreateObject(“ADODB.Connection”)
conn.ConnectionTimeout = 15
conn.CommandTimeout = 30
conn.Open CONNECTION_STRING
Set OpenDatabaseConnection = conn
Exit Function
ErrorHandler:
If Not conn Is Nothing Then
If conn.State = 1 Then conn.Close
Set conn = Nothing
End If
Err.Raise Err.Number, “OpenDatabaseConnection”, “DB接続に失敗しました: ” & Err.Description
End Function
Public Sub CloseDatabaseConnection(ByRef conn As Object)
On Error Resume Next
If Not conn Is Nothing Then
If conn.State = 1 Then conn.Close
Set conn = Nothing
End If
On Error GoTo 0
End Sub
—
3. コアロジック:CorelDRAWドキュメントとDB間のシームレスな同期
パーツを登録する際は、アクティブ選択図形を一時的にローカルのテンポラリCDRとして書き出し、そのバイナリモジュールをSQL Serverへ流し込む。逆にインポート時は、DBからバイナリをADOストリーム経由で一時ファイルに戻し、`ActiveLayer.LoadEx`でインポートする。
アセットマネージャーモジュール (`modAssetManager.bas`)
Option Explicit
‘ 選択図形をSQL Serverへバイナリとして登録・更新(Upsert)する
Public Sub SyncSelectedAssetToDB(ByVal assetName As String, ByVal category As String)
Dim conn As Object
Dim cmd As Object
Dim stream As Object
Dim tempPath As String
Dim s As ShapeRange
‘ 1. 選択チェック
If ActiveSelection.Shapes.Count = 0 Then
MsgBox “同期するベクターパーツを選択してください。”, vbExclamation
Exit Sub
End If
On Error GoTo ErrorHandler
‘ 2. 一時ファイルのパス生成
tempPath = Environ(“TEMP”) & “\corel_sync_temp.cdr”
‘ 3. 選択図形を一時CDRとしてエクスポート(CorelDRAW 2019以降対応の形式を指定)
Set s = ActiveSelectionRange
s.Export tempPath, cdrCDR, cdrSelection, , , 0 ‘ 圧縮オプション等は環境に依存
‘ 4. DB接続とADODB.Streamによるバイナリ読み込み
Set conn = OpenDatabaseConnection()
Set stream = CreateObject(“ADODB.Stream”)
stream.Type = 1 ‘ adTypeBinary
stream.Open
stream.LoadFromFile tempPath
‘ 5. パラメータ化クエリによるSQLインジェクション対策とバイナリ転送
Set cmd = CreateObject(“ADODB.Command”)
Set cmd.ActiveConnection = conn
‘ ストアドプロシージャを用いたUpsert処理を想定
cmd.CommandText = “sp_UpsertVectorAsset”
cmd.CommandType = 4 ‘ adCmdStoredProc
cmd.Parameters.Append cmd.CreateParameter(“@AssetName”, 200, 1, 100, assetName) ‘ adVarChar
cmd.Parameters.Append cmd.CreateParameter(“@Category”, 200, 1, 50, category) ‘ adVarChar
cmd.Parameters.Append cmd.CreateParameter(“@AssetBinary”, 205, 2, -1, stream.Read) ‘ adLongVarBinary
cmd.Execute
‘ 6. クリーンアップ
Kill tempPath
MsgBox “パーツ [” & assetName & “] のDB同期が完了しました。”, vbInformation
GoTo Finally
ErrorHandler:
MsgBox “同期処理中に致命的なエラーが発生しました: ” & Err.Description, vbCritical
If Dir(tempPath) <> “” Then Kill tempPath
Finally:
‘ オブジェクトの明示的解放(メモリリーク防止の鉄則)
If Not stream Is Nothing Then
stream.Close
Set stream = Nothing
End If
Set cmd = Nothing
CloseDatabaseConnection conn
End Sub
‘ DBからパーツを非同期風にインポートする
Public Sub ImportAssetFromDB(ByVal assetID As Long)
Dim conn As Object
Dim rs As Object
Dim stream As Object
Dim tempPath As String
On Error GoTo ErrorHandler
tempPath = Environ(“TEMP”) & “\corel_import_temp.cdr”
Set conn = OpenDatabaseConnection()
Set rs = CreateObject(“ADODB.Recordset”)
rs.Open “SELECT AssetBinary FROM VectorAssets WHERE AssetID = ” & assetID, conn, 0, 1 ‘ adOpenForwardOnly, adLockReadOnly
If Not rs.EOF Then
Set stream = CreateObject(“ADODB.Stream”)
stream.Type = 1 ‘ adTypeBinary
stream.Open
stream.Write rs.Fields(“AssetBinary”).Value
stream.SaveToFile tempPath, 2 ‘ adSaveCreateOverWrite
‘ CorelDRAWドキュメントへのインポート
ActiveLayer.LoadEx tempPath, cdrCDR
Kill tempPath
Else
MsgBox “指定されたIDのパーツが見つかりません。”, vbExclamation
End If
GoTo Finally
ErrorHandler:
MsgBox “インポートエラー: ” & Err.Description, vbCritical
If Dir(tempPath) <> “” Then Kill tempPath
Finally:
If Not stream Is Nothing Then
stream.Close
Set stream = Nothing
End If
If Not rs Is Nothing Then
If rs.State = 1 Then rs.Close
Set rs = Nothing
End If
CloseDatabaseConnection conn
End Sub
—
4. チーフアーキテクトの知見:VBAにおけるメモリ最適化とガベージコレクションのハック
CorelDRAW VBAで数万回に及ぶアセット操作や巨大なベクターデータの処理を行う際、最も恐れなければならないのは「VBAランタイムのメモリリーク(COMラッパーの蓄積)」である。
1. `Nothing` 代入の厳密なスコープ管理
VBAは参照カウンタ方式でメモリ管理を行っているが、ローカルスコープを抜けるまでオブジェクト変数がメモリ上に残るケースがある。特にループ内でのADOオブジェクトやCorelDRAWの Shape / ShapeRange オブジェクトの生成は、数イテレーションでメモリ枯渇(Out of Memory)を引き起こす。
ループ内でCOMオブジェクトを生成する場合は、必ず都度 `Set obj = Nothing` を実行し、さらに `Application.Optimization = True` を活用して画面描画とイベント処理を抑制すべきだ。
2. CorelDRAWの描画最適化ブロック
大量のベクターパーツを配置する際は、以下の最適化構文で囲むことで、実行速度が最大数十倍に跳ね上がる。
Sub OptimizeExecution(ByVal enable As Boolean)
With Application
.Optimization = enable
.EventsEnabled = Not enable
.ScreenRefresh
End With
End Sub
これをインポート処理の前後で挟むことにより、CorelDRAWが個々のシェイプ追加ごとに走らせる再描画や再計算のオーバーヘッドを完全に排除できる。
—
5. レガシー保守と将来への布石
本アーキテクチャは、CorelDRAWのバージョンが上がったとしても(COMインターフェースの互換性が保たれている限り)、SQL Server側のスキーマを拡張することで半永久的に耐えうるシステムとなる。
また、将来的にVBAから.NET Framework / .NET Core製のアドイン(COM Add-in)へ移行する際も、このデータベース設計(`VARBINARY` による一元管理)をそのまま流用できるため、技術的負債を残さない。
真のエンジニアリングとは、枯れた技術(VBA)と堅牢なインフラ(SQL Server)を極限までチューニングし、現場の生産性を暴力的に引き上げることに他ならない。コードの行間に宿る意図を汲み取り、今すぐ実務の現場へ実装してほしい。
