オブジェクト変数または With ブロック変数が設定されていません。
エラー表示
このエラーが発生すると、マクロ起動時(コンパイル時)に次のエラーが表示されます。
実行時エラー '91'
オブジェクト変数または With ブロック変数が設定されていません。
エラーの発生理由について
Microsoft公式の解答
Microsoft公式によると次のようにあります。
オブジェクト変数を作成する手順には 2 つのステップがあります。 まず、オブジェクト変数を宣言する必要があります。 次に、Set ステートメントを使用してそのオブジェクト変数に有効な参照を代入する必要があります。
同様に、With...End With ブロックは、With ステートメントのエントリ ポイントを実行して初期化する必要があります。 このエラーの原因と解決策は次のとおりです。
(以下、続く…)
比較的分かりやすいですが、「Set ステートメント」とか「エントリ ポイント」等の初心者に優しくない単語がポツポツとありますね。詳しく見てみましょう。
【原因1】Setの記載漏れ
1つ目は単純に"Set"の記載漏れです。オブジェクト変数にオブジェクトの参照を格納する際には"Set"を付ける必要があります。
例1:Setによる初期化が出来ていない
'Arr(1) に 1を格納したかった
Sub Sample1()
Dim ws As Worksheet
'先頭に"Set" を忘れた(「Set ws = Worksheets("Sheet1")」が正しい)
ws = Worksheets("Sheet1")
ws.Cells(1, 1) = "a"
End Sub
【予防策】オブジェクト変数が空か確認する方法(変数 is Nothing)
【原因2】オブジェクト変数の初期化漏れ
オブジェクト変数にオブジェクトを代入せずにプロパティやメソッドを使用しようとすると、本エラーとなります。
例1:Withブロックで使う変数に、オブジェクトが代入されていない
'「book1」のSheet1のセルA1の値を表示したかった
Sub Sample2_1()
Dim ws As Worksheet
'Set ws = ThisWorkbook.ActiveSheet の代入を忘れている
ws.Cells(1, 2) = 2
End Sub
【予防策】オブジェクト変数が空か確認する方法(変数 is Nothing)
【原因3】With ブロックの変数の初期化漏れ
With ブロックを使用時「With 変数名」とした時、この変数名にオブジェクトの代入が漏れていると、メソッドやプロパティを使用しようとした時に本エラーが発生します。
例1:Withブロックで使う変数に、オブジェクトが代入されていない
'「book1」のSheet1のセルA1の値を表示したかった
Sub Sample3()
Dim ws As Worksheet
'Set ws = ThisWorkbook.ActiveSheet の忘れ
With ws '← wsがNothingの状態だが、まだエラーが発生しない
.Cells(1, 2) = 2 '← ここでエラーが発生する
End With
End Sub
【予防策】オブジェクト変数が空か確認する方法(変数 is Nothing)
【原因4】Gotoの使用により「With 変数」が出来てない
GoToを使用して、Withブロック外からWithブロック内へステップの移動をした時に、本エラーが発生します。なお、エラーハンドリング(エラートラップ)によるGoToの移動も同様に注意が必要です。
例1:GoToの使用により、Withブロックの設定が出来てない
'セルA2を指定したかった
Sub Sample4_1()
GoTo AAA
With ThisWorkbook.ActiveSheet '← GoToによりスキップされた'
'GoTo によるステップの移動で、With ThisWorkbook.ActiveSheetができていない
AAA:
.Cells(1, 2) = 2 '← ここでエラーが発生する
End With
End Sub
例2:エラートラップによるGotoの使用により、Withブロックの設定が出来てない
Sub Sample4_2()
On Error GoTo ErrTrap
Dim str As String
' VLookupで検索値が見つからない場合、エラーとなる
str = Application.WorksheetFunction.VLookup(1, Range("B3:D10"), 2, False)
' ↑でエラーとなった場合、↓のWith ThisWorkbook.ActiveSheetはスキップされる
With ThisWorkbook.ActiveSheet
.Cells(1, 2) = val
'エラートラップ(GoTo)により「With ThisWorkbook.ActiveSheet」がスキップされている
ErrTrap:
MsgBox .Cells(1, 2)
End With
End Sub
【原因5】Find等で返された変数がNothing
Findで検索すると、検索値のセルオブジェクトが返ってきます。しかし、検索値が見つからない場合は、Nothingが返ってきます。そのNothingを参照すると本エラーとなります。
例:Findで検索した結果、検索値が見つからず、Nothingを参照しようとした
Sub Sample5()
Dim rng As Range
'Findは検索範囲に検索値が見つからない場合、Nothingを返す
Set rng = Range("A1:A10").Find("存在しない記憶")
MsgBox rng.Address '← ここでエラーが発生する
End Sub
【原因6】Nothingで空にした後に、変数を使用
Nothingで空にした後にその変数を使用してしまったケースです。一度完成したマクロを修正する時等、加筆時にやりがちなので注意しましょう。
例1:セルの範囲の指定ミス
'セルA1~A3の範囲指定をしたかった
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
'変数ws をまだ使用するのに、Nothingで空にしている
Set ws = Nothing
ws.Cells(1, 2) = 3 '← ここでエラーが発生する
End Sub
解決方法は?
基本的にケアレスミスが原因となります。次のPointを確認してましょう。
Point!
まず、オブジェクト変数にオブジェクトの代入漏れを防ぐには『変数 is Nothing』で空か確認しましょう。
次に、エラートラップを除きGoToを使用しないようにします。エラートラップでGoToを使用する場合、ステップの移動先は「エラーログを残す」、「エラー内容を表示させる」等の単純な処理のみにしましょう。
オブジェクト変数 is Nothing
<オブジェクト変数 is Nothing>でオブジェクト変数が空の時、空の場合に「True」となります。 一般的に見やすさを重視して、この結果を逆にする反転演算子「Not」をつけます。 つまり、<Not オブジェクト変数 is Nothing>とすることで変数が空でない場合の操作ができます。
例1:オブジェクト変数が空か確認する『変数 is Nothing』
Sub SolutionSample1()
Dim ws As Worksheet
Set ws = ThisWorkbook.ActiveSheet
If Not ws Is Nothing Then
' 変数ws が空でない場合の処理
ws.Cells(1, 2) = 2
Else
' 変数ws が空の場合の処理
MsgBox "オブジェクト変数:ws が空です!"
End If
End Sub
Sub SolutionSample2()
Dim rng As Range
'Findは検索範囲に検索値が見つからない場合、Nothingを返す
Set rng = Range("A1:A10").Find("存在しない記憶")
' 変数rng が空か確認する
If Not rng Is Nothing Then
' 変数rng が空でない場合の処理
MsgBox rng.Address
Else
' 変数rng が空の場合の処理
MsgBox "検索値が見つかりません!"
End If
End Sub
このエラーの予防策
エラーが発生しそうなプログラムは重点的にテストを行いましょう。
不安な箇所は、Is Nothingでオブジェクトが空になっていないか確認をします。ただし、操作のたびにこの確認をしてしまうと処理が遅くなりますので極力重点的なテストで済ませましょう。
GoToは可読性を大きく下げ、エラーの原因となりえます。エラートラップ以外、極力使用しないようにしましょう。