VBA 오류 처리(On Error) 핵심 정리 — 매크로가 중간에 멈추지 않게

VBA에서 On Error Resume Next를 넓게 남기면 실패한 작업을 성공처럼 지나칠 수 있습니다. 이 글은 존재하지 않는 시트 조회와 연습 파일 열기를 나누어 오류 정보를 보존하고, 성공·실패 양쪽에서 Excel 상태를 복원하는 구조를 보여 줍니다. 원본 파일을 고치거나 오류를 무시해 완료 메시지를 만드는 방식은 쓰지 않습니다.

실습 파일과 두 진입점 준비

Windows 데스크톱 Excel에서 빈 매크로 사용 통합 문서를 연습_OnError.xlsm으로 저장합니다. Alt+F11 → 삽입 → 모듈에서 아래 코드를 넣습니다. 첨부 ErrorPractice.bas를 텍스트 편집기로 열어 복사할 때는 파일 가져오기용 첫 Attribute VB_Name 줄을 제외합니다. 한글 이름이 깨지면 실행 전에 월별집계, 원본.xlsx 문자열을 다시 확인합니다.

월별집계 시트조회와 원본파일 읽기오류를 분리하고 저장없이 닫아 원본을 보존하는 설명 도해
월별집계 시트조회와 원본파일 읽기오류를 분리하고 저장없이 닫아 원본을 보존하는 설명 도해. 가상 예제를 설명하는 도해이며 실제 앱 실행 결과 화면이 아닙니다.
진입점 연습 입력 코드가 바꾸는 범위
CheckSummarySheet 월별집계 시트 유무 시트가 있을 때만 A1에 OK
OpenPracticeFile 같은 폴더의 원본.xlsx 유무 읽기 전용으로 연 메모리상의 첫 시트 A1; 파일에는 저장하지 않음

두 예제를 분리했으므로 월별집계 시트가 없는 경우와 원본.xlsx 파일이 없는 경우를 같은 원인으로 취급하지 않습니다. 실무 파일 대신 빈 연습 파일을 사용하고, 파일을 자동 생성하거나 삭제하는 코드가 없음을 먼저 확인합니다.

오류 정보를 먼저 저장하는 전체 코드

오류번호와 설명을 먼저 보관하고 CleanUp으로 복귀해 설정복원을 시도하는 설명 도해
오류번호와 설명을 먼저 보관하고 CleanUp으로 복귀해 설정복원을 시도하는 설명 도해. 가상 예제를 설명하는 도해이며 실제 앱 실행 결과 화면이 아닙니다.
Option Explicit

Public Sub CheckSummarySheet()
    Dim ws As Worksheet, code As Long, detail As String
    On Error Resume Next
    Err.Clear
    Set ws = ThisWorkbook.Worksheets("월별집계")
    code = Err.Number
    detail = Err.Description
    On Error GoTo 0
    If code <> 0 Then
        Debug.Print code, detail
        MsgBox "월별집계 시트 조회 실패. 시트 이름을 확인하세요. 오류=" & CStr(code), vbExclamation
        Exit Sub
    End If
    ws.Range("A1").Value = "OK"
    MsgBox "월별집계!A1 = OK"
End Sub

Public Sub OpenPracticeFile()
    Dim wb As Workbook, openBook As Workbook, path As String
    Dim previousUpdating As Boolean, previousEvents As Boolean
    Dim previousSecurity As Long, code As Long, detail As String
    Dim cleanupCode As Long
    previousUpdating = Application.ScreenUpdating
    previousEvents = Application.EnableEvents
    previousSecurity = Application.AutomationSecurity
    On Error GoTo Failed
    If Len(ThisWorkbook.Path) = 0 Then Err.Raise vbObjectError + 1060, , "Save the practice XLSM first."
    path = ThisWorkbook.Path & Application.PathSeparator & "원본.xlsx"
    If Len(Dir$(path)) = 0 Then Err.Raise vbObjectError + 1061, , "Practice source is missing."
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    Application.AutomationSecurity = 3
    For Each openBook In Application.Workbooks
        If StrComp(openBook.FullName, path, vbTextCompare) = 0 Then
            Err.Raise vbObjectError + 1062, , "Practice source is already open. Close it yourself before retrying."
        End If
    Next openBook
    Set wb = Workbooks.Open(path, UpdateLinks:=0, ReadOnly:=True)
    wb.Worksheets(1).Range("A1").Value = "검산"
    wb.Close SaveChanges:=False
    Set wb = Nothing
