ExcelVBAでマクロを書いていると、「昨日まで正常に動いていたのに、他のブックを開いたら急におかしな動作をする」というトラブルに遭遇したことはないでしょうか。その多くは、ThisWorkbookとActiveWorkbookの違いを正しく理解していないことが原因です。
この記事では、この2つのオブジェクトの違いを基本から解説し、実際に不具合が起きるパターンと、その防止策をサンプルコード付きで紹介します。マクロを配布する予定がある方や、複数ブックを同時に扱う処理を書く方は特に押さえておきたい内容です。
ThisWorkbookとは
ThisWorkbookは、そのVBAコードが書かれているブック自身を指すオブジェクトです。マクロがどのブックから実行されたか、どのブックがアクティブになっているかに関わらず、常に同じブックを参照します。
Sub ShowThisWorkbookName()
Dim wb As Workbook
Set wb = ThisWorkbook
MsgBox wb.Name & " はこのマクロが書かれているブックです"
End Sub
例えば、アドインやマクロ付きのテンプレートブックを配布する場合、ユーザーが他のブックを開いた状態でマクロを実行することもあります。そうした状況でも「自分自身のブック」を確実に操作したいときはThisWorkbookを使います。
ActiveWorkbookとは
ActiveWorkbookは、現在アクティブになっている(前面に表示されている)ブックを指すオブジェクトです。ユーザーの操作やコードの実行によって、参照先が変わります。
Sub ShowActiveWorkbookName()
MsgBox ActiveWorkbook.Name & " が現在アクティブなブックです"
End Sub
例えば、複数のブックを開いている状態でユーザーが別のブックのウィンドウをクリックすると、ActiveWorkbookが指すブックも切り替わります。マクロを実行しているブックと、ActiveWorkbookが同じとは限らない点に注意が必要です。
不具合が起きる典型パターン
以下のコードは、集計用のブック(マクロ本体)から、別の作業ブックのデータを読み込んで保存する処理です。一見問題なさそうですが、ActiveWorkbookを使っているために不具合の原因になります。
Sub SaveDataBad()
' 作業ブックのデータを集計してから保存するつもり
Call ImportData
' ここで保存したいのは「集計用マクロブック」のはず
ActiveWorkbook.Save
End Sub
ImportDataプロシージャの中で別のブックをアクティブにする処理(Workbooks.OpenやWindows(...).Activateなど)が実行されていた場合、このActiveWorkbook.Saveは集計用ブックではなく、直前に操作していた別の作業ブックを保存してしまいます。ユーザーの環境によって開いているブックの数や順序が異なるため、開発時には再現せず、配布後に「保存されない」「違うファイルが上書きされた」といった不具合として発覚しやすいパターンです。
修正版:ThisWorkbookで明示的に指定する
保存対象が「マクロが書かれているブック自身」であることが分かっている場合は、ThisWorkbookを使うことで、他のブックの状態に影響されない安全なコードになります。
Sub SaveDataGood()
Call ImportData
' マクロが書かれているブックを明示的に保存する
ThisWorkbook.Save
End Sub
こうすることで、ImportDataの中でどれだけ他のブックをアクティブにしても、保存対象は常に集計用ブックに固定されます。
ActiveWorkbookが役立つ場面
反対に、「ユーザーが今操作しているブックに対して処理したい」という場合はActiveWorkbookが適しています。例えば、アドインから呼び出して「現在開いている作業ブックに書式を適用する」ようなツールでは、ActiveWorkbookを使うのが自然です。
Sub FormatActiveSheet()
' アドインから呼び出し、今ユーザーが作業しているブックに適用する
With ActiveWorkbook.ActiveSheet
.Rows(1).Font.Bold = True
.Rows(1).Interior.Color = RGB(220, 230, 241)
End With
End Sub
このように、「マクロ自身のブックを操作したいのか」「ユーザーが今見ているブックを操作したいのか」を意識して使い分けることが重要です。
Workbooksコレクションでブック名を直接指定する方法
複数ブックを扱う処理では、ThisWorkbookやActiveWorkbookだけに頼らず、Workbooksコレクションでブック名を直接指定する方法も有効です。どのブックがアクティブかに関係なく、対象を確実に指定できます。
Sub SaveSpecificWorkbook()
Dim targetBook As Workbook
On Error Resume Next
Set targetBook = Workbooks("集計データ.xlsx")
On Error GoTo 0
If targetBook Is Nothing Then
MsgBox "対象のブックが開かれていません"
Exit Sub
End If
targetBook.Save
End Sub
処理の途中で複数のブックを開いたり閉じたりする複雑なマクロほど、名前で明示的に指定する方法が安全です。
まとめ
ThisWorkbookはマクロが書かれているブック自身を常に指すActiveWorkbookは現在アクティブなブックを指し、状況によって変化する- 複数ブックを扱う処理で
ActiveWorkbookを使うと、意図しないブックを操作してしまう不具合につながりやすい - 「自分自身のブック」を確実に操作したい場合は
ThisWorkbook、「ユーザーが今見ているブック」を操作したい場合はActiveWorkbookを使う - さらに確実に対象を指定したい場合は
Workbooks("ブック名")で明示する
この2つの違いを意識するだけで、複数ブックを扱うマクロの安定性は大きく向上します。ぜひ自分のマクロを見直すきっかけにしてみてください。

コメント