【テクニカル・上級編】【実務中級者向け】図面保存完了を検知する待機ループの実装:非同期書き込みによるエラーを防ぐ – AutoCAD VBA解析バイブル

スポンサーリンク

AutoCAD VBAの死角:なぜ「SaveAs」の直後にファイルを開くと落ちるのか

AutoCADの自動化において、中級者が必ず直面する「壁」がある。
プログラムで `ThisDrawing.SaveAs` を実行し、その直後に外部プロセスや別ルーチンでそのファイルにアクセスしようとした瞬間、AutoCADは無慈悲にも「ファイルが使用中です」というエラーを吐き出す。あるいは、ファイルが破損した状態で保存される。

なぜか? AutoCADのファイル保存処理は、OSレベルでは非同期的に完了するからだ。VBAのコードが一行実行されたからといって、HDD/SSD上の書き込みバッファがフラッシュされ、ファイルロックが解除されたわけではない。

今日は、この「非同期書き込みの罠」を叩き潰すための、現場で使える堅牢な待機ロジックを伝授する。

—

1. DoEventsの「甘え」を捨てろ

初心者はよく `DoEvents` をループさせるが、これはCPUリソースを無駄に食う上に、OSのタイマー精度に依存するため極めて不安定だ。

我々が目指すべきは、「ファイルが排他制御から解放されるまで、OSのAPIを通じてアクティブに監視する」ことだ。これには、VBAの `CreateFile` APIを用いた「共有モード確認」が最も確実である。

実装コード:堅牢なファイル保存待機関数

以下のコードは、Windows APIを叩き、対象のDWGが「書き込み可能」になるまで待機するアーキテクチャである。

Option Explicit

‘ カーネルAPIの定義(排他制御を確認するために使用)
If VBA7 Then
Private Declare PtrSafe Function CreateFile Lib “kernel32” Alias “CreateFileA” ( _
ByVal lpFileName As String, ByVal dwDesiredAccess As Long, _
ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, _
ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, _
ByVal hTemplateFile As Long) As LongPtr
Private Declare PtrSafe Function CloseHandle Lib “kernel32” (ByVal hObject As LongPtr) As Long
Else
Private Declare Function CreateFile Lib “kernel32” Alias “CreateFileA” ( _
ByVal lpFileName As String, ByVal dwDesiredAccess As Long, _
ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, _
ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, _
ByVal hTemplateFile As Long) As Long
Private Declare Function CloseHandle Lib “kernel32″ (ByVal hObject As Long) As Long
End If

Private Const GENERIC_READ = &H80000000
Private Const FILE_SHARE_READ = &H1
Private Const OPEN_EXISTING = 3
Private Const INVALID_HANDLE_VALUE = -1

”’

”’ 指定したファイルが保存完了し、アクセス可能になるまでブロックする
”’

Public Sub WaitForFileAccess(ByVal filePath As String, Optional ByVal timeoutSeconds As Integer = 10)
Dim startTime As Double: startTime = Timer
Dim hFile As LongPtr

Do
‘ ファイルを開こうと試みる(読み取り専用で共有モードを許可)
hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0)

If hFile <> INVALID_HANDLE_VALUE Then
CloseHandle hFile
Exit Sub ‘ 成功:ファイルは解放されている
End If

DoEvents ‘ OSのイベント処理を許可

‘ タイムアウト処理
If (Timer – startTime) > timeoutSeconds Then
Err.Raise vbObjectError + 1000, “WaitForFileAccess”, “保存待機タイムアウト: ” & filePath
End If
Loop
End Sub

—

2. アーキテクチャの真髄:オブジェクトのライフサイクル管理

このコードのポイントは、`CreateFile` で `GENERIC_READ` かつ `FILE_SHARE_READ` を要求している点だ。もしAutoCADがまだ保存処理の最中であれば、APIはエラー(`INVALID_HANDLE_VALUE`)を返し、我々はそれを検知してループを継続できる。

ここで重要なのは、「いつ、どのタイミングでこの待機を挟むか」である。

大容量図面における「パージ」と「監査」

大規模なDWGを扱う際、`SaveAs` を行う前に必ず以下の手順を踏むのがプロの定石である。

1. オブジェクトの明示的解放: `Set obj = Nothing` を徹底せよ。メモリ上に残留した図形オブジェクトが保存処理のボトルネックになることは珍しくない。
2. SaveAsの後の待機: 保存の直後に `WaitForFileAccess` を実行し、次の処理(例:別システムへのファイルコピー、DBへのパス登録)へ移行する。
3. エラーハンドリング: ネットワークドライブの場合、保存完了のシグナルが遅延することがある。`timeoutSeconds` は環境に合わせて調整せよ。

—

3. レガシーシステムを生き抜くための提言

AutoCAD VBAは、現代の .NET 開発から見れば「化石」のように見えるかもしれない。しかし、その安定性とCAD操作への直接アクセスは、未だに唯一無二の価値がある。

もしあなたが今後、システムを拡張したいと考えているなら、「VBAで制御するのはCADの操作まで」という境界線を引くことだ。

  • VBA: 図面の保存、画層の切り替え、ブロックの挿入に専念。
  • 外部プロセス(C# / .NET): ファイルの監視、データベース連携、ファイルサーバーへの転送を担う。

今回紹介した「APIによるロック監視」は、いわばVBAとOSの間を取り持つブリッジだ。この手法を習得したなら、もう「保存中エラー」に泣くことはない。

伝説的なシステムは、一見すると泥臭いAPIの呼び出しと、細部への異常なこだわりから生まれる。コードは綺麗に書くのではない。「エラーが起こり得ない環境」を、コードで構築するのだ。

健闘を祈る。

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