えくせるちゅんちゅん

ことりがエクセルをちゅんちゅんするブログ

ExcelVBAのCurrentRegionにはバグがある

先日、Excel VBA のCurrentRegionにはバグがあるらしい情報を耳にしました。

実際に私の手元の全ての環境で再現できたため、勝手にバグとして認定し公表します。


CurrentRegionとは

https://docs.microsoft.com/ja-jp/office/vba/api/excel.range.currentregion

現在の領域を表すRangeオブジェクトを返します。

現在の選択範囲は、空白の行と空白の列の任意の組み合わせで囲まれた範囲です。

と、言われても、理解は困難でしょう。


私が説明するならこの一言。

Ctrl+Aした時のセル範囲

である。(※私の知る限り同じだと思うが、完全に同一の動きをするかは保証できない)


え?Ctrl+Aを使わないから分からんって?


でも次の動画を見れば一目瞭然でしょう。

f:id:Kotori-ChunChun:20200221011117g:plain


というわけで、CurrentRegionの例はこんな感じ

A B C
1 名前 年齢 性別
2 ああああ 12
3 いいいい 34
4 ううううう 45
?Range("A1").CurrentRegion.Address(False, False)
A1:C4


CurrentRegionの使い方

動画の通り、選択範囲には少々癖があります。

空の行・列が予想される場合などは予定通りに動かない恐れがあるので、データ設計が重要となります。

何でもかんでもCurrentRegionで済ませるのは難しいかもしれません。


CurrentRegionが適している場面

  • CSVやデータベース等を開いただけのデータ
  • VBA等により作成されるデータ
  • 数式で特定の列がキッチリ埋まっており、表の周りにヘッダ等のゴミが無いデータ
  • テーブル化されているデータ(そもそもCurrentRegionを使う必要がないが)


CurrentRegionが適していない場面

  • ユーザーが加工する恐れのあるデータ
  • 表の周りに不要な情報が記載されているデータ
  • これから説明するバグに該当する状況下


以上のような性質から、ユーザーが触ることのある表でCurrentRegionを使うのは難しいです。


※筆者はUsedRangeや二次元配列で対応しているため、CurrentRegionをあまり使った経験がありません。従ってこれは想像上の一例です。


CurrentRegionのバグ

概要

ようやく本題です。

とある筋からの情報で、VBAからWorkbook.Saveを実行した時にのみWorkbook_BeforeSaveイベントCurrentRegionプロパティが働かない事がわかりました。

普通にユーザーがCtrl+Sやリボンから上書き保存した場合には正常に動作するため、なかなか気がつくことができません。


ThisWorkbookソースコード

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
    Debug.Print Me.ActiveSheet.Range("A1").CurrentRegion.Address
End Sub

Sub Test_Save()
    Debug.Print "-----"
    Debug.Print "マクロからのSave"
    Me.Save
End Sub

実行結果

$A$1:$C$5 ・・・ Ctrl+SによるSave
-----
マクロからのSave
$A$1

再現例

見ての通り、CurrentRegionが無いものとして扱われているかのような結果を返します。


類似例

さらにWorkbook.Closeを実行した場合にも、Workbook_BeforeCloseイベントCurrentRegionプロパティが働かない。ということが分かっています。

しかし全てのイベントで再現するという訳ではないようで、SheetSelectionChangeイベントでは再現されませんでした。

Before系イベントのCancelで取り消しができるようなイベントで再現できるのかもしれません。(全ては未確認)


環境依存の調査

私の手元には、

がありますが、全ての環境において再現されました。


本件がバグであることを、ここに認定します。


現場への影響

バグだということが分かったとして、実害はどの程度あるのかが気になると思いますので、私の所感を書いておきます。


まず、CurrentRegionを使わない人はスルーしてOKです。

バグを再現するには、次の2つの条件を両方とも満たす必要があります。

  • 該当イベント処理中にCurrentRegionを使用すること
  • 該当イベントを起こすようなプログラムを書くこと

普段からCurrentRegionを使わない人は、確実に対象外ですからスルーしても大丈夫ですね。


しかし、CurrentRegionを使う人は知っておいたほうが良いかもしれません。

滅多に使うようなロジックではないので、問題となりにくいとは思いますが

  • Saveしつつ、Saveしたことでセル範囲に何らかの処理を行う
  • Closeしつつ、Closeされたことでセル範囲に何らかの処理を行う

に当てはまるプログラムを書いてしまうかもしれません。


たとえば、

  • Saveボタンを設置してWorkbook.Saveする
  • BeforeSaveイベントで、入力データをチェックして問題なければ保存する

  • Closeボタンを設置してWorkbook.Closeする
  • BeforeCloseイベントで、データを別のデータベースに転写してから終了する

とか

  • フォルダ内のブックを順番に開いて、加工してWorkbook.Saveする
  • BeforeSaveイベントで、入力データをデータベースに書き込む

なんてのが想像できます。


そもそも、CurrentRegionを使わなければどうということはありません。

もしCurrentRegionを使ってVBAを書いている人は、イベント処理には含めないようにだけ注意しておけば良いでしょう。

UsedRange、二次元配列、名前定義など、他の手段はいくらでもあります。


というわけで、利用率加味した総合的な危険度は低めという認識です。


参考資料

発端のツイート


情報源となった質問サイト

<http://www.excel.studio-kazu.jp/kw/20200219181222.html


↓最終行を求める式に関して

www.excel-chunchun.com

↓非表示のセルの除外にも対応した二次元配列格納関数

www.excel-chunchun.com


まとめ

  • CurrentRegionにはバグがあります。
  • CurrentRegionは一部のイベント処理で書いてはいけません。
  • UsedRangeや二次元配列と使い分けるのをお勧めします。

以上


何か御座いましたらコメント欄、またはTwitterからどうぞ♪

それではまた来週♪ ちゅんちゅん(・8・)