수색…


비고

각 스레드는 고유의 마지막 오류 코드를 갖습니다. Windows API는 호출 스레드의 마지막 오류 코드를 설정합니다.

Windows API 함수의 반환 값을 확인한 후에는 항상 GetLastError 함수를 호출해야합니다.

대부분의 Windows API 함수는 실패 할 때 마지막 오류 코드를 설정합니다. 일부는 성공할 때 마지막 오류 코드도 설정합니다. 마지막 오류 코드를 설정하지 않는 여러 가지 기능이 있습니다. 항상 Windows API 함수의 설명서를 참조하십시오.

FormatMessage 함수를 사용하여 오류 코드에 대한 설명을 가져올 때 FORMAT_MESSAGE_FROM_SYSTEM 없이 FORMAT_MESSAGE_IGNORE_INSERTS 을 사용하는 것은 안전하지 FORMAT_MESSAGE_IGNORE_INSERTS .

소개

Windows API는 C 호출 가능 인터페이스를 통해 제공됩니다. API 호출의 성공 또는 실패는 반환 값을 통해보고됩니다. 일부 API 구현 은 읽기 전용 lpCommandLine 인수를 CreateProcess에 전달할 때 SEH 예외를 발생시킬 수 있지만 예외는 문서화 된 계약의 일부가 아닙니다.

오류보고는 크게 네 범주 중 하나에 속합니다.

각 API 호출에 대한 문서는 명시 적으로 오류를보고하는 방법을 호출합니다. 항상 설명서를 참조하십시오.

반환 값에 의해서만보고 된 오류

일부 API 호출은 추가 정보 (예 : GetObject )없이 단일 실패 / 성공 플래그를 반환합니다.

if ( GetObjectW( obj, 0, NULL ) == 0 ) {
    // Failure: no additional information available.
}

오류에 대한 추가 정보가있는 오류가보고되었습니다.

실패 / 성공 반환 값 외에도 일부 API 호출은 실패시 마지막 오류 (예 : CreateWindow )를 설정합니다. 문서에는 대개이 경우 다음과 같은 표준 문구가 포함됩니다.

함수가 성공하면 반환 값은 <API 관련 성공 값> 입니다.
함수가 실패하면 반환 값은 <API 관련 오류 값> 입니다. 확장 된 오류 정보를 얻으려면 GetLastError를 호출하십시오.

if ( CreateWindowW( ... ) == NULL ) {
    // Failure: get additional information.
    DWORD dwError = GetLastError();
} else {
    // Success: must not call GetLastError.
}

GetLastError() 즉시 호출하는 것이 중요합니다. 실패한 기능과 호출 사이에 추가 함수 호출이 있다면, 그래서 마지막 오류 코드가 다른 기능에 의해 덮어 쓸 수 GetLastError() 에서 반환 GetLastError() 더 이상 신뢰할 수 없습니다. C ++ 생성자를 다룰 때는 특히주의하십시오.

오류 코드를 받으면 해석해야합니다. MSDN의 시스템 오류 코드 (Windows) 페이지 에서 포괄적 인 오류 코드 목록을 얻을 수 있습니다. 또는 시스템 헤더 파일을 볼 수도 있습니다. 모든 오류 코드 상수를 가진 파일은 winerror.h 입니다. (Windows 8 용 Microsoft의 공식 SDK가있는 경우이 폴더는 include 폴더의 shared 하위 폴더에 있습니다.)

다른 프로그래밍 언어로 GetLastError() 를 호출 할 때의주의 사항

.net 언어 (C #, VB 등)

.net을 사용하면 GetLastError() P / Invoke를 직접 해서는 안됩니다 . NET 런타임이 등 뒤의 동일한 스레드에서 다른 Windows API 호출을 수행하기 때문입니다. 예를 들어 가비지 컬렉터는 더 이상 사용하지 않는 메모리를 발견하면 VirtualFree() 호출 할 수 있으며 , 이는 의도 한 함수 호출과 GetLastError() 호출 사이에서 발생할 수 있습니다 .

그 대신 .net은 마지막 P / Invoke 호출에서 마지막으로 발생한 오류를 검색하는 Marshal.GetLastWin32Error() 함수를 제공합니다. GetLastError() 직접 호출하는 대신이 GetLastError() 사용하십시오.

(.net 어쨌든 GetLastError() 가져 오기 중지하지 않는 것, 왜 모르겠어요.)

가기

DLL 함수를 호출하기 위해 Go가 제공하는 다양한 기능 (패키지 syscall 과 패키지 golang.org/x/sys/windows 모두에 golang.org/x/sys/windows )은 r1 , r2err 세 가지 값을 반환합니다. r2 는 사용되지 않습니다. 빈 식별자를 사용할 수 있습니다. r1 은 함수의 반환 값입니다. errGetLastError() 를 호출 한 결과이지만 error 를 구현하는 유형으로 변환되므로 처리 할 호출 함수에 전달할 수 있습니다.

Go는 GetLastError() 를 호출 GetLastError() 알지 못하며 그렇지 않을 경우 항상 nil 이 아닌 오류를 반환합니다. 따라서 일반적인 Go 오류 처리 관용구

r1, _, err := syscall.Syscall12(CreateWindowW.Addr(), ...)
if err != nil {
    // handle err
}
// use r1

작동하지 않을 것이다. 대신, C에서와 똑같이 r1 검사해야하며, 함수가 오류를 반환 했다는 것을 나타내는 경우에만 err 사용하십시오.

r1, _, err := syscall.Syscall12(CreateWindowW.Addr(), ...)
if r1 == 0 {
    // handle err
}
// use r1

실패 및 성공에 대한 추가 정보가있는 오류보고

일부 API 호출은 여러 가지 방법으로 성공하거나 실패 할 수 있습니다. API는 일반적으로 성공적인 호출과 오류 (예 : CreateMutex )에 대한 추가 정보를 반환합니다.

if ( CreateMutexW( NULL, TRUE, L"Global\\MyNamedMutex" ) == NULL ) {
    // Failure: get additional information.
    DWORD dwError = GetLastError();
} else {
    // Success: Determine which mutex was returned.
    if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
        // Existing mutex object returned.
    } else {
        // Newly created mutex object returned.
    }
}

