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是有规定的,错误代码域也就是说错误代码的定义规则是怎样的。
应用程序可以根据业务需求按照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
Windows系统错误处理机制的更多相关文章
- windows程序消息机制(Winform界面更新有关)
windows程序消息机制(Winform界面更新有关) 转自:http://www.cnblogs.com/blosaa/archive/2013/05/31/3109586.html 1. Win ...
- windows程序消息机制(Winform界面更新有关)--转
1. Windows程序消息机制 Windows GUI程序是基于消息机制的,有个主线程维护着消息泵.这个消息泵让windows程序生生不息. Windows程序有个消息队列,窗体上的所有消息是这个队 ...
- 深入详解windows安全认证机制ntlm&Kerberos
0x01 为什么要理解windows 安全认证机制: 加深对后续各种漏洞利用的理解深度,还是那句话,要知其然,更要知其所以然,不废话,咱们直接开始 0x02 windows认证协议主要有以下两种: 基 ...
- 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
本文背景: 在编程中,很多Windows或C++的内存函数不知道有什么区别,更别谈有效使用:根本的原因是,没有清楚的理解操作系统的内存管理机制,本文企图通过简单的总结描述,结合实例来阐明这个机制. 本 ...
- 全面介绍Windows内存管理机制及C++内存分配实例
转自:http://blog.csdn.net/yeming81/article/details/2046193 本文基本上是windows via c/c++上的内容,笔记做得不错.. 本文背景: ...
- windows 系统错误码总结
windows 错误码大全: 操作成功完成. 功能错误. 系统找不到指定的文件. 系统找不到指定的路径. 系统无法打开文件. 拒绝访问. 句柄无效. 存储控制块被损坏. 存储空间不足,无法处理此命令. ...
- 逆向工程学习第四天--Windows栈溢出保护机制(GS)原理及绕过测试
GS简介: Windows的缓冲区安全监测机制(GS)可以有效的阻止经典的BOF攻击,因为GS会在函数调用前往函数栈帧内压入一个随机数(canary),然后等函数返回前,会对canary进行核查,判断 ...
- 【笨嘴拙舌WINDOWS】消息机制
如果将WINDOWS比做一个人,那么他就是为你提供各种服务的巫师,他手上有各式各样,奇形怪状的奇葩物品.他脑子充满了智慧,能够为你解决你所不能解决的疑难杂症.但是他不认识你! 你从小立志要想考状元,去 ...
- Windows程序消息机制浅析
1.消息 消息是由MSG结构体来表示的.如下: typedef struct tagMSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lPar ...
随机推荐
- CF936C Lock Puzzle 构造
传送门 好久不做构造题脑子都僵化了qwq 无解的条件是\(s\)包含的字符可重集和\(t\)包含的字符可重集不相等,相等的时候下文会给出一种一定可行的构造方案. 考虑增量构造.定义某个字符串\(x\) ...
- 阿里云ECS云服务器Linux Tomcat启动慢 访问网页转圈
状况: 今天购买了一台阿里云云服务器,按照正常的方式安装JDK,mysql,以及Tomcat 这里的版本信息有 系统 :Centos 7 tomcat: apache-tomcat-8.5.45.ta ...
- java之hibernate之双向的多对一关联映射
这篇讲解 双向的多对一关联映射 1.表结构和多对一时,一致 2.类结构 Book.java public class Book implements Serializable{ private int ...
- CSS 各种形状
制作圆形: 要使用CSS来制作一个圆形,我们需要一个div,被给它设置一个ID <div id="circle"></div> 圆形在设置CSS时要设置宽 ...
- 【转载】关于SimpleDateFormat安全的时间格式化线程安全问题
想必大家对SimpleDateFormat并不陌生.SimpleDateFormat 是 Java 中一个非常常用的类,该类用来对日期字符串进行解析和格式化输出,但如果使用不小心会导致非常微妙和难以调 ...
- javascript 四舍五入; js 四舍五入
方法 Math.round round() 方法可把一个数字舍入为最接近的整数. 对于 0.5,该方法将进行上舍入. 例如,3.5 将舍入为 4,而 -3.5 将舍入为 -3. Math.round( ...
- linux防火墙开放端口,针对固定ip开放端口
编辑/etc/sysconfig/iptables,添加 -A INPUT -m state --state NEW -m tcp -p tcp -s 127.0.0.1 --dport 6379 - ...
- 随Linux开机自动启动mysql
在MySQL的管理过程中,会遇到PC Server脱机或者重启,我需要在主机启动后再将MySQL服务启动.如果上百台或者更多的MySQL主机进行维护时,可能会有多台主机出现类似问题,要是每次都手动操作 ...
- HTML tabindex 属性
tabindex 属性规定元素的 tab 键控制次序(当 tab 键用于导航时).
- 倍增法求lca:暗的连锁
https://loj.ac/problem/10131 #include<bits/stdc++.h> using namespace std; struct node{ int to, ...