VBAからMicrosoftExcelのブックが更新可能かを判断する場合、ブックをファイルとしてAppendモードで開いて、エラーコードを確認するというのが定番のテクニックだそうだ。単なるファイルとして開くのでパフォーマンスが良いらしい。
しかしながら、そのブックがネットワーク上にある場合、ほかの人が使用中でもAppendモードで開けてしまうようである。
これでは使えない。そもそも更新可能かを確かめるときは、いずれにせよMicrosoftExcelから開くことになる。そうであれば、「だれかが開いている事がむしろ多いです」という事が前提でなければ、ワークブックとしてきっちりと開いて確認したほうがむしろ速いかもしれない。なのでそうするよう作り直した。
開いてみて[読み取り専用]モードであったなら書込み不能と判断し、戻り値としてFalseをセットして、開いたブックは閉じる。そうでなければ、Trueを返し、ブックは開いたままとする。
関数名は"OpenBookWritable”とし、開こうとするブックのフルパスで引数として渡すこととする。
Function OpenBookWritable(フルパス名) As Boolean
Application.DisplayAlerts = False
'↑ ブックをほかの人が開いていたとき、「編集可能となった際に
'通知しますか」のメッセージが出ないように抑止
Workbooks.Open Filename:=フルパス名, Notify:=False
'↑ 「読み取り専用で開きますか」の メッセージが出ないように抑止
If ActiveWorkbook.ReadOnly Then
'↑ 開いたブックが [読み取り専用]になっていたら
ActiveWorkbook.Close
'↑ ブックを閉じます。 開いた直後なので必ずActiveになる。
OpenBookWritable = False '<= ブックは開かれてますよ、と返す。
Else
OpenBookWritable = True '<= ブックは開かれてませんよ、と返す。
End If
Application.DisplayAlerts = True
'↑「編集可能となった際に通知しますか」のメッセージ抑止解除
End Function
より丁寧には、目的のブックが存在するかどうかを確認してからブックを開くことが望ましく、その場合は関数冒頭に次のような処理を追加するのもいいかな。
If Not CreateObject("Scripting.FileSystemObject").FileExists(フルパス名) Then
OpenBookWritable = False
Exit Function
End If
おそらく問題とならないことが多いが、上のチェックを追加で入れた場合、「ブックがなくてFalseなのか、ブックがあるが誰かがつかんでいるのでFalseなのか」区別がつかないので、全体を関数として紹介するのは保留とする。ファイルが開かれていればスルー、というパターンは多いが、ファイルがなくてもスルー、というのは抵抗があるかも。
なのでこの関数のテスト用に書いたドライバ。呼び出しはダイアログボックスから読み込みブックを指定するようにして「ブックがない場合はどうしよう」は考えずに済むようにした。
Sub OpenBookWritableドライバ()
Dim フルパス名 As String
Dim ブック名 As String
'<ダイアログボックスを出して、 開くブックを選択する。 >
フルパス名 = Application.GetOpenFilename("Microsoft Excel ブック,*.xls*")
If フルパス名 = "False" Then
MsgBox "キャンセルされました"
Exit Sub
End If
If Not OpenBookWritable(フルパス名) Then
MsgBox "ファイルが使用できません"
Else
DoEvents '何か処理
'<FileSystemObject を利用して、ブック名を取り出す>
ブック名 = CreateObject("Scripting.FileSystemObject").GetFileName(フルパス名)
Application.DisplayAlerts = False
Workbooks(ブック名).Save
Workbooks(ブック名).Close
Application.DisplayAlerts = True
End If
End Sub