【上級プロ向け】SharePoint / OneDrive APIと直接対話するCorelDRAW VBAの排他制御&自動同期パイプライン設計
CorelDRAWを用いたプロダクション環境において、複数人のデザイナーが同一のCDR(CorelDRAW Vector Graphics)データを同時編集する際に発生するコンフリクト(競合)問題は、企業におけるクリエイティブパイプラインの最大の死角である。
CDRファイルは、膨大なベクターパス、埋め込みラスタ画像、効果メタデータなどが高度に圧縮されたバイナリ構造体である。これをOneDrive for BusinessやSharePoint Onlineの同期クライアントに無防備に委ねた場合、ファイルアクセス競合によるデータの先祖返りや、同期タイミングのズレによるファイル破壊(破損したZipアーカイブ構造)を引き起こす。
本稿では、レガシーなファイル共有の概念を捨て去り、CorelDRAW VBAから直接SharePoint REST API / Microsoft Graph APIをコールし、完全なファイル排他制御(Check-out / Check-in)とアトミックな保存パイプラインを構築するアーキテクチャを解説する。
—
1. 全体アーキテクチャ:アトミック保存とリモート排他制御
ネットワークストレージ上の直接編集は、I/Oレイテンシおよび排他ロックの不完全さから絶対に避けるべきである。設計すべきは、「ローカル・ステージング領域での安全なI/O」と「クラウド側の明示的排他ロック」を完全に分離・連携させた以下のアトミックパイプラインである。
[CorelDRAW VBA Core]
│
├─ (1) REST API Check-out 要求 ──────────> [SharePoint / Graph API]
│ │
├─ (2) Remote Lock 成功確認 │ (ファイルロック完了)
│ │
├─ (3) ローカル・ステージング領域へ保存 (CDR) │
│ │
├─ (4) ファイル完全性チェック (MD5/サイズ検証) │
│ │
├─ (5) バックグラウンド同期 (API Upload / Commit) ───┘
│
└─ (6) Check-in & Lock 解除
パフォーマンスと信頼性の要件
1. COM参照カウントの制御と明示的メモリ解放:CorelDRAWの`Document`オブジェクトや`ShapeRange`の不適切な保持は、プロセスメモリのリークを引き起こす。VBA実行終了時にGC(ガベージコレクション)に頼らず、明示的にオブジェクトのライフサイクルを完結させる。
2. 64ビット環境(x64 CorelDRAW)対応:`PtrSafe`宣言および`LongPtr`型の正当なハンドリングによるWin32 APIとの整合性確保。
3. 無停止(Non-blocking)エラーハンドリング:ネットワーク不達時のロールバック機構と指数バックオフ(Exponential Backoff)の実装。
—
2. 64ビット対応 Win32 API および HTTP通信基盤
まず、VBAからWindowsの低層ネットワークおよびシステム機能、そして非同期HTTP通信を安全に行うための基本宣言を定義する。標準の`MSXML2.XMLHTTP`ではなく、スレッド分離とタイムアウト制御が厳格な`WinHttp.WinHttpRequest.5.1`をCOMラッピングして利用する。
`mod_API_Declarations.bas`
Attribute VB_Name = “mod_API_Declarations”
Option Explicit
‘ ==============================================================================
‘ 64-bit API Declarations for CorelDRAW x64 Architecture
‘ ==============================================================================
If VBA7 Then
Public Declare PtrSafe Function GetTempPathLib Lib “kernel32” Alias “GetTempPathA” ( _
ByVal nBufferLength As Long, _
ByVal lpBuffer As String) As Long
Public Declare PtrSafe Function PathFileExistsLib Lib “shlwapi” Alias “PathFileExistsA” ( _
ByVal pszPath As String) As Long
Else
Public Declare Function GetTempPathLib Lib “kernel32” Alias “GetTempPathA” ( _
ByVal nBufferLength As Long, _
ByVal lpBuffer As String) As Long
Public Declare Function PathFileExistsLib Lib “shlwapi” Alias “PathFileExistsA” ( _
ByVal pszPath As String) As Long
End If
‘ カスタム構造体: HTTPレスポンス保持用
Public Type HttpResponse
StatusCode As Long
ResponseText As String
IsSuccess As Boolean
End Type
”’
”’
Public Function ExecuteHttpRequest( _
ByVal Method As String, _
ByVal Url As String, _
ByRef AuthToken As String, _
Optional ByVal Payload As String = “”) As HttpResponse
Dim xmlHttp As Object
Dim result As HttpResponse
On Error GoTo ErrHandler
‘ MSXML2.ServerXMLHTTP.6.0 はマルチスレッド環境およびサービス用途で安定動作する
Set xmlHttp = CreateObject(“MSXML2.ServerXMLHTTP.6.0”)
‘ タイムアウト設定: (Resolve, Connect, Send, Receive) in msec
xmlHttp.setTimeouts 5000, 5000, 30000, 60000
xmlHttp.Open Method, Url, False ‘ 同期通信
xmlHttp.setRequestHeader “Authorization”, “Bearer ” & AuthToken
xmlHttp.setRequestHeader “Accept”, “application/json;odata=verbose”
If Method = “POST” Or Method = “PUT” Then
xmlHttp.setRequestHeader “Content-Type”, “application/json;odata=verbose”
xmlHttp.Send Payload
Else
xmlHttp.Send
End If
result.StatusCode = xmlHttp.Status
result.ResponseText = xmlHttp.responseText
result.IsSuccess = (xmlHttp.Status >= 200 And xmlHttp.Status < 300)
ExecuteHttpRequest = result
ExitPoint:
' 明示的なCOMオブジェクトの解放
Set xmlHttp = Nothing
Exit Function
ErrHandler:
result.StatusCode = 500
result.ResponseText = Err.Description
result.IsSuccess = False
ExecuteHttpRequest = result
Resume ExitPoint
End Function
---
3. SharePoint / OneDrive API排他制御ロジック
SharePoint APIの「CheckOut」「CheckIn」エンドポイントを直接叩くことで、OneDrive同期クライアントが介入する前にクラウド上のマスターファイルを物理的にロックする。
`mod_CloudSyncEngine.bas`
Attribute VB_Name = “mod_CloudSyncEngine”
Option Explicit
Private Const TENANT_URL As String = “https://yourtenant.sharepoint.com/sites/DesignTeam”
Private Const SITE_RELATIVE_PATH As String = “/sites/DesignTeam/Shared Documents/CDR_Master/Catalog2024.cdr”
”’
”’
Public Function CheckoutCloudFile(ByRef AuthToken As String) As Boolean
Dim endpoint As String
Dim res As HttpResponse
‘ SharePoint REST API Checkout Endpoint
endpoint = TENANT_URL & “/_api/web/GetFileByServerRelativeUrl(‘” & SITE_RELATIVE_PATH & “‘)/Checkout()”
res = ExecuteHttpRequest(“POST”, endpoint, AuthToken)
If res.IsSuccess Then
CheckoutCloudFile = True
Else
‘ 409 Conflict または 423 Locked の判定
MsgBox “ファイルの排他ロックに失敗しました。” & vbCrLf & _
“他のユーザーが編集中か、権限がありません。” & vbCrLf & _
“HTTP Status: ” & res.StatusCode, vbCritical, “クラウド同期エラー”
CheckoutCloudFile = False
End If
End Function
”’
”’
Public Function CheckinCloudFile(ByRef AuthToken As String, ByVal Comment As String) As Boolean
Dim endpoint As String
Dim payload As String
Dim res As HttpResponse
endpoint = TENANT_URL & “/_api/web/GetFileByServerRelativeUrl(‘” & SITE_RELATIVE_PATH & “‘)/CheckIn(comment='” & Comment & “‘,checkintype=0)”
res = ExecuteHttpRequest(“POST”, endpoint, AuthToken)
CheckinCloudFile = res.IsSuccess
End Function
—
4. CorelDRAW内部パイプライン:アトミック保存と完全メモリクリーンアップ
CorelDRAWのドキュメント保存時、直接同期フォルダに上書き保存を実行すると、OneDriveプロセスのファイルハンドリングとCorelDRAWのZip圧縮書き込み処理が衝突し、壊れた0バイトのCDRファイルが生成される危険性がある。
これを防ぐため、「ローカルTempでの生成」→「整合性検証」→「アトミック移動/APIアップロード」を実行する。また、CorelDRAWのレンダリングエンジンおよびメモリの無駄な消費を抑えるため、`Application.Optimization`を厳格に制御する。
`cls_DocumentPipeline.cls` (クラスモジュール)
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 ‘True
END
Attribute VB_Name = “cls_DocumentPipeline”
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
Private m_doc As Document
Private Sub Class_Initialize()
Set m_doc = ActiveDocument
End Sub
Private Sub Class_Terminate()
‘ 明示的なオブジェクト参照の破棄(CorelDRAWのメモリリーク防止)
Set m_doc = Nothing
End Sub
”’
”’
Public Function ExecuteSafeSavePipeline(ByRef AuthToken As String, ByVal CommitMessage As String) As Boolean
If m_doc Is Nothing Then Exit Function
Dim tempFolderPath As String
Dim tempFilePath As String
Dim saveOpts As StructSaveAsOptions
Dim isSuccess As Boolean
On Error GoTo ErrorHandler
‘ 1. CorelDRAW UI描画の最適化・一時停止(パフォーマンス極大化)
Application.Optimization = True
Application.EventsEnabled = False
‘ 2. ローカルTempパスの取得
tempFolderPath = GetSystemTempPath()
tempFilePath = tempFolderPath & “CDR_TMP_” & Format(Now, “yyyyMMdd_HHmmss”) & “.cdr”
‘ 3. SaveOptionsオブジェクトの明示的生成と設定
Set saveOpts = CreateStructSaveAsOptions()
With saveOpts
.EmbedVBAProject = False
.Filter = cdrCDR
.IncludeBitmapColorProfile = True
.Version = cdrCurrentVersion
End With
‘ 4. ローカル・ステージング領域への書き込み
m_doc.SaveAs tempFilePath, saveOpts
‘ 5. 書き込み完了・ファイルサイズ検証(簡易完全性チェック)
If FileLen(tempFilePath) = 0 Then
Err.Raise vbObjectError + 512, , “ローカル一時ファイルの作成に失敗しました(0バイト検知)。”
End If
‘ 6. クラウド排他ロックの獲得 (Check-Out)
If Not CheckoutCloudFile(AuthToken) Then
Err.Raise vbObjectError + 513, , “クラウド上のファイルロックの獲得に失敗したため、保存を中止しました。”
End If
‘ 7. バックグラウンドアップロード処理 (バイナリストリーム送信)
‘ ※本稿では概念コードとして示し、実際のバイナリ転送はWinHttpで行う
If UploadFileToSharePoint(tempFilePath, AuthToken) Then
‘ 8. ロック解除 (Check-In)
Call CheckinCloudFile(AuthToken, CommitMessage)
isSuccess = True
Else
Err.Raise vbObjectError + 514, , “クラウドへのファイルアップロードに失敗しました。”
End If
CleanUp:
‘ 一時ファイルの完全抹消
If PathFileExistsLib(tempFilePath) <> 0 Then
Kill tempFilePath
End If
‘ CorelDRAW UI制御の復元
Application.Optimization = False
Application.EventsEnabled = True
Application.Refresh
‘ COM構造体の破棄
Set saveOpts = Nothing
ExecuteSafeSavePipeline = isSuccess
Exit Function
ErrorHandler:
isSuccess = False
MsgBox “パイプラインエラー: ” & Err.Description, vbCritical, “致命的エラー”
Resume CleanUp
End Function
”’
”’
Private Function GetSystemTempPath() As String
Dim buffer As String 512
Dim length As Long
length = GetTempPathLib(512, buffer)
GetSystemTempPath = Left(buffer, length)
End Function
”’
”’
Private Function UploadFileToSharePoint(ByVal LocalPath As String, ByRef AuthToken As String) As Boolean
‘ 注: 実際の実装では大容量ファイルの場合、APIの /Files/Add(overwrite=true) または
‘ StartUpload / ContinueUpload / FinishUpload のセッション構造を適用する。
‘ ここでは正常終了したものとしてダミーインターフェースを定義。
UploadFileToSharePoint = True
End Function
—
5. バックグラウンド運用と障害回復(Fail-safe)メカニズム
運用時において最も恐れるべきは、「CorelDRAWがクラッシュした際、クラウド上にCheck-out(排他ロック)状態が残留し、他のユーザーが永久に編集不能となる(Zombie Lock)」現象である。
これを防ぐため、パイプラインには以下の3重の安全装置(Fail-safe)を組み込む。
1. 指数バックオフによる再試行(Exponential Backoff)
一時的なネットワークの瞬断(Wi-Fi切り替えやVPN再接続)による保存失敗を救済するため、HTTP API呼び出し部にリトライループを実装する。
Public Function ExecuteHttpRequestWithRetry( _
ByVal Method As String, _
ByVal Url As String, _
ByRef AuthToken As String, _
Optional ByVal MaxRetries As Long = 3) As HttpResponse
Dim attempt As Long
Dim res As HttpResponse
Dim waitTime As Long
For attempt = 1 To MaxRetries
res = ExecuteHttpRequest(Method, Url, AuthToken)
If res.IsSuccess Then
ExecuteHttpRequestWithRetry = res
Exit Function
End If
‘ 失敗時は 2^attempt 秒ウェイトを入れる(2s, 4s, 8s)
waitTime = (2 ^ attempt) 1000
SleepWait waitTime
Next attempt
ExecuteHttpRequestWithRetry = res
End Function
Private Sub SleepWait(ByVal MilliSeconds As Long)
Dim startTime As Single
startTime = Timer
Do While (Timer – startTime) < (MilliSeconds / 1000)
DoEvents
Loop
End Sub
2. Zombie Lockの自動検出とTTL(Time To Live)管理
SharePoint上のファイルメタデータに最終ロック獲得日時(`CustomLockTimestamp`)を付与し、ロック獲得から一定時間(例:12時間)以上経過している場合は、他ユーザーから強制チェックアウト解除(`UndoCheckOut`)を可能とする運用スクリプトをVBA側で実装する。
3. CorelDRAWプロセスメモリの定期的解放
CorelDRAW VBA内で無制限にオブジェクトの操作(`ActiveDocument.Pages`の反復処理など)を行うと、CorelDRAW自身の内部COM参照カウントが正常に破棄されず、メモリが急速に膨張する。
スクリプト内で明示的に`Set obj = Nothing`を行うだけでなく、大規模処理後は以下のように`CollectGarbage`(非公開COMインターフェース呼び出しに相当する処理)を促すコード設計を導入する。
Public Sub ForceMemoryCleanup()
‘ CorelDRAWに対して内部描画キャッシュの強制解放を促す
On Error Resume Next
Application.FrameWork.Automation.Invoke “Engine.PurgeMemory”
On Error GoTo 0
End Sub
—
6. アーキテクチャの結論
従来の「CorelDRAWでローカル同期フォルダを開き、そのまま保存する」という運用は、複数人マルチテナント環境においては潜在的なデータ破壊リスクを常に抱えている。
本稿で示した、
1. WinHTTPを用いたSharePoint APIによる明示的Check-out/Check-in制御
2. ローカル・ステージング領域を利用したアトミック保存
3. `Application.Optimization`と明示的COM破棄によるメモリリークの徹底追放
というエンジニアリングアプローチを導入することで、CorelDRAWを中心としたエンタープライズ・デザインパイプラインの堅牢性は極限にまで高められる。レガシー技術と見なされがちなVBAであっても、適切なWin32 APIの拡張とモダンなクラウドAPIの直接結合によって、現代のミッションクリティカルな要求に耐えうるシステムへと変貌させることが可能である。
