VBA

【Excel VBA】ブックが閉じられた事を検出する方法

投稿日:2017.04.23 更新日:

先日ちょっとしたツールを作っている時に他のブックが閉じられた事を検出したい場面に遭遇したのですが、WorkbookオブジェクトにもApplicationオブジェクトにも既定のイベントにはそれっぽいのは見当たらない…。

でも無いものは仕方ないですよね。とは言え無いと困ります。

なので作っちゃいました。あった方が便利ですもんね。

既定のイベントでは検出できない

VBAには様々イベントが実装されています。「イベント」とは『あるアクションが実行された時に自動で実行されるプロシージャ』だと思って下さい。例えばブックが開かれた時はWorkbook.Openイベントが自動で実行されます。このようなブックのアクションに関連したイベントはWorkbookオブジェクトやApplicationオブジェクトに実装されているのですが、ブックが閉じられた時に実行されるイベントがないのです。いや、あるのかも知れませんが僕には見つけられませんでしたのでご存知の方がいらっしゃいましたら教えてください!

惜しいイベントとして、閉じられる直前に実行されるWorkbook.BeforeCloseイベントやApplication.WorkbookBeforeCloseイベントがあるのですが、このイベントが発生したからと言って必ずその後にブックが閉じられる訳ではありません。ブックが変更されている場合に閉じる前に出る「~への変更を保存しますか?」の確認で「キャンセル」を選択するとブックは閉じられないためです。

他のブックが閉じられた事を検出するサンプルクラス

今回はブックが閉じられた時に発生する独自イベントを追加したので一連の処理をクラスモジュールに纏めてみました。

解説

Class_Initializeイベント

まずこのクラスのインスタンスが生成された時に以下の処理を行います。

  1. WithEventsキーワードでイベントに対応したApplicationオブジェクトの変数Appをインスタンス化する。
  2. 変数cntに現在のブックの数を保存する。

これで準備はOKです。あとはAppで検出するブックがアクティブ/非アクティブになった時に発生するActivate/Deactivateイベントでブックが閉じられた事を検出します。

Application.NewWorkbookイベント

後述する処理で行われるブックが閉じられた事の判定にはブック数を保存しておく必要があります。そのため新しいブックが作成された場合は変数cntを更新しておきます。

Application.WorkbookOpenイベント

NewWorkbookと同様に、新しいブックが開かれた時に変数cntを更新します。NewWorkbookは新規ブック作成時に発生しますが、WorkbookOpenイベントは既存のブックが開かれた時に発生します。

Application.WorkbookActivateイベント

あるブックが閉じられた場合は他のブックがアクティブになります。この仕組みを利用してブックがアクティブになった時に変数cntに保存しておいたブック数と現在のブック数(Workbooks.Count)を比較し、現在のブック数が少なくなっていれば他のブックが閉じられたと判定できます。

Application.WorkbookDeactivateイベント

先述したWorkbookActivateイベントでの検出はブックが複数開かれている場合にのみ有効となります。開いているブックが1つしかなかった場合はそのブックが閉じられても次にアクティブになる他のブックがないためです。しかし、逆に言えばブックが非アクティブになった時にブック数(Workbooks.Count)が1つであれば閉じるアクションが実行されたと判定できる事になります。

因みにWorkbookBeforeCloseイベントもブックを閉じる前にほぼ同じタイミングで発生しますが、先述の通りイベントが発生た後にブックが閉じられない可能性があるためNGです。

厳密にはWorkbookDeactivateイベントが発生した時点では、ブックが閉じられる事が確定しているだけでまだブックは閉じられていません。このサンプルを使用する際はこの点にご注意ください。

RaiseEvent

ブックが閉じられた時に、モジュールの冒頭で定義した独自イベントWorkbookClosedRaiseEventステートメントで発生させています。RaiseEventの使用例はダウンロードサンプルをご覧ください。

まとめ

標準で無い機能は別の機能を組み合わせると実現出来る事が多いです。標準で実装されていない場合は、別の方法(仕様)を探すか、今回のように別の標準機能を組み合わせて実現すればいいんです:)

最後に今回のサンプルを置いておきますので自己責任でご利用くださいまし。

HAYs

-VBA
-,


comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連記事

VBA配列基礎

通常の変数は1つの変数に1つの値しか格納できませんが、配列を利用すれば一つの変数に同じデータ型の複数の値を格納することができます。このエントリーでは、VBAで配列を利用するための基本事項をご紹介致しま …

Excel VBA 高速化アプローチ【プロパティ編】

Excel VBA を高速化する方法をまとめてみました。今回は「プロパティ編」です。 このエントリーで記載しているサンプルコードは説明のためにあえて冗長にしてる部分もあります。ご自分のマクロに適した形 …

Alphabet blocks

Mid関数とMidステートメント

Excel VBA のヘルプで「Mid」と検索すると、Midキーワードは「Mid関数」と「Midステートメント」の2つの構文で使用される旨の説明が表示されます。今回はこの「Mid関数」と「Midステー …

options

省略可能な引数を定義するOptionalキーワード

Excel VBA で省略可能な引数を持つプロシージャを作成するにはOptionalキーワードを使用します。このエントリーではOptionalキーワードの概要を説明します。 Optionalキーワード …

StringBuilder For Excel VBA

Excel VBAでStringBuilderを使う

 VB.NET には StringBuilder というクラスが実装されています。このクラスは文字列連結に特化しており、ループ内での文字列連結など処理中に文字列の連結が何度も出現する場合にその力を発揮 …