跳转至

错误处理API

概述

Windows API使用错误码来表示操作结果,正确处理错误对于应用程序稳定性至关重要。

获取错误码

GetLastError - 获取最后错误码

C++
DWORD GetLastError();

说明: - 返回调用线程的最后错误码 - 错误码在每次API调用后更新 - 成功的API调用可能会清除错误码

示例

C++
#include <windows.h>
#include <stdio.h>

int main() {
    HANDLE hFile = CreateFile(
        L"C:\\nonexistent.txt",
        GENERIC_READ,
        0, NULL, OPEN_EXISTING, 0, NULL
    );
    
    if (hFile == INVALID_HANDLE_VALUE) {
        DWORD error = GetLastError();
        printf("Error code: %d\n", error);
    }
    
    return 0;
}

SetLastError - 设置错误码

C++
1
2
3
VOID SetLastError(
    DWORD dwErrCode
);

用途:用于自定义函数设置错误码。

示例

C++
1
2
3
4
5
6
7
BOOL MyFunction() {
    if (some_error_condition) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }
    return TRUE;
}

错误码常量

常见错误码

错误码 说明
ERROR_SUCCESS 0 操作成功
ERROR_INVALID_FUNCTION 1 函数不正确
ERROR_FILE_NOT_FOUND 2 文件不存在
ERROR_PATH_NOT_FOUND 3 路径不存在
ERROR_ACCESS_DENIED 5 拒绝访问
ERROR_INVALID_HANDLE 6 句柄无效
ERROR_NOT_ENOUGH_MEMORY 8 内存不足
ERROR_INVALID_PARAMETER 87 参数无效
ERROR_SHARING_VIOLATION 32 共享冲突
ERROR_LOCK_VIOLATION 33 锁定冲突
ERROR_ALREADY_EXISTS 183 已存在
ERROR_PRIVILEGE_NOT_HELD 1314 权限不足

系统错误码范围

  • 0-499:系统错误码
  • 500-999:保留
  • 1000-2999:组件错误码
  • 3000-3999:保留
  • 4000-5999:Internet错误码
  • 6000-15999:其他错误码

错误信息转换

FormatMessage - 格式化错误信息

C++
1
2
3
4
5
6
7
8
9
DWORD FormatMessage(
    DWORD   dwFlags,
    LPCVOID lpSource,
    DWORD   dwMessageId,
    DWORD   dwLanguageId,
    LPTSTR  lpBuffer,
    DWORD   nSize,
    va_list *Arguments
);

标志: - FORMAT_MESSAGE_ALLOCATE_BUFFER:分配缓冲区 - FORMAT_MESSAGE_FROM_SYSTEM:从系统消息表获取 - FORMAT_MESSAGE_IGNORE_INSERTS:忽略插入序列 - FORMAT_MESSAGE_FROM_HMODULE:从模块获取

示例

C++
#include <windows.h>
#include <stdio.h>

void PrintError(DWORD error) {
    LPVOID lpMsgBuf = NULL;
    
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        error,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&lpMsgBuf,
        0, NULL
    );
    
    wprintf(L"Error %d: %s\n", error, (LPCTSTR)lpMsgBuf);
    LocalFree(lpMsgBuf);
}

int main() {
    PrintError(ERROR_FILE_NOT_FOUND);
    PrintError(ERROR_ACCESS_DENIED);
    return 0;
}

错误处理辅助函数

C++
#include <windows.h>
#include <stdio.h>

void CheckError(BOOL success, const char* operation) {
    if (!success) {
        DWORD error = GetLastError();
        LPVOID lpMsgBuf = NULL;
        
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, error,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR)&lpMsgBuf, 0, NULL
        );
        
        printf("%s failed: Error %d - %s\n", operation, error, (char*)lpMsgBuf);
        LocalFree(lpMsgBuf);
    }
}

结构化异常处理

__try/__except

C++
#include <windows.h>
#include <stdio.h>

int main() {
    int* p = NULL;
    
    __try {
        *p = 10;  // 引发访问违规
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        printf("Exception caught: Access violation\n");
    }
    
    printf("Program continues\n");
    return 0;
}

