Access VBAで「ユーザー定義型が定義されていません」clsMoldを引数にすると出る原因と解決策

Access VBAで自作クラスを引数型に指定した瞬間に「ユーザー定義型が定義されていません(User-type not defined)」が出ると、つい「参照設定(ツール > 参照設定)の追加が必要?」と考えがちです。ですが、As clsMold のように“クラス名っぽい型”で起きる場合、原因はもっと単純で、プロジェクト内にそのクラスが無い・名前が違う・外部プロジェクトとして見えていない、のどれかであることがほとんどです。

目次

よくある再現例:「As clsMold」でコンパイルが止まる

たとえば次のように、独自クラス型を引数にした関数を作るとします。

Function BuildSQLInsertNewMold(objCurrMold As clsMold) As String
    ' ここでINSERT文を組み立てる想定
End Function

このときVBAが clsMold という型を解決できないと、コンパイル時点で「User-type not defined(ユーザー定義型が定義されていません)」になります。結論から言うと、ここで必要なのは参照設定の追加ではなく、まず clsMold という“クラス”が存在して、正しい名前で認識されている状態 を作ることです。

まず押さえる:VBAの「型」はどこから来るのか

VBAで型が解決されるルートは大きく3つです。

型の出どころAccess VBAでの扱い
標準ライブラリ/参照ライブラリDAO.Database / ADODB.Connection / Excel.Application参照設定で解決されることが多い
自作クラス(クラスモジュール)clsMold / clsLogger同一プロジェクト内にクラスモジュールが必要
ユーザー定義型(Type…End Type)Public Type TMold … End Type標準モジュール内で定義する(クラスとは別物)

今回の clsMold は、一般的には 「自作のクラスモジュール名」 を指します。つまり、そのクラスモジュールが無いなら必ず落ちます

原因の最優先チェック:clsMold というクラスモジュールが“存在しない”

クラスモジュールを作っていない(コードだけコピーした)

どこかのサンプルコードから関数だけコピーした場合、クラス側(clsMold)がプロジェクトに入っていないケースが頻発します。AccessのVBE(VBAエディター)で次を確認してください。

  1. VBEを開く(Alt + F11)
  2. プロジェクトエクスプローラーで「クラス モジュール」に clsMold が存在するか確認
  3. 無ければ「挿入」→「クラス モジュール」で作成

この時点で As clsMold のエラーが消えるなら、原因はほぼ確定です。

“モジュール名” と “(Name)プロパティ” が一致していない

クラスモジュールを作っていても、プロパティウィンドウの (Name) が clsMold になっていない と同じエラーになります。ここが最大の落とし穴です。

  • クラスモジュールをクリック
  • プロパティウィンドウで (Name) を確認
  • 厳密に clsMold になっているかチェック(綴り違いがNG)

大文字小文字は通常気にしなくてOKですが、clsMord / clsModl のような綴り違いは一発で詰みます。

次に多い:参照設定の「MISSING」で別の型解決が崩れている

「clsMoldがあるのにエラーが出る」場合は、参照設定の問題が“間接的に”影響している可能性があります。特に、VBAはコンパイルが通っていないと型情報が正しく更新されず、結果として関係ない場所で「ユーザー定義型が定義されていません」に見えることがあります。

チェック手順

  1. VBEの「ツール」→「参照設定」を開く
  2. リスト上部に MISSING: 〜 がないか確認
  3. あればチェックを外す、または正しいライブラリに差し替える
  4. 「デバッグ」→「コンパイル(VBAProjectのコンパイル)」を実行

この「コンパイル」は地味に重要です。Accessはオブジェクト(フォーム/レポート)側にもモジュールがぶら下がり、どこか1か所でも壊れていると全体が不安定になりがちです。

“同名”トラップ:標準モジュール名が clsMold になっている

意外にやりがちなのが、標準モジュール(Module)を clsMold という名前にしている パターンです。標準モジュール名は型になりません(Type定義をしていない限り)。

