windows为错误处理提供了很多函数。
https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms679321(v=vs.85).aspx
上面链接罗列了我们在处理处理错误时可能需要的函数。其中最为重要的就是GetLastError了
GetLastError
首先除了GetLastError还有一个GetLastErrorEx函数。但是现在
GetLastErrorEx和GetLastError都是相同的了。所以GetLastErrorEx的第二参数被忽略了。
GetLastError函数来让我们检查函数操作时产生的错误。它使用一种叫做“线程本地存储区”(thread-local storage)的机制将相应的错误代码和主调线程关联到一起。
通常我们使用这个函数只需要类似下面这样就可以了。
HANDLE file = CreateFile(TEXT("C:\\test.txt"), 0, 0, nullptr, OPEN_EXISTING, 0, nullptr);
DWORD dwResoult=GetLastError();
switch (dwResoult) {
//...
}
所有的错误码都在WinError中定义着(被Windows.h包括)。当然想全部记下来是不可能的只能边学习边积累了。
我们可以是用HRESULT_FORM_WIN32来转换为HRESULT的返回值然后在使用SUCCEEDED/FAILED宏判读是不是成功的
为了我们调试程序的方便visual studio为我们提供了相应的工具来查看错误码。
监视窗口
我们只需要打上断点然后在监视窗口(watch)写入下面伪变量就可以参考断点处的GetLastError返回的结果了。
很方便 还会自动翻译成我们的语言。
如果想了解玩什么监视串口玩什么会显示???可以参考下面链接(要vpn的)
https://stackoverflow.com/questions/4001023/what-do-question-marks-in-visual-studio-watch-window-signify
错误查找
windows 还有一个小工具可以查看相应错误码是什么意思
但是只能输入数字,不能输入宏哦。
相应的API
当然如果想实现上面的工具的话windows 也提供了相应的api。
首先我们要用GetLastError来获得错误码(DWORD值)。然后就用到下面的函数了
//下面是UNICODE版本的
WINBASEAPI
_Success_(return != 0)
DWORD
WINAPI
FormatMessageW(
_In_ DWORD dwFlags,
_In_opt_ LPCVOID lpSource,
_In_ DWORD dwMessageId,
_In_ DWORD dwLanguageId,
_When_((dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) != 0, _At_((LPWSTR*)lpBuffer, _Outptr_result_z_))
_When_((dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) == 0, _Out_writes_z_(nSize))
LPWSTR lpBuffer,
_In_ DWORD nSize,
_In_opt_ va_list *Arguments
);
其实这个函数的功能是通过语言标识符来寻找相应的语言文本然后返回该文本。所以我们必须先翻译字符串,然后把并把翻译好的消息表(message table)资源嵌在.exe或者DLL模块的中。
如果希望穿件信息表可以使用Message Compiler(MC.exe)。或者上面错误查找工具的某块按钮
dwFlags
设置一些影响函数工作的标记。一般就是下面三个标记
- FORMAT_MESSAGE_ALLOCATE_BUFFER | :分配一块能容下翻译完的字符串,地址就是lpBuffer参数返回的值
- FORMAT_MESSAGE_FROM_SYSTEM |:获得系统定义的错误代码对应的字符串
- FORMAT_MESSAGE_IGNORE_INSERTS:字符串中可以出现%号。这个就像printf函数一样我们使用%来占位,但是因为有的异常会出现%号来显示一些设备信息所。如果设置这个参数,出现%号时Arguments参数就要提供相应的占位符值了
lpSource
我们的消息表地址。如果使用系统的错误码的话设置为nullptr就行了。
dwMessageId
指出想要查找的错误码ID
dwLanguageId
使用什么语言来显示.
lpBuffer
翻译完的字符串存储的地方
nSize
如果没有设置FORMAT_MESSAGE_ALLOCATE_BUFFER值就会返回需要缓冲区的大小(和字符串处理函数一样)。如果设置了就会返回其中字符的多少个。
Arguments
为占位符提供信息
下面是我从msdn上拔下来的一个例子
#include <windows.h>
#include <strsafe.h>
void ErrorExit(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
//MAKELANGID宏会把LANG_NEUTRAL,SUBLANG_DEFAULT揉成一个数,这个数就是0表示使用系统默认的语言
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
// Display the error message and exit the process
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
ExitProcess(dw);
}
void main()
{
// Generate an error
if(!GetProcessId(NULL))
ErrorExit(TEXT("GetProcessId"));
}
自定义错误码
当我们想使用自己的错误码时可以使用SetLastError函数来设置错误码。但是请遵守下面的规定
错误代码的不同字段位:
错误代码的不同字段位: | 31–30 | 29 | 28 | 27–16 | 15–0 |
内容 | 严重性 | Microsoft/ 客户 | 保留 | Facility 代码 | 异常代码 |
含义 | 0 = 成功 1 = 信息(提示) 2 = 警告 3 = 错误 | 0 = Microsoft 定义的代码 1 = 客户定义的代码 | 必须为 0 | 前 256个值由Microsoft保留 | Microsoft/ 客户定义的代码 |