【入門編】【上級プロフェッショナル向け】Windows APIを用いた「ファイル使用ユーザー名」の特定と、オープン待機キューの構築 – AutoCAD VBA解析バイブル

スポンサーリンク
スポンサーリンク

エラーで止まるマクロは卒業。Windows APIとDWL解析で実現する「プロ仕様」の図面オープン制御

「あ、またファイルがロックされてる……」

自動化ツールを運用していると、必ずと言っていいほど直面する壁があります。それは、「誰かがその図面を開いているために、プログラムがエラーで止まってしまう」という問題です。

多くの初学者は、ここで `On Error Resume Next` を使い、エラーを無理やり無視して進もうとします。しかし、それはエンジニアとして「もっとも避けるべき禁忌」の一つです。エラーを無視すれば、データの上書き失敗や、不完全な図面状態での処理といった、取り返しのつかない事故を招くからです。

今日は、マクロの記録レベルを脱却し、「誰が使っているか」を特定し、「解放されるまでスマートに待機する」という、実務レベルのシステム設計(アーキテクチャ)の考え方を伝授します。ここをマスターすれば、あなたの作るツールは「単なるマクロ」から「信頼される業務アプリケーション」へと進化します。

1. なぜ「エラーが出る」だけで終わってはいけないのか?

プロフェッショナルな自動化エンジニアは、エラーを「異常事態」としてではなく、「制御すべき状態(ステート)」として捉えます。

図面がロックされているとき、ユーザーが求めているのは「エラーメッセージ」ではなく、「いつ開けるのか?」、あるいは「誰に声をかければいいのか?」という情報です。

プロが設計する「高度なオープン制御」の3ステップ

1. 検知 (Detection): ファイルがロックされているか、誰が持っているかを特定する。
2. 待機 (Waiting): CPUに負荷をかけず、スマートにリトライ(再試行)を行う。
3. 通知 (Notification): ユーザーに状況を伝え、キャンセル手段も提供する。

2. AutoCADの秘密:`.dwl` ファイルを読み解く

AutoCADは図面を開くと、同じフォルダ内に `.dwl` または `.dwl2` という拡張子の小さなファイルを作成します。これが「ロックファイル」です。

実は、このファイルの中には「現在その図面を開いているユーザー名」がテキストとして書き込まれています。Windows APIを駆使して複雑なハンドル操作を行う必要はありません。この「AutoCADの仕様」を逆手に取るのが、最もスマートで軽量なアプローチです。

3. 実装:オープン待機キューの構築

では、実際に「誰が使っているか」を特定し、指定回数リトライするコードを書いていきましょう。

ここでは、以下の2つのWindows APIを使用します。

  • `Sleep`: CPUを休ませ、PCが固まるのを防ぐため。
  • `DoEvents`: プログラム実行中も、ユーザーが「キャンセル」ボタンを押せるようにするため。
Option Explicit

' --- Windows API の宣言 ---
' プログラムの実行を一時停止させるためのAPI

If VBA7 Then

Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)

Else

Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

End If

