If ブロックに対応する End If がありません。


Ifステートメントの書式

Ifステートメントの書式は次の通りです。

【書式1】
If 条件 Then 処理
【書式2】
If 条件 Then
    処理
End If
【書式3】
If 条件 Then
    処理1
Else
    処理2
End If

条件が正しいとき「処理1」を実行し、正しくなかったとき「処理2」を実行するような場合は【書式3】を使います。条件が正しかったときだけ「処理」を実行し、正しくなかったときは何もしないようなケースでは【書式2】か【書式1】を使いますが、「処理」が複数行になるときは【書式2】を使います。「処理」を1行で表せる場合は【書式1】の書き方ができます。もっとも、可読性や見栄えの目的で、「処理」が1行で表せる場合でも、あえて【書式2】を使うときもあります。

いずれにしても大事なことは、【書式1】では行末にEnd Ifをつけないということと、【書式2】と【書式3】では必ずEnd Ifが必要だということです。【書式2】と【書式3】でEnd Ifを書き忘れると、このエラーが発生します。

Endステートメント

もう少し細かい話をします。

Ifステートメントは、正式にはIf...Then...Elseステートメントといいます。よく見てください。If...Then...Else...Endステートメントではありません。If...Then...Elseステートメントです。【書式2】や【書式3】の最後につけるEnd Ifは、実はEndステートメントという、If...Then...Elseステートメントとは別のステートメントです。Endステートメントは、【書式2】や【書式3】のような、ブロック(命令の集まり)を終わらせる働きをします。

Select Caseステートメントを終わらせるEnd SelectもEndステートメントです。Withステートメントの最後に付けるEnd Withや、ユーザー定義型変数を定義するTypeステートメントを終わらせるEnd TypeもEndステートメントです。それだけでありません。プロシージャを定義するSubステートメントを終わらせるEnd SubもEndステートメントです。

このようにEndステートメントは、いろいろなブロックの終わりを表すための命令です。ちなみに、ただEndとだけ書くと、マクロの実行そのものを終わらせます。

【書式1】の最後にEnd Ifが必要ないのは、1行だけの「If 条件 Then 処理」はブロックではないからです。

エラーと認識される場所

この手の「○○に対する××がありません」的なエラーでは、実際のミスとは異なるメッセージが表示されるのでアテにならないと言われています。たとえば次のようなケースです。

ミスをしているのは、Ifステートメントの最後に付けるべきEnd Ifです。これがありません。なのに、エラーメッセージは「End Withに対するWithがありません」と、Withステートメントを犯人扱いし、ご丁寧にEnd Withを反転させて「ほら、ここだよ」と指摘しています。もちろん、これが冤罪なのは一目瞭然です。しかし、思い出してください。End IfもEnd Withも同じEndステートメントです。VBAは、おそらく次のように考えたのだと思われます。

このコードは、全体で次の3つのブロックに分割されています。

このようにブロックがネストしているコードでは、最も内側のブロックから先にコンパイルされます。このコードでは、Ifステートメントのブロックです。しかし、ここで注意が必要です。コードの可読性を高めるために、上図のコードは適所でインデントしたり改行していますが、VBAにとってはインデントは無視される存在です。どんなインデントをしても、VBAの実行には関係ないんです。上図は、VBAにとって次のように認識されます。

まずIfステートメントのブロックがコンパイルされます。Ifステートメントのブロックだけに注目すれば、これは次のようなコードと同じ意味になります。

これなら、確かに「End Withに対するWithがありません」と指摘されても納得です。実際に犯したミスは「End Ifがない」ことですが、その外側ブロックの「End With」に対するエラーが発生したのは、こういう理由です。一般的に「○○に対する××がありません」というエラーが発生したときは、VBAが指摘した項目の1つ内側のブロックに誤りがないかどうかをチェックしてください。

次のようなコードで試してみましょう。外側から「Subブロック」「Withブロック」「Select Caseブロック」「Ifブロック」に分かれていることに注目してください。

Sub Sample()
    With Range("A1")
        Select Case Range("B1")
        Case 1
            If Range("C1") = 100 Then
                .Value = "OK"
            Else
                .Value = "NG"
            End If
        End Select
    End With
End Sub

まず、最も内側の「End Ifがない」パターンです。

エラーの指摘は「End Select」ですから、その内側である「Ifブロック」に誤りがあります。

次に「End Selectがない」パターン。

これも、指摘された「End With」の内側にある「Select Caseブロック」が誤っています。

では「End Withがない」パターンではどうでしょう。

エラーメッセージは「End Withが必要です」と正しいですが、反転したのは、誤っている「Withブロック」の1つ外側である「End Sub」です。ここではシンプルな例で解説しましたが、実際のコードは複雑です。「○○に対する××がありません」エラーが発生したとき1つ内側のブロックの誤りをすぐ見つけるためにも、ブロックごとに適切なインデントをするよう心がけましょう。