ブックを開こうとした際、こんな警告メッセージが出ることがあります。
手作業ならここで「はい」を選択し、修復結果の報告を見てからブックを開けます。
この「破損したブック」をマクロで開くとき、
ただApplication.DisplayAlerts = Falseとしただけでは、
実行時エラー1004「'Open' メソッドは失敗しました: 'Workbooks' オブジェクト」 |
このエラーが発生してしまいます。
これを解決する方法を解説します。
ソースコード
Sub ブックが破損していたら修復して開く() Dim ファイルパス As String ファイルパス = "C:\Users\○○\Desktop\テスト\破損したブック.xlsm" Dim 処理ブック As Workbook ' 各種メッセージをOFFに Application.DisplayAlerts = False ' まずはVBAエラーをスキップして開いてみる On Error Resume Next Set 処理ブック = Workbooks.Open(ファイルパス, UpdateLinks:=False) On Error GoTo 0 ' 開けなかったら「修復」を指定して開く If 処理ブック Is Nothing Then On Error Resume Next Set 処理ブック = Workbooks.Open(ファイルパス, UpdateLinks:=False _ , Corruptload:=xlRepairFile) On Error GoTo 0 ' 同名でSaveAsして修復を保存 処理ブック.SaveAs 処理ブック.FullName ' DisplayAlerts=False下のため上書き保存になる ' xlsmの場合はFileFormat:=xlOpenXMLWorkbookMacroEnabledもつける End If ' 警告メッセージをONに戻す Application.DisplayAlerts = True ' それでダメなら別の原因 If 処理ブック Is Nothing Then Exit Sub End If ~~ ここから実際の処理 End Sub
解説
とりあえず破損したブックを修復して開くだけなら、
Corruptload:=xlRepairFile
これをOpenメソッドで指定すればOKです。
しかしこれには一つ問題があり、修復して開いたブックは、
こんな通知がブック名の右に表示されます。
これは手作業でも同じですね。
そしてこの「修復済み」状態にはひとつ大きな制限があり、
手作業・マクロともに「上書き保存」が実行不可能になります。
手作業で上書き保存をしようとすると「名前をを付けて保存」がはじまり、
同名で保存しようとすると「上書きしますか?」ウィンドウが表示されます。
マクロでWorkbook.Saveメソッドを実行すると、
実行時エラー1004「'Save' メソッドは失敗しました: '_Workbook' オブジェクト」 |
このエラーが発生してそもそも保存ができません。
加えて重大な仕様として、
Corruptload:=xlRepairFile
これを指定すると壊れていないブックでも「修復済み」で開かれます。
つまり問題が起きていないブックもSaveが不可能になるということですね。
それでは困るため、このCorruptloadの設定は、
破損したブックだけで指定する必要があるのですが、
しかし破損しているかどうかを開かずに調べる方法がありません。
よって、
- On Error Resume Next下で開いてみる
- ダメだったらCorruptload:=xlRepairFileで開いてみる
- 開けた=修復できたならそれを同名で保存する
- 開けなかったらエラーの原因は破損ではない
という手順を踏む必要があります。
しかもこれでも万全ではなく、以下の問題にも注意してください。
そもそも同名で保存していいのかまず検討すべき
上記のコードは「軽微な破損を無視してマクロを動かす」ことに主眼を置いています。
よく壊れるものとして、
- 入力規則(特に文字数オーバー)
- 図形(大量に配置しすぎるなど)
- グラフ(複雑なデータ範囲を切り貼りするなど)
このあたりですが、これらは「修復」で大丈夫な場合が多いでしょう。
このあたりをユーザーが壊してもマクロを動かすためには、
上記のコードで対応する必要があります。
しかし、もっと重大な破損、例えば「VBAプロジェクトの破損」などの場合、
上記のコードでは有無を言わさずソースコードを全消去してしかも上書き保存されます。
このコードは「ファイルを頑張って保護する」ことには主眼をおいていませんので、
大事なファイルにこの処理を実行するのはなるべく避けてください。
別の原因でのエラーは先につぶしておくべき
解説をわかりやすくする都合上、
- On Error Resume Next下で開いてみる
- ダメだったらCorruptload:=xlRepairFileで開いてみる
- 開けた=修復できたならそれを同名で保存する
- 開けなかったらエラーの原因は破損ではない
という順番で説明し、マクロも
' ※ それでもダメなら別の原因 If 処理ブック Is Nothing Then Exit Sub End If
これを最後に書いていました。
ですが、この「修復」は最後の手段ですので、本当は
- Openがエラーにならないよう最善を尽くす
- On Error Resume Next下で開いてみる
- ダメだったらCorruptload:=xlRepairFileで開いてみる
- 開けた=修復できたならそれを同名で保存する
と、4でやっていたエラー原因の特定は本来1でやるべきです。
一番わかりやすい例として、
上記のコードは「開こうとするファイルパスが存在しない」場合でも修復を試します。
これはちょっと間抜けですよね。
Openのエラー対策としてよくある「UpdateLinks:=False」は一応書きましたが、
他のエラーもしっかりつぶし、最後の手段として今回のコードは実行して下さい。