知らずに落ちると抜け出せなくなるVBAの落とし穴です。
- マクロがエラーもなく停止する
- マクロのエラーの原因がわからない
- マクロがたまに謎の挙動を起こす
あたりにお悩みの方は、この落とし穴に落ちていないかご確認ください。
DisplayAlertsを切ったことが原因で起こる不具合
Application.DisplayAlertsプロパティはExcelからの確認メッセージを非表示にする機能で、多くは「削除」「閉じる」といった処理と組み合わせて使います。
例えばシートを削除する際、手作業でもVBAでも、
この確認メッセージが表示されてしまいますので、
Application.DisplayAlerts = False 削除したいシート.Delete Application.DisplayAlerts = True
と記載することで、マクロを止めずに削除ができます。
この使い方がメインとなるプロパティなのですが、
↑のコードを見てわかる通り結構コード量が増えることになり、
例だと3倍になっているなど、下手するとメインコードより多くなるんですよね。
それが面倒ということで、
' マクロ高速化四天王 + 1 With Application .Calculation = xlCalculationManual ' 自動計算OFF .ScreenUpdating = False ' 描画OFF .EnableEvents = False ' イベントOFF .Cursor = xlDefault ' マウスカーソルをくるくる状態に .DisplayAlerts = True ' ←問題のコード End With
こんな風に、他のApplication系コードと一緒に、
マクロの開始時に一緒にOFFにしているコードをたまに見かけます。
が、これはかなり危険ですのでやめた方が良いです。
理由は単純で、想定していなかった確認メッセージも出てくれなくなるからです。
簡単な例で行くと、「名前を付けて保存」時に、
同じ名前のファイルを上書きしたい場合は、
Application.DisplayAlerts = False 保存したいブック.SaveAs "~~" Application.DisplayAlerts = True
とやるのですが、これが意図せず出ることにつながります。
例えばよくあるミスなのですが、
' 新しいフォルダを作成 Dim 新規フォルダパス As String 新規フォルダパス = Thisworkbook.Path & "\" & Format(Date,"yyyymmdd") MkDir 新規フォルダパス ' そこにブックを保存 新規ブック.SaveAs Thisworkbook.Path & "\" & "新規ブック.xlsx" ' ↑と見せかけて作ったフォルダになってない
こんな風にフォルダを作っておきながら使わない凡ミスをしたとします。
このSaveAsは「作ったばかりのフォルダ」に実行しますので、
コードを書いた本人は「上書きかどうか」を考慮していません。
しかし実際は既存のフォルダに保存されてしまうのですが、
このときDisplayAlertsを切ってしまっていると、
意図しないファイルの上書きが発生するうえ、しかもそれに気づけません。
大事なファイルが消えるのも怖いのですが、
「バグを書いたことに気づけない」のも結構怖いんですよね。
バグって直すより見つける方が大変なので、
バグに気づくチャンスが減るというのは結構な損害なのです。
この「意図しない上書き保存」の他には、
wb○○.Close ' ←本当は「未編集のブック」を閉じるつもり
このコードで○○を誤って書いてしまった際に、
閉じたくないブックが閉じられてしまうという罠もありますね。
また、これらより頻度は落ちますが、だからこそ怖いバグにつながることがあります。
最近見た例なのですが、
Worksheets("○○").Copy
この行でマクロが止まってしまうというバグがありました。
エラーで「デバッグ」の画面が出るとかではなく、
Endが実行されたように本当に音もなく止まるのです。
原因に見当つきます?
もしこれに遭遇したら、意味わからなくて解決に時間を要しそうですよね。
まあこの記事ですから原因はDisplayAlerts=Falseなんですが、
この○○シートにはイベントマクロが書いてありました。
そしてこのコードは「新規ブックにコピー」というコードのため、
事実上は「マクロブックを新しく作るコード」だったのです。
この「マクロブックの新設」に対し、Windowsさんの設定次第では、
https://www.limecode.jp/entry/trap/always-displayalerts-false
という確認が表示されてしまうのです。
そして「処理の中止」が自動で選択されたんですね。
「マクロがEndもなく止まる」という謎の現象だったのですが、
ふたを開けて見れば「処理の中止を指示していただけ」だったということです。
このようにDisplayAlertsは「思いもよらない確認メッセージ」をOFFにしてしまう危険があります。
最近見たやつだと、「ユーザーが保存先にOneDriveを指定」した際に、
このファイルをネットワークに云々~~ |
みたいなメッセージが出たのですが、
これもDisplayAlertsを切っていたらと思うと恐ろしいです。
プログラムのバグというのは2種類あります。
- たまにエラーで止まるが、エラーなく終了したときは正しい結果になる
- 常にエラーなく終了するが、たまに間違った結果になる
もちろん2が嫌ですよね?
DisplayAlertsを切るという行為は、この1を2に変える危険を常にはらみます。
細心の注意をもって使用し、そして使用した場合は即座に
Application.DisplayAlerts = True
を入れて、安全装置の電源をしっかり入れなおしましょう。
おまけ:DisplayAlertsのコード書くのが面倒問題の対策
さてDisplayAlertsの大事さをわかってもらえたと思いますが、
だからと言ってこれを書く面倒さが軽減されるわけではありません。
Application.DisplayAlerts = False Application.DisplayAlerts = True
この対策には以下の2つの方法が便利です。
ユーザー辞書を使う
上記のコードは完全な固定文ですので、
変換辞書に登録してしまいましょう。
だf | Application.DisplayAlerts = False |
---|---|
だt | Application.DisplayAlerts = True |
ちなみにユーザー辞書の「読み」にはアルファベットも使えます。
↑のサンプルは、DATとDAFの頭文字になります。
普通の日本語の変換時に出てこない対策に便利ですね。
汎用関数にする
DisplayAlerts入りのコードを汎用関数にしておくと、
入力も簡単で、しかもコードも1行になってくれます。
Sub シートを削除する(対象シート As Worksheet) Application.DisplayAlerts = False 対象シート.Delete Application.DisplayAlerts = True End Sub ' 実行例 Call シートを削除する(Worksheets("○○"))
一度作ってしまえばあとは使いまわせますし、
書くだけでなく読むのも楽になるのが大きいです。
DisplayAlertsを書くのが面倒という方は、
この2つの方法で対策してみてください。