CleanUp:
    On Error Resume Next
    Err.Clear
    If Not wb Is Nothing Then wb.Close SaveChanges:=False
    cleanupCode = Err.Number
    Application.ScreenUpdating = previousUpdating
    Application.EnableEvents = previousEvents
    Application.AutomationSecurity = previousSecurity
    On Error GoTo 0
    If code <> 0 Then
        Debug.Print code, detail
        MsgBox "실행 중단. 연습 파일 위치와 접근 권한을 확인하세요. 오류=" & CStr(code), vbExclamation
    ElseIf cleanupCode = 0 Then
        MsgBox "정상 종료: 원본 파일을 저장하지 않았습니다."
    End If
    If cleanupCode <> 0 Then MsgBox "연습 파일 닫기 실패. 열린 파일을 확인하고 변경 내용을 저장하지 마세요.", vbExclamation
    Exit Sub
Failed:
    code = Err.Number
    detail = Err.Description
    Resume CleanUp
End Sub

CheckSummarySheet는 시트 조회 직전 Err.Clear를 실행하고 조회 직후 번호와 설명을 지역 변수에 저장합니다. 그 뒤 On Error GoTo 0으로 좁은 무시 구간을 닫습니다. 이 구문은 0번 줄로 점프하는 명령이 아닙니다. 저장한 오류가 있으면 새 시트를 만들지 않고 안내 후 종료합니다.

OpenPracticeFile은 파일 열기·쓰기·닫기에서 생긴 오류를 Failed로 보내고 Resume CleanUp으로 정리 구간에 복귀합니다. 정리에서 원본을 저장하지 않고 닫으며, 닫기 자체의 오류를 cleanupCode로 별도 보관합니다. 처리기가 이미 활성인 채 닫기를 시도하다 두 번째 오류가 나서 상태 복원을 건너뛰는 문제를 줄이기 위한 구조입니다.

시트 조회의 실패와 정상 값을 대조

원본.xlsx 재개방값·Excel세설정·닫기실패·기존창을 각각 확인하는 설명 도해
원본.xlsx 재개방값·Excel세설정·닫기실패·기존창을 각각 확인하는 설명 도해. 가상 예제를 설명하는 도해이며 실제 앱 실행 결과 화면이 아닙니다.
  1. 월별집계라는 시트가 없는 상태에서 CheckSummarySheet를 실행합니다. 조회 실패 안내가 나오고 새 시트가 생기지 않아야 합니다.

  2. 연습 파일에 월별집계 시트를 직접 추가합니다. A1의 값이 덮어써질 수 있으므로 빈 연습 셀인지 확인합니다.

  3. 같은 매크로를 다시 실행합니다. A1이 정확히 OK이고 메시지가 월별집계!A1 = OK이면 정상 경로의 기대 결과입니다.

  4. 다른 업무 시트의 값을 확인하려고 시트 이름만 바꾸지 않습니다. 그 이름의 A1을 실제로 수정하는 코드라는 점을 먼저 검토합니다.

오류 번호는 발생한 정확한 문장과 같이 읽습니다. 시트 조회에서 나온 번호만 외워 파일 열기·권한 문제에 그대로 적용하지 않습니다. 상세 설명은 직접 실행 창의 Debug.Print로 확인하며 사용자 메시지는 경로 전체를 표시하지 않습니다.

파일을 저장하지 않았는지 재개방으로 확인