やりたいこと必要なものモジュール種類
プロパティやメソッドを持つ“オブジェクト”clsMold クラスクラスモジュール
構造体っぽい入れ物(メソッド無し)Public Type TMold標準モジュール

もし標準モジュールが clsMold という名前なら、クラスモジュール側を別名にするか、標準モジュールの方を modMold などに改名して衝突を避けるのが安全です。

外部のAccessファイルに clsMold がある場合:参照追加だけでは足りないことがある

質問文の「参照設定で追加すれば解決する?」は、clsMold が別のACCDB/MDB側にある 場合に成立します。ただし、ここには追加の条件があります。

外部プロジェクト参照の基本

  • 参照元と参照先の両方を開いた状態で、参照元のVBEで「ツール → 参照設定」
  • 一覧に VBAProject(参照先ファイル名) のような項目が出る場合があるのでチェック
  • 参照先のクラスが外部から見える状態である必要がある

外部から見える状態とは(よく詰まるポイント)

参照先が「自分の中だけで使う設計」になっていると、参照を付けても型として認識できないことがあります。環境により表示項目は異なりますが、少なくとも次は意識してください。

  • クラスモジュールやメンバーが Private 扱いになっていないか
  • 参照先をACCDE化している場合、参照元から利用できる設計か
  • 参照先を開いていないと参照できない構成になっていないか(開き方・信頼済みか)

外部参照は便利ですが、運用面(配布・更新・信頼設定・バージョン差)で詰まりやすいので、まずは同一プロジェクトにクラスを入れて解決するのが最短ルートです。

最短で切り分ける:即席テストコード

「本当に clsMold が認識されているか」を切り分けるには、イミディエイトウィンドウ(Ctrl + G)や小さなテストプロシージャが有効です。

Public Sub TestClsMold()
    Dim m As clsMold
    Set m = New clsMold
    Debug.Print TypeName(m)
End Sub

これがコンパイル/実行できれば、少なくとも clsMold は型として解決できています。逆に、この段階で止まるなら、クラスモジュールの存在・名前・参照・MISSING を上から順に疑うのが正攻法です。

「クラス」と「ユーザー定義型(Type)」は別物:混同を防ぐ

エラーメッセージが「ユーザー定義型」と言っているせいで、Type 文の話に引っ張られがちですが、今回の主役は“クラス”です。とはいえ、設計によっては Type の方が適していることもあります。

クラスが向いているケース

  • 入力値の検証(例:型番のルールチェック)を持たせたい
  • SQL生成・整形・ログ出力などの振る舞いをまとめたい
  • プロパティ変更時に関連値を更新したい

Typeが向いているケース

  • 単純なデータの入れ物で、処理は別モジュールに置く
  • 大量に生成して高速に扱いたい(オブジェクト生成コストを減らす)
  • API宣言などで構造体が必要

「SQLを組み立てる」目的なら、clsMoldに“SQL用の整形メソッド”を持たせる など、クラス設計のメリットが出やすいです。

実用例:clsMold を引数にSQLを作るときの安全な書き方

