【入門編】【上級プロ向け】CorelDRAWの外部API連携:VBAからWindows APIを呼び出してファイルダイアログやクリップボードを高度に制御する – CorelDRAW VBA解析バイブル

スポンサーリンク

こんにちは!CorelDRAW VBAの世界へようこそ。
マクロの記録ボタンを押して、生成されたコードを眺めるフェーズはもう卒業しましたか?おめでとうございます。ここからが、真のCorelDRAW自動化の領域です。

今回は、プロフェッショナルな開発現場で避けて通れない「Windows APIとの連携」をテーマにお届けします。

「標準の`InputBox`や`MsgBox`では物足りない……」
「モダンなファイル選択ダイアログを出したい!」
「CorelDRAWの枠を超えて、クリップボードと高度にデータをやり取りしたい!」

そんな欲求をすべて叶えるのが、`user32.dll`などのWindows APIをVBAから直接たたく技術です。一歩間違えるとCorelDRAWごと強制終了するスリリングな世界ですが、ルールさえ守ればあなたのツールは劇的に洗練されます。

さあ、知的でエレガントなAPI連携の扉を開きましょう。ここをクリアすれば、あなたのVBAスキルは間違いなく一段上のステージに到達しますよ。

1. なぜCorelDRAW VBAからWindows APIを呼ぶのか?

CorelDRAWのVBA環境は強力ですが、いかんせんレガシーです。
例えば、標準のファイル操作機能は非常に簡素で、マルチ選択やフィルタリングの細やかな制御、モダンなWindows 11スタイルのダイアログを出すことはできません。

そこで登場するのが、WindowsのOS本体が持つ機能(API)の呼び出しです。
VBAの `Declare` ステートメントを使い、C言語で作られたOSの関数(DLL)を直接呼び出すことで、OSネイティブの強力な機能をVBAの手に手繰り寄せることができます。

【重要】32bit / 64bit 環境の「罠」

近年のCorelDRAWは完全に64bit化されています。
Windows APIを宣言する際、ここを見誤ると一瞬でCorelDRAWがクラッシュ(落ちる)します。
ポインタのサイズ(32bitなら `Long`、64bitなら `LongPtr`)を厳密に使い分ける「PtrSafe」宣言の作法を、まずは体に叩き込みましょう。

2. 実装:Windows APIでモダンなファイルオープンダイアログを実装する

まずは、標準のショボいダイアログではなく、Windowsのコモンダイアログ(`GetOpenFileNameW`)を直接呼び出すコードを見てみましょう。Unicode(`W`)に対応させるのがプロの嗜みです。

以下のコードを、CorelDRAWの標準モジュールにそのまま貼り付けてみてください。

Option Explicit

‘ — Windows APIの構造体定義 —
Private Type OPENFILENAME
lStructSize As Long
hwndOwner As LongPtr
hInstance As LongPtr
lpstrFilter As LongPtr
lpstrCustomFilter As LongPtr
nMaxCustFilter As Long
nFilterIndex As Long
lpstrFile As LongPtr
nMaxFile As Long
lpstrFileTitle As LongPtr
nMaxFileTitle As Long
lpstrInitialDir As LongPtr
lpstrTitle As LongPtr
flags As Long
nFileOffset As Integer
nFileExtension As Integer
lpstrDefExt As LongPtr
lCustData As LongPtr
lpfnHook As LongPtr
lpTemplateName As LongPtr
End Type

‘ — user32.dll から API 関数をインポート (64bit完全対応) —
If Win64 Then
Private Declare PtrSafe Function GetOpenFileNameW Lib “comdlg32.dll” (pOpenfn As OPENFILENAME) As Long
Private Declare PtrSafe Function GetActiveWindow Lib “user32” () As LongPtr
Else
‘ 32bit環境への配慮(現代ではほぼ無いですが一応の作法として)
Private Declare Function GetOpenFileNameW Lib “comdlg32.dll” (pOpenfn As OPENFILENAME) As Long
Private Declare Function GetActiveWindow Lib “user32” () As Long
End If

‘ 定数定義
Const OFN_FILEMUSTEXIST = &H1000
Const OFN_PATHMUSTEXIST = &H800
Const OFN_HIDEREADONLY = &H4

