Windows错误处理

Windows错误码

  Windows函数执行前会首先验证传递的参数,如果参数无效或者因为某些原因无法执行,失败原因会通过返回值来指出

数据类型失败的值
VOID不可能失败
BOOL失败返回0,否则返回非0.尽量检查返回值不为FALSE,而不是是否为TRUE
HANDLE函数失败通常返回NULL,某些函数失败返回INVALID_HANDLE_VALUE,否则,HANDLE将标识一个可以被操作的对象。查询文档来得知返回值
PVOID调用失败返回NULL,否则PVOID将标识一个数据块的内存地址
LONG/DWORD返回计数的函数通常返回LONG或者DWORD。如果函数不能对我们想要计数的东西进行计数,就会返回0或-1.需要查阅文档

在内部,当Windows函数检测到错误,就会使用“线程本地存储区”的机制将相应的错误码与“主调线程”关联到一起。这种机制保证不同的线程能独立运行,不会出现相互干扰对方错误代码的情况。

函数返回时返回值会指出错误,可以调用API函数来查询:

DWORD GetLastError();

这个函数返回由上一个函数调用设置的线程的32位错误码。我们获取错误码后需要转换为更有用的信息,可以查看WinError.h的头文件,头文件的一部分如下:


WinError.h
//MessageId: ERROR_SUCCESS

//MessageText:
//The operation completed successfully.

#define ERROR_SUCCESS       0L

每个错误都有三种表示:

  • 消息ID:一个可以在源代码中使用的宏,用于与GetLastError的返回值进行比较
  • 消息文本:描述错误的英文文本
  • 编号:避免使用此编号,尽量使用文本表示

Windows函数失败后要马上调用 GetLastError,如果在调用之前又调用了另一个Windows函数,那么此值很可能就被改写了。

在VS中,我们在代码的debug模式下查看watch窗口(监视),在某一行输入$err,hr就可以让它始终显示线程的上一个错误码和错误的描述文本。或者直接使用工具中的错误查找(Error lookup),将错误代码转换为文本。
在这里插入图片描述
在这里插入图片描述
Windows提供了一个函数,可以将错误代码转换为相应的文本描述,以便我们把错误描述打印出来,而且支持多种自然语言。它获取一个语言标识符作为参数,并返回那种语言的文本。我们应首先翻译字符串,并将翻译好的消息表嵌入到自己的.exe或DLL模块中。之后,这个函数就能自动选择正确的字符串。

DWORD FormatMessage(
	DWORD dwFlags,
	LPCVOID pSource,
	DWORD dwMessageId,
	DWORD dwLanguageId,
	PTSTR pszBuffer,
	DWORD nSize,
	va_list *Arguments);
  • dwFlags:格式化选项
    • FORMAT_MESSAGE_ALLOCATE_BUFFER // 此函数会分配内存以包含描述字串
    • FORMAT_MESSAGE_FROM_SYSTEM, // 在系统的id映射表中寻找描述字串
    • FORMAT_MESSAGE_FROM_HMODULE // 在其他资源模块中寻找描述字串
    • FORMAT_MESSAGE_FROM_STRING // 消息ID是个字串,不是个DWORD
    • 通常为:FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
  • pSource:消息表资源来自哪里,这个值依靠dwFlags.
    • 指定了FORMAT_MESSAGE_FROM_HMODULE的话,此参数表示模块的HANDLE.
    • 指定了FORMAT_MESSAGE_FROM_STRING的话,此参数表示id字串.
    • 如果这两个标示符都没设置,那么lpSource将会被忽略。
  • dwMessageId:所需格式化消息的标识符。当dwFlags设置了FORMAT_MESSAGE_FROM_STRING,这个参数将会被忽略
  • dwLanguageId:消息描述所用的语言.通常为:0表示自动选择
  • pszBuffer: 一个缓冲区指针来接受格式化后的消息。如果dwFlags没有指定FORMAT_MESSAGE_ALLOCATE_BUFFER,则为自己提供的缓冲区.否则为系统LocalAlloc分配,需要被用户LocalFree
  • nSize:如果FORMAT_MESSAGE_ALLOCATE_BUFFER没有设置,那么这个参数指定了输出缓冲区的消息,以TCHAR为单位。如果FORMAT_MESSAGE_ALLOCATE_BUFFER设置了,这个参数设置以TCHARs为单位的输出缓冲区的最小值。这个输出缓冲区不能大于64KB。
  • Arguments:通常不使用

定义自己的错误码

Windows可以向调用者指出错误,我们还可以把这种机制用在自己的函数中。我们自己的代码需要被他人调用,如果我们的函数调用失败,就要向他人指出错误。
我们只需要设置线程的上一个错误代码,然后令自己的函数返回FALSE、INVALID_HANDLE_VALUE、NULL或其他合适的值。我们可以调用下面的函数来设置上一个线程的错误代码,并传递我们认为合适的任何32位的值:

VOID SetLastError(DWORD dwErrCode);

只要Windows自己的代码能反映我们的错误,我们就应该用Windows的代码,如果WinError.h中的代码不能反映我们的错误,我们就可以创建自己的代码。错误代码是一个32位的数:

31-30292827-1615-0
内容严重性Microsift/客户保留Facility代码异常代码
含义0成功,1提示信息,2警告,3错误0是Microsift的代码,1是客户定义的代码必须是0前256个值由Microsift保留Microsift/客户定义的代码

我们要注意第29位,我们要自己创建错误码就要将此位设置为1.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值