第一章主要讨论了Microsoft Windows程序错误的处理机制。以下是核心内容的总结:
参数有效性检验:Windows函数在执行任务前会检查传递给它的参数是否有效。如果参数无效或操作无法执行,函数会返回一个指示失败的值。
返回值类型:表1-1列出了Windows函数常用的返回值类型及其表示失败的值:
VOID:函数不可能失败。
BOOL:失败返回0,成功返回非0值。
HANDLE:失败返回NULL或INVALID_HANDLE_VALUE(-1)。
PVOID:失败返回NULL,成功返回内存地址。
LONG/DWORD:返回数量,失败可能返回0或-1。
错误代码:Windows函数失败时会返回一个错误代码,可通过调用GetLastError函数获取。错误代码是一个32位的数值,包含错误类型和设备特定代码。
错误处理:当函数失败时,应立即调用GetLastError以获取错误代码。需要注意的是,调用其他Windows函数可能会改写这个错误代码。
Windows 98的特殊性:许多Windows 98函数是基于16位代码实现的,这些函数不会通过GetLastError报告错误,因此无法确定失败原因。
成功原因的确定:有时函数成功运行可能有不同的原因,可以通过GetLastError获取额外信息。
调试工具:Visual Studio 6.0提供了调试工具,如Watch窗口和Error Lookup,帮助开发者监控和查找错误代码。
错误消息的本地化:FormatMessage函数可以根据用户的首选语言返回错误代码的文本描述。
自定义错误代码:开发者可以定义自己的错误代码,但必须确保与Microsoft定义的错误代码不冲突,这通常通过设置特定的位来实现。
ErrorShow示例应用程序:展示了如何使用FormatMessage函数获取错误代码的文本描述。
GetLastError:用于获取线程的32位错误代码,这个函数返回线程的最后一个错误。
FormatMessage:用于将错误代码转换成文本描述。函数原型大致如下:
DWORD FormatMessage(
DWORD dwFlags,
LPCVOID lpSource,
DWORD dwMessageId,
DWORD dwLanguageId,
LPTSTR lpBuffer,
DWORD nSize,
va_list *Arguments
);
CreateEvent:创建或打开一个事件对象的函数,示例中提到了这个函数。
CreateFile:示例中提到了这个函数,用于打开或创建文件。
ErrorShow:示例应用程序,用于展示如何获取错误代码的文本描述。
NetMsg.dll:示例中提到使用这个模块来获取与网络相关的错误消息。
Message Compiler (MC.exe):用于将错误代码添加给模块,并将资源添加给模块的工具。
错误代码域的位表示,例如严重性位、Microsoft/客户保留位、设备代码位、异常代码位等。
错误代码的自定义设置,例如设置第29位为1以区分自定义错误代码。
在实际的Windows开发过程中,第一章提到的知识点非常关键,以下是一些常用到的知识点:
参数有效性检验:在调用任何Windows API之前,检查参数的有效性是一个基本的实践,以确保函数调用不会因参数错误而失败。
错误处理机制:了解如何通过返回值和错误代码来识别和处理函数调用失败的情况。
使用GetLastError:在函数调用后立即使用GetLastError来获取和诊断错误,这是调试和错误处理的标准步骤。
理解返回值类型:根据函数返回的数据类型(如BOOL、HANDLE、PVOID、LONG/DWORD等),正确地解释返回值,以判断函数是否成功执行。
错误消息的本地化:使用FormatMessage函数来获取适合用户语言的错误描述,这对于创建多语言应用程序尤为重要。
自定义错误代码:在开发自己的函数或应用程序时,定义和使用自定义错误代码,以便更精确地传达错误信息。
调试工具的使用:利用Visual Studio等IDE的调试工具,如Watch窗口,来监控和诊断运行时错误。
错误消息的显示:使用FormatMessage和其他相关函数向用户显示友好的错误信息,而不是直接显示技术性的错误代码。
跨平台兼容性:了解Windows 98等旧版本系统的特定行为,以及它们与现代Windows系统在错误处理上的差异。
错误代码域的理解:理解错误代码的各个组成部分,如严重性、设备代码等,这有助于更准确地诊断问题。
资源管理:正确处理函数可能返回的资源句柄,如文件句柄、窗口句柄等,并在不再需要时适当释放它们。
异常处理:在可能的情况下,使用结构化异常处理(SEH)来捕获和处理运行时异常