VBAでコードを書いているとき、実行前に突然表示される「コンパイルエラー: 参照が不正または修飾されていません」というメッセージ――このエラーは実行時エラーと違い、マクロを動かす前の段階でVBAが構文チェックを行い、コードに問題があると判断したときに発生します。エラーメッセージが抽象的で「どこが間違っているのか」が分かりにくいため、初心者だけでなく中級者でも原因の特定に時間を取られることがあります。本記事では、このコンパイルエラーが発生するすべての主要パターンを、その場でコピーして使える修正コードとともに体系的に解説します。


目次


コンパイルエラー「参照が不正または修飾されていません」とは何か

VBAのエラーには大きく分けて「コンパイルエラー」と「実行時エラー」の2種類があります。実行時エラー(1004・9・13・91・438など)はマクロを実行した後に発生しますが、コンパイルエラーは実行前にVBAがコードを解析するフェーズ(コンパイル)で検出されるため、1行たりとも実行されずにエラーが表示されます。

「参照が不正または修飾されていません(Invalid or unqualified reference)」というメッセージは、VBAが変数・プロパティ・メソッド・オブジェクトへの参照を解決できなかったときに表示されます。具体的には次のような状況が該当します。

  • Withブロックの外でピリオド(.)始まりのメンバー参照を記述した
  • 別のモジュール・プロシージャのスコープ内にある変数を外部から直接参照しようとした
  • 参照設定で登録されているライブラリが見つからなくなり、その型・定数が未解決になった
  • イベントプロシージャのシグネチャ(引数名・型)がExcelの期待するものと異なる
  • 列挙型(Enum)や定数(Const)を修飾せずに別モジュールから参照した
  • モジュール名とプロシージャ名・変数名が衝突している

コンパイルエラーはVBAエディタがコードを自動チェックする際にも発生します。コードを入力してEnterを押した瞬間にエラーが出る場合は、その行の構文に直接問題があります。一方、マクロを実行しようとしたタイミングで出る場合は、モジュール全体のコンパイル時に発見された問題です。


原因1:Withブロック外でのピリオド始まりの参照

「参照が不正または修飾されていません」が発生する原因として、もっとも多いのがWithブロックの外でピリオド始まりの参照を書いてしまうケースです。Withブロックの内部では .Value.Font.Bold のようにオブジェクトを省略してピリオドから書き始めることができますが、Withブロックの外でこの書き方をすると「何に対するプロパティか」をVBAが解決できずコンパイルエラーになります。

エラーが起きるコード例

' NG:Withブロックの外でピリオド始まりの参照を使っている
Sub CompileErrorExample()

    Dim ws As Worksheet
    Set ws = ThisWorkbook.Sheets(1)

    ' このWith以外の箇所でピリオド始まりを書いてしまっている
    .Value = "エラー"   ' → コンパイルエラー:参照が不正または修飾されていません

    With ws.Range("A1")
        .Value     = "正常"
        .Font.Bold = True
    End With

End Sub
' NG:Withブロックのネストがずれている
Sub NestedWithError()

    Dim ws As Worksheet
    Set ws = ThisWorkbook.Sheets(1)

    With ws
        With .Range("A1:C5")
            .Value = "データ"
        ' End With が1つ抜けている(Withブロックが閉じていない)
    End With

    ' ここ以降でWith外のピリオド参照とみなされてエラー
    .Cells(10, 1).Value = "ここでエラー"   ' → コンパイルエラー

End Sub

修正後のコード

' OK:Withブロックを正しく閉じる・ピリオド始まりはWith内にのみ書く
Sub CorrectWithUsage()

    Dim ws As Worksheet
    Set ws = ThisWorkbook.Sheets(1)

    ' With内のみでピリオド始まりを使う
    With ws.Range("A1")
        .Value          = "テスト"
        .Font.Bold      = True
        .Font.Size      = 12
        .Interior.Color = RGB(255, 255, 200)
    End With   ' ← End Withを忘れずに

    ' Withの外ではフルパスで記述する
    ws.Cells(10, 1).Value = "With外はフルパスで書く"

    Set ws = Nothing

