错误处理API
概述
Windows API使用错误码来表示操作结果,正确处理错误对于应用程序稳定性至关重要。
获取错误码
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++ |
|---|
| VOID SetLastError(
DWORD dwErrCode
);
|
用途:用于自定义函数设置错误码。
示例:
| C++ |
|---|
| 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:其他错误码
错误信息转换
| C++ |
|---|
| 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++ |
|---|
| HRESULT hr = SomeFunction();
if (SUCCEEDED(hr)) {
printf("Success\n");
} else {
printf("Failed: 0x%08X\n", hr);
}
|
错误日志记录
OutputDebugString - 输出调试信息
| C++ |
|---|
| 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;
}
|
参考资料