0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VBAでシートモジュールを経由するとErr.Raiseのエラーを正しく捕捉できなかった話

0
Last updated at Posted at 2026-08-23

はじめに

クラスモジュールでチェックを行い、エラーの場合はErr.Raiseで独自のエラーを発生させるようにしていました。

呼び出し経路は以下の通りです。

  1. 標準モジュール
  2. シートモジュール
  3. クラスモジュール

この時、3で発生した例外が、1の標準モジュールで正しく捕捉できませんでした。

原因までは特定できていませんが、シートモジュールを経由してエラーが伝播すると、元のErr.Raiseで設定したエラーではなく、オートメーションエラーに置き換わることまでは確認できました。

発生したエラー

Excelには以下のような表があります。

EmployeeExcel

これらのデータが書いてあるシートモジュールにFindAllメソッドを定義し、Employeeクラスのリストに変換します。

' EmployeeSheet
Function FindAll() As Collection
    Dim lastRow As Long
    Dim i As Long
    
    Dim result As Collection
    Set result = New Collection
    
    lastRow = Me.Cells(Rows.Count, "A").End(xlUp).Row
    
    Dim emp As Employee
    For i = 2 To lastRow
        Set emp = New Employee
        ' 変換部
        emp.Id         = Me.Cells.item(i, 1)
        emp.Name       = Me.Cells.item(i, 2)
        emp.Department = Me.Cells.item(i, 3)
        emp.ManagerId  = Me.Cells.item(i, 4)
        emp.Email      = Me.Cells.item(i, 5)
        emp.Active     = Me.Cells.item(i, 6)
        
        result.Add emp
    Next i
    
    Set FindAll = result
End Function

Employeeクラスは以下の通りです。

Option Explicit

Private mId As Long
Private mName As String
Private mDepartment As String
Private mManagerId As Variant
Private mEmail As String
Private mActive As Boolean

' その他のアクセサーメソッドは省略しています
Public Property Let Department(ByVal value As String)
    If value = "" Then
        ' 例外発生
       Err.Raise vbObjectError + 513, "Employee.LetDepartment", "値が空欄です。"
    End If
    
    mDepartment = value
End Property

上記Excelデータの黄色セルではdepartment列を空欄に設定しているため、EmployeeクラスのLet Departmentメソッドで例外が発生します。

標準モジュールではこの例外を捕捉するように、On Error Go Toを利用しています。

Sub Main_Error()
On Error GoTo ErrHandler

  Dim result As Collection
  
  Set result = EmployeeSheet_Error.FindAll()
  
  Dim item As Employee
  
  For Each item In result
    Debug.Print item.Name
  Next item
Exit Sub

ErrHandler:
  ' 例外を捕捉
  MsgBox Err.Description, vbCritical
End Sub

この時、例外を捕捉し独誌のエラーメッセージ「値が空欄です。」が表示される想定でしたが、以下のメッセージが表示されました。

オートメーションエラーです。
イベントはどのサブスクライバーも呼び出すことができませんでした

ErrorMessage

回避方法

シートモジュールを経由するのをやめました。
ですので、標準モジュールに以下全てを書くようにしました。

Sub Main_Solution()
On Error GoTo ErrHandler

  Dim result As Collection

  ' 標準モジュールのFindAllを呼び出す。
  Set result = FindAll()
  
  Dim item As Employee
  
  For Each item In result
    Debug.Print item.Name
  Next item

Exit Sub
ErrHandler:
  MsgBox Err.Description, vbCritical
End Sub

Function FindAll() As Collection
    Dim lastRow As Long
    Dim i As Long
    
    Dim result As Collection
    Set result = New Collection
    
    lastRow = EmployeeSheet.Cells(Rows.Count, "A").End(xlUp).Row
    
    Dim emp As Employee
    For i = 2 To lastRow
        Set emp = New Employee

        emp.Id         = EmployeeSheet.Cells.item(i, 1)
        emp.Name       = EmployeeSheet.Cells.item(i, 2)
        emp.Department = EmployeeSheet.Cells.item(i, 3)
        emp.ManagerId  = EmployeeSheet.Cells.item(i, 4)
        emp.Email      = EmployeeSheet.Cells.item(i, 5)
        emp.Active     = EmployeeSheet.Cells.item(i, 6)
        
        result.Add emp
    Next i
    
    Set FindAll = result
End Function

シートモジュールを経由しないと正しいメッセージが表示されました。

image.png

実行環境

Microsoft 365 Apps for business

まとめ

なんだか、納得性の低い解決法になってしまいました。
シートモジュールに書きつつ、解決する方法ももしかしたらあるのかもしれません。

ちなみにサンプルでは1つの標準モジュールに書いてしまっていますが、実際にはEmployeeRepositoryという標準モジュールを作成してそこに記載しています。よく考えるとシートモジュールに書くより、分かりやすいのかもしれません。

何か知見のあるかたおりましたら、コメントしていただけると幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?