《Windows核心编程》のWindows返回值

当调用一个Windows函数时,它首先检验传递给它的各个参数的有效性,然后再设法执行任务。如果传递了一个无效参数,或者由于某种原因无法执行这项操作,那么操作系统就会返回一个值,指明该函数在某种程度上运行失败了。

 

下面说说Windows常见的返回值类型:

1)  VOID:表明该函数运行不可能失败,Windows函数的返回值很少是VOID

2) BOOL:如果函数运行失败,返回值是0,否则返回值是非0值。最好对返回值进行测试,以确定它是0还是非0,而不是测试返回值是否是TRUE

3) HANDLE:如果函数运行失败,则返回值通常是NULL,否则返回值是某个HANDLE,用于标识你可以操作的一个对象。F.Y.I,有些函数失败时会返回一个句柄值INVALID_HANDLE_VALUE,它被定义为-1。函数的Platform SDK文档将会清楚地说明函数运行失败时返回值是NULL还是INVALID_HANDLE_VALUE

4) PVOID:如果函数运行失败,返回值是NULL,否则返回PVOID,以标识数据块的内存地址。

5) LONG/DWORD:这是个难以处理的值。返回数量的函数通常返回LONGDWORD,如果由于某种原因,函数无法对想要进行计数的对象进行计数,那么该函数通常返回0-1(根据函数而定)。如果调用的函数返回值为LONGDWORD,那么得阅读Platform SDK以确保能正确检测潜在的错误。

 

一个Windows函数返回的错误代码对了解函数运行失败的原因是很有用的。Microsoft编译了一个所有可能的错误代码的列表,并且为每个错误代码分配了一个32位的号码。若要确定这是个什么错误,可以调用GetLastError函数:

DWORD GetLastError();

该函数只返回线程的32位错误代码,我们需要将它转换成更便于理解的某种东西。在WinError.h头文件中包含了Microsoft定义的错误代码的列表。格式如下:

// DNS_INFO_NO_RECORDS                   0x0000251d

//

// MessageId: DNS_INFO_NO_RECORDS

//

// MessageText:

//

//  No records found for given DNS query.

//

#define DNS_INFO_NO_RECORDS              9501L  //(0x0000251d的十进制值)

 

 