''' <summary> ''' 図面をスマートに開くメインルーチン ''' </summary> ''' <param name="dwgPath">開きたいDWGファイルのフルパス</param> Sub SmartOpenDWG(dwgPath As String) Dim maxRetries As Integer: maxRetries = 5 ' 最大試行回数 Dim retryInterval As Long: retryInterval = 5000 ' 試行間隔(5秒) Dim currentTry As Integer Dim isOpened As Boolean Dim lockedUser As String isOpened = False For currentTry = 1 To maxRetries ' 1. ファイルが開けるかチェック If IsFileReady(dwgPath) Then ' ファイルが解放されていればオープン On Error Resume Next Documents.Open dwgPath If Err.Number = 0 Then isOpened = True Exit For Else MsgBox "図面のオープンに失敗しました: " & Err.Description, vbCritical Exit Sub End If On Error GoTo 0 Else ' 2. ロックされている場合、ユーザー名を特定 lockedUser = GetLockingUser(dwgPath) If currentTry < maxRetries Then ' ユーザーへの通知(ステータスバーへの表示など) Debug.Print "試行 " & currentTry & ": " & lockedUser & " が使用中です。待機します..." ' 3. 待機(ここが重要!) ' SleepでCPU負荷を下げ、DoEventsでWindowsのイベント(クリック等)を受け付ける Dim startTime As Double startTime = Timer Do While Timer < startTime + (retryInterval / 1000) DoEvents ' これがないと、待機中にExcel/AutoCADが「応答なし」になる Loop Else MsgBox "図面が長時間ロックされています。" & vbCrLf & _ "使用中のユーザー: " & lockedUser & vbCrLf & _ "作業を中断します。", vbExclamation, "オープン待機タイムアウト" End If End If Next currentTry If isOpened Then Debug.Print "図面のオープンに成功しました。" End If End Sub ''' <summary> ''' ファイルが他のプロセスで使用中かどうかを判定する ''' </summary> Function IsFileReady(filePath As String) As Boolean Dim fileNum As Integer Dim errNum As Long On Error Resume Next fileNum = FreeFile ' 書き込みモードで開こうとしてみる(これができればロックされていない) Open filePath For Binary Access Read Write Lock Read Write As #fileNum Close #fileNum errNum = Err.Number On Error GoTo 0 ' エラー番号70は「書き込み禁止(使用中)」を指す If errNum = 0 Then IsFileReady = True Else IsFileReady = False End If End Function ''' <summary> ''' .dwlファイルから使用中のユーザー名を抽出する ''' </summary> Function GetLockingUser(dwgPath As String) As String Dim dwlPath As String Dim fileNum As Integer Dim line As String Dim userName As String ' .dwl または .dwl2 を探す dwlPath = Replace(dwgPath, ".dwg", ".dwl") If Dir(dwlPath) = "" Then dwlPath = Replace(dwgPath, ".dwg", ".dwl2") If Dir(dwlPath) = "" Then GetLockingUser = "不明(ロックファイルが見つかりません)" Exit Function End If ' ロックファイルの中身を解析 On Error Resume Next fileNum = FreeFile Open dwlPath For Input As #fileNum Do While Not EOF(fileNum) Line Input #fileNum, line ' DWLファイル内にはユーザー名が含まれている(形式はAutoCADバージョンに依存するが、基本は行末付近) ' ここでは簡易的に行の内容を返す If InStr(line, " ") > 0 Then userName = Trim(line) Exit Do End If Loop Close #fileNum On Error GoTo 0 If userName <> "" Then GetLockingUser = userName Else GetLockingUser = "不明なユーザー" End If End Function

4. エンジニアとしての「こだわり」:ここが設計の肝です

このコードには、単なる「動くコード」を超えた、設計上の意図が3つ込められています。

① `DoEvents` による「ユーザー体験(UX)」の確保

`Sleep` 関数だけを使うと、プログラムが待機している間、AutoCADの画面は真っ白になり、マウス操作も受け付けない「フリーズ状態」になります。`DoEvents` をループ内で回すことで、待機中もユーザーが「キャンセル」ボタンを押したり、他のウィンドウを操作したりできるようになります。これは、「道具としての使いやすさ」を決定づける要素です。

② `IsFileReady` による「先行検知」

いきなり `Documents.Open` を叩いてエラーを待つのではなく、事前に `Open … For Binary Access Read Write` を試みることで、エラーハンドリングのコストを下げ、より確実に「使用中かどうか」を判定しています。

③ ライフサイクルに基づいた `.dwl` 解析

Windowsの高度なAPI(`NtQuerySystemInformation`など)を使えば、全プロセスのハンドルをスキャンしてファイル所有者を特定できますが、これは管理者権限が必要だったり、非常に動作が重かったりします。AutoCADが自ら書き出す `.dwl` を読む手法は、「対象となるソフトウェアの振る舞いを知り尽くした者」だけがたどり着ける、軽量で確実な最適解です。

5. まとめ:次のステップへ

今回学んだことは、単なる「ファイルを開くテクニック」ではありません。

  • エラーを予測し、制御する
  • OSやアプリケーションの仕組み(仕様)を利用する
  • ユーザーを不安にさせない設計をする

これらは、どのようなプログラミング言語においても共通する「設計思想」です。

もし、あなたが作成したツールが「誰かが開いているだけで止まる」のであれば、ぜひこの「待機キュー」の考え方を導入してみてください。それだけで、あなたのマクロの格は、周囲のエンジニアから一目置かれるレベルへと跳ね上がるはずです。

ここをクリアすれば、AutoCAD VBAの基本はバッチリですよ。さあ、もっと複雑な自動化の世界へ踏み出しましょう!

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