赞
踩
在开发当中难免会出现函数调用失败,一般情况下我们肯定很急切的想知道是什么致使函数调用失败,作为初级程序员的我们一般为了判断自己的函数调用失败的原因都会选择使用很多的if-else函数来实现,但是要是函数当中会有很多执行失败那么if-else会使我们的函数很杂乱。为了解决这种问题Microsoft提供了错误处理机制。
在一个函数调用完之后我们可以运用两个函数:
GetLastError();
SetLastError():
首先GetLastError会返回我们上次函数的执行情况,它的返回值为一个32位的编号:根据此编号我们可以去WinError.h中查找;WinError.h 结构如下所示:
/************************************************************************
* *
* winerror.h -- error code definitions for the Win32 API functions *
* *
* Copyright (c) Microsoft Corp. All rights reserved. *
* *
************************************************************************/#ifndef _WINERROR_
#define _WINERROR_#if defined (_MSC_VER) && (_MSC_VER >= 1020) && !defined(__midl)
#pragma once
#endif#ifndef FORCEINLINE
#if (_MSC_VER >= 1200)
#define FORCEINLINE __forceinline
#else
#define FORCEINLINE __inline
#endif
#endif#include <specstrings.h>
//
// Note: There is a slightly modified layout for HRESULT values below,
// after the heading "COM Error Codes".
//
// Values are 32 bit values laid out as follows:
//
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// +---+-+-+-----------------------+-------------------------------+
// |Sev|C|R| Facility | Code |
// +---+-+-+-----------------------+-------------------------------+
//
// where
//
// Sev - is the severity code
//
// 00 - Success
// 01 - Informational
// 10 - Warning
// 11 - Error
//
// C - is the Customer code flag
//
// R - is a reserved bit
//
// Facility - is the facility code
//
// Code - is the facility's status code
//
//
// Define the facility codes
//
#define FACILITY_XPS 82
#define FACILITY_WINRM 51
#define FACILITY_WINDOWSUPDATE 36
#define FACILITY_WINDOWS_DEFENDER 80
#define FACILITY_WINDOWS_CE 24
#define FACILITY_WINDOWS 8
#define FACILITY_USERMODE_VOLMGR 56
#define FACILITY_USERMODE_VIRTUALIZATION 55
#define FACILITY_USERMODE_VHD 58
#define FACILITY_URT 19
#define FACILITY_UMI 22
#define FACILITY_UI 42
#define FACILITY_TPM_SOFTWARE 41
#define FACILITY_TPM_SERVICES 40
#define FACILITY_SXS 23
#define FACILITY_STORAGE 3
#define FACILITY_STATE_MANAGEMENT 34
#define FACILITY_SSPI 9
#define FACILITY_SCARD 16
#define FACILITY_SHELL 39
#define FACILITY_SETUPAPI 15
#define FACILITY_SECURITY 9
#define FACILITY_SDIAG 60
#define FACILITY_RPC 1
#define FACILITY_RAS 83
#define FACILITY_PLA 48
#define FACILITY_OPC 81
#define FACILITY_WIN32 7
#define FACILITY_CONTROL 10
#define FACILITY_WEBSERVICES 61
#define FACILITY_NULL 0
#define FACILITY_NDIS 52
#define FACILITY_METADIRECTORY 35
#define FACILITY_MSMQ 14
#define FACILITY_MEDIASERVER 13
#define FACILITY_MBN 84
#define FACILITY_INTERNET 12
#define FACILITY_ITF 4
#define FACILITY_USERMODE_HYPERVISOR 53
#define FACILITY_HTTP 25
#define FACILITY_GRAPHICS 38
#define FACILITY_FWP 50
#define FACILITY_FVE 49
#define FACILITY_USERMODE_FILTER_MANAGER 31
#define FACILITY_DPLAY 21
#define FACILITY_DISPATCH 2
#define FACILITY_DIRECTORYSERVICE 37
#define FACILITY_CONFIGURATION 33
#define FACILITY_COMPLUS 17
#define FACILITY_USERMODE_COMMONLOG 26
#define FACILITY_CMI 54
#define FACILITY_CERT 11
#define FACILITY_BCD 57
#define FACILITY_BACKGROUNDCOPY 32
#define FACILITY_ACS 20
#define FACILITY_AAF 18
// Define the severity codes
// 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
可以看出,每个错误都有三种表示:一个消息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。
对于查找错误信息的文本格式我们特别要提到的就是: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定义的错误代码编号转换为相应的文本描述。
定义自己的错误代码前面讲述了Windows函数如何向其调用者指出错误。除此之外,Microsoft还允许将这种机制用于你自己的函数中。假定你要写一个供其他人调用的函数。这个函数可能会因为这样或那样的原因而失败,所以需要向调用者指出错误。为了指出错误,只需设置线程的上一个错误代码,然后令自己的函数返回FALSE,INVALID_HANDLE_VALUE、NULL或者其他合适的值。为了设置线程的上一个错误代码,只需调用以下函数,并传递你认为合适的任何32位值:
VOID SetLastError(DWORD dwErrCode);
我会尽量使用WinError.h中现有的代码??只要代码能很好地反映我想报告的错误。如果WinError.h中的任何一个代码都不能准确反映一个错误,就可以创建自己的代码。错误代码是一个32位数,由表1-2描述的几个不同的字段组成。
表1-2错误代码的不同字段位:
表 1-2错误代码的不同字段位: | 31–30 | 29 | 28 | 27–16 | 15–0 |
内容 | 严重性 | Microsoft/ 客户 | 保留 | Facility 代码 | 异常代码 |
含义 | 0 = 成功 1 = 信息(提示) 2 = 警告 3 = 错误 | 0 = Microsoft 定义的代码 1 = 客户定义的代码 | 必须为 0 | 前 256个值由Microsoft保留 | Microsoft/ 客户定义的代码 |
/ / Get the error code
DWORD dwError = GetDlgItemInt(hwnd, IDC_ERRORCODE, NULL, FALSE);
HLOCAL hlocal = NULL; // Buffer that gets the error message string
// Use the default system locale since we look for Windows messages
// Note: this MAKELANGID combination has a value of 0
DWORD systemLocale = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
// Get the error code's textual description
BOOL fOk = FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, dwError, systemLocale,
(PTSTR) &hlocal, 0, NULL);
if (!fOk) {
// Is it a network-related error?
HMODULE hDll = LoadLibraryEx(TEXT("netmsg.dll"), NULL,
DONT_RESOLVE_DLL_REFERENCES);
if (hDll != NULL) {
fOk = FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
hDll, dwError, systemLocale,
(PTSTR) &hlocal, 0, NULL);
FreeLibrary(hDll);
}
}
if (fOk && (hlocal != NULL)) {
SetDlgItemText(hwnd, IDC_ERRORTEXT, (PCTSTR) LocalLock(hlocal));
LocalFree(hlocal);
} else {
SetDlgItemText(hwnd, IDC_ERRORTEXT,
TEXT("No text found for this error number."));
第一行从编辑控件获取错误代码。然后,指向一个内存块的句柄被实例化并初始化为NULL。FormatMessage函数在内部分配内存块,并返回指向这个内存块的句柄。调用FormatMessage时,我们向它传入了FORMAT_MESSAGE_FROM_SYSTEM标志。该标志告诉FormatMessage:我们希望获得与一个系统定义的错误代码对应的字符串。另外,还传入了FORMAT_MESSAGE_ALLOCATE_BUFFER标志,要求该函数分配一个足以容纳错误文本描述的内存块。此内存块的句柄将在hlocal变量中返回。FORMAT_MESSAGE_IGNORE_INSERTS标志则允许你获得含有%占位符的消息。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。