现在的位置: 首页 > 综合 > 正文

FormatMessage使用详解

2013年03月05日 ⁄ 综合 ⁄ 共 5493字 ⁄ 字号 评论关闭

FormatMessage

函数

在《
windows

核心编程》中第一个示例便是它的使用。

这个函数是用来格式化消息字符串,就是处理消息资源的
。消息资源是由
mc.exe

编译的,详细请在msdn中搜索mc.exe。

先来看下它的函数原型

 

DWORD WINAPI FormatMessage(


  __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
0x00000100

lpBuffer

参数是一个
PVOID

指针,
nSize

参数指定按
TCHARs

为单位的分配给输出消息缓冲区的最小值。当你不适用这个缓冲区的时候也就是
lpBuffer

的时候需要用
LocalFree

将其释放

FORMAT_MESSAGE_ARGUMENT_ARRAY
0x00002000

Arguments

参数不是一个
va_list

结构,但是它表示一个数组指针。这个标识符不能在
64

位整数值时使用,你如果要使用
64

位整数值,那么你必须使用
va_list

结构体

FORMAT_MESSAGE_FROM_HMODULE
0x00000800

lpSource

参数是一个包含了消息表资源(
Message-table resources

)模块(
dll

)句柄。如果
lpSource

句柄为
NULL

,系统会自动搜索当前进程文件的消息资源。

这个标示符不可以和
FORMAT_MESSAGE_FROM_STRING

共用。

如果模块中没有资源表,这个函数执行失败并且返回
ERROR_RESOURCE_TYPE_NOT_FOUND

错误值。

FORMAT_MESSAGE_FROM_STRING
0x00000400

lpSource

参数指向一个包含了消息定义的字符串
.

这个消息定义里面可能包含了插入序列(
insert sequence

),像消息表资源中包含消息文本一样
.

和这个标示符不和
FORMAT_MESSAGE_FROM_HMODULE

或者
FORMAT_MESSAGE_FROM_SYSTEM


一起使用
.

FORMAT_MESSAGE_FROM_SYSTEM
0x00001000

函数将会搜索系统消息表资源来寻找所需消息资源。


如果这个标示符同时定义了
FORMAT_MESSAGE_FROM_HMODULE,

那么如果函数在模块中没有搜索到所需消息的话将会在系统中搜索。这个标示符不能和
FORMAT_MESSAGE_FROM_STRING

一起使用
.

当这个标示符设置的时候,可以使用
GetLastError

函数返回值来搜索这个错误码在系统定义错误中相应的消息文本。

FORMAT_MESSAGE_IGNORE_INSERTS
0x00000200

在消息定义中的插入序列将会被忽略,这个标示符在获取一个格式化好的消息十分有用,如果这个标示符设置好了,那么
Arguments

参数将被忽略。

开始在上面说了
dwflags

参数低位值作用,你可以使用以下值来设置低位值。

Value

Meaning

0

将不会有输出行宽度限制。

FORMAT_MESSAGE_MAX_WIDTH_MASK
0x000000FF

将会有限制输出行宽度,使用硬编码设定。

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


中的几个例子可以让人豁然开朗。


例一:使用系统的消息资源来报错,这也是这个函数最有用的地方。

#include 
<
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

调用为

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,而且消息模块中没有我们所需资源,函数调用失败。




#include 
<
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;

    }





    

//

抱歉!评论已关闭.