zoukankan      html  css  js  c++  java
  • Windows系统错误处理机制

    一、什么是错误

    意为意为不正确,与正确答案相反。我们这里讲的是Windows操作系统里进程运行时产生的错误。对我们程序员来说,其实也就是我们编程过程中,调用Windows系统提供的API、COM 接口、内核驱动开发接口,这些API或接口失败时产生的错误。这些错误会导致我们的程序代码完成不了预设的功能或效果。

    二、Windows 错误机制

    首先,Windows会为各种API、接口失败的各种错误预先定义好,一种错误用一个错误码(Error Code)来表示。当错误产生时,API或接口会失败,有的是用返回值返回错误码,同时也表示调用成功或失败,比如COM接口;有的是用返回值代表成功或失败,错误码放在特定的区域,通过特定API去获取,比如大部分Win32 API,它将错误码存储在线程局部存储区里,永远记住最后一个错误码 ;有的是用状态码作为错误码,比如内核驱动开发接口

    Windows系统的错误机制,当进程产生非致命错误时,它不会改变线程的执行路径,但这不代表对程序没有影响。如果一个错误发生,我们不处理,而让程序继续往下跑,可能会导致后面更严重的问题。那么我们在Windows上编程时,应该调用API和接口后,及时检测是否失败,如果失败,检测错误,看是什么错误,做不同处理。

    在我们编程的过程种,经常遇到下面三种错误:

    • Win32 Error
    • COM Error
    • NTSTATUS

    三、Windows 错误代码(Error Code)

    3.1、Windows错误代码

    由前面我们知道常见的三种错误,他们都是通过错误代码来代表不同错误消息,它是一个DWORD值,也就是32bit,那么这个值得每一位或几位代表什么意思,Windows是有规定的,错误代码域也就是说错误代码的定义规则是怎样的。

    3.2、错误代码的生成
    3.2.1、编写错误信息文本文件
    应用程序可以根据业务需求按照Windows错误代码域的规则定义自己的错误码, 自定义错误码需要先编写一个错误信息文本文件。文件以.mc为后缀,其语法相对来说比较简单,该文件主要包括三部分,注释、信息头(Header Section)和信息体(Message Section)。
    • 注释
      注释是以分号(;)开头的行,在编译后生成的C/C++头文件中,MC编译器会去掉这些分号,也就是说,如果你要生成一些带C/C++的注释,在分号后再加入C/C++的注释即可,如:
    ;#ifndef _YOUR_MESSAGE_ERROR_TEXT_
    ;#define _YOUR_MESSAGE_ERROR_TEXT_
    
    ;// C/C++单行注释
    ;
    ;/*
    ; 
    ; C/C++块注释
    ; 
    ;*/
    ;#endif
    
    • 信息头部(Header Section)
      信息头部定义信息体中需要使用的一些名称和语言标识,可以包含以下0个或多个语法声明。
    语法说明
    MessageIdTypedef=type 声明错误码类型,该定义一般放到信息头部最前面,type在消息头文件(.h)中被使用。定义的类型(32位)必须要能够容纳所有的错误码。
    SeverityNames=(name=number[:SymbolName]) 声明错误等级集合,在30-31位中定义。可以定义多个错误等级,以空格分隔。默认定义为:
    SeverityNames=(Success=0x0 Informational=0x1 Warning=0x2 Error=0x3) ;name是错误等级名称,是在信息体中引用的名字。SymbolName是自定义的符号名,该符号编译后会在头文件中定义,具体见实例。
    FacilityNames=(name=number[:SymbolName]) 声明设备代码集合,在16-27位中定义,可以定义多个设备代码,中间以空格分隔。如果29为没有标记为1,则前256位系统保留使用,应用可以在0x100-0xFFF中定义。name是设备代码名称,是在信息体中引用的名字。SymbolName是自定义的符号名,该符号编译后会在头文件中定义,具体见实例。
    LanguageNames=(name=number:filename) 声明语言集合,其中name语句名称,是在信息体中需要引用的名字,可以支持多种语言,中间以空格分隔。number是语言标识,filename是包含对应语言的文件名,不带后缀,由MC编译器生成一个指定文件名加.bin的文件,用于存储对应语言的错误文本信息。语言标识(language identifier)由一个16bit的数组成,其中高6位是次语言标识(SubLanguage ID), 低10位是主语言标识(Primary Language ID)。关于语言标识的常量定义在这里。比如我要定义简体中文,主语言标识为0x04,次语言标识为0x02,故简体中文的语言标识为0x804,于是可以这样定义:
    LanguageNames=(Chinese=0x804:MSG00804)
    • 错误信息体(Message Section)
      信息体在信息头之后定义,下表是一个信息体可能包含的一些定义,每个信息体以MessageId开头,以单独成行的句点结束。Severity和Facility可选。
    语法说明
    MessageId=[number|+number] 消息标识,必须要定义,但其值是可选的,如果没有定义值,将使用上一个消息id加1。如果使用了+号,消息标识为在上一个消息id上加指定的number。所定义的消息标识大小不能超过16位;
    Severity=name 错误等级,如果Severity=Error;
    Facility=name 设备代码,如Facility=Application;
    SymbolicName=name 符号名称,该名称会被定义在C/C++头文件中,格式如:
    #define name ((type)0xnnnnnnnn);其中type在信息头MessageIdTypedef中声明;
    Language=name 信息语言,语言名称在信息头部定义,如果没定义默认为English。 如:Language=Chinese
    message text 信息对应语言的文本;
    . 以一个独立成行的句点作为信息体结束符;

    如果一个信息体支持多种语言,对每一种语言都需要一个语言声明、语言文本和独立成行的句点,如:

    MessageId=0x1
    Severity=Error
    Facility=Runtime
    SymbolicName=MSG_BAD_COMMAND
    Language=English
    You have chosen an incorrect command.
    .
    Language=Chinese
    <Chinese message string goes here>
    
    3.2.2、编译(MC.exe)
    编写好错误信息文本文件之后需要用Message Compiler(MC.exe)编译工具进行编译,mc的具体用法见这里。由于我们需要支持中文,所以需要指定-u参数,另外,如果我们想为设置29位为1,需要指定-c参数,如:

    mc.exe -cu MessageTable.mc

    编译成功后会生成四个文件:MessageTable.h、MessageTable.rc、MSG00409.bin、MSG00804.bin
    其中MessageTable.h的内容如下:

    #ifndef _ERROR_MESSAGE_TEXT_
    #define _ERROR_MESSAGE_TEXT_
    
    //
    //  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_TEST_3                  0x101
    #define FACILITY_TEST_2                  0x101
    #define FACILITY_TEST_1                  0x100
    
    
    //
    // Define the severity codes
    //
    #define ITEST_SEVERITY_WARNING           0x2
    #define TEST_SEVERITY_SUCESS             0x0
    #define ITEST_SEVERITY_INFORMATIONAL     0x1
    #define TEST_SEVERITY_ERROR              0x3
    
    
    //
    // MessageId: TEST_E_01
    //
    // MessageText:
    //
    // Define english string error message for TEST_E_01
    //
    #define TEST_E_01                        ((HRESULT)0xE1000001L)
    
    //
    // MessageId: TEST_E_02
    //
    // MessageText:
    //
    // Define english string error message for TEST_E_02
    //
    #define TEST_E_02                        ((HRESULT)0xE1000002L)
    
    //
    // MessageId: TEST_E_03
    //
    // MessageText:
    //
    // Define english string error message for TEST_E_03
    //
    #define TEST_E_03                        ((HRESULT)0xE1000003L)
    
    #endif
    

    注意,在生成的头文件中发现没有错误信息的中文文本说明,由于生成的头文件中只展示第一个定义的语言文本说明,如果想展示中文说明的话,在信息体把中文定义放在第一位就行了。如:

    MessageId=0x1 Severity=Error Facility=TestFacility1 SymbolicName=TEST_E_01
    Language=Chinese
    在这儿定义TEST_E_01的中文错误文本
    .
    Language=English
    Define english string error message for TEST_E_01

    更多参考:
    https://www.jianshu.com/p/04a4ace9a31d

  • 相关阅读:
    maven打包时加入依赖包及加入本地依赖包
    is_file和file_exists效率比较
    window.open()详解及浏览器兼容性问题示例探讨
    Zend Studio汉化失败,如何给Zend Studio进行汉化
    HTML页面跳转的5种方法
    PHP中的符号 ->、=> 和 :: 分别表示什么意思?
    php中$this->是什么意思
    关于define('DISCUZ_ROOT', substr(dirname(__FILE__), 0, -7));的理解
    【精华】PHP网站验证码不显示的终结解决方案
    php提示undefined index的几种解决方法
  • 原文地址:https://www.cnblogs.com/yilang/p/11150318.html
Copyright © 2011-2022 走看看