FormatMessage
函数
在《
windows
核心编程》中第一个示例便是它的使用。
这个函数是用来格式化消息字符串,就是处理消息资源的
。消息资源是由
mc.exe
编译的,详细请在msdn中搜索mc.exe。
先来看下它的函数原型
__in DWORD dwFlags,
__in LPCVOID lpSource,
__in DWORD dwMessageId,
__in DWORD dwLanguageId,
__out LPTSTR lpBuffer,
__in DWORD nSize,
__in va_list
*
Arguments
);
在使用这个函数的时候要明确以下几点
l
你要处理的消息资源来自哪里,这一点尤为重要。
l
你的消息
ID
来自哪里
.
以下是每个参数的详细介绍
dwFlags
:
格式化选项,对
lpSource
参数值有指导作用。
dwFlags
的低位值指定了函数如何处理输出缓冲区处理行转换,也可以指定格式化输出字符串输出行的最大宽度。
它的位标示符如下:
Value |
Meaning |
FORMAT_MESSAGE_ALLOCATE_BUFFER |
lpBuffer |
FORMAT_MESSAGE_ARGUMENT_ARRAY |
Arguments |
FORMAT_MESSAGE_FROM_HMODULE |
lpSource 这个标示符不可以和 如果模块中没有资源表,这个函数执行失败并且返回 |
FORMAT_MESSAGE_FROM_STRING |
lpSource |
FORMAT_MESSAGE_FROM_SYSTEM |
函数将会搜索系统消息表资源来寻找所需消息资源。 当这个标示符设置的时候,可以使用 |
FORMAT_MESSAGE_IGNORE_INSERTS |
在消息定义中的插入序列将会被忽略,这个标示符在获取一个格式化好的消息十分有用,如果这个标示符设置好了,那么 |
开始在上面说了
dwflags
参数低位值作用,你可以使用以下值来设置低位值。
Value |
Meaning |
0 |
将不会有输出行宽度限制。 |
FORMAT_MESSAGE_MAX_WIDTH_MASK |
将会有限制输出行宽度,使用硬编码设定。 |
lpSource
:这个值是消息表资源来自哪里,这个值依靠
dwFlags
,
详细请看
FORMAT_MESSAGE_FROM_HMODULE
和
FORMAT_MESSAGE_FROM_STRING
,如果这两个标示符都没设置,那么
lpSource
将会被忽略。
dwMessageId
:
所需格式化消息的标识符。当
dwFlags
设置了
FORMAT_MESSAGE_FROM_STRING
,这个参数将会被忽略。
dwLanguageId
:
格式化消息语言标识符。
lpBuffer
:
一个缓冲区指针来接受格式化后的消息。当
dwFlags
包括了
FORMAT_MESSAGE_ALLOCATE_BUFFER
标志符,这个函数将会使用
LocalAlloc
函数分配一块缓冲区,
lpBuffer
需要接受一个地址来使用这个缓冲区。(这里要注意传参一定要传地址)。
nSize
如果
FORMAT_MESSAGE_ALLOCATE_BUFFER
没有设置,那么这个参数指定了输出缓冲区的消息,以
TCHARs
为单位。如果
FORMAT_MESSAGE_ALLOCATE_BUFFER
设置了,这个参数设置以
TCHARs
为单位的输出缓冲区的最小值。
这个输出缓冲区不能大于
64KB
。
Arguments:
一个数组中的值在格式化消息中作为插入值,根据消息文本的格式里面的内容(详见
mc.exe
使用),可以知道
%n
[!format_specifier
!]
为这个参数的指定形式。
比如说在格式字符串中的
%1
为数组中的第一个值,
%2
为第二个值。
n
就代表数组第几个值。那么
[
!
format_specifier!]
如何解释呢?这个格式化指定具体解释在
Format Specification Fields
,也就是
printf
的格式形式安排。在
msdn
中可以搜索
Format Specification Fields: printf and wprintf Functions
关键字进行查询详细的值。
看完以上详细参数的解释其实我自己还没太明白如何用。
msdn
中的几个例子可以让人豁然开朗。
例一:使用系统的消息资源来报错,这也是这个函数最有用的地方。
<
windows.h
>
#include
<
strsafe.h
>
void
ErrorExit(LPTSTR lpszFunction)
{
//
Retrieve the system error message for the last-error code
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw
=
GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
FORMAT_MESSAGE_FROM_SYSTEM
|
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)
&
lpMsgBuf,
0
, NULL );
//
Display the error message and exit the process
lpDisplayBuf
=
(LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf)
+
lstrlen((LPCTSTR)lpszFunction)
+
40
)
*
sizeof
(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf),
TEXT(
"
%s failed with error %d: %s
"
),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT(
"
Error
"
), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
ExitProcess(dw);
}
void
main()
{
//
Generate an error
if
(
!
GetProcessId(NULL))
ErrorExit(TEXT(
"
GetProcessId
"
));
}
FormatMessage
调用为
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
FORMAT_MESSAGE_FROM_SYSTEM
|
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)
&
lpMsgBuf,
0
, NULL );
我们可以看到函数选项
dwFlags
分别为
FORMAT_MESSAGE_ALLOCATE_BUFFER
由函数分配输出缓冲区,
FORMAT_MESSAGE_FROM_SYSTEM
表示程序将会在系统消息表资源中搜索所需消息,
FORMAT_MESSAGE_IGNORE_INSERTS
程序将会忽略搜索到消息中的插入序列。
lpSource
值为
NULL,
并没有模块值和字符串直接传入所以为
NULL
,详细看以上各参数解析。
dwMessageId
为
dw
,即
GetLastError
的返回值。就是消息资源的
ID
号。
dwLanguageId
设置为本地默认
lpBuffer
输出缓冲区这里注意
&
为什么要
&
呢?
因为
LPVOID lpMsgBuf
只是一个指针对象,那么要必须要把它的地址传给
lpBuffer
参数。
剩下两个参数可以上面参数的详解。
最后注意一点:由于
lpBuffer
这个参数的值是
FormatMessage
函数动态分配的缓冲区,所以在不使用的时候要
LocalFree.
例二:格式化模块中的消息资源,这里加载的模块之中要有消息资源,如果FormatMessage函数中传递了FORMAT_MESSAGE_FROM_SYSTEM,如果消息模块中没有我们所需的资源,那么将会在系统中寻找;如果没有 FORMAT_MESSAGE_FROM_SYSTEM,而且消息模块中没有我们所需资源,函数调用失败。
<
windows.h
>
#include
<
stdio.h
>
#include
<
lmerr.h
>
void
DisplayErrorText(
DWORD dwLastError
);
#define
RTN_OK 0
#define
RTN_USAGE 1
#define
RTN_ERROR 13
int
__cdecl
main(
int
argc,
char
*
argv[]
)
{
if
(argc
!=
2
)
{
fprintf(stderr,
"
Usage: %s <error number>/n
"
, argv[
0
]);
return
RTN_USAGE;
}
DisplayErrorText( atoi(argv[
1
]) );
return
RTN_OK;
}
void
DisplayErrorText(
DWORD dwLastError
)
{
HMODULE hModule
=
NULL;
//
default to system source
LPSTR MessageBuffer;
DWORD dwBufferLength;
DWORD dwFormatFlags
=
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
FORMAT_MESSAGE_IGNORE_INSERTS
|
FORMAT_MESSAGE_FROM_SYSTEM ;
//
//
If dwLastError is in the network range,
//
load the message source.
//
if
(dwLastError
>=
NERR_BASE
&&
dwLastError
<=
MAX_NERR)
{
hModule
=
LoadLibraryEx(
TEXT(
"
netmsg.dll
"
),
NULL,
LOAD_LIBRARY_AS_DATAFILE
);
if
(hModule
!=
NULL)
dwFormatFlags
|=
FORMAT_MESSAGE_FROM_HMODULE;
}
//