Excel 2010 で動いていたマクロが Excel 2013 や 2016 で動かすと挙動が異なって困った経験はありますか?私はあります(汗
結論からいうと、私が経験した事例では以下のようなことに気を付ける必要があります。
- 使用しないセルに条件付き書式を残さないようにする。
- 条件付き書式でユーザー関数を呼ぶ場合、そのユーザー関数内でエラーが生じないようにする。
よくわからない。「ともあれこれをしておけばいい」的な対処方法はないの?という場合は、マクロの開始直後と終了直前に EnableFormatConditionsCalculation を操作を追加します。以下は ActiveSheet に対して操作を追加した例です。
Sub Macro1() ' 条件付き書式の適用を停止 ActiveSheet.EnableFormatConditionsCalculation = False ' Excel 2010 まで動いていたマクロの処理 ' 条件付き書式の適用を再開 ActiveSheet.EnableFormatConditionsCalculation = True End Sub
再現手順を以下に示します。(以下の手順は Excel 2013 64bit 版 を Windows 10 (Ver1703) 64bit 版で確認しています)
何が起こるかを一言でいうと、マクロのプログラムカウンターが途中で消失します。つまりマクロが最後まで実行されません。(= End Sub まで行かない)
- Module1 シートに FuncA ユーザー関数を作成します。また作成するユーザー関数は a = 0 のときにエラーが発生するようにします。(配列でない変数を配列としてアクセスしようとしています)
Function FuncA(a As Integer) As String Dim b As Variant If a = 0 Then c = b(1) End If End Function
- A1 セルに FuncA() を使用した条件付き書式を設定します。今回は FuncA(自身のセル) が "" のときセルの色を替えるようにします。A1 セルの値を 1 とします。
- A1 セルを A2 にコピーします。A2 セルの値(数式)は =A1+1 に変更します。
- B1 セルに A1 セルをコピーします。B1 セルの値はクリアします。従ってセルの色が変更されないことを確認します。また合計 3 つのセルに同じ条件付き書式が設定されていることを確認します。
- Module2 シートに Macro1() を作成します。内容はなにも設定していないセルをクリアするだけのものです。今回は C1 セルと C2 セルをクリアするマクロを作成します。
Sub Macro1() Range("C1").ClearContents Range("C2").ClearContents End Sub
- 動作の確認のために作成したマクロの全ての行にブレイクポイントを設定します。また End Sub の部分にもブレイクポイントを設定します。
- Sub Macro1() から End Sub までの間にカーソルを置いた後に F5 キーを押しマクロを実行します。ブレイクポイントで停止しされるのを確認しながら、繰り返し F5 キーを押し End Sub までプログラムカウンタ (黄色の表示) が移動していくのを確認します。 (=期待通りに動作する)
- End Sub の実行も終了したら C1 セルのクリアを D1 セルのクリアに変更します。またこの操作はマクロのプログラムコードを変更することのみが目的です。D1 セルに変更すること自体に意味はありません、C1 以外ならどこのセルでも OK です。
- F5 を押しマクロを実行します。D1 セルのクリアのところでブレイクする(黄色表示になる)ことを確認します。
- ふたたび F5 を押しマクロを実行します。D1 セルのクリアの行を実行の後 C2 セルをクリアする行にプログラムカウンタが移動してブレイクされる(C2 セルのクリアのところが黄色表示になる)のを期待しますが、プログラムカウンタ (黄色の表示) は消失したまま戻ってきません。また、A2 のセル色が白になってしまいます。
- また B1 セルに空白や 0 以外の値を入れ上記手順を行った場合は本現象は再現しません。以下は B1 セルに値を入れてから、マクロの変更した D1 セルのクリアを C1 セルのクリアに戻して F5 を押していった場合です。プログラムカウンタ (黄色の表示) は End Sub まで移動します。(=期待通りに動作する)
この現象は条件付き書式で呼んだユーザー関数がエラーを起こした場合に発生します。エラーがない場合は発生しません。
しかも意図しない動作となるのは問題のある条件付き書式側の処理ではなくて、エラーが発生する関数とはまったく関係のないマクロ側だということです。マクロが途中で止まるからと言ってマクロ側のコードを一生懸命眺めても、マクロ側にはエラーはないので解決の糸口がつかめないのが特徴です(汗
そしてこの現象は Excel のバグか?(ディグレードか?)というと、そうであろうと思います。(厳密には「バグ」ではなく「未定義の動作」なのだろうけども。)
しかしこの現象を発生させるためにはユーザー関数のコードがバグっている必要があるのです。なので、自分の作りこんだバグを棚に上げて Microsoft を非難するわけにも・・・とモニョってしまうわけですね(汗
ともかくも大切なことは、この現象は不要となった条件付き書式を設定したセルが放置されることによって起きる可能性が高いことです。少なくとも私が遭遇した事例はそうでした。今回の B1 セルのように見た目は異常がない場合はそれが原因になっているとは想像することすら難しいです。
従って不要な条件付き書式付きセルが残らないようにする必要があります。残っているとパフォーマンスも無駄にしますのできれいさっぱり削除しましょう。
いやそうはいってもチェックするのは大変すぎて・・・という場合は冒頭の通り EnableFormatConditionsCalculation で対応してみてください。おそらく期待通りに動作するはずです。しかし EnableFormatConditionsCalculation = True より後のコードを実行しない場合があるので EnableFormatConditionsCalculation = True より後には処理は入れないようにします。
Sub Macro1()
' 条件付き書式の適用を停止
ActiveSheet.EnableFormatConditionsCalculation = False
' Excel 2010 まで動いていたマクロの処理
Range("D1").ClearContents
Range("C2").ClearContents
Range("D3").ClearContents
' 条件付き書式の適用を再開
ActiveSheet.EnableFormatConditionsCalculation = True
' ここより下は実行されない場合がある
End Sub
本質的な解決は条件付き書式の条件でエラーを発生されないこと、ユーザー関数でエラーを出さないことなので、その点は踏まえたうえで EnableFormatConditionsCalculation は次善の対策とするようにしてください。