Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)
(시리즈 글이 3개 있습니다.)
디버깅 기술: 20. 예외 처리를 방해하는 WPF Modal 대화창
; https://www.sysnet.pe.kr/2/0/619

.NET Framework: 148. WPF - 데이터 바인딩 시의 예외 처리 방법
; https://www.sysnet.pe.kr/2/0/746

.NET Framework: 656. Windows Forms의 오류(Exception) 처리 방법에 대한 차이점 설명
; https://www.sysnet.pe.kr/2/0/11198




Windows Forms의 오류(Exception) 처리 방법에 대한 차이점 설명

다음의 질문에 달린 덧글에,

프로그램 비정상 종료 메시지 창 없애는 방법
; https://www.sysnet.pe.kr/3/0/4830

0으로 나누기 했을때의 메시지 창과 비정상 종료했을 때의 메시지 창 유형이 다르다고 나옵니다.

사실 이것은 0으로 나누기에 대한 문제가 아니라 Windows Forms이 제공하는 환경 위에서 오류가 발생했냐/안 했냐의 문제입니다. 예를 한번 들어 볼까요? ^^

간단하게 Windows Forms 위에 버튼을 하나 두고, 그 버튼 Click 이벤트에 다음의 코드를 넣어 실행해 봅니다.

private void button1_Click(object sender, EventArgs e)
{
    int a = 5;
    int b = 0;

    int c = a / b;
}

(버튼을 누르면, 당연히) 다음과 같은 오류 대화창이 뜨고,

error_handler_1.png

이때 Visual Studio를 이용해 디버거를 붙여 콜 스택을 확인하면 그 이유를 조사할 수 있습니다.

System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(System.IntPtr dwComponentID, int reason, int pvLoopData)  Unknown
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason, System.Windows.Forms.ApplicationContext context)    Unknown
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) Unknown
System.Windows.Forms.dll!System.Windows.Forms.Application.RunDialog(System.Windows.Forms.Form form) Unknown
System.Windows.Forms.dll!System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window owner)  Unknown
System.Windows.Forms.dll!System.Windows.Forms.Form.ShowDialog() Unknown
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.OnThreadException(System.Exception t)   Unknown
System.Windows.Forms.dll!System.Windows.Forms.Control.WndProcException(System.Exception e)  Unknown
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnThreadException(System.Exception e) Unknown
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Callback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam)    Unknown

그럼, 대화창을 실제로 만드는 코드를 OnThreadException에서 찾아볼 수 있습니다.

internal void OnThreadException(Exception t)
{
    if (!this.GetState(4))
    {
        this.SetState(4, true);
        try
        {
            ...[생략]...
            else if (SystemInformation.UserInteractive)
            {
                ThreadExceptionDialog dialog = new ThreadExceptionDialog(t);
                DialogResult oK = DialogResult.OK;
                IntSecurity.ModifyFocus.Assert();
                try
                {
                    oK = dialog.ShowDialog();
                }
            ...[생략]...
            }
            return;
        Label_0084:
            ...[생략]...
        }
        finally
        {
            this.SetState(4, false);
        }
    }
}

그리고 OnThreadException은 Windows 응용 프로그램의 필수 요소인 메시지 루프의 Win32 Message 처리 시 예외가 발생한 경우 수행된다는 것을 System.Windows.Forms.NativeWindow.Callback에서 찾아 볼 수 있습니다.

private IntPtr Callback(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam)
{
    Message m = Message.Create(hWnd, msg, wparam, lparam);
    try
    {}
        if (this.weakThisPtr.IsAlive && (this.weakThisPtr.Target != null))
        {
            this.WndProc(ref m);
        }
        else
        {
            this.DefWndProc(ref m);
        }
    }
    catch (Exception exception)
    {
        this.OnThreadException(exception);
    }
    finally
    {
        if (msg == 130)
        {
            this.ReleaseHandle(false);
        }
        if (msg == NativeMethods.WM_UIUNSUBCLASS)
        {
            this.ReleaseHandle(true);
        }
    }
    return m.Result;
}

따라서, Win32 Message 처리 도중 예외가 발생한다면 .NET Windows Forms에서 마련한 예외 창이 뜨게 됩니다.

그렇다면, 당연히 다른 곳에서 예외가 발생하면 Windows Forms도 처리를 할 수 없으므로 시스템에 넘어가게 됩니다. 그 결과로 나온 아래와 같은 형식의 창은 (디버거 설치 유무 등의 정보 등을 조사한 다음 적절한 사후 처리를 할 수 있도록) 운영체제가 담당하게 됩니다. 다음은 디버거가 설치된 시스템에서 운영체제가 띄우는 오류 보고 창입니다.

error_handler_2.png

