和風スパゲティのレシピ

日本語でコーディングするExcelVBA

ブックの読み取り専用を解除する - ChangeFileAccess

ブックの読み取り専用を解除する方法を解説します。

WorkbookオブジェクトのChangeFileAccessメソッドを実行するか、
一旦ブックを閉じてWorkbooks.Openで再度ブックを開き直します。


ChangeFileAccessの方がストレートな処理で推奨されそうに思われますが、
実際は癖が強すぎてあまり実用的でありません。


「読み取り専用ならいったん閉じてOpenし直してみる」
の方が普通に安定なマクロになることが多いので、
以下で解説する仕様をよく読んでどちらで実装するか判断して下さい。

読み取り専用の設定/解除 - ChangeFileAccess

ブックの読み取り専用を設定/解除するには、
WorkbookオブジェクトのChangeFileAccessメソッドを実行します。

Dim wb処理ブック As Workbook
Set wb処理ブック = Workbooks("テストブック.xlsx")

wb処理ブック.ChangeFileAccess xlReadOnly ' 読み取り専用にする
wb処理ブック.ChangeFileAccess xlReadWrite ' 読み取り専用を解除する

 
読み取り専用を判定するReadOnlyプロパティは値の代入ができないため、
以下のコードはいずれもエラーとなる点にご注意ください。

' どちらのコードもエラー
wb処理ブック.ReadOnly =True
wb処理ブック.ReadOnly =False

 

ChangeFileAccessメソッドの注意点

さてこのコード自体は単純なのですが、
ChangeFileAccessはかなり癖のあるメソッドのため注意が必要です。

現在と同じ状態に変更しようとするとエラー

ChangeFileAccessメソッドは現在と同じ状態にしようとするとエラーとなります。

' ↓すでに読み取り専用のブックで実行しようとするとエラー
wb処理ブック.ChangeFileAccess xlReadOnly

' 読み取り専用ではないブックで実行しようとするとエラー
wb処理ブック.ChangeFileAccess xlReadWrite

 
読み取り専用を解除するコードは確実に読み取り専用のファイルに実行してください。

If wb処理ブック.ReadOnly = False Then
    wb処理ブック.ChangeFileAccess xlReadWrite
End If

 

他の人がファイルを開いている場合

そしてここからが厄介な仕様なのですが、
他の人が開いているファイルの読み取り専用は当然ながら解除できません。

他の人が開いているファイルに対してChangeFileAccessを実行すると、
以下のウィンドウが表示されてしまいます。

他のユーザーが開いている警告

他の人が開いているファイルを開く際に出る見慣れたウィンドウそっくりで、
第1ボタンである「読取専用で開く」がないことだけが違いですね。


このウィンドウが厄介なのは、これを非表示にすることができない点です。

このウィンドウはApplication.DisplayAlertsの対象外のようで、
これをFalseにしていてもこのウィンドウは表示されてしまいます。


しかもこのウィンドウは「キャンセルを押してもマクロがエラーにならない」ため、
ブックが読取専用のままマクロが進んでしまう恐れがあります。


対策としてはChangeFileAccessを実行後に、
再度ReadOnlyを調べて読取専用が解除されているか調べるしかありません。

' 読取専用を解除してみる(失敗してもエラーになるわけではない)
wb処理ブック.ChangeFileAccess xlReadWrite

' 成功したか確認してからマクロを続行する
If wb読取ブック.ReadOnly Then
    MsgBox "ブックの読み取り専用が解除できませんでした。"
    Exit Sub
End If

ブックに未保存の編集がある場合

さらにもうひとつ、ChangeFileAccessメソッドで行う読取専用の解除は、
実際のところ「ブックの開き直し」が裏で行われているだけのようです。

現在の編集状況のまま読取専用を解除することはできず、
未保存の編集がある場合は以下のウィンドウが表示されます。

未保存の確認ダイアログ

要は「破棄して開き直し」「保存して開き直し」のどちらかを選ぶわけですが、
例によってこのウィンドウはDisplayAlertsの設定でOFFにできません。


結局「メッセージが出る可能性があるマクロ」にしかならないため、
ユーザーの選択に委ねられてしまうという点は避けようがない訳ですね。


一応未保存の編集は破棄してよいという場合には、

wb処理ブック.Saved = True
wb処理ブック.ChangeFileAccess xlReadWrite

このようにブックの保存済みフラグをTrueにしてから実行することで、
上記のウィンドウを出さずにChangeFileAccessメソッドを実行可能です。

Workbook_Openが発動する

先ほどChangeFileAccessメソッドで行う読取専用の解除は、
実際のところ「ブックの開き直しが裏で行われているだけ」と解説しました。

これを裏付ける挙動として、ChangeFileAccessメソッドを実行すると、
Workbook_Openイベントが発火します。

' ChangeFileAccess実行時にもこれは実行される
Private Sub Workbook_Open()
    MsgBox "テスト"
End Sub

イベントを実行させたくない場合は通常のWorkbooks.Openと同様、
Application.EnableEventsをFalseにしてから実行して下さい。

Workbooks.Openでファイルを開き直す

上記の通りChangeFileAccessメソッドは、

  • 今と同じ設定にしようとするとエラー
  • 他の人が開いていると設定変更に失敗するがエラーにならない
  • 故にReadOnlyを前後で2回チェックする必要がある
  • 他の人が開いていると設定変更ができないことを通知するダイアログが出る
  • 未保存の編集があると破棄/保存の選択ダイアログが出る
  • 上記2つのダイアログはDisplayAlerts=Falseで非表示にできない
  • 故にマクロの実行が必ずユーザーの操作に委ねられる仕様になってしまう

という2つの問題を抱えています。


その上で実際の挙動は「ファイルの開き直し」が行われているだけで、
Workbook_Openイベントが発火する点にも注意する必要があります。


じゃあ普通にWorkbooks.Openで開き直しても同じですよね。

むしろOFFにできないダイアログが表示されない分、
ユーザー操作に影響されない安定したマクロになることが多いです。

Dim wb処理ブック As Workbook
Set wb処理ブック = Workbooks("テストブック.xlsm")

Dim ファイルパス As String
ファイルパス = wb処理ブック.FullName

' ファイルが読み取り専用なら一度開き直してみる
If wb処理ブック.ReadOnly Then
    
    wb処理ブック.Close False
    
    Application.EnableEvents = False
    Set wb処理ブック = Workbooks.Open(ファイルパス)
    
    ' 読み取り専用を解除できなければマクロを中断
    If wb処理ブック.ReadOnly Then
        wb処理ブック.Close False
        MsgBox "処理ブックを書き込み権限で開くことができませんでした。"
        Exit Sub
    End If
    
End If

' ここからマクロ本体

 
このコードがChangeFileAccessコードに比べて優れるのは、
MsgBox以外のウィンドウが確実に表示されない点です。
(もちろんブック破損時のエラーなどは表示されますが)

これならユーザーの操作によらないマクロにすることができますね。


ChangeFileAccessというと聞こえはいいですが、
実際のところはReOpenメソッドでしかないようです。

だったらWorkbooks.Openを使った方が挙動はつかみやすいですので、
このことを念頭にChangeFileAccessメソッドを使用してください。


ChangeFileAccessメソッドは逆に「ユーザー操作に委ねたい」とき、
いわゆる実行型の汎用マクロなどで使用すると良いでしょう。