プログラミング_VBA_ヘッダー_s

[プログラミング: ExcelVBA] Excelファイルが誰かに使われてないかチェックする

 お疲れ様です  (  'ω')ノ

 VBAからExcelファイルを開こうとした時に 対象のファイルが書き込みできる状態かどうかを調べたい時ってありますよね。

 今回はExcelファイルを書き込みできる状態で開けるかどうか、またどういう状態であるかをチェックするコード(Functionプロシージャ)を作ろうと思います。

< 想定できるファイルの状態 >

想定できるファイルの状態は・・・
・ファイルが開かれていない
・ファイルが開かれていないが、他のアプリや誰かに使われている
・ファイルが開かれている
・ファイルが開かれているが[読み取り専用]で開かれている
・ファイルが開かれているが[保護ビュー]で開かれている
・そもそもファイルが存在しない

 ・・・ざっと、こんな状態でしょうか?

< ブックが書き込み可能か状態をチェックするコード >

'***** Excelファイルが書き込みできるかチェック
' 引数1   : vlFileFullPath     / ファイルのフルパス
' 戻り値  : [Integer]          / -1 = ファイルが見つからない
'                             /  0 = 開かれている & 書き込みできる
'                             /  1 = 開かれている & 保護ビュー
'                             /  2 = 開かれている & 読み取り専用
'                             /  3 = 開かれていない & 書き込み可能な状態で開けそう
'                             /  4 = 開かれていない & 書き込みできない
'                                    (他のアプリケーションか誰かに使われているとか)
Function Check_Writing(ByVal vlFileFullPath As String) As Integer
'===== 変数宣言 =============================================================
 Dim intFFile As Integer
 Dim strLine As String
 Dim blnWbOpen As Boolean
 Dim varTmp As Variant
 
 Dim objFSO As Object
'==========================================================================
 
 With Application
   For Each varTmp In .ProtectedViewWindows
     With varTmp
       If .SourcePath & "\" & .SourceName = vlFileFullPath Then
         '----- 保護ビューで開かれているか?
         Check_Writing = 1
         GoTo EndLine
       End If
     End With
   Next
 End With
 
 For Each varTmp In Workbooks
   If varTmp.FullName = vlFileFullPath Then
     If varTmp.ReadOnly Then
       '----- 読み取り専用 で開いていた場合
       Check_Writing = 2
     Else
       '----- 書き込み可能状態 で開いていた場合
       Check_Writing = 0
     End If
     
     blnWbOpen = True
     GoTo EndLine
   End If
 Next
 
 
 Set objFSO = CreateObject("Scripting.FileSystemObject")
 
 If Not objFSO.FileExists(vlFileFullPath) Then
   '----- ファイルが無い場合
   Check_Writing = -1
   Exit Function
 End If
 
 '----- 書き込みできる状態か?
 On Error Resume Next
 intFFile = FreeFile
 Open vlFileFullPath For Binary Access Read Lock Read As #intFFile
 Line Input #intFFile, strLine
 Close #intFFile
 
 If Err.Number = 0 Then
   '----- 書き込みできそう
   Check_Writing = 3
 Else
   
   If Not blnWbOpen Then
     '----- その他 (ファイル共有とかで)自分以外の誰かに開かれてた場合等
     Check_Writing = 4
   End If
 End If
 On Error GoTo 0

EndLine:
 Set objFSO = Nothing
End Function

 ・・・はい、できました(笑)

 今回はコードを書きながらフローを考えていたので、こんな感じになりました。

 それでは簡単に説明をします。
 まず、ブックが開かれていてもWorkbooksコレクションからは”読み取り専用”かどうかはわかりますが、”保護ビュー”かどうかは分からないようです。
 しかし、ApplicationオブジェクトProtectedViewWindows コレクションにファイルが保護ビューで開かれているとファイル名が格納されるようなので、ForEachで指定のブックがあるかを探します。

 次にWorkbooksコレクションから指定のブック名が開かれているかどうかをForEachで探します。その際にReadOnlyプロパティが True であれば”読み取り専用”になっているので、それで”読み取り専用”を判断します。

 次にブックの存在をチェックします。ブック名に環境依存文字が使われているといけないので、FSO(FileSystemObject)を使ってファイルの存在を確認します。今回はDir関数は使いません。

 ファイルが存在していることが確認できれば、ファイルを開けばいいんですが、、、ここでは普通にブックを開きたくないので、Openステートメントを使います。
 本来はテキストや画像ファイルを読み書きさせるときに使いますが、オプションでRead Lockをしようとした時に他で使用されているとエラーが発生するという仕組みを利用します。ここでエラーが発生しなければ、書き込みできる状態であることがわかります。

 そして、ここまで来て、ファイルが存在しているが、開かれておらず、且つ書き込みできる状態にもない、ということは他のアプリケーションやプロセス、又は共有ファイルとして使用されている可能性があることがわかります。

< 使い方 >

 [戻り値: Integer] = Check_Writing("ファイルのフルパス")
戻り値 :
 -1 = ファイルが見つからない
  0 = 開かれている & 書き込みできる
  1 = 開かれている & 保護ビュー
  2 = 開かれている & 読み取り専用
  3 = 開かれていない & 書き込み可能な状態で開けそう
  4 = 開かれていない & 書き込みできない
   (他のアプリケーションか誰かに使われているとか)

< サンプル >

Sub ファイルの状態チェック()
 
 Dim strMsg As String
 Dim intRet As Integer
 
 intRet = mdlFunc.Check_Writing(ThisWorkbook.Path & "\なにかのファイル.xlsx")
 
 Select Case intRet
 Case -1:    strMsg = "ファイルが見つかりません"
 Case 0:     strMsg = "開かれている & 書き込みできる"
 Case 1:     strMsg = "開かれている & 保護ビュー"
 Case 2:     strMsg = "開かれている & 読み取り専用"
 Case 3:     strMsg = "開かれていない & 書き込み可能な状態で開けそう"
 Case Else:  strMsg = "開かれていない & 書き込みできない"
 End Select
 
 MsgBox strMsg
End Sub

 以上で、流れや仕組みの説明は終わりです。

 最後にこのコードを作りながら、注意しなければならないと思ったことがあります。
 例えば、ネットワーク上のファイルサーバを利用する場合、ネットワークドライブとしてドライブレター(C: などのアルファベット)を割り当てて使うことがあります。
 しかし、ドライブレターを割り当てておきながらUNCパス(\\コンピュータ名\\フォルダ名\.)でショートカットを作成し、そこからアクセスする人がいます。
 そうした時に、プログラム上は”U:\ファイル名"とコーディングしていても"\\コンピュータ名\フォルダ\ファイル名"でアクセスすると、余程上手くコーディングしておかないと別物として扱われます。
 そういった問題が発生することもありますので、ネットワーク上のファイルを読み書きする場合は、ファイルの使用者でパソコンの設定などを統一するようにしましょう。

 最後まで読んでいただきありがとうございます。

 記事を読んで良ければ ”スキ” をしてもらえると次回へのモチベーションアップにつながりますので、どうぞ宜しくお願いします。

 それじゃ ('ω')ノ

この記事が気に入ったらサポートをしてみませんか?