이를 테스트하고 싶다면 Windows Forms에 또 다른 버튼을 만들고 그 이벤트 핸들러에 다음과 같은 식으로 별도의 스레드를 이용해 처리를 맡겨 보면 됩니다.

private void button2_Click(object sender, EventArgs e)
{
    ThreadPool.QueueUserWorkItem((arg) =>
    {
        int a = 5;
        int b = 0;

        int c = a / b;
    }, null);
}

저 스레드에서는 Windows Forms의 Message Loop 처리 코드가 없기 때문에 예외가 발생하면 운영체제로 곧장 넘어가 비정상 종료를 하게 됩니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 5/10/2017]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 61  62  [63]  64  65  66  67  68  69  70  71  72  73  74  75  ...
NoWriterDateCnt.TitleFile(s)
12365정성태10/12/202018663.NET Framework: 949. C# 9.0 - (3) 람다 메서드의 매개 변수 무시(Lambda discard parameters)파일 다운로드1
12364정성태10/11/202019540.NET Framework: 948. C# 9.0 - (2) localsinit 플래그 내보내기 무시(Suppress emitting localsinit flag)파일 다운로드1
12363정성태10/11/202021255.NET Framework: 947. C# 9.0 - (1) 대상으로 형식화된 new 식(Target-typed new expressions) [2]파일 다운로드1
12362정성태10/11/202017854VS.NET IDE: 151. Visual Studio 2019에 .NET 5 rc/preview 적용하는 방법
12361정성태10/11/202019951.NET Framework: 946. C# 9.0을 위한 개발 환경 구성
12360정성태10/8/202015100오류 유형: 666. The type or namespace name '...' does not exist in the namespace 'Microsoft.VisualStudio.TestTools' (are you missing an assembly reference?)
12359정성태10/7/202017312오류 유형: 665. Windows - 재부팅 후 iSCSI 연결이 끊기는 문제
12358정성태10/7/202018245오류 유형: 664. Web Deploy 설치 시 "A newer version of Microsoft Web Deploy 3.6 was found on this machine." 오류 [3]
12357정성태10/7/202015846오류 유형: 663. 이벤트 로그 - The storage optimizer couldn't complete retrim on New Volume
12356정성태10/7/202031488오류 유형: 662. ASP.NET Core와 500.19, 500.21 오류 (0x8007000d)
12355정성태10/3/202014992오류 유형: 661. Hyper-V Linux VM의 Internal 유형의 가상 Switch에 대한 IP 연결이 되지 않는 경우
12354정성태10/2/202029079오류 유형: 660. Web Deploy (msdeploy.axd) 실행 시 오류 기록 [1]
12353정성태10/2/202018437개발 환경 구성: 518. 비주얼 스튜디오에서 IIS 웹 서버로 "Web Deploy"를 이용해 배포하는 방법
12352정성태10/2/202019651개발 환경 구성: 517. Hyper-V Internal 네트워크에 NAT을 이용한 인터넷 연결 제공
12351정성태10/2/202018124오류 유형: 659. Nox 실행이 안 되는 경우 - Unable to bind to the underlying transport for ...
12350정성태9/25/202022692Windows: 175. 윈도우 환경에서 클라이언트 소켓의 최대 접속 수 [2]파일 다운로드1
12349정성태9/25/202016793Linux: 32. Ubuntu 20.04 - docker를 위한 tcp 바인딩 추가
12348정성태9/25/202017785오류 유형: 658. 리눅스 docker - Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
12347정성태9/25/202033329Windows: 174. WSL 2의 네트워크 통신 방법 [4]
12346정성태9/25/202016759오류 유형: 657. IIS - http://localhost 방문 시 Service Unavailable 503 오류 발생
12345정성태9/25/202016379오류 유형: 656. iisreset 실행 시 "Restart attempt failed." 오류가 발생하지만 웹 서비스는 정상적인 경우파일 다운로드1
12344정성태9/25/202018299Windows: 173. 서비스 관리자에 "IIS Admin Service"가 등록되어 있지 않다면?
12343정성태9/24/202029312.NET Framework: 945. C# - 닷넷 응용 프로그램에서 메모리 누수가 발생할 수 있는 패턴 [5]
12342정성태9/24/202019238디버깅 기술: 171. windbg - 인스턴스가 살아 있어 메모리 누수가 발생하고 있는지 확인하는 방법
12341정성태9/23/202017311.NET Framework: 944. C# - 인스턴스가 살아 있어 메모리 누수가 발생하고 있는지 확인하는 방법파일 다운로드1
12340정성태9/23/202016954.NET Framework: 943. WPF - WindowsFormsHost를 담은 윈도우 생성 시 메모리 누수
... 61  62  [63]  64  65  66  67  68  69  70  71  72  73  74  75  ...