프로그래밍

Windows 에러 핸들링, GetLastError

ZenoAhn 2017. 12. 28. 00:17

Windows 에러 핸들링


대부분의 Windows 함수가 사용하고 있는 반환 자료형은 아래의 표와 같다.


자료형 실패 했을 때의 값

VOID

이 함수는 절대 실패하지 않는다. 소수의 윈도우 함수만이 VOID 반환 자료형을 가짐

BOOL

함수가 실패하면 0을 반환, 성공시에는 0이 아닌 값을 반환한다. 즉, 비교시 TRUE와 비교하는 것보단, FALSE와 비교하는것이 나음

HANDLE

실패시 대개 NULL을 반환. 성공시 유효한 오브젝트 핸들을 반환한다. 몇몇 함수들은 -1로 정의된 INVALID HANDLE VALUE도 있기 때문에 주의 요망. SDK 문서에 명확하게 기술되어 있음

PVOID

함수가 실패하면 NULL을 반환, 성공시 PVOID가 데이터를 저장하고 있는 메모리 주소를 가르킴

LONG/DWORD

상당히 까다로운 형태이다. 대개 개수를 반환하나 어떤 이유로 인해 개수를 반환하지 못하면 0이나 -1을 반환한다. 이 반환형의 함수를 사용할 경우 플랫폼 SDK 문서를 주의깊게 살펴보길 바람


함수 호출 실패 원인 찾기

함수가 실패하면 왜 실패했는지 알아내야 하는데 이 때, GetLastError 함수를 사용할 수 있다.

GetLastError 함수를 통해 MS는 발생할 가능성이 있는 모든 에러 코드를 32bit의 숫자로 정의해 두었다.

함수의 형태는 다음과 같다.

DWORD GetLastError();


윈도우 함수가 실패할 경우, 내부적으로 함수를 호출한 스레드의 스레드 지역 저장소(thread-local storage)에 적절한 에러코드를 저장해둔다. 이러한 메커니즘을 통해 멀티 스레드에서 동시에 수행 된 경우라도 상호간의 영향을

미치지 않고 각 스레드별로 에러 코드를 유지할 수 있다.

따라서, GetLastError가 하는 일은 단순히 가장 최근에 호출된 함수의 에러코드를 스레드 지역 저장소로부터 가져오는 것이다.

WinError.h 헤더 파일은 MS가 정의한 모든 에러코드의 리스트를 가지고 있다.

다음은 WinError.h의 일부를 발췌한 것이며 이 파일은 약 39,000행을 넘는다.


#define ERROR_SUCCESS   0L
#define NOERROR         0L

#define ERROR_INVALID_FUNCTION      1L
#define ERROR_FILE_NOT_FOUND        2L
#define ERROR_PATH_NOT_FOUND        3L
#define ERROR_TOO_MANY_OPEN_FILES   4L

함수를 실패하게 되면 지체없이 GetLastError를 호출해야한다. 만약 GetLastError를 호출하기 전에 다른 함수를 호출하게 되면 수행 결과가 덮어 써지게 된다.
함수 호출이 성공하면 ERROR_SUCCESS를 ERROR 코드로 기록한다.


함수 호출 성공 이유 찾기

몇몇 윈도우 함수들은 몇가지 서로 다른 성공 이유가 존재한다.

예를 들면, 명명된 이벤트 커널 오브젝트를 생성하는 함수를 호출 할 경우 다음과 같은 두가지 경우 모두 성공을 반환한다.

  1. 실제로 새로운 커널 오브젝트가 생성되는 경우
  2. 이미 동일 이름의 커널 오브젝트가 존재하는 경우

이 경우 어떤 이유로 함수가 성공했는지 정확히 구분해야 할 필요가 있다.

이 경우에도, 에러 코드 저장 방식과 같은 메커니즘을 통해 성공 이유를 구분할 수 있게 제공해준다.

따라서, 함수 호출이 성공하더라도, GetLastError를 통해 부가적으로 성공한 이유를 구분해야 할 경우도 생길 수 있다.


Utility Error Lookup

Visual studio는 Error Lookup이라는 작은 유틸리티를 포함하고 있다.
이를 이용하면, 에러코드에 해당하는 메시지 텍스트를 쉽게 확인 할 수 있다.

어플리케이션에서 발생한 에러 메시지를 사용자에게 보여주고 싶을 경우 윈도우에서 제공해주는 FormatMessage 함수를 제공한다.

DWORD WINAPI FormatMessage(
  _In_     DWORD   dwFlags,
  _In_opt_ LPCVOID lpSource,
  _In_     DWORD   dwMessageId,
  _In_     DWORD   dwLanguageId,
  _Out_    LPTSTR  lpBuffer,
  _In_     DWORD   nSize,
  _In_opt_ va_list *Arguments
);


'프로그래밍' 카테고리의 다른 글

CUDA Tutorial 2  (2) 2018.05.12
CUDA Tutorial 1  (0) 2018.04.15
X86 Disassembly/Data Structures  (0) 2017.11.26
Uninformed Search, Informed Search  (0) 2017.04.21
알고리즘 스터디 - 1주차  (0) 2017.03.17