クラウドストレージの罠を突破せよ:AutoCAD VBAにおける「同期待ち」堅牢設計の極意
AutoCADのバッチ処理を組んでいると、必ず突き当たる壁がある。「DropboxやOneDriveで同期中のファイルにアクセスし、プロセスがクラッシュする」という現象だ。
多くの初学者は `Application.Wait` で数秒間停止させるような稚拙なコードを書くが、それはエンジニアの怠慢だ。クラウドの同期速度はネットワーク環境に依存する。決め打ちの待機時間は、低速回線では「不足」し、高速回線では「無駄」を生む。
今日は、プロフェッショナルとして恥ずかしくない、同期状態を正しく検知する堅牢なセーブ待機ロジックを伝授する。
—
1. なぜ「単純なWait」が死を招くのか
Windowsのファイルシステムにおいて、クラウドストレージクライアント(Dropbox/OneDrive等)は、保存された瞬間に排他ロックをかける。AutoCAD側が `SaveAs` を発行した直後、プログラムが次の処理へ進もうとすると、OSは「ファイルは使用中です」と例外を投げる。
ここで重要なのは、「ファイルが保存されたか」ではなく「ファイルが解放されたか」を監視することだ。
2. 実装の核心:排他制御による監視
ファイルが同期クライアントによってロックされている間、そのファイルに対して「書き込みモードでオープン」を試みる。成功すればロックは解除されている。この単純かつ強力なロジックを実装する。
プロダクションコード:同期完了監視ロジック
以下は、標準モジュールに配置して呼び出すための汎用関数である。
Option Explicit
‘ ファイルの排他オープンを試行し、同期完了を待機する関数
‘ @param filePath 監視対象のフルパス
‘ @param timeoutSeconds 最大待機時間(秒)
‘ @return 成功ならTrue、タイムアウトならFalse
Public Function WaitForFileSync(ByVal filePath As String, Optional ByVal timeoutSeconds As Integer = 30) As Boolean
Dim fileNum As Integer
Dim startTime As Double
startTime = Timer
Do
‘ ファイルが存在するか確認
If Dir(filePath) <> “” Then
‘ ファイルをバイナリモードで開こうとする
‘ ロックされていればエラーが発生し、解放されていれば成功する
On Error Resume Next
fileNum = FreeFile
Open filePath For Binary Access Write Lock Write As #fileNum
If Err.Number = 0 Then
‘ 成功:ロックが解除されている
Close #fileNum
WaitForFileSync = True
Exit Function
End If
‘ エラーをクリアしてリトライ
Err.Clear
On Error GoTo 0
End If
‘ 0.5秒間隔でポーリング(CPU負荷を抑制)
DoEvents
Sleep 500
Loop While (Timer – startTime) < timeoutSeconds WaitForFileSync = False End Function ' Windows APIによる高精度な待機(標準モジュール冒頭に配置) If VBA7 Then Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Else Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) End If ---
3. 実務でこのコードをどう組み込むか
この関数を `Main` プロセスに組み込む際は、AutoCADの `Document.SaveAs` の直後に配置するのが鉄則だ。
Public Sub BatchProcessDrawing()
Dim doc As AcadDocument
Dim targetPath As String
targetPath = “C:\Users\Name\Dropbox\Project\Drawing01.dwg”
Set doc = ThisDrawing
‘ 保存実行
doc.SaveAs targetPath
‘ 同期完了を待機
If WaitForFileSync(targetPath) Then
Debug.Print “同期完了:次のプロセスへ移行します。”
‘ ここに次の処理(DB更新や別ツールへの連携)を記述
Else
Err.Raise vbObjectError + 1000, , “タイムアウト:同期が完了しませんでした。”
End If
End Sub
4. チーフアーキテクトからの助言:注意点
1. DoEventsの重要性: `DoEvents` を入れないと、AutoCADのUIがフリーズし、「応答なし」と判定される。長時間処理では必須だ。
2. ネットワークドライブの挙動: 本ロジックはクラウド同期を想定しているが、遅延の激しいNASやVPN環境でも有効に働く。ただし、過度なポーリングはサーバー負荷になるため、`Sleep` の間隔は環境に合わせて調整してほしい。
3. データベース連携: もし保存完了後にDB(Access/SQL Server)へ図面情報を書き込む場合、この待機ロジックがないと「DBにはデータがあるが、ファイルはまだ旧版」という不整合が起きる。「ファイル解放=データとしての整合性担保」と定義せよ。
最後に:職人たれ
コードは書けば動く。しかし、環境の変化(クラウドの同期遅延など)に左右されず、常に安定した挙動を保証するのが「エンジニア」の仕事だ。
あなたの書いたツールが、ユーザーのストレスを1秒でも減らすことを願っている。もしこのロジックで解決できない特殊なケースがあれば、それはAPI側ではなく、OSのファイルシステムキャッシュレベルの問題だ。その時は、素直に `FileSystemObject` の監視機能や、より低レイヤーなWindows APIの利用を検討すべきだ。
健闘を祈る。