我们可以看到,每个错误有三种表示法:一个消息ID(这是我们可以在源代码中使用的一个宏,以便于与GetLastError的返回值进行比较)、消息文本(对错误的英文描述)和一个号码(应该避免直接使用该号码,而是使用消息ID

 

Windows函数运行失败时,应该立即调用GetLastError函数。因为如果调用另一个Windows函数,GetLastError的返回值很可能被改写。

 

如果在编写的应用程序中发现一个错误,可能需要向用户显示该错误的文本描述。Windows提供了一个函数,可以将错误代码转换成它的文本描述。该函数就是FormatMessage

DWORD FormatMessage(

  __in  DWORD dwFlags,      // source and processing options

  __in_opt  LPCVOID lpSource,   // pointer to message source

  __in  DWORD dwMessageId,  // requested message identifier

  __in  DWORD dwLanguageId, // language identifier for requested message

  __out  LPTSTR lpBuffer,    // pointer to message buffer

  __in  DWORD nSize,        // maximum size of message buffer

  __in_opt  va_list *Arguments  // pointer to array of message inserts

);

 

FormatMessage函数的功能是非常丰富的,在创建向用户显示的字符串信息时,它是首选函数。原因之一是它很容易用多种语言进行操作,该函数能够检测出用户首选地语言,并返回相应的文本。

下面是FormatMessage的实例代码:

#include <windows.h>

#include <lmerr.h>

#include <tchar.h>

 

#define ERRMSGBUFFERSIZE 256

 

void fnDisplayError( DWORD dwErrorMsgId )

{

         DWORD ret;        // Temp space to hold a return value.

         HINSTANCE hInst;  // Instance handle for DLL.

         HLOCAL pBuffer;   // Buffer to hold the textual error description.

 

         if ( HRESULT_FACILITY(dwErrorMsgId) == FACILITY_MSMQ )

         {

                   // MSMQ errors only (see winerror.h for facility info).

                   // Load the MSMQ library containing the error message strings.

                   hInst = LoadLibrary( TEXT("MQUTIL.DLL") );

                   if(hInst != 0)

                   {

                            // hInst not NULL if the library was successfully loaded.

                            // Get the text string for a message definition

                            ret = FormatMessage(

                                              FORMAT_MESSAGE_ALLOCATE_BUFFER | // Function will handle memory allocation.

                                               FORMAT_MESSAGE_FROM_HMODULE | // Using a module's message table.

                                               FORMAT_MESSAGE_IGNORE_INSERTS,

                                               hInst, // Handle to the DLL.

                                               dwErrorMsgId, // Message identifier.

                                               MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language.

                                               (LPTSTR)&pBuffer, // Buffer that will hold the text string.

                                                                                                          ERRMSGBUFFERSIZE, // Allocate at least this many chars for pBuffer.

                                               NULL // No insert values.

                                               );

                   } // hInst not NULL if the library was successfully loaded.

         } // MSMQ errors only.

         else if ( dwErrorMsgId >= NERR_BASE && dwErrorMsgId <= MAX_NERR )

         {

                   // Could be a network error.

                   // Load the library containing network messages.

                   hInst = LoadLibrary( TEXT("NETMSG.DLL") );

                   if(hInst != 0)

                   {

                            // Not NULL if successfully loaded.

                            // Get a text string for the message definition.

                            ret = FormatMessage( 

                                               FORMAT_MESSAGE_ALLOCATE_BUFFER | // The function will allocate memory for the message.

                                               FORMAT_MESSAGE_FROM_HMODULE | // Message definition is in a module.

                                               FORMAT_MESSAGE_IGNORE_INSERTS,  // No inserts used.

                                               hInst, // Handle to the module containing the definition.

                                               dwErrorMsgId, // Message identifier.

                                               MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language.

                                               (LPTSTR)&pBuffer, // Buffer to hold the text string.

                                               ERRMSGBUFFERSIZE, // Smallest size that will be allocated for pBuffer.

                                               NULL // No inserts.

                                     );

                   } // Not NULL if successfully loaded.

         } // Could be a network error.

         else

         {

                   // Unknown message source.

                   // Get the message string from the system.

                   ret = FormatMessage( 

                                     FORMAT_MESSAGE_ALLOCATE_BUFFER | // The function will allocate space for pBuffer.

                                     FORMAT_MESSAGE_FROM_SYSTEM | // System wide message.

                                     FORMAT_MESSAGE_IGNORE_INSERTS, // No inserts.

                                     NULL, // Message is not in a module.

                                     dwErrorMsgId, // Message identifier.

                                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language.

                                     (LPTSTR)&pBuffer, // Buffer to hold the text string.

                                     ERRMSGBUFFERSIZE, // The function will allocate at least this much for pBuffer.

                                     NULL // No inserts.

                            );

         }

         // Display the string.

         if( ret )

         {

                   _tprintf( _TEXT("/tERRORMESSAGE: %s/n"), (LPTSTR)pBuffer );

         }

         else

         {

                   _tprintf( _TEXT("/tERRORNUMBER: %d/n"), dwErrorMsgId );

         }

         // Free the buffer.

         LocalFree( pBuffer );

}

 

 

我们如何利用该机制来定义自己函数返回的错误代码呢?若要指明函数运行失败,只需要设定线程的最后的错误代码,然后让我们的函数返回FALSEINVALID_HANDLE_VALUENULL或返回任何合适的信息。设定线程的最后错误代码只需调用下面代码:

VOID SetLastError(DWORD dwErrCode);         

可以将合适的任何32位号码传递给该函数,包括WinError.h中已经存在的代码,只要该代码能够正确指明想要报告的错误即可。我们也可以创建自己的错误代码。错误代码是一个32位的数字,格式如下表:

31~30

29

28

27~16

15~0

内容

含义

严重性

0=成功

1=供参考

2=警告

3=错误

0=Microsoft定义的代码

 

1=客户定义的代码

保留

必须是0

设备代码

Microsoft定义

异常代码

Microsoft或用户定义

posted on 2010-04-18 22:52  android开发实例  阅读(498)  评论(0编辑  收藏  举报

导航