[プログラミング: 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:\ファイル名"とコーディングしていても"\\コンピュータ名\フォルダ\ファイル名"でアクセスすると、余程上手くコーディングしておかないと別物として扱われます。
そういった問題が発生することもありますので、ネットワーク上のファイルを読み書きする場合は、ファイルの使用者でパソコンの設定などを統一するようにしましょう。
最後まで読んでいただきありがとうございます。
記事を読んで良ければ ”スキ” をしてもらえると次回へのモチベーションアップにつながりますので、どうぞ宜しくお願いします。
それじゃ ('ω')ノ
この記事が気に入ったらサポートをしてみませんか?