TL;DR —
ThisWorkbookは、どのウィンドウをユーザーがクリックしようと、常に 実行中のコードを 抱えている唯一のブック を指します。ActiveWorkbookは 今いちばん手前にあるもの を指し、それは 足元で変わりえます。限定なしのRange("A1")はさらに厄介です。ブックもシートも一切名指ししないので、 その瞬間にアクティブなものに着地します。書き込みはThisWorkbook(または自分でSetしたブック変数) にアンカーし、マクロが「マウスを最後にどこでクリックしたか」に依存するのをやめさせましょう。
Sub WhereDoesItLand()
' ThisWorkbook = このコードが住んでいるファイル - 永遠に不動
ThisWorkbook.Worksheets("Summary").Range("A1").Value = "Report"
' ActiveWorkbook = この行が走る瞬間に手前にあるもの - 気まぐれ
Debug.Print ThisWorkbook.Name ' 例: Macros.xlsm - 常に
Debug.Print ActiveWorkbook.Name ' ユーザーが最後にクリックしたもの
End Sub
この記事で学べること
- 考え方の軸 —
ThisWorkbookは不動の住所、ActiveWorkbookは動く場所 - どのオブジェクトを指すかを言い切る3つの道具と、限定なしの参照が危険な理由
ThisWorkbookとActiveWorkbookの違い — 信頼できるVBAで最も重要なただ一つの区別- 静かな罠 — 自分の席では動くマクロが、同僚の開いているファイルを壊す理由
- 開いている別のブックを名前で参照する方法と、開いてハンドルを保持する方法
- 意見 — すべての参照を限定し、既定は
ThisWorkbookにする
考え方の軸:不動の住所であって、動く場所ではない
VBAのすべての参照は一つの問いに答えます。どの ブックか、どの シートか、どの セルか。
ThisWorkbook は最初の問いに答え、その答えを決して変えません。それは あなたが実行しているコードを
含むブック — モジュールやマクロが住んでいるファイルです。他のブックを10個開き、そのすべてをクリック
して回っても、ThisWorkbook はマクロが始まったときと同じファイルを指し続けます。
ActiveWorkbook は同じ問いに、今この瞬間に手前にあるもの で答えます。それは設計からして動く標的です。
ユーザーが別のウィンドウをクリックした瞬間、あるいはあなた自身のコードが新しいファイルを開いた瞬間、
アクティブなブックは変わります。どちらも便利です — ですが両者は交換可能ではなく、片方をもう片方として
扱うことが、「マクロが間違ったファイルを編集した」というバグ一族すべての根っこです。
どのオブジェクトを指すかを言う3つの方法
ThisWorkbook は、コードに推測させる代わりに、欲しいオブジェクトを 名指しする ためにVBAがくれる
3つの道具の一つです。この3つが、マクロが信頼できるか脆いかを決め、この短いクラスターの背骨になっています。
| 道具 | 何を指すか | どんなときに使うか |
|---|---|---|
ThisWorkbook |
このコードを抱えるブック — 不動 | マクロに属する設定を読む、または出力を書く |
| ActiveWorkbook / ActiveSheet | 今 いちばん手前にあるもの — 気まぐれ | 「ユーザーが開いているもの」に対して動く汎用ツール |
| Worksheets(...) | ブック内の名前付きシート — コレクション | 特定のタブを名前・インデックス・CodeName で指定する |
これらを結ぶルールはこうです。限定なしの参照は、アクティブなものへ手を伸ばします。 ブックもシートも
前に置かずに Range("A1") = 1 と書くと、VBAはその瞬間のアクティブなブックとアクティブなシートで空欄を
埋めます。それはイミディエイトウィンドウでは便利で、保存されたマクロでは破滅的です。
ThisWorkbook と ActiveWorkbook:不動か、気まぐれか
これは記憶に焼き付けるべき区別です。あなたのマクロが Macros.xlsm に住んでいて、ユーザーは
Sales.xlsx も開いており、ボタンを押すときにそちらを見ている、と想像してください。
Sub FixedVsFickle()
ThisWorkbook.Worksheets(1).Range("A1").Value = "written by the macro"
' ^ 常に Macros.xlsm に着地する。このコードが住んでいるファイル
ActiveWorkbook.Worksheets(1).Range("A1").Value = "written by the macro"
' ^ Sales.xlsx に着地する。ユーザーが見ていたのがそれだから
End Sub
見た目は同じコード、着地するのは別々のファイル。ターゲットが「マクロが属するファイル」— 設定シート、
ログ、ツールに同梱される出力タブ — のとき、ThisWorkbook が正直な選択です。ActiveWorkbook が正しいのは、
本当に「ユーザーが手前に持ってきたもの」を意味するときだけです。どちらを意図したか迷ったなら、あなたが
意図したのは ThisWorkbook です。それは、あなたを驚かせられない唯一のものだからです。
知っておく価値のある親戚関係:ThisWorkbook は常にアクティブなものとは限らず、常に最初に開かれたものとも
限りません。単に、コードを持つものです。Macros.xlsm のマクロが Report.xlsx を開くと、新しいファイルが
ActiveWorkbook になりますが、ThisWorkbook は微動だにしません。
静かな罠:自分の席では動き、相手の席では壊れる
このバグが実際に出荷される経緯はこうです。あなたはブックを1つ — 自分のもの — だけ開いてマクロを書き、
テストします。ブックが1つのとき、アクティブなブックは あなたの ブックなので、限定なしの Range("A1") と
ThisWorkbook で限定したものは同じ挙動になります。すべてのテストが通ります。
やがて同僚が、ブックを3つ開いた状態でそれを実行します。いまや「アクティブ」は彼らが見ていたものであり、
限定なしの書き込みは 彼らの ファイルに着地し、あなたのマクロは触れるはずのなかったレポートのセルを
黙って上書きします。エラーは出ません — コードは書かれたとおり「アクティブなものに書き込む」を正確に実行
しただけです。直し方は On Error ハンドラーではありません。ブックを名無しのままにするのをやめることです。
' もろい - ユーザーが最後にクリックしたものに依存する
Range("A1").Value = total
' 堅牢 - 毎回、ブックとシートを名指しする
ThisWorkbook.Worksheets("Summary").Range("A1").Value = total
参照を限定すれば、マクロはどの席でも、いくつファイルを開いていても同じ挙動になります。だからこそ、
ブックレベルのVBAで最も価値ある習慣はこれです。Range や Cells の呼び出しを、ブックとシートを前に
置かずに漂わせてはいけません。
開いている別のブックを名前で参照する
ときには本当に 別の ブックが必要になります — ユーザーが開いたデータファイルや、あなた自身が開くものです。
ActiveWorkbook を経由して幸運を祈ってはいけません。名指しするか、ハンドルを保持してください。
Sub TalkToAnotherFile()
Dim src As Workbook
' すでに開いている? ファイル名(拡張子つき)で取得する
Set src = Workbooks("Sales.xlsx")
' まだ開いていない? 開いて、Open が返すハンドルを保持する
Set src = Workbooks.Open("C:\Data\Sales.xlsx")
' これで参照はすべて明示的 - どのファイルかを推測しない
Debug.Print src.Worksheets("Jan").Range("A1").Value
ThisWorkbook.Worksheets("Summary").Range("A1").Value = _
src.Worksheets("Jan").Range("A1").Value
End Sub
2つのルールがこれを安全にします。第一に、Workbooks("Sales.xlsx") はファイル名を 拡張子つきで
必要とし、ファイルはすでに開いていなければ Subscript out of range を投げます。第二に、Workbooks.Open
は開いたブックを 返します — それを同じ行で Set 変数に受け取れば、「今どれがアクティブか」を尋ねる
必要が二度となくなります。自分で Set したブック変数は、ThisWorkbook よりさらに優れています。不動で
かつ どのファイルを意味するかが明示的だからです。
意見:すべてを限定し、既定は ThisWorkbook
マクロのすべての参照は、そのブックとシートを名指しすべきで、既定のブックは ThisWorkbook にすべきです。
限定なしの参照は、持つ価値のある「短いコード」ではありません — それは、行が走るまさにその瞬間に正しい
ファイルがアクティブである、という賭けであり、その賭けは、誰かがファイルを2つ以上開いてマクロを実行した
日に負けます。
規律は小さく、見返りは永遠です。ターゲットがあなたのツールに属するなら ThisWorkbook に手を伸ばし、
特定の別ファイルを意味するなら Workbook 変数を Set し、ActiveWorkbook は「ユーザーが手前に持って
いるもの」が本当に正しいターゲットである稀なケースのために取っておきます。ブックを前に置かない裸の
Range は、未宣言の変数とまったく同じように、未完成の行として扱ってください。
本当の仕事が、正しいブックを選ぶことより大きいとき
参照を正しくするのは前提条件にすぎません。実際の仕事はたいてい、その上に載るロジックです — この2つの ファイルを突き合わせる、先月分の行を引っ張る、地域ごとに合計してサマリーへ入れる。それを手で書くとは、 ブック参照 も ループ も エッジケース も、毎回正しく仕上げるということです。 ExcelMaster なら、結果を普通の 言葉で説明するだけ — 「Sales.xlsx をこのファイルのサマリータブと比べて、一致しない行に印を付けて」 — で、 まずブックをバックアップしたうえでコードを書いて実行し、すべての参照をあなたの代わりに限定します。あなたは どのファイルを指すかを述べるだけ。この記事が扱っている配管は、ExcelMaster が引き受けます。
よくある質問
VBAのThisWorkbookとActiveWorkbookの違いは?
ThisWorkbook は常に実行中のコードを含むブックを指し、決して変わりません。ActiveWorkbook は行が走る
瞬間にいちばん手前にあるブックを指し、ユーザーが別のウィンドウをクリックしたり、コードが新しいファイルを
開くたびに変わります。マクロ自身のファイルを意味するなら ThisWorkbook を、本当に「ユーザーが手前に
持っているもの」を意味するときだけ ActiveWorkbook を使ってください。
ThisWorkbookは常にアクティブなブックですか?
いいえ。ThisWorkbook はコードを抱えるファイルで、アクティブなブックは手前にあるものです。両者が
一致するのは、たまたまマクロ自身のファイルが手前にあるときだけです。別のブックがアクティブになった瞬間 —
ユーザーがクリックした、あるいはマクロが開いた — 2つは別々のファイルを指します。
VBAで別のブックを参照するには?
すでに開いているなら、ファイル名と拡張子を付けて Workbooks("Name.xlsx") を使います。開いていないなら
Set wb = Workbooks.Open("C:\path\Name.xlsx") を使います — これはブックを返すので、ハンドルを保持
できます。あとはアクティブなブックに頼る代わりに、その変数を通してすべての参照を限定してください。
マクロが間違ったブックに書き込むのはなぜですか?
ほぼ必ず、Range や Cells の呼び出しの前にブックがなく、行が走るときにアクティブなものへ着地するから
です。ファイルを1つ開いてテストする間は動き、複数開いていると同僚のファイルに書き込みます。参照を
ThisWorkbook かブック変数で限定すれば、毎回正しいファイルに着地します。
ThisWorkbookはアドインでも使えますか?
はい、そしてまさにそこでこそ真価を発揮します。アドインでは ThisWorkbook はアドインファイル自身を指し、
ユーザーのデータは別のブックにあります。アドイン自身のリソースには ThisWorkbook を、ユーザーのデータには
Set したブック変数(または意図的に ActiveWorkbook)を使ってください。
検証環境
検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-09-07.
関連ガイド: VBA ActiveWorkbook · VBA Worksheets · VBA Workbook · VBA Range · VBA Dim
