제가 설명드렸었던 17번 API가 뭔지 기억나시나요? 바로, FormatMessage API였습니다.

저 API를 응용해서, 마지막으로 발생한 오류 코드에 대한 오류 메세지를 가져오는 방법을 설명하기도 했습니다.


그런데, 제가 설명드리지 않은 것이 있으니... 그건 바로 Win32Exception 예외 클래스였습니다.

(Win32Exception 예외 클래스, MSDN)

이 예외 클래스는 너무나 친절하게도.. 인자를 전달하지 않고 기본 생성자로 호출을 하면 내부적으로 GetLastError API를 이용해 마지막 오류 코드를 가져오고 FormatMessage API를 사용해 오류 코드에 대한 메세지를 내부에 저장시킵니다.


그리고! 예외처리까지 해주니 이건 일석이조!!!!!

일단, 제가 FormatMessage API 및 GetLastError API가 Win32Exception 예외 클래스에서 사용되었는지를 알아보기 위해서 디컴파일을 해보았습니다. Win32Exception 클래스 내부에 GetErrorMessage 라는 함수가 있구.. 코드는 아래와 같습니다.

private static string GetErrorMessage(int error)
{
    StringBuilder stringBuilder = new StringBuilder(256);
    int num = SafeNativeMethods.FormatMessage(12800, NativeMethods.NullHandleRef, error, 0, stringBuilder, stringBuilder.Capacity + 1, IntPtr.Zero);
    string result;
    if (num != 0)
    {
        int i;
        for (i = stringBuilder.Length; i > 0; i--)
        {
            char c = stringBuilder[i - 1];
            if (c > ' ' && c != '.')
            {
                break;
            }
        }
        result = stringBuilder.ToString(0, i);
    }
    else
    {
        result = "Unknown error (0x" + Convert.ToString(error, 16) + ")";
    }
    return result;
}


보시면 FormatMessage 를 호출하는 부분이 보이시죠? API를 호출해서 메세지 정보를 가져오고, 그 문자열을 가공한 후에 반환하는 것을 알 수 있습니다. FormatMessage API 실패 시엔 해당되는 오류 코드를 unknown error (0x16진수) 형식으로 메세지를 저장하고 있구요..


그럼 이 예외 클래스를 이용해서 오류 코드에 대한 메세지를 가져오는 코드를 작성해 보겠습니다.

using System;

namespace Win32Exception_Test {
    class Program {
        public static void Main(string[] args) {
            Console.WriteLine("오류 코드 5번에 대한 메세지는?");
            try {
                throw new System.ComponentModel.Win32Exception(5);
            } catch (Exception ex) {
                Console.WriteLine(ex.Message);
            }

            Console.ReadKey(true);
        }
    }
}


예외를 발생시키는 부분을 try ~ catch 로 감싸 예외처리를 해주지 않으면, 디버그 상태로 넘어가게 됩니다.

(디버깅하지 않는 경우엔 프로그램이 종료됩니다..)


위 코드의 결과는 아래의 그림과 같습니다.


그럼 이 결과의 정확성을 알아보기 위해 MSDN에서 오류 코드 5번에 대한 정보를 검색해본 결과 MSDN 페이지에서도 이렇게 기술되어 있었습니다.

ERROR_ACCESS_DENIED

Access is denied.


엑세스가 거부되었다는 메세지는 정확하다는 것을 알 수 있게 되었네요!

그리고 이 예외 클래스는 앞서 말했듯이 인자를 전달하지 않고 기본 생성자로 호출할 경우, 마지막으로 실패한 오류 코드와 오류 코드에 대한 메세지를 저장하게 됩니다. 이걸 증명하기 위해 아래와 같은 코드를 작성하였습니다.

using System;
using System.Runtime.InteropServices;

namespace Win32Exception_Test {
    class Program {
        [DllImport("kernel32", CharSet = CharSet.Auto)]
        public static extern Int32 CreateDirectory(String PathName, IntPtr SecAttr);
        
        public static void Main(string[] args) {
            Console.WriteLine(@"'C:\h?ell*o? worl\\ld\\\\\\d\d\d?' 폴더를 생성합니다...");
            try {
                CreateDirectory(@"C:\h?ell*o? worl\\ld\\\\\\d\d\d?", IntPtr.Zero);
                throw new System.ComponentModel.Win32Exception();
            } catch (Exception ex) {
                Console.WriteLine(ex.Message);
            }

            Console.ReadKey(true);
        }
    }
}


그리고, 위 코드의 결과는 다음과 같습니다.


기대한 결과가 나왔네요!


Win32Exception 예외 클래스는 System.ComponentModel 네임스페이스에 포함되어 있구, 따로 .NET 어셈블리를 불러올 필요가 없습니다. (System.dll 에 정의되어 있기 때문입니다)


.NET 에는 자료형이나 메서드들이 너무나 다양해서 모든 걸 알기도 힘들지만, 이렇게 하나 하나 유용한 자료형/메서드 들이 숨어 있습니다. 프로그래밍을 못하는 저도 유용한 메서드를 많이 알아서 프로그래밍을 잘하게 됬으면 하는 바램입니다. (ㅋㅋ)


그럼 이상으로 Win32Exception 예외 클래스에 대한 설명을 마치겠습니다..

긴 글 읽어주셔서 감사합니다!!!


+ Recent posts