일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- C#
- 열혈 TCP/IP 소켓 프로그래밍
- 스프링 핵심 원리
- Four Squares
- Operating System
- Operating System.
- 토마토
- 윤성우 저자
- OS
- n타일링2
- redis
- 열혈 tcp/ip 프로그래밍
- 우아한레디스
- inflearn
- 우아한 테크 세미나
- Window-Via-c/c++
- 2475번
- 운영체제
- 10026번
- C++
- 이펙티브코틀린
- HTTP
- BOJ
- 에러핸들링
- 스프링 입문
- FIFO paging
- TCP/IP
- 김영한
- Spring
- 제프리리처
- Today
- Total
나의 브을로오그으
#1. 에러 핸들링 본문
1) 윈도우즈 함수의 대표적인 반환 자료형
자료형 | 실패했을 때의 값 |
VOID | 이 함수는 절대 실패 x, 아주 적은 수의 윈도우즈 함수만이 VOID 반환 자료형을 가짐. |
BOOL | 함수 실패 시 FALSE(0), 성공 시 FALSE(0)이 아닌 값. 그렇기 때문에 TRUE와 비교 하지 말 것. |
HANDLE | 함수가 실패하면 반환 값은 대개 NULL 이다. 성공 시에는 유효한 오브젝트 핸들을 반환한다. 몇몇 함수들은 INVALID_HANDLE_VALUE(-1)를 반환하는 경우가 있기 때문에 주의가 필요하다. 문서를 꼼꼼히 볼것. |
PVOID | 함수가 실패하면 NULL을 반환. 성공 시 데이터를 저장하고 있는 메모리 주소를 가리킴. |
LONG/DWORD | 이러한 종류의 함수는 대개 개수 같은 것을 반환한다. 만약 개수 반환에 실패하면 대개 0이나 -1을 반환한다. 문서를 꼼꼼히 볼것. |
윈도우 함수가 실패하면 왜 함수가 실패했는지의 여부를 알아내는 과정이 반드시 필요하다. 마이크로 소프트는 발생할 가능성이 있는 모든 에러 코드를 32비트 숫자로 정의해 두었다.
윈도우 함수가 실패하게 되면 내부적으로 함수를 호출한 스레드의 스레드의 지역 저장소(thread-local storage)에 적절한 에러 코드를 저장해 둔다. 이러한 매커니즘을 통해 여러 개의 스레드가 동시에 수행될 경우라도 상호간에 영향을 미치지 않고 각 스레드별로 에러 코드를 유지할 수 있게 된다. 호출한 함수가 실패한 것으로 판단되면 어떤 에러가 발생했는지 확인하기 위해 GetLastError 함수를 사용할 수 있다.
DWORD GetLastError();
이 함수는 단순히 가장 최근에 호출된 함수의 에러 코드를 스레드 지역 저장소(thread-local storage)로부터 가져온다.
2) 에러코드의 구조
- 메시지 ID(GetLastError 함수의 반환 값과 비교할 수 있도록 정의된 매크로)
- 메시지 텍스트(영어로 된 에러 설명)
- 에러 코드(메시지 ID 대신 이 값을 직접 사용해서는 안 된다.)
에러 발생 시 에러 코드를 획득하기 위해 바로 GetLastError() 함수를 호출해야 한다. 이 함수를 호출하기 전에 다른 함수를 호출하게 되면 다른 함수의 수행 결과가 겹쳐 써지게 된다. (함수 호출이 성공하면 ERROR_SUCCESS를 에러 코드로 기록한다.)
설령 함수 호출에 성공하였더라도 성공 사유가 다를 수 있기 때문에 마이크로소프트에서는 비슷한 매커니즘으로 지정해 놓았다. 몇몇 함수의 경우 함수 호출이 성공해도 부가적인 성공의 이유를 확인하기 위해 GetLastError()를 이용할 것을 명확하게 기술하고 있다.
3) 디버깅 수행
디버깅 수행 동안에 스레드 지역 저장소(thread-local storage)에 기록된 에러 코드를 지속적으로 확인할 수 있으면 편리한데, 마이크로소프트의 Visual Studio 내에 포함된 디버거는 Watch 창을 통해 현재 수행중인 스레드의 마지막 에러 코드와 메시지 텍스트를 확인할 수 있는 기능을 제공하고 있다. 이를 위해 Watch 창에 $err, hr을 입력하면 된다.
4) FormatMessage
DWORD FormatMessage(
[in] DWORD dwFlags,
[in, optional] LPCVOID lpSource,
[in] DWORD dwMessageId,
[in] DWORD dwLanguageId,
[out] LPTSTR lpBuffer,
[in] DWORD nSize,
[in, optional] va_list *Arguments
);
: 사용자에게 보여줄 메시지 텍스트를 구성하는 더 나은 방법들을 제공해 준다. 이 함수의 유용성 중 하나는 이 함수가 다양한 언어로 문자열을 구성할 수 있다는 것이다. 이 함수가 언어 식별자를 인자로 받기 때문에 언어 식별자에 준하는 언어로 메시지 텍스트를 구성할 수 있다.
물론 최초에는 애플리케이션 개발자가 메시지를 번역하고 번역된 메시지를 스트링 테이블 리소스 형태로 .exe나 DLL 모듈에 포함시켜야 하지만, 이 함수를 통해서 그중 적절한 것을 선택할 수 있다.
1. 자신만의 에러 코드를 정의하는 방법
VOID SetLastError(DWORD dwErrCode);
: 가능한 "WinError.h"에 정의되어 있는 에러 코드를 사용하는 편이 낫다.
1) 에러 코드의 의미
비트 | 31-30 | 29 | 28 | 27-16 | 15-0 |
내용 | 심각도 | 마이크로소프트/고객 | 예약됨 | 식별 코드 | 예외 코드 |
의미 | 0 = 성공 1 = 정보 2 = 주의 3 = 에러 |
0 = 마이크로소프트 가 정의한 코드 1 = 고객이 정의한 코드 |
항상 0 | 256까지는 마이크로소프트에 의해 예약 됨. |
마이크로소프트 나 고객이 정의 한 코드 |
마이크로소프트가 정의한 모든 에러 코드는 29번째 비트를 0으로 설정할 것을 규정하기 때문에 에러 코드를 직접 만드는 경우에는 겹치지 않는 것을 보장받으려면 1로 설정해야 한다.
2. ErrorShow 예제 애플리케이션
[UI]
1. EditControl: Sample이라고 작성된 EditBox의 경우 ID는 IDC_ERRORCODE이며, 해당 BOX에는 ErrorCode를 작성.
2. Button: 해당 버튼 클릭 시 에러 코드에 맞는 메시지를 찾아서 하단의 EditControl에 표시한다.
3. EditControl: 에러 코드에 맞는 메시지를 표시한다.
[코드 분석]
// 에러코드를 획득
DWORD dwError = GetDlgItemInt(hWnd, IDC_ERRORCODE, NULL, FALSE);
// 에러 메시지를 저장하기 위한 버퍼
HLOCAL hLocal = NULL;
// 윈도우 메시지 문자열을 얻기 위해 기본 시스템 지역을 설정한다.
DWORD systemLocal = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
// 에러 코드의 메시지를 가져온다.
BOOL fOk = FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, dwError, systemLocale,
(PTSTR) &hlocal, 0, NULL
);
if (fOk == FALSE) {
// 에러 코드의 메시지 로드 실패 시 네트워크 문제인지 확인
HMOUDLE hDll = LocalLibraryEx(TEXT("netmsg.dll"),
NULL, DONT_RESOLVE_DLL_REFERENCES);
if (hDll != NULL) {
fOk = FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, dwError, systemLocale,
(PTSTR) &hlocal, 0, NULL
);
FreeLibrary(hDll);
}
if (fOk && (hLocal != NULL)) {
SetDlgItemText(hwnd, IDC_ERRORTEXT, (PCTSTR) LocalLock(hlocal));
LocalFree(hlocal);
} else {
SetDlgItemText(hwnd, IDC_ERRORTEXT,
TEXT("No text found for this error number."));
}
}