向自己的模块添加错误代码
原文链接:https://blog.****.net/s634772208/article/details/46402677
本文主要介绍怎么使用Visual Studio自带的MC.exe工具来创建一个消息资源并将其添加到自己的DLL(或.exe)中,从而达到为自己的模块添加错误代码的目的。
一、MC工具介绍
Message Compiler(MC) 是用来创建消息资源的工具,这些消息资源被DLL(或EXE)模块引用。MC的输入是一个特定格式的文本文件,即*.mc文件,这种特定格式使得在一个文件中定义多种语言支持变得非常容易。
当编写完成一个*.mc文件之后,为了在程序中使用这个文件,你需要一些操作。首先,使用MC工具将这种文件编译成一个*.rc文件(还会生成*.h和*.bin文件);然后将*.rc及*.h添加进相应的DLL(EXE)模块中编译;最后通过相应的事件日志函数或者FomatMessage函数对其中的消息文本进行使用。(具体的操作过程请看后面的例子)
二、消息文本文件定义(*.mc文件)
1、概述
Messages定义在一个*.mc文件中,MC工具会自动为每条消息赋一个编号,然后会生成一个*.h文件,以供程序引用其中的消息ID。
*.mc文件里定义消息最常见的语法为KEYWORD=VALUE,等号两边的空格会被忽略。下一条类似的定义以空格或者换行来分隔。其中VALUE可以是一个整型常量,或者一个类似宏标识的符号,或者是一个8个字符(或更少)的名字。
2、注释
单行注释:以一个分号开头,然后后面接注释文字,为了在生成的*.h文件中也以注释状态出现,勿必在分号后面撞上一个//。如下:
;//这是一个单行注释
多行注释:每行都以分号开头,但是为了同样的目的,勿必如以下写多行注释:
;/*这是多行注释
;这是多行注释
;这是多行注释*/
3、头部定义块
*.mc文件以头部定义开始,头部定义一些名字标识以及语言标识供后面消息定义使用。头部通常包含以下0个或多个声明(可以是多个相同的声明,比如语言部分)。
MessageIdTypedef=type----用于消息标识定义的类型,如#define name ((type)0xnnnnnnnn) 注:在*.h文件中可看到此类定义。这个类型必须能够容下消息码的范围(32位),比如DWORD。这个类型也可以是程序部分中自定义的。默认状态下是无类型的,也就没有相应的转换。你可以在需要使用这个声明时,才开始定义它。如:MessageIdTypedef=DWORD。
SeverityNames=(name=number[:name])----设置消息码中第31、30位,即Severity部分。
默认的设置如下:
SeverityNames=(
Success=0x0
Informational=0x1
Warning=0x2
Error=0x3
)
FacilityNames=(name=number[:name])----设置消息码中27--16位,即Facility部分,默认的设置如下:
FacilityName=(
System=0x0FF
Application=0xFFF
)
LanguageNames=(name=number:filename)----设置消息所用语言标识,可设置多个语言版本。默认的设置如下:
LanguageNames=(English=1:MSG0001),其中1可由宏MAKELANGID生成,比如生成简体中文的,MAKELANGID( LAN_CHINES, SUBLANG_CHINESE_SIMPLIFIED),生成的值 为0x804,则我们可以定义LanguageNames=(Chinese=0x804:MSG0804),其中MSG0804是我们自定义的名字,生成的*.bin文件会以其命令,如MSG0804.bin。
OutputBase=number----生成消息常量数值格式,比如指定16,生成16进制的数,指定10,生成10进制的数等。
4、消息主体定义
消息文本文件包含以下0个或多个声明,其中MessageId标识了一个消息定义的开始,必须存在,Severity、Facility声明是可选的。
MessageId=[number|+number]----消息序号标识,这项必须要有,但是值是可选的。如果没有指定值,此值等于上一个Facility加上1,如果在指定的值前面带上了一个+号,则用上一个Facility加上此值来生成MessageId。
Severity=name----在头部声明FacilityNames指定的一个名字,这个声明是可选的。如果没有指定值,则使用在消息定义块中最后指定的那个值。默认的第一个消息定义是
Facility=Application。
SymbolicName=name----一个标识符,在*.h文件中可看到,如#define name ((type)0xnnnnnnnn)。
OutpubBase={number}----生成消息常量数值格式,比如指定16,生成16进制的数,指定10,生成10进制的数等。
Language=name----在头部声明LanguageNames指定的一个名字,此项是可选项,如果没有指定值,则使用在消息定义块中最后指定的那个值。默认的第一个消息定义是
Language=English。
Message Text----消息文本。
.(点号) ----消息定义终止符,注:此终止符为英文输入模式下输入,否则使用mc工具进行编译时会提示无终止符的。消息定义例子如下:
MessageId=0x1
Severity=Error
Facility=Runtime
SymbolicName=MSG_BAD_COMMAND
Language=English
You have chosen an incorrect command.
.
Language=Chinese
你选择了一个不正常的命令。
.
你还可以在消息文本定义中使用一些控制符,具体的可查看MSDN。
三、*.mc文件定义的例子
1、文件内容,文件名字McFile.mc
- ;//***** Sample.mc *****
- ;//This is the header section.
- MessageIdTypedef=DWORD
- SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
- Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
- Warning=0x2:STATUS_SEVERITY_WARNING
- Error=0x3:STATUS_SEVERITY_ERROR
- )
- FacilityNames=(System=0x0:FACILITY_SYSTEM
- Runtime=0x2:FACILITY_RUNTIME
- Stubs=0x3:FACILITY_STUBS
- Io=0x4:FACILITY_IO_ERROR_CODE
- )
- LanguageNames=(English=0x409:MSG00409)
- LanguageNames=(Chinese=0x804:MSG00804)
- ; // The following are message definitions.
- MessageId=0x1
- Severity=Error
- Facility=Runtime
- SymbolicName=MSG_BAD_COMMAND
- Language=English
- You have chosen an incorrect command.
- .
- Language=Chinese
- 你选择了一个不正常的命令。
- .
- MessageId=0x2
- Severity=Warning
- Facility=Io
- SymbolicName=MSG_BAD_PARM1
- Language=English
- Cannot reconnect to the server.
- .
- Language=Chinese
- 无法连接服务器。
- .
- MessageId=0x3
- Severity=Success
- Facility=System
- SymbolicName=MSG_STRIKE_ANY_KEY
- Language=English
- Press any key to continue . . . %0
- .
- Language=Chinese
- 按任意键继续...
- .
- MessageId=0x4
- Severity=Error
- Facility=System
- SymbolicName=MSG_CMD_DELETE
- Language=English
- File %1 contains %2 which is in error
- .
- Language=Chinese
- 文件 %1 包含 %2 r损坏。
- .
- MessageId=0x5
- Severity=Informational
- Facility=System
- SymbolicName=MSG_RETRYS
- Language=English
- There have been %1!d! attempts with %2!d!%% success%! Disconnect from the server and try again later.
- .
- Language=Chinese
- 未知错误!无法连接服务器,请稍后重试!
- .
2、使用MC工具编译
打开visual studio的命令行界面,进入McFile.mc文件目录,使用命令mc -a -A McFile.mc进行编译,如下:
编译成功后,会在当前目录下生成McFile.h,McFile.rc,MSG00409.bin,MSG00804.bin四个文件,因为文本文件中支持中英文,所以生成了两个*.bin文件。
McFile.h文件部分预览如下:
- //***** Sample.mc *****
- //This is the header section.
- // The following are message definitions.
- //
- // Values are 32 bit values layed 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_SYSTEM 0x0
- #define FACILITY_STUBS 0x3
- #define FACILITY_RUNTIME 0x2
- #define FACILITY_IO_ERROR_CODE 0x4
- //
- // Define the severity codes
- //
- #define STATUS_SEVERITY_WARNING 0x2
- #define STATUS_SEVERITY_SUCCESS 0x0
- #define STATUS_SEVERITY_INFORMATIONAL 0x1
- #define STATUS_SEVERITY_ERROR 0x3
- //
- // MessageId: MSG_BAD_COMMAND
- //
- // MessageText:
- //
- // You have chosen an incorrect command.
- //
- #define MSG_BAD_COMMAND ((DWORD)0xC0020001L)
3、将生成的资源文件编译进dll(或exe)模块中。
创建一个WIN32DLL工程,将McFile.h与McFile.rc文件添加进去,进行编译,生成相应的dll即可提供给我们的程序使用。
四、使用自己定义的错误代码,即第三步生成的消息资源模块
- #include <iostream>
- #include <windows.h>
- using namespace std;
- //
- #ifdef _UNICODE
- #define COUT wcout
- #else
- #define COUT cout
- #endif
- int main()
- {
- DWORD dwError = 0;
- DWORD dwLanguageId = MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL );
- //解决问题:wcout输出时显示不了中文
- COUT.imbue( std::locale( "chs" ) );
- HLOCAL lpMsgTextBuf = NULL;
- COUT << TEXT("输入一个自定义的错误代码(如:3221356545(0xC0020001) ):");
- while( cin >> dwError )
- {
- lpMsgTextBuf = NULL;
- HMODULE ghResDll = LoadLibrary( TEXT("WinMsgDll.dll") );
- if ( NULL == ghResDll )
- {
- COUT << TEXT("加载消息模块失败!") << endl;
- return -1;
- }
- BOOL bOk = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE |
- FORMAT_MESSAGE_IGNORE_INSERTS |
- FORMAT_MESSAGE_ALLOCATE_BUFFER,
- ghResDll, dwError, dwLanguageId, (LPTSTR)&lpMsgTextBuf, 0, NULL );
- if ( !bOk )
- {
- COUT << TEXT("error ") << GetLastError() << endl;
- }
- if ( NULL != lpMsgTextBuf )
- {
- COUT << (LPTSTR)lpMsgTextBuf << endl;
- LocalFree( lpMsgTextBuf );
- }
- COUT << TEXT("输入一个自定义的错误代码(如:3221356545(0xC0020001) ):");
- }
- return 0;
- }