异常过滤

C++
#include <windows.h>
#include <stdio.h>

LONG WINAPI VectoredHandler(PEXCEPTION_POINTERS ExceptionInfo) {
    printf("Vectored exception handler called\n");
    printf("Exception code: %X\n", ExceptionInfo->ExceptionRecord->ExceptionCode);
    return EXCEPTION_CONTINUE_SEARCH;
}

int main() {
    AddVectoredExceptionHandler(1, VectoredHandler);
    
    __try {
        int* p = NULL;
        *p = 10;
    }
    __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION 
              ? EXCEPTION_EXECUTE_HANDLER 
              : EXCEPTION_CONTINUE_SEARCH) {
        printf("Access violation handled\n");
    }
    
    RemoveVectoredExceptionHandler(VectoredHandler);
    return 0;
}

__try/__finally

C++
#include <windows.h>
#include <stdio.h>

int main() {
    HANDLE hFile = INVALID_HANDLE_VALUE;
    
    __try {
        hFile = CreateFile(L"test.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
        if (hFile == INVALID_HANDLE_VALUE) {
            printf("File open failed\n");
            return -1;
        }
        
        // 使用文件...
    }
    __finally {
        if (hFile != INVALID_HANDLE_VALUE) {
            CloseHandle(hFile);
            printf("File handle closed\n");
        }
    }
    
    return 0;
}

错误查找工具

HRESULT_FROM_WIN32 - Win32错误转HRESULT

C++
HRESULT hresult = HRESULT_FROM_WIN32(GetLastError());

SUCCEEDED / FAILED - 检查HRESULT

C++
1
2
3
4
5
6
HRESULT hr = SomeFunction();
if (SUCCEEDED(hr)) {
    printf("Success\n");
} else {
    printf("Failed: 0x%08X\n", hr);
}

错误日志记录

OutputDebugString - 输出调试信息

C++
1
2
3
void OutputDebugString(
    LPCTSTR lpOutputString
);

示例

C++
#include <windows.h>

void LogError(const char* format, ...) {
    char buffer[1024];
    va_list args;
    va_start(args, format);
    vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);
    
    OutputDebugStringA(buffer);
}

int main() {
    LogError("Error at line %d in %s\n", __LINE__, __FILE__);
    return 0;
}

Event Log - 事件日志

C++
#include <windows.h>

void LogToEventLog(LPCWSTR message, WORD eventType) {
    HANDLE hEventLog = RegisterEventSourceW(NULL, L"MyApplication");
    if (hEventLog) {
        ReportEventW(
            hEventLog,
            eventType,
            0,
            0,
            NULL,
            1,
            0,
            &message,
            NULL
        );
        DeregisterEventSource(hEventLog);
    }
}

int main() {
    LogToEventLog(L"Application started", EVENTLOG_INFORMATION_TYPE);
    return 0;
}

实用错误处理宏

C++
#include <windows.h>
#include <stdio.h>

#define CHECK_WIN32(result, operation) \
    do { \
        if (!(result)) { \
            DWORD err = GetLastError(); \
            fprintf(stderr, "%s failed at %s:%d - Error %d\n", \
                    operation, __FILE__, __LINE__, err); \
        } \
    } while (0)

#define CHECK_HANDLE(handle, operation) \
    do { \
        if ((handle) == NULL || (handle) == INVALID_HANDLE_VALUE) { \
            DWORD err = GetLastError(); \
            fprintf(stderr, "%s failed at %s:%d - Error %d\n", \
                    operation, __FILE__, __LINE__, err); \
        } \
    } while (0)

int main() {
    HANDLE hFile = CreateFile(L"test.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
    CHECK_HANDLE(hFile, "CreateFile");
    
    if (hFile != INVALID_HANDLE_VALUE) {
        char buffer[1024];
        DWORD bytesRead;
        BOOL result = ReadFile(hFile, buffer, sizeof(buffer), &bytesRead, NULL);
        CHECK_WIN32(result, "ReadFile");
        
        CloseHandle(hFile);
    }
    
    return 0;
}

参考资料