OpenPracticeFile의 정상 시나리오에는 별도로 만든 원본.xlsx가 필요합니다. 파일 첫 시트 A1에 원본을 입력하고 연습_OnError.xlsm과 같은 폴더에 저장합니다. 코드가 A1을 일시적으로 검산으로 바꾸지만 SaveChanges:=False로 닫으므로 다시 열었을 때는 원본이어야 합니다.

본문 코드는 이미 열려 있는 원본을 먼저 거르는 검사를 추가한 버전입니다. 다운로드 ZIP의 ErrorPractice.bas도 현재 본문과 같은 코드입니다. 이전 ZIP의 BAS를 가져왔던 사본은 해당 모듈의 전체 코드를 교체하고 이름이 같은 매크로를 중복 추가하지 마세요. 원본.xlsx가 같은 Excel 인스턴스에 열려 있으면 중단하고 직접 실행 창에 원인을 남기며, 사용자가 편집 내용을 먼저 저장하거나 별도 보관한 뒤 직접 닫도록 합니다. 읽기 전용 열기 옵션을 지정했다고 기존 창의 미저장 편집까지 보호되는 것으로 가정하지 않습니다.

검사는 현재 인스턴스의 FullName과 경로 문자열을 비교합니다. 네트워크 드라이브·UNC 별칭이나 다른 인스턴스까지 파일 동일성을 판별하는 잠금 장치는 아닙니다. 실제 VBA 실행은 미검증이며, 연습 사본에서 먼저 원본을 열어 둔 경우의 중단과 원본을 닫은 경우의 정상 경로를 각각 확인하세요.

입력 또는 확인 시점 기대 결과
XLSM이 아직 저장되지 않음 실행 중단 안내; 파일 열기 없음
같은 폴더에 원본.xlsx 없음 실행 중단 안내; 새 파일 없음
원본.xlsx의 첫 시트 A1=원본 정상 종료 안내
실행 뒤 원본.xlsx 재개방 A1은 여전히 원본
실행 전·후 Excel 설정 ScreenUpdating, EnableEvents, AutomationSecurity 각각 이전 값

재개방 값이 검산이라면 저장하지 않는다는 계약을 어긴 것입니다. 성공 팝업만 보고 통과시키지 마세요. 이 표는 실제 Excel 실행 기록이 아니라 복사본에서 대조할 기대값입니다. 첨부 코드의 정적 검토는 했지만 Excel/VBA 실행은 아직 확인하지 않았습니다.

정리 실패가 남았을 때의 한계와 복구

파일 닫기가 실패하면 별도 안내가 나오므로 열려 있는 연습 통합 문서를 확인하고 변경 내용을 저장하지 않습니다. 오류 처리기가 파일 시스템의 모든 상태를 되돌리는 트랜잭션을 제공하는 것은 아닙니다. Excel 강제 종료나 외부 COM 오류까지 복원을 보장하지 않습니다.

권한이 없는 폴더·암호 파일·네트워크 경로는 이 입력으로 검증하지 않았습니다. 경로와 접근 권한을 확인한 뒤 연습용 로컬 파일에서 재현하세요. 자동 덮어쓰기, 삭제, 보안 설정 전체 해제는 복구 단계에 포함하지 않습니다. 다른 프로시저를 추가한다면 그 프로시저의 오류 처리와 반환 계약도 따로 점검해야 합니다.

구문의 공식 정의

Microsoft On Error 문서와 Workbooks.Open 문서에서 API 범위를 확인할 수 있습니다. 이 예제는 런타임 오류 흐름을 설명합니다. 운영체제 API가 예외 대신 실패 값을 반환하는 경우에는 그 API의 반환값 검사까지 별도로 필요합니다.

On Error GoTo 0은 현재 프로시저의 오류 처리기를 비활성화합니다. Workbooks.Open의 ReadOnly 인수는 읽기 전용으로 여는 옵션입니다.

출처 원문 수집일: S1 2026-09-23; S2 2026-09-23.

작성자 소개