End Sub
' OK:ネストしたWithブロックの正しい書き方
Sub CorrectNestedWith()

    Dim ws As Worksheet
    Set ws = ThisWorkbook.Sheets(1)

    With ws                           ' ← 外側のWith開始
        .Name = "整形済みデータ"

        With .Range("A1:C5")          ' ← 内側のWith開始
            .Value              = "データ"
            .Font.Name          = "メイリオ"
            .Font.Size          = 10

            With .Interior              ' ← さらに内側のWith開始
                .Color   = RGB(240, 248, 255)
                .Pattern = xlSolid
            End With                    ' ← 内側のEnd With(Interiorに対応)

        End With                       ' ← 内側のEnd With(Rangeに対応)

        .Cells(10, 1).Value = "完了"

    End With                          ' ← 外側のEnd With(wsに対応)

    Set ws = Nothing

End Sub

WithブロックのEnd With対応を確認するコツ

  • VBAエディタでWithの行にカーソルを置き、対応するEnd Withをコメントに書く習慣をつける(例:End With ' wsEnd With ' Range
  • インデントを統一することでWithブロックの深さを視覚的に把握しやすくなる
  • ネストが3段以上になる場合は、内側のWithを別プロシージャに分割することを検討する

原因2:スコープ外の変数・プロシージャへの参照

VBAの変数にはスコープ(有効範囲)があります。プロシージャ内で Dim で宣言した変数はそのプロシージャ内でしか使えません。これを別のプロシージャや別のモジュールから直接参照しようとするとコンパイルエラーになります。また、Private で宣言したモジュールレベル変数や Private Sub を外部から呼び出そうとしても同様です。

エラーが起きるコード例

' Module1 の内容
Sub ProcedureA()
    Dim localVar As String
    localVar = "ローカル変数"
End Sub

Sub ProcedureB()
    ' ProcedureAのlocalVarは別プロシージャのローカル変数なのでアクセス不可
    Debug.Print localVar   ' → コンパイルエラー(Option Explicit宣言時)
                           '    または実行時に空値(Option Explicit未宣言時)
End Sub
' Module1 の内容(Privateスコープの問題)
Private Sub PrivateHelper()
    Debug.Print "ヘルパー処理"
End Sub

' Module2 の内容
Sub CallFromOtherModule()
    ' Module1のPrivate Subは別モジュールから呼べない
    PrivateHelper   ' → コンパイルエラー:参照が不正または修飾されていません
End Sub

修正後のコード(スコープを適切に設計する)

' ========================================
' スコープ設計のベストプラクティス
' ========================================

' ---- Module1 ----

' モジュールレベルで共有したい変数はPublicまたはPrivateで宣言
' (プロシージャ外・モジュール先頭に記述)
Public  g_ProjectName As String    ' 全モジュールから参照可能
Private m_ModuleData  As String    ' このモジュール内からのみ参照可能

' 別モジュールから呼び出したいサブルーチンはPublic(またはSubのみ、デフォルトPublic)
Public Sub PublicHelper()
    Debug.Print "どのモジュールからでも呼べる"
End Sub

' このモジュール内からしか呼ばないサブルーチンはPrivateにする
Private Sub InternalHelper()
    Debug.Print "このモジュール内からしか呼べない"
End Sub

' データを渡し合うにはプロシージャの引数を使う
Public Sub ProcedureA(ByRef sharedData As String)
    sharedData = "Module1で設定したデータ"
End Sub

' ---- Module2 ----
Sub ProcedureB()
    ' 引数を介してデータを受け取る(スコープ外変数への直接アクセスは行わない)
    Dim data As String
    Call Module1.ProcedureA(data)   ' Module1.を付けてモジュール名を修飾
    Debug.Print data   ' → "Module1で設定したデータ"

    ' Publicな関数・サブルーチンは修飾なしでも呼べるが、明示的に修飾するほうが安全
    Call Module1.PublicHelper
End Sub

スコープの種類と使い分け

  • プロシージャスコープ(ローカル変数)Dim で宣言。そのプロシージャ内のみ有効。最も安全なスコープで基本はこれを使う
  • モジュールスコープ(モジュール変数)Private でモジュール先頭に宣言。そのモジュール内のすべてのプロシージャから参照可能
  • プロジェクトスコープ(グローバル変数)Public で標準モジュール先頭に宣言。すべてのモジュールから参照可能。乱用するとデバッグが困難になるため最小限に留める

原因3:参照設定が切れている(参照不可)

VBAプロジェクトの「参照設定」で登録した外部ライブラリ(ADODBやScripting Runtimeなど)が、別のPCへファイルを移動したりOfficeのバージョンが変わったりすることで見つからなくなると、そのライブラリが提供していた型・定数・クラスが未解決となりコンパイルエラーが発生します。参照設定ダイアログで「MISSING:」と表示されているライブラリがあれば、これが原因です。

確認手順と修正方法

  • VBAエディタのメニューから「ツール」→「参照設定」を開く
  • 一覧の中に 「MISSING: ライブラリ名」 と表示されているものがないか確認する
  • MISSINGになっている場合はチェックを外し、正しいバージョンのライブラリを改めてチェックして追加する

よく参照設定が切れるライブラリと対処法

' ----------------------------------------
' Microsoft Scripting Runtime(FileSystemObject用)
' ----------------------------------------
' 参照設定が切れている場合にコンパイルエラーになるコード
Dim fso As FileSystemObject   ' → MISSING時にコンパイルエラー

' 対処法1:参照設定を復元する
' ツール→参照設定→「Microsoft Scripting Runtime」にチェック

' 対処法2:参照設定なしで動作するようにCreateObjectを使う(遅延バインディング)
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")

If fso.FolderExists("C:\data") Then
    Debug.Print "フォルダが存在します"
End If
Set fso = Nothing
' ----------------------------------------
' Microsoft ActiveX Data Objects(ADODB用)
' ----------------------------------------
' 参照設定が切れている場合
Dim conn As ADODB.Connection   ' → MISSING時にコンパイルエラー
Dim rs   As ADODB.Recordset    ' → MISSING時にコンパイルエラー

' 対処法1:参照設定を復元する
' ツール→参照設定→「Microsoft ActiveX Data Objects X.X Library」にチェック

' 対処法2:遅延バインディングに切り替える(参照設定不要)
Dim conn As Object
Dim rs   As Object
Set conn = CreateObject("ADODB.Connection")
Set rs   = CreateObject("ADODB.Recordset")
' ----------------------------------------
' Microsoft Outlook Object Library(メール送信用)
' ----------------------------------------
' 参照設定が切れている場合
Dim olApp As Outlook.Application   ' → MISSING時にコンパイルエラー

' 遅延バインディングへの切り替え
Dim olApp As Object
Set olApp = CreateObject("Outlook.Application")

早期バインディングと遅延バインディングの使い分け

  • 早期バインディング(参照設定あり・Dim conn As ADODB.Connection):IntelliSenseが効く・コンパイル時に型チェックが行われる・処理が若干速い。ただし参照設定が切れるとコンパイルエラーになる
  • 遅延バインディング(参照設定なし・Dim conn As Object + CreateObject):IntelliSenseが効かない・コンパイル時の型チェックがない。ただし参照設定なしで動作するため、配布するファイルや異なるPC間で共有するファイルには遅延バインディングが安全
' ========================================
' 参照設定に依存しない汎用ファイル操作(遅延バインディング版)
' ========================================
Sub SafeFileOperation()

    Dim fso    As Object
    Dim folder As Object
    Dim file   As Object
    Dim path   As String

    path = ThisWorkbook.Path & "\output"
    Set fso = CreateObject("Scripting.FileSystemObject")

    ' フォルダが存在しない場合は作成
    If Not fso.FolderExists(path) Then
        fso.CreateFolder path
        Debug.Print "フォルダを作成しました: " & path
    End If

    ' フォルダ内のファイル一覧を取得
    Set folder = fso.GetFolder(path)
    For Each file In folder.Files
        Debug.Print file.Name & " (" & file.Size & " bytes)"
    Next file

    Set folder = Nothing
    Set fso    = Nothing

End Sub

原因4:イベントプロシージャの引数名・型の不一致

Excelのシートイベント(Worksheet_ChangeWorksheet_SelectionChange など)やブックイベント(Workbook_Open など)は、VBAが期待する正確なシグネチャ(プロシージャ名・引数名・引数の型)で記述しなければなりません。引数の型や名前を手入力で変えてしまうとコンパイルエラーが発生します。

エラーが起きるコード例

' NG:Worksheet_Changeの引数の型を誤って変更している
' 正しくは ByVal Target As Range だが、型や名前を変えてしまっている
Private Sub Worksheet_Change(ByVal changedCell As Range)   ' 引数名を変えた
    ' → コンパイルエラー:参照が不正または修飾されていません
    Debug.Print changedCell.Address
End Sub

' NG:引数の型を間違えている
Private Sub Worksheet_SelectionChange(ByVal Target As Variant)   ' RangeをVariantにした
    ' → コンパイルエラー
    Debug.Print Target.Address
End Sub

修正後のコード(正しいシグネチャで記述する)

' ========================================
' Excelイベントプロシージャの正しいシグネチャ一覧
' ========================================

' ---- シートモジュール(Sheet1など)に記述 ----

' セルの値が変更されたとき
Private Sub Worksheet_Change(ByVal Target As Range)
    If Target.Column = 1 Then   ' A列が変更された場合のみ処理
        Application.EnableEvents = False
        Target.Interior.Color = RGB(255, 255, 200)
        Application.EnableEvents = True
    End If
End Sub

' セルの選択範囲が変更されたとき
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    Application.StatusBar = "選択中: " & Target.Address
End Sub

' シートがアクティブになったとき
Private Sub Worksheet_Activate()
    MsgBox "このシートがアクティブになりました。", vbInformation
End Sub

' シートが非アクティブになったとき
Private Sub Worksheet_Deactivate()
    Application.StatusBar = False
End Sub

' ダブルクリックされたとき
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
    If Not Intersect(Target, Me.Range("A:A")) Is Nothing Then
        Cancel = True   ' デフォルトの編集モード移行をキャンセル
        MsgBox "A列がダブルクリックされました: " & Target.Address
    End If
End Sub

' 右クリックされたとき
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
    ' Cancel = True にするとデフォルトの右クリックメニューを非表示にできる
End Sub

' ---- ThisWorkbookモジュールに記述 ----

' ブックを開いたとき
Private Sub Workbook_Open()
    MsgBox "ブックが開かれました。", vbInformation
End Sub

' ブックを保存する前
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
    If SaveAsUI Then
        Cancel = True
        MsgBox "名前を付けて保存は禁止されています。", vbExclamation
    End If
End Sub

' ブックを閉じる前
Private Sub Workbook_BeforeClose(Cancel As Boolean)
    If MsgBox("本当に閉じますか?", vbYesNo) = vbNo Then
        Cancel = True
    End If
End Sub

' シートがアクティブになったとき(ブックレベル)
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
    Debug.Print Sh.Name & " がアクティブになりました"
End Sub

イベントプロシージャを安全に作成する方法

  • シートモジュール・ThisWorkbookモジュールを開き、コードウィンドウ左上のドロップダウンから「Worksheet」または「Workbook」を選択する
  • 右上のドロップダウンからイベント名(Change・SelectionChangeなど)を選択するとVBAが自動的に正しいシグネチャのひな形を生成する
  • 手入力でイベントプロシージャを書く場合は引数の型・名前を変更しない。引数名は自由に変えても動作するケースもあるが、型は変えてはいけない

原因5:列挙型・定数の修飾なし使用

別のモジュールやクラスで定義した列挙型(Enum)や定数(Const)を、修飾子なしで参照しようとしてVBAがどこで定義されたものか解決できないときにコンパイルエラーが発生します。特にクラスモジュールで定義したEnumを外部から参照するケースでよく起きます。

エラーが起きるコード例

' ---- クラスモジュール(clsOrder)の内容 ----
' クラス内でPrivateなEnumを定義
Private Enum OrderStatus
    Pending  = 0
    Approved = 1
    Shipped  = 2
    Completed = 3
End Enum

Public Function GetStatusName(status As OrderStatus) As String
    Select Case status
        Case Pending   : GetStatusName = "保留"
        Case Approved  : GetStatusName = "承認済"
        Case Shipped   : GetStatusName = "発送済"
        Case Completed : GetStatusName = "完了"
    End Select
End Function

' ---- 標準モジュールの内容 ----
Sub UseOrder()
    Dim order As New clsOrder

    ' PrivateなEnumは外部から参照できない
    Dim status As OrderStatus    ' → コンパイルエラー:参照が不正または修飾されていません
    status = Approved            ' → コンパイルエラー
End Sub

修正後のコード(PublicなEnumにするか標準モジュールに移動する)

' ========================================
' 方法1:EnumをPublicに変更する(クラスモジュールではEnum全体をPublicにできる)
' ========================================

' ---- 標準モジュール(ModuleEnums)の内容 ----
' クラスをまたいで使うEnumは標準モジュールにPublicで定義する
Public Enum OrderStatus
    Pending   = 0
    Approved  = 1
    Shipped   = 2
    Completed = 3
End Enum

Public Enum Priority
    Low    = 1
    Medium = 2
    High   = 3
End Enum

' ---- 標準モジュール(Main)の内容 ----
Sub UseOrder()

    ' 標準モジュールに定義したPublic Enumはどこからでも参照できる
    Dim status As OrderStatus
    status = Approved

    Debug.Print GetOrderStatusName(status)   ' → "承認済"

End Sub

Function GetOrderStatusName(status As OrderStatus) As String
    Select Case status
        Case Pending   : GetOrderStatusName = "保留"
        Case Approved  : GetOrderStatusName = "承認済"
        Case Shipped   : GetOrderStatusName = "発送済"
        Case Completed : GetOrderStatusName = "完了"
        Case Else      : GetOrderStatusName = "不明"
    End Select
End Function
' ========================================
' 方法2:定数をPublicで標準モジュールにまとめる
' ========================================

' ---- 標準モジュール(ModuleConstants)の内容 ----
' プロジェクト全体で使う定数はここに集約する
Public Const APP_NAME     As String = "売上管理システム"
Public Const VERSION      As String = "2.1.0"
Public Const MAX_ROWS     As Long   = 100000
Public Const DEFAULT_FONT As String = "メイリオ"
Public Const DEFAULT_SIZE As Long   = 10

' ---- 任意のモジュールから参照 ----
Sub UseConstants()
    Debug.Print APP_NAME & " v" & VERSION
    Debug.Print "最大行数: " & MAX_ROWS
End Sub

原因6:モジュール名・プロジェクト名の衝突

VBAプロジェクト内でモジュール名と変数名・プロシージャ名が同じになっている場合や、プロジェクト名が参照先のライブラリ名と衝突している場合にコンパイルエラーが発生することがあります。特にモジュールに「Worksheet」や「Workbook」「Range」のようなVBAの組み込みオブジェクト名と同じ名前を付けると衝突して意図しないコンパイルエラーが発生します。

エラーが起きるコード例

' NG:モジュール名にVBA組み込みオブジェクトと同じ名前を使っている
' モジュール名を「Worksheet」にすると、以降のコードで参照が曖昧になる
' (プロジェクトエクスプローラーでモジュール名を確認)

' NG:モジュール名と同じ名前の変数を宣言している
' モジュール名:DataManager
' そのモジュール内でDataManagerという変数を宣言すると衝突する
Dim DataManager As String   ' モジュール名と同名 → コンパイルエラーの原因になる場合がある

' NG:プロシージャ名とモジュール名が同じ
' モジュール名:Utility
' そのモジュール内にSub Utility()を定義すると参照が曖昧になる
Sub Utility()   ' モジュール名と同名 → コンパイルエラー
    Debug.Print "あいまいな参照"
End Sub

修正後のコード(命名規則を整備する)

' ========================================
' VBAモジュールの命名規則ベストプラクティス
' ========================================

' 標準モジュールの命名規則:
'   mod + 機能名(例:modMain, modUtility, modDatabase, modConstants)
'   ※「mod」プレフィックスを付けることでVBA組み込み名との衝突を防ぐ

' クラスモジュールの命名規則:
'   cls + クラス名(例:clsPerson, clsOrder, clsLogger)

' フォームモジュールの命名規則:
'   frm + フォーム名(例:frmSettings, frmInput)

' 変数の命名規則:
'   スコープ + 型 + 名前 の組み合わせ(例:g_strProjectName, m_lngRowCount)
'   ただし厳密でなくても、少なくともVBA組み込み名との衝突を避ける

' NG な名前(VBA組み込みと衝突する危険がある)
' モジュール名:Worksheet, Workbook, Range, Sheet, Module, Form
' 変数名:Name, Value, Index, Type, Error, Date

' OK な名前
' モジュール名:modSheetManager, modRangeHelper
' 変数名:targetName, cellValue, rowIndex, dataType, errMsg, targetDate
' ========================================
' プロジェクト名の確認と変更方法
' ========================================
' VBAエディタのメニュー:ツール → VBAProjectのプロパティ
' 「プロジェクト名」タブでプロジェクト名を確認・変更できる
'
' 参照しているライブラリ名(Excel, Word, MSForms など)と
' 同じプロジェクト名にしないこと
'
' 推奨プロジェクト名:
'   会社名_システム名(例:MyCompany_SalesManager)
'   または意味のある英語名(例:SalesReportSystem)

Option Explicitと変数宣言でコンパイルエラーを未然に防ぐ

Option Explicit をモジュールの先頭に記述すると、宣言されていない変数を使ったときにコンパイルエラーを発生させることができます。これにより、タイポによる変数名の誤りを実行前に検出でき、「参照が不正または修飾されていません」系のエラーを大幅に減らすことができます。

Option Explicitの設定方法

' ========================================
' モジュールの先頭に記述する(各モジュールに個別に設定が必要)
' ========================================
Option Explicit

' Option Explicitがあると、Dimで宣言していない変数を使うとコンパイルエラーになる
Sub WithOptionExplicit()

    ' NG:宣言なしに変数を使おうとするとコンパイルエラー
    ' toal = 100   ' ← "total"のつもりが"toal"とタイポ → コンパイルエラーで即検出

    ' OK:必ず宣言してから使う
    Dim total As Long
    total = 100
    Debug.Print total

End Sub
' ========================================
' すべての新規モジュールに自動でOption Explicitを追加する設定
' ========================================
' VBAエディタのメニュー:ツール → オプション → 編集タブ
' 「変数の宣言を強制する」にチェックを入れる
' → 以後、新しく作成するモジュールには自動でOption Explicitが追加される
'
' 既存モジュールには手動で追加が必要
' (全モジュールの先頭に「Option Explicit」と記述する)

Option Explicitと合わせて使う宣言のベストプラクティス

' ========================================
' モジュール先頭のテンプレート(コピーして使用)
' ========================================
Option Explicit
' Option Base 1   ' 配列を1始まりにする場合(プロジェクト統一が必要)

' ---- モジュールレベル定数 ----
Private Const MODULE_NAME As String = "modMain"

' ---- モジュールレベル変数 ----
' Private m_xxx As 型名

' ========================================
' プロシージャのテンプレート
' ========================================
Sub ProcedureTemplate()

    ' ---- ローカル変数の宣言 ----
    Dim ws      As Worksheet
    Dim rng     As Range
    Dim i       As Long
    Dim lastRow As Long
    Dim result  As Variant

    ' ---- 初期化 ----
    Application.ScreenUpdating = False
    Application.Calculation    = xlCalculationManual
    Application.EnableEvents   = False

    On Error GoTo ErrorHandler

    ' ===== メイン処理 =====

    ' =====================

    GoTo CleanUp

ErrorHandler:
    MsgBox "エラーが発生しました。" & vbCrLf & _
           "番号: " & Err.Number & vbCrLf & _
           "内容: " & Err.Description, vbCritical

CleanUp:
    Application.ScreenUpdating = True
    Application.Calculation    = xlCalculationAutomatic
    Application.EnableEvents   = True

    Set rng = Nothing
    Set ws  = Nothing

End Sub

オブジェクトブラウザと参照設定の確認方法

コンパイルエラーが発生したとき、原因が「参照設定の切れ」か「プロパティ名のミス」かを判別するためにオブジェクトブラウザと参照設定ダイアログを活用してください。

参照設定のMISSINGを確認する手順

  • VBAエディタのメニューから「ツール」→「参照設定」を開く
  • チェックリストの中に 「MISSING: ○○ Library」 と表示されているものがないか確認する
  • MISSINGになっている参照のチェックを外し、「OK」で閉じてコンパイルエラーが解消するか確認する
  • 必要なライブラリを改めて追加する場合は、参照設定ダイアログの「参照」ボタンからDLLファイルを探して追加する

オブジェクトブラウザで型・定数を確認する手順

  • VBAエディタで F2キー を押してオブジェクトブラウザを開く
  • 左上の検索ボックスにプロパティ名・定数名・クラス名を入力して Enter を押す
  • 検索結果にヒットするものがあればスペルは正しい。ヒットしない場合はスペルが間違っているか、そのライブラリが参照設定に追加されていない
  • 左のドロップダウンで「すべてのライブラリ」を選択すると参照設定にあるすべてのライブラリを横断して検索できる
' ========================================
' 参照設定の状態をイミディエイトウィンドウに出力する診断コード
' ========================================
Sub DiagnoseReferences()

    Dim ref As Object   ' VBComponent参照のためObject型で宣言

    Debug.Print "=== 参照設定の状態 ==="

    Dim vbProj As Object
    Set vbProj = ThisWorkbook.VBProject

    Dim refs As Object
    Set refs = vbProj.References

    Dim i As Integer
    For i = 1 To refs.Count
        Dim r As Object
        Set r = refs.Item(i)

        Dim status As String
        If r.IsBroken Then
            status = "*** MISSING ***"
        Else
            status = "OK"
        End If

        Debug.Print status & " | " & r.Name & " | " & r.Description
    Next i

    Debug.Print "====================="
    Set refs   = Nothing
    Set vbProj = Nothing

End Sub

デバッグ手順:コンパイルエラーの発生箇所を特定する

ステップ1:エラーダイアログで「OK」を押して問題箇所を確認する

コンパイルエラーが発生すると、エラーダイアログが表示されます。「OK」を押すとVBAエディタが開き、問題のある行または行の一部がハイライトされます。まずそのハイライト箇所を確認してください。

ステップ2:メニューから「デバッグ」→「VBAProjectのコンパイル」で全体確認

VBAエディタのメニューから「デバッグ」→「VBAProjectのコンパイル」を実行すると、プロジェクト全体をコンパイルして最初に見つかったエラー箇所をハイライトします。1つ修正したら再度コンパイルを実行して次のエラーを確認するというサイクルで問題を1つずつ解消してください。

ステップ3:問題のある行のコードを読み解く

' コンパイルエラー解析の思考フロー

' 1. ピリオドから始まる行でエラーが出ている
'    → Withブロックの外に書いてしまっていないかを確認
'    → 対応するEnd Withが抜けていないかを確認

' 2. 変数名・定数名・Enum名でエラーが出ている
'    → Option Explicitが有効なら宣言されていない変数
'    → 別モジュールのPrivate変数を参照しようとしている
'    → 参照設定が切れてライブラリの型が未解決になっている

' 3. イベントプロシージャの定義行でエラーが出ている
'    → 引数の型を変更してしまっていないかを確認
'    → ドロップダウンからシグネチャを自動生成し直す

' 4. モジュール・プロシージャ名の定義行でエラーが出ている
'    → VBA組み込み名と同じ名前を使っていないかを確認

ステップ4:切り分けのためにコードをコメントアウトする

' 問題の行が特定できない場合、疑わしい範囲をコメントアウトして
' コンパイルが通るかどうかで原因を切り分ける

Sub TroubleshootCompileError()

    Dim ws As Worksheet
    Set ws = ThisWorkbook.Sheets(1)

    ' 以下の行をコメントアウトしてコンパイルエラーが消えるか確認
    ' .Value = "テスト"           ' ← Withブロック外のピリオド参照?
    ' ws.UnknownProperty = True   ' ← 存在しないプロパティ?

    ' コメントアウトしてエラーが消えた行が原因行
    ' その行のコードを正しく修正してコメントを外す

End Sub

コンパイルエラーを防ぐコーディング規約チェックリスト

コンパイルエラー「参照が不正または修飾されていません」を未然に防ぐための、プロジェクト全体で実践すべきコーディング規約です。チームでVBAを開発・共有する場合には特に重要です。

  • すべてのモジュール先頭に Option Explicit を記述しているか(VBAエディタの「変数の宣言を強制する」設定も有効にする)
  • 変数はすべて Dim で宣言し、できるだけ具体的な型(WorksheetRangeなど)を指定しているか
  • Withブロックは必ず End With で閉じる。ネストしているときはコメントで対応関係を明示しているか(例:End With ' ws
  • ピリオド始まりの参照は Withブロックの内側にのみ書いているか
  • モジュール名・変数名・プロシージャ名に VBA組み込みオブジェクト名と同じ名前を使っていない
  • モジュール名に 「mod」「cls」「frm」などのプレフィックスを付けて組み込み名との衝突を回避しているか
  • イベントプロシージャは ドロップダウンから自動生成し、引数の型を手動で変更していないか
  • 外部ライブラリを使う場合、配布先のPCでも動作するよう遅延バインディングCreateObject)を使っているか
  • 参照設定に 「MISSING:」と表示されているライブラリがないことを確認しているか
  • Enumや共有定数は 標準モジュールにPublicで定義し、クラス内にPrivateで定義していないか
  • コードを修正したら 「デバッグ」→「VBAProjectのコンパイル」でプロジェクト全体をコンパイルして確認しているか
  • 別のPCや別のExcelバージョンで使う場合は、事前に動作確認をしているか

まとめ

VBAのコンパイルエラー「参照が不正または修飾されていません」は、実行時エラーと違ってコードを動かす前に発見できるエラーです。発生パターンを把握しておけば、原因の特定は難しくありません。本記事の要点をまとめると次のとおりです。

  • Withブロックのピリオド参照:ピリオド始まりの参照はWithブロック内にのみ書く。End Withの閉じ忘れに注意し、ネストするときはコメントで対応関係を明示する
  • スコープ管理:ローカル変数は外部から参照できない。共有したいデータは引数・Publicモジュール変数・戻り値で受け渡す。PrivateとPublicを明示的に使い分ける
  • 参照設定の切れ:「MISSING:」が表示されているライブラリをチェックし直す。配布するファイルは遅延バインディング(CreateObject)に切り替えると安全
  • イベントプロシージャ:シグネチャはドロップダウンから自動生成する。引数の型を手動で変更しない
  • Enum・定数のスコープ:プロジェクト全体で使うEnumや定数は標準モジュールにPublicで集約する
  • 命名の衝突:モジュール名・変数名にVBA組み込み名と同じ名前を使わない。プレフィックス(mod・cls・frm)で区別する
  • 予防策:全モジュールに Option Explicit を記述し、変数を具体的な型で宣言してIntelliSenseを有効にする。定期的に「デバッグ」→「VBAProjectのコンパイル」で全体チェックを行う

コンパイルエラーは実行前に発見・修正できるという点では実行時エラーよりも対処しやすい部類です。本記事のチェックリストとデバッグ手順を活用して、コンパイルが通らないコードを素早く修正し、安定したVBAプロジェクトを構築してください。