第一范文网 - 专业文章范例文档资料分享平台

Windows核心编程(第5版)ch01

来源:用户分享 时间:2025/5/26 4:44:47 本文由loading 分享 下载这篇文档手机版
说明:文章内容仅供预览,部分内容可能不全,需要完整文档或者需要复制内容,请下载word后使用。下载word有问题请添加微信号:xxxxxxx或QQ:xxxxxx 处理(尽可能给您提供完整文档),感谢您的支持与谅解。

第1章 错 误 处 理

本章内容

1.1 定义自己的错误代码 1.2 ErrorShow示例程序

在深入讨论Microsoft Windows 提供的诸多特性之前,应该先理解各个Windows函数是如何进行错误处理的。

调用Windows函数时,它会先验证我们传给它的参数,然后再开始执行任务。如果传入的参数无效,或者由于其他原因导致操作无法执行,则函数的返回值将指出函数因为某些原因失败了。表1-1展示了大多数Windows函数使用的返回值的数据类型。

表1-1 常见的Windows函数返回值数据类型

数据类型 VOID BOOL HANDLE 指出函数调用失败的值 这个函数不可能失败。只有极少数Windows函数的返回值类型为VOID 如果函数失败,返回值为0;否则,返回值是一个非0值。应避免测试返回值是否为TRUE;最稳妥的做法是检查它是否不为FALSE 如果函数失败,则返回值通常为NULL;否则,HANDLE将标识一个可以操纵的对象。请注意这种返回值,因为某些函数会返回为INVALID_HANDLE_VALUE的一个句柄值,它被定义为–1。函数的Platform SDK文档清楚说明了函数是返回NULL还是INVALID_HANDLE_VALUE来标识失败 PVOID LONG/DWORD 如果函数调用失败,则返回值为NULL;否则,PVOID将标识一个数据块的内存地址 这种类型比较棘手。返回计数的函数通常会返回一个LONG或DWORD。如果函数出于某种原因不能对我们想要计数的东西进行计数,它通常会返回0 或–1(具体取决于函数)。如果要调用一个返回LONG/DWORD的函数,务必仔细阅读Platform SDK文档,确保我们会正确地检查可能出现的错误 通常情况下,如果Windows函数能返回错误代码,将有助于我们理解函数调用为什么会失

败。Microsoft编辑了一个列表,其中列出了所有可能的错误代码,并为每个错误代码都分配了一个32位的编号。

3

(thread-local 在内部,当Windows函数检测到错误时,它会使用一种名为“线程本地存储区”

Windows核心编程(第5版)

storage)的机制将相应的错误代码与“主调线程”(或者说发出调用的线程,即calling thread)关联到一起(线程本地存储区的详情将在第21章讨论)。这种机制使不同的线程能独立运行,不会出现相互干扰对方的错误代码的情况。函数返回时,其返回值会指出已发生一个错误。要查看具体是什么错误,请调用GetLastError函数,如下所示:

DWORD GetLastError();

此函数的作用很简单,就是返回由上一个函数调用设置的线程的32位错误代码。 有了32位错误代码之后,接着需要把它转换为更有用的信息。WinError.h头文件包含了Microsoft定义的错误代码列表。为便于体验,下面摘录了其中的一部分:

// MessageId: ERROR_SUCCESS //

// MessageText: //

// The operation completed successfully. //

#define ERROR_SUCCESS 0L

#define NO_ERROR 0L // dderror #define SEC_E_OK ((HRESULT)0x00000000L) //

// MessageId: ERROR_INVALID_FUNCTION //

// MessageText: //

// Incorrect function. //

#define ERROR_INVALID_FUNCTION 1L // dderror //

// MessageId: ERROR_FILE_NOT_FOUND //

// MessageText: //

// The system cannot find the file specified. //

#define ERROR_FILE_NOT_FOUND 2L //

// MessageId: ERROR_PATH_NOT_FOUND //

// MessageText: //

// The system cannot find the path specified. //

#define ERROR_PATH_NOT_FOUND 3L //

// MessageId: ERROR_TOO_MANY_OPEN_FILES //

// MessageText: //

// The system cannot open the file. //

#define ERROR_TOO_MANY_OPEN_FILES 4L //

// MessageId: ERROR_ACCESS_DENIED //

// MessageText:

4

//

// Access is denied. //

#define ERROR_ACCESS_DENIED

第1章 错误处理

5L

3~5

可以看出,每个错误都有三种表示:一个消息ID(一个可在源代码中使用的宏,用于与

GetLastError的返回值进行比较)、消息文本(描述错误的英文文本)和一个编号(应该避免使用此编号,尽量使用消息ID)。注意,这里只摘录了WinError.h头文件的极小一部分,整个文件的长度超过39 000行!