Public Sub ShowModernOpenDialog()
Dim ofn As OPENFILENAME
Dim szFile As String 260
Dim ret As Long

‘ バッファの初期化
szFile = String(260, 0)

‘ OPENFILENAME構造体の設定
With ofn
.lStructSize = LenB(ofn)
.hwndOwner = GetActiveWindow() ‘ CorelDRAWのウィンドウを親にする
.lpstrFile = StrPtr(szFile)
.nMaxFile = Len(szFile)
.lpstrFilter = StrPtr(“CorelDRAW Files (.cdr)|.cdr|All Files (.)|.||”)
.nFilterIndex = 1
.lpstrTitle = StrPtr(“極上のファイル選択ダイアログ by Windows API”)
.flags = OFN_PATHMUSTEXIST Or OFN_FILEMUSTEXIST Or OFN_HIDEREADONLY
End With

‘ APIの実行(ここでWindowsのネイティブダイアログがモーダル表示されます)
ret = GetOpenFileNameW(ofn)

If ret <> 0 Then
‘ 選択されたファイルのパスをトリミングして取得
Dim selectedPath As String
selectedPath = Left$(szFile, InStr(szFile, vbNullChar) – 1)

MsgBox “選択されたファイル:” & vbCrLf & selectedPath, vbInformation, “API連携成功”

‘ ここでCorelDRAWのドキュメントとして開く処理が書けます
‘ Dim doc As Document
‘ Set doc = OpenDocument(selectedPath)
Else
MsgBox “キャンセルされました。”, vbInformation
End If
End Sub

コードのここがポイント!

  • `hwndOwner = GetActiveWindow()`

ダイアログの親ウィンドウにCorelDRAWを指定しています。これをサボると、ダイアログの裏にCorelDRAWが隠れてしまい、フリーズしたような錯覚に陥るトラブルの原因になります。

  • `StrPtr` とバッファ確保

APIへ文字列を渡す際は、メモリ上のポインタ(`StrPtr`)を正確に渡す必要があります。また、C言語の作法に合わせ、あらかじめ `260バイト(MAX_PATH)` の空き箱(バッファ)を準備しておくのが鉄則です。

3. クリップボードの高度な制御:文字列の安全な流し込み

次に、CorelDRAWの選択オブジェクトの情報をテキストとしてクリップボードへ綺麗に送り出す、あるいは外部からデータを取得する処理です。標準の `DataObject` は動作が不安定なことが多いため、Windows APIを使った確実な方法をマスターしましょう。

‘ — クリップボード操作用 API の宣言 —
If Win64 Then
Private Declare PtrSafe Function OpenClipboard Lib “user32” (ByVal hWnd As LongPtr) As Long
Private Declare PtrSafe Function CloseClipboard Lib “user32” () As Long
Private Declare PtrSafe Function EmptyClipboard Lib “user32” () As Long
Private Declare PtrSafe Function SetClipboardData Lib “user32” (ByVal wFormat As Long, ByVal hMem As LongPtr) As LongPtr
Private Declare PtrSafe Function GlobalAlloc Lib “kernel32” (ByVal wFlags As Long, ByVal dwBytes As LongPtr) As LongPtr
Private Declare PtrSafe Function GlobalLock Lib “kernel32” (ByVal hMem As LongPtr) As LongPtr
Private Declare PtrSafe Function GlobalUnlock Lib “kernel32” (ByVal hMem As LongPtr) As Long
Private Declare PtrSafe Sub CopyMemory Lib “kernel32” Alias “RtlMoveMemory” (Destination As Any, Source As Any, ByVal Length As LongPtr)
End If

Const CF_UNICODETEXT = 13
Const GMEM_MOVEABLE = &H2

Public Sub CopySelectionInfoToClipboard()
Dim doc As Document
Set doc = ActiveDocument

If doc Is Nothing Then
MsgBox “ドキュメントが開かれていません。”, vbCritical
Exit Sub
End If

If doc.Selection.Shapes.Count = 0 Then
MsgBox “オブジェクトが選択されていません。”, vbExclamation
Exit Sub
End If

‘ 選択オブジェクトの情報をテキスト化
Dim infoText As String
infoText = “=== CorelDRAW セレクション情報 ===” & vbCrLf & _
“選択数: ” & doc.Selection.Shapes.Count & ” 個” & vbCrLf & _
“アクティブレイヤー: ” & doc.ActiveLayer.Name