ここからは、エラー解消後に「実際どう書くと事故りにくいか」を具体化します。AccessのSQL生成で多い事故は、シングルクォート、Null、日付(#) の扱いです。SQLインジェクション対策という意味でも、文字列を安易に連結しない工夫が必要です(最優先はクエリパラメータですが、どうしても文字列生成が必要な場面もあります)。

clsMold(例)

クラスモジュール clsMold を作成し、最低限のプロパティを置いた例です。

'=== Class Module: clsMold ===
Option Explicit

Private mMoldId As Long
Private mMoldName As String
Private mCreatedAt As Date
Private mIsActive As Boolean

Public Property Get MoldId() As Long
    MoldId = mMoldId
End Property
Public Property Let MoldId(ByVal v As Long)
    mMoldId = v
End Property

Public Property Get MoldName() As String
    MoldName = mMoldName
End Property
Public Property Let MoldName(ByVal v As String)
    mMoldName = v
End Property

Public Property Get CreatedAt() As Date
    CreatedAt = mCreatedAt
End Property
Public Property Let CreatedAt(ByVal v As Date)
    mCreatedAt = v
End Property

Public Property Get IsActive() As Boolean
    IsActive = mIsActive
End Property
Public Property Let IsActive(ByVal v As Boolean)
    mIsActive = v
End Property

SQL整形用のヘルパー(標準モジュール)

SQL文字列生成をするなら、整形はヘルパーに寄せて“同じ地雷を何度も踏まない”のがコツです。

'=== Standard Module: modSqlHelper ===
Option Explicit

Public Function SqlText(ByVal v As Variant) As String
    If IsNull(v) Then
        SqlText = "NULL"
    Else
        SqlText = "'" & Replace(CStr(v), "'", "''") & "'"
    End If
End Function

Public Function SqlNumber(ByVal v As Variant) As String
    If IsNull(v) Or (Len(Trim$(v & "")) = 0) Then
        SqlNumber = "NULL"
    Else
        SqlNumber = CStr(v)
    End If
End Function

Public Function SqlDate(ByVal v As Variant) As String
    If IsNull(v) Then
        SqlDate = "NULL"
    Else
        ' Access SQL: #yyyy-mm-dd hh:nn:ss#
        SqlDate = "#" & Format$(CDate(v), "yyyy-mm-dd hh:nn:ss") & "#"
    End If
End Function

Public Function SqlBool(ByVal v As Variant) As String
    If IsNull(v) Then
        SqlBool = "NULL"
    Else
        SqlBool = IIf(CBool(v), "True", "False")
    End If
End Function

本題:clsMold を引数にした関数(完成形)

Public Function BuildSQLInsertNewMold(ByVal objCurrMold As clsMold) As String
    Dim sql As String


sql = "INSERT INTO T_Mold (MoldId, MoldName, CreatedAt, IsActive) VALUES ("
sql = sql & SqlNumber(objCurrMold.MoldId) & ", "
sql = sql & SqlText(objCurrMold.MoldName) & ", "
sql = sql & SqlDate(objCurrMold.CreatedAt) & ", "
sql = sql & SqlBool(objCurrMold.IsActive)
sql = sql & ");"

BuildSQLInsertNewMold = sql


End Function

これで、clsMold が正しく定義されている限り、As clsMold で落ちることはありません。さらに、SQL文字列の整形も一貫するため、現場でありがちな「ある画面は動くが別画面でコケる」系の事故が減ります。

まだ直らないときのチェックリスト(上から順に潰す)

最後に、現場での“詰まりポイント”を短い手順にまとめます。

症状最優先で見る場所対処
As clsMold で即エラークラスモジュールの有無クラスモジュールを作成/インポート
クラスはあるのにエラー(Name) プロパティ(Name)=clsMold に合わせる
環境によって出たり消えたり参照設定のMISSINGMISSINGを解消してコンパイル
別DBのclsMoldを使いたい外部参照の可視性参照追加+外部公開できる設計にする
同名のモジュールがある標準モジュール名modMold などに改名して衝突回避

まとめ:参照設定より先に“クラスの存在と名前”を疑う

Function ... (objCurrMold As clsMold) で「ユーザー定義型が定義されていません」が出たとき、最初にやるべきことは参照設定の追加ではなく、clsMold というクラスモジュールがプロジェクト内に存在し、(Name) が一致しているか を確認することです。そこを通過した上で、MISSING参照や外部プロジェクト参照など“次の層”を疑うと、最短で原因に到達できます。

もし今後、同様のSQL生成やデータ受け渡しが増えるなら、クラス+SQLヘルパー の組み合わせは保守性が上がりやすい構成です。まずは TestClsMold のような小さな検証から始めて、型解決ができている状態を作っていきましょう。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次