自ブックとそうでないブックの見分け方

複数のワークブックが開かれている状態でマクロを起動する時に意図しない結果になることを避ける方法です。

例えば、単純なシート間のセルの値の転記を考えてみましょう。


Option Explicit

Sub TEST()
     Worksheets("Sheet1").Range("$A$1").Value = _
         Worksheets("Sheet2").Range("$A$1").Value
End Sub
これは、Sheet2A1セルをSheet1A1セルに転記だけのマクロで、書いて動かしてみれば問題なく動くものです。

ですが、他のブックがアクティブになっている状態でこのマクロを起動しようとすると、
マクロの起動にブック名が付加されている
このように、マクロの起動のダイアログのマクロ(プロシージャ)の表示にブック名が付加されているのが判ります。これは、複数のワークブックが開かれている時に、同じプロシージャ名が存在してもどのブックのものかと明示するための表記です。
このサンプルではマクロは一つしかないので、そのまま起動させます。すると、
インデックスが有効範囲にありません。
このようにエラーになってしまいます。
ここでデバッグをクリックすると、

Option Explicit

Sub TEST()
     Worksheets("Sheet1").Range("$A$1").Value = _
         Worksheets("Sheet2").Range("$A$1").Value
End Sub
このように、動作の確認が取れている記述(黄色く表示される)がエラーとなります。何がいけないのでしょうか。

まず、Excelというアプリケーションの動作環境を考えて下さい。
Excelは複数のワークブックを同時に開いておけるわけです。
ですが、上記のマクロは、転記項目の指定にシート名とセル位置しか指定していないのです。
このように、ワークブックを明示しない(省略した)処理記述では、動作する時点でのアクティブなワークブックに対して動作します。ですから、アクティブなワークブックに「Sheet1」「Sheet2」がないので上記のエラーになるのです。

マクロの目的が、マクロを登録したブック(自ブック)に対して作用することだけををもくろんでいるなら、

Option Explicit

Sub TEST2()
     ThisWorkbook.Activate
     Worksheets("Sheet1").Range("$A$1").Value = _
         Worksheets("Sheet2").Range("$A$1").Value
End Sub
このように「ThisWorkbook」を指定して、自ブックをアクティブにしてから処理させるか、

Option Explicit

Sub TEST3()
     With ThisWorkbook
         .Worksheets("Sheet1").Range("$A$1").Value = _
             .Worksheets("Sheet2").Range("$A$1").Value
     End With
End Sub
シートの明示の上で、作用するワークブックを指定する必要があります。

この「ThisWorkbook」プロパティは、マクロが書き込まれている自身のワークブックオブジェクト返すので、自ブックを前提とするマクロでは、利用方法を考えて、ブックを明示した方が良いです。
一方、ワークブックを明示しなければ、アクティブなワークブックに対して処理されますが、これは「ActiveWorkbook」として明示可能です。

ただ、これでは記述が長くなるので、何度も参照する場合はシートをオブジェクト変数で明示させると良いでしょう。サンプル記述でも行の折り返しもなくなります。

Option Explicit

Sub TEST4()
     Dim objSh1 As Worksheet                                        ' 自ブックのSheet1
     Dim objSh2 As Worksheet                                        ' 自ブックのSheet2
     Set objSh1 = ThisWorkbook.Worksheets("Sheet1")
     Set objSh2 = ThisWorkbook.Worksheets("Sheet2")
     objSh1.Range("$A$1").Value = objSh2.Range("$A$1").Value
End Sub

※この場合、「SH1」「SH2」は共に「ThisWorkbook」の中のシートとして明示されていますが、別ブック間のデータ移送などでも利用できます。このような転記では、Withステートメントを使うにも、片側しか作用できませんが、このようにシートをオブジェクト変数に格納してしまえば済むわけです。

さて、では複数のワークブックが開かれている前提で、アクティブなブックが自ブックか判断するにはどうしたら良いのでしょう。

Option Explicit

Sub TEST5()
    Dim objWbk1 As Workbook                                         ' 自ブック
    Dim objWbk2 As Workbook                                         ' 現在ブック
    Set objWbk1 = ThisWorkbook
    Set objWbk2 = ActiveWorkbook
    ' 1つしか開いていないか
    If Workbooks.Count <= 1 Then
        MsgBox "2つ以上のブックを開いてから起動させて下さい。", vbExclamation
        Exit Sub
    ElseIf objWbk1.Name = objWbk2.Name Then
        MsgBox "本ブック以外のブックをアクティブにして下さい。", vbExclamation
        Exit Sub
    End If
    ' 自ブックをアクティブに
    MsgBox "本ブックをアクティブにします。", vbInformation
    objWbk1.Activate
    ' 元アクティブだったブックを戻す
    MsgBox "元アクティブだったブックを戻します。", vbInformation
    objWbk2.Activate
End Sub
このようなサンプルで理解していただけると思います。