‘ クリップボードへ書き込むメイン処理
Call SetTextToClipboard(infoText)

MsgBox “選択オブジェクトの情報をクリップボードにコピーしました!”, vbInformation
End Sub

Private Sub SetTextToClipboard(ByVal text As String)
Dim hMem As LongPtr
Dim pMem As LongPtr
Dim byteLen As LongPtr

‘ クリップボードを開く
If OpenClipboard(0) = 0 Then
MsgBox “クリップボードを開けませんでした。”, vbCritical
Exit Sub
End If

‘ 一度クリップボードを空にする
EmptyClipboard

‘ 文字列のバイト数を計算(終端文字の分 +2バイト)
byteLen = (Len(text) + 1) 2

‘ グローバルメモリを確保
hMem = GlobalAlloc(GMEM_MOVEABLE, byteLen)
If hMem <> 0 Then
‘ メモリをロックしてポインタを取得
pMem = GlobalLock(hMem)
If pMem <> 0 Then
‘ メモリに文字列データをコピー
CopyMemory ByVal pMem, ByVal StrPtr(text), byteLen
GlobalUnlock hMem

‘ クリップボードにデータをセット
SetClipboardData CF_UNICODETEXT, hMem
End If
End If

‘ クリップボードを閉じる
CloseClipboard
End Sub

オブジェクトのライフサイクルとメモリ管理の哲学

Windows APIを使う上で絶対に忘れてはならない鉄則があります。
「確保したメモリは、責任を持って解放(またはOSに委譲)する」ことです。

今回のコードでは `GlobalAlloc` でメモリを確保していますが、`SetClipboardData` に成功した場合、そのメモリの管理権はクリップボード(OS側)に移行します。そのため、VBA側で無理に `GlobalFree` を呼ぶとダブルフリーエラー(二重解放によるクラッシュ)を引き起こします。
APIの裏側にあるメモリのライフサイクルまで意識できるようになれば、あなたはもう立派なアーキテクトです。

4. 陥りやすいエラーとトラブルシューティング

最後に、現場で開発しているときによく直面する「罠」と、その回避策をシェアします。

1. 「DLL の呼び出し規則が間違っています」という実行時エラー(Error 49)

  • 原因: 32bit用の宣言(`Declare`)のまま、64bitのCorelDRAWで実行しています。
  • 対策: `#If Win64 Then` を使った条件付きコンパイルを必ず導入し、`PtrSafe` と `LongPtr` を正しく使い分けましょう。

2. APIを叩いた直後にCorelDRAWがフリーズ・シャットダウンする

  • 原因: 文字列のポインタ渡し(`StrPtr`)のミス、またはバッファサイズ不足によるメモリオーバーランです。
  • 対策: APIに渡す変数は固定長文字列(`Dim szFile As String 260`など)や、適切なバイト数を確保した領域を使い、安易にString型をそのまま渡さないように注意してください。

3. クリップボードがロックされたまま他のアプリが固まる

  • 原因: `OpenClipboard` を呼んだあと、エラーハンドリングの不備で `CloseClipboard` が実行されずにプロシージャが抜けてしまった。
  • 対策: 必ず `On Error GoTo ErrorHandler` などを記述し、エラーが発生した場合でも確実に `CloseClipboard` が呼ばれる構造にしてください。

まとめ

今回は、CorelDRAW VBAからWindows APIを呼び出し、モダンなファイルダイアログの表示やクリップボードの高度な制御を行う手法を解説しました。

  • Windows APIを使うことで、CorelDRAW標準の限界を突破できる。
  • 64bit環境では `PtrSafe` と `LongPtr` を用いた厳密な型定義が必須。
  • OSのリソース(メモリやクリップボード)を扱う際は、ライフサイクルを意識し、確実な開放・クローズを行うこと。

この領域をマスターすれば、もはやCorelDRAW VBAで出来ないことはほとんどありません。社内のデザイナーや作業者を驚かせるような、スマートで実用的な自動化ツールをぜひ作り上げてください。

あなたのVBAライフが、さらに深淵で快適なものになりますように。次の現場でお会いしましょう!

タイトルとURLをコピーしました