Windows函数失败之后,应该马上调用GetLastError,因为假如又调用了另一个Windows函数,则此值很可能被改写。注意,成功调用的Windows函数可能用ERROR_SUCCESS改写此值。

一些Windows函数调用成功可能是缘于不同的原因。例如,创建一个具名事件内核对象时,以下两种情况均会成功:对象实际完成创建,或者存在一个同名的事件内核对象。应用程

Microsoft选择采用“上一个错误代码”(last 序也许需要知道成功的原因。为返回这种信息,

error code)机制。所以,特定函数调用成功时,可以调用GetLastError来确定额外的信息。

Platform SDK文档会清楚指明能以这种方式调用GetLastError。对于具有这种行为的函数,

文档中提供了CreateEvent函数的一个例子;如果已经存在具名事件,就返回ERROR_ALREADY_EXISTS。

调试程序时,我发现对线程的“上一个错误代码”进行监视是相当有用的。在Microsoft Visual Studio中,Microsoft的调试器支持一个很有用的功能——我们可以配置Watch(监视)窗口,让它始终显示线程的上一个错误代码和错误的文本描述。具体的做法是:在Watch窗口中选择一行,然后输入$err,hr。我们来看看图1-1的例子。在这个例子中,我已经调用了CreateFile函数。该函数返回值为INVALID_HANDLE_VALUE (–1)的一个HANDLE,指出它无法打开指定文件。但是Watch窗口指出,上一个错误代码(也就是调用GetLastError函数返回的错误代码)是0x00000002。多亏有了,hr限定符,Watch窗口进一步指出错误代码2是“The system cannot find the file specified.”(系统找不到指定文件)。这就是在WinError.h头文件中为错误代码2列出的消息文本。

5

图1-1 在Visual Studio的Watch窗口中使用$err,hr来查看当前线程的“上一个错误代码”

5

Windows核心编程(第5版)

Visual Studio还搭载了一个很小的实用程序,名为Error Lookup。利用它,可以将错误代码转换为相应的文本描述。如下图所示。

如果我在自己写的程序中检测到一个错误,我可能希望向用户显示错误的文本描述,而不是显示一个干巴巴的错误编号。Windows提供了一个函数,可以将错误代码转换为相应的文本描述。此函数名为FormatMessage,如下所示:

DWORD FormatMessage( DWORD dwFlags, LPCVOID pSource, DWORD dwMessageId, DWORD dwLanguageId, PTSTR pszBuffer, DWORD nSize,

va_list *Arguments);

FormatMessage的功能实际相当丰富,若想生成向用户显示的字符串,那么它是首选的一

种方式。之所以说它好用,一个原因是它能轻松地支持多种语言。它能获取一个语言标识符作为参数,并返回那种语言的文本。当然,我们首先必须翻译字符串,并将翻译好的消息表(message table)资源嵌入自己的.exe或DLL模块中。但在此之后,这个函数就能自动选择正确的字符串。ErrorShow示例程序(参见后文)演示了如何调用这个函数将Microsoft定义的错误代码编号转换为相应的文本描述。

经常有人问我,Microsoft是否维护着一个主控列表,其中完整列出了每个Windows函数可能返回的所有错误代码。很遗憾,答案是否定的。而且,Microsoft决不可能提供这样的列表,因为随着新版本的操作系统的问世,这样的列表将很难构建和维护。

6

这种列表的问题在于,我们可以调用一个Windows函数,但在内部,这个函数可能调用另一个函数,后者又可能调用其他函数??以此类推。出于众多原因,任何一个函数都可能失败。有时,当一个函数失败时,较高级别的函数也许能够恢复,并继续执行我们希望的操作。要创建这种主控列表,Microsoft必须跟踪每个函数的路径,生成所有可能的错误代码的列表。这是非常难的。而且,随着新版本的操作系统的发布,这些函数的执行路径也可能发生改变。

① 译注:这里的语言是自然语言,如汉语、英语等,而不是计算机编程语言。

6

搜索更多关于: Windows核心编程(第5版)ch01 的文档
Windows核心编程(第5版)ch01.doc 将本文的Word文档下载到电脑,方便复制、编辑、收藏和打印
本文链接:https://www.diyifanwen.net/c30njk7808n9emep57bjn_1.html(转载请注明文章来源)
热门推荐
Copyright © 2012-2023 第一范文网 版权所有 免责声明 | 联系我们
声明 :本网站尊重并保护知识产权,根据《信息网络传播权保护条例》,如果我们转载的作品侵犯了您的权利,请在一个月内通知我们,我们会及时删除。
客服QQ:xxxxxx 邮箱:xxxxxx@qq.com
渝ICP备2023013149号
Top