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

  • 相关阅读:
    Spring boot unable to determine jdbc url from datasouce
    Unable to create initial connections of pool. spring boot mysql
    spring boot MySQL Public Key Retrieval is not allowed
    spring boot no identifier specified for entity
    Establishing SSL connection without server's identity verification is not recommended
    eclipse unable to start within 45 seconds
    Oracle 数据库,远程访问 ora-12541:TNS:无监听程序
    macOS 下安装tomcat
    在macOS 上添加 JAVA_HOME 环境变量
    Maven2: Missing artifact but jars are in place
  • 原文地址:https://www.cnblogs.com/yilang/p/11150318.html
Copyright © 2011-2022 走看看