HRESULT 값으로보고 된 오류

HRESULT 는 숫자 32 비트 값이며 비트 또는 비트 범위는 잘 정의 된 정보를 인코딩합니다. MSB는 실패 / 성공 플래그이며 나머지 비트는 추가 정보를 저장합니다. 실패 또는 성공은 FAILED 또는 SUCCEEDED 매크로를 사용하여 판별 할 수 있습니다. HRESULT 는 일반적으로 COM과 함께 사용되지만 non-COM 구현에도 사용됩니다 (예 : StringCchPrintf ).

const size_t cchBuf = 5;
wchar_t buffer[cchBuf] = { 0 };
HRESULT hr = StringCchPrintfW( buffer, cchBuf, L"%s", L"Hello, world!" );
if ( FAILED( hr ) ) {
    // Failure: Determine specific reason.
    switch ( hr ) {
    case STRSAFE_E_INSUFFICIENT_BUFFER:
        // Buffer too small; increase buffer and retry.
        ...
    case STRSAFE_E_INVALID_PARAMETER:
        // Invalid parameter; implement custom error handling (e.g. logging).
        ...
    default:
        // Some other error code; implement custom error handling (e.g. logging).
        ...
    }
}

오류 코드를 메시지 문자열로 변환

GetLastError 는 숫자 오류 코드를 반환합니다. 설명적인 오류 메시지 ( 예 : 사용자에게 표시)를 얻으려면 FormatMessage 를 호출 할 수 있습니다.

// This functions fills a caller-defined character buffer (pBuffer)
// of max length (cchBufferLength) with the human-readable error message
// for a Win32 error code (dwErrorCode).
// 
// Returns TRUE if successful, or FALSE otherwise.
// If successful, pBuffer is guaranteed to be NUL-terminated.
// On failure, the contents of pBuffer are undefined.
BOOL GetErrorMessage(DWORD dwErrorCode, LPTSTR pBuffer, DWORD cchBufferLength)
{
    if (cchBufferLength == 0)
    {
        return FALSE;
    }

    DWORD cchMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                 NULL,  /* (not used with FORMAT_MESSAGE_FROM_SYSTEM) */
                                 dwErrorCode,
                                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                                 pBuffer,
                                 cchBufferLength,
                                 NULL);
    return (cchMsg > 0);
}

C ++ 에서는 std::string 클래스를 사용하여 인터페이스를 상당히 단순화 할 수 있습니다.

#include <Windows.h>
#include <exception>
#include <stdexcept>
#include <memory>
#include <string>
typedef std::basic_string<TCHAR> String;

String GetErrorMessage(DWORD dwErrorCode)
{
    LPTSTR psz = NULL;
    const DWORD cchMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
                                         | FORMAT_MESSAGE_IGNORE_INSERTS
                                         | FORMAT_MESSAGE_ALLOCATE_BUFFER,
                                       NULL, // (not used with FORMAT_MESSAGE_FROM_SYSTEM)
                                       dwErrorCode,
                                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                                       reinterpret_cast<LPTSTR>(&psz),
                                       0,
                                       NULL);
    if (cchMsg > 0)
    {
        // Assign buffer to smart pointer with custom deleter so that memory gets released
        // in case String's c'tor throws an exception.
        auto deleter = [](void* p) { ::HeapFree(::GetProcessHeap(), 0, p); };
        std::unique_ptr<TCHAR, decltype(deleter)> ptrBuffer(psz, deleter);
        return String(ptrBuffer.get(), cchMsg);
    }
    else
    {
        throw std::runtime_error("Failed to retrieve error message string.");
    }
}

참고 : 이러한 함수는 HRESULT 값에 대해서도 작동 합니다 . DWORD dwErrorCode 에서 HRESULT hResult 첫 번째 매개 변수를 변경하기 DWORD dwErrorCode 됩니다. 나머지 코드는 변경되지 않습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow