Windows核心编程笔记(一) 错误处理

    在Windows编程中我们调用各种Windows API函数来使用系统提供的各种基础支持,这些API函数并不是总是都能够预期完成所规定的工作的,有些时候会因为各种原因导致函数调用失败,比如传给函数的参数不正确,调用函数的权限不够,请求的资源系统暂时分配不了等等。

   大多时候根据函数的返回值,可以判断函数是否失败

Windows核心编程笔记(一) 错误处理_第1张图片


    Windows除了使用返回值标识函数执行情况,外还引入了错误代码机制。返回值指出函数已发生一个错误。要查看具体是什么错误,就应该使用错误代码。如当我们调用函数打开一个文件,如果打开失败,可能出现多种原因。一是:文件不存在,另一种是该文件被其他程序互斥使用。在这两种情况下都导致文件打开失败,返回值仅仅标识打开失败,但我们不知道原因。这时错误代码就派上用场了。


     Windows将错误代码存储于独立于线程的,线程局部存储区中。顾名思义,这个区域是每个线程独有的其他线程无法更改。它存储着一些线程独有的东西,在第二十一章有详细的介绍。在函数执行后,就可以通过调用GetLastError()来获得错误代码。因此这个错误代码永远反映的是上一个函数的执行情况,也就是说它的值是由上一个函数设置的。因此,当调用一个API函数后应该在调用其他API之前使用GetLastError'来获取具体的错误代码(避免被其他API改写Error值),进而判定失败的原因。


      有些时候从API函数的返回值来判定为成功,但是函数的成功可能缘于不同的原因,例如使用CreateEvent创建一个具名的事件对象时,函数成存在两种情况:1、对象实际创建成功2、打开了已存在的同名事件对象。这时我们可以调用GetLastError根据返回值是不是ERROR_ALREADY_EXISTS来判定是不是打开了同名的对象。


     GetLastError函数的原型如下

DWORD WINAPI GetLastError(void);

他的返回值是一个DWORD类型,在Windows SDK的winerror.h文件中为这些表示错误的DWORD值定义了宏和注释,格式如下

//
// 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.

    第一行是错误代码的宏定义  每一个DWORD对应一个宏标记,方面理解错误代码的函数,这些宏都以ERROR_开头,宏下面的第三行是对错误代码的含义注释

    在我们自己编写的函数中可以使用这种机制,我们的函数可能因为N中原因导致失败,我们可以再让函数返回失败的值得同时为每一种失败原因设置同Windows AP一样的错误码,Windows提供了让我们来设置错误码的系统函数  SetLastError,


void WINAPI SetLastError(
  __in  DWORD dwErrCode
);

我们应该尽量使用WinError.h中现有的错误码,只要可以很好的反应想报告的错我。如果没有合适的可以定义自己错误码,32位的错误码被分为了不同的字段,其结构如下

Windows核心编程笔记(一) 错误处理_第2张图片


可以定义自己的错误代码宏,来方便的完成错误的定义

例如  我们定义一个错误码表示在一个获取网页的函数中域名不正确,可以这样来做

#define    FACILITY_HTTP    257

#define     COVERT_HTTP(x)    (x<=0?x:((x&0x0000FFFF)|((FACILITY_HTTP<<16)|0xA0000000)))


#define    ERROR_DOMAIN_NO_EXISTS COVERT_HTTP(1L)


   另外Windwos提供了一个API函数FormatMessage函数来获取相应错误码的 详细描述 具体使用参见MSDN


DWORD WINAPI FormatMessage(
  __in      DWORD dwFlags,
  __in_opt  LPCVOID lpSource,
  __in      DWORD dwMessageId,
  __in      DWORD dwLanguageId,
  __out     LPTSTR lpBuffer,
  __in      DWORD nSize,
  __in_opt  va_list *Arguments
);

QT实现了下Error Lookup程序


#include "dialog.h"
#include "ui_dialog.h"
#include 
Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    ui->edit_ErrorCode->setValidator(new QIntValidator(0,65536,this));
    hlocal =  (LPSTR)VirtualAlloc(NULL,256,MEM_COMMIT | MEM_RESERVE,PAGE_READWRITE);
}

Dialog::~Dialog()
{
    delete ui;
}


void Dialog::on_btn_LookUp_pressed()

{
    QString str = ui->edit_ErrorCode->text();
    DWORD systemLocale = MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL);
    BOOL bRet = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS \
        | FORMAT_MESSAGE_MAX_WIDTH_MASK,NULL,str.toLong(),0,(LPSTR)hlocal,256,NULL);
    if(!bRet)
    {
        HMODULE hDll = LoadLibraryExA("netmsg.dll",NULL,DONT_RESOLVE_DLL_REFERENCES);
        if(hDll != NULL)
        {
             bRet = FormatMessageA(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS \
                | FORMAT_MESSAGE_ALLOCATE_BUFFER,hDll,str.toLong(),systemLocale,hlocal,256,NULL);
            FreeLibrary(hDll);
        }
    }
    QString strMsg;
    if(!bRet)
    {
        memset(hlocal,0,256);
        sprintf(hlocal,"无法找到关于%d的描述",str.toLong());
        strMsg = QString::fromUtf8(hlocal);
    }
    else
    {
        strMsg = QString::fromLocal8Bit(hlocal);
    }

    ui->textEdit->clear();
    ui->textEdit->append(strMsg);
    memset(hlocal,0,256);
}


你可能感兴趣的:(Windows核心编程,笔记)