捐助郴维网
感谢您对郴维网的支持,你的支持将是郴维网持续发展的动力!
二维码
×
当前位置:郴维网 >API档案 > 正文
1 2017.07

FormatMessage

点击次数:1300 更新时间:2017-7-1 21:43:27  【打印此页

原文链接 -> 传送门

函数功能:

FormatsMessate 函数用于格式化一个信息字符串。该函数需要一个消息定义作为输入。该消息定义可能来自能够进入该函数的缓冲区。也可能来自于已经被加载的模块的消息表资源。或者调用者可以调用该函数来搜索该系统消息表资源中的消息定义。该函数在基于消息标识符和语言标识符的消息表资源中查找消息定义。如果有请求,该函数会将格式化消息文本复制到输出缓冲区,并处理任何嵌入的插入序列。


API 函数原型:

注释:_In_ 说明该参数是输入的,_Out_说明该参数是输出的,_In_opt_ 说明该参数是输入同时是可选的

DWORD WINAPI FormatMessage(
  _In_     DWORD   dwFlags,
  _In_opt_ LPCVOID lpSource,
  _In_     DWORD   dwMessageId,
  _In_     DWORD   dwLanguageId,
  _Out_    LPTSTR  lpBuffer,
  _In_     DWORD   nSize,
  _In_opt_ va_list *Arguments
);


参数解析:
 

参数

含义

dwFlags

1. 该参数指定用于格式化的选项、解释 lpsource 参数的方式

2. dwFlag 参数的低位字节用来表明该函数如何处理输出缓冲区中的行中断。该低位字节也能表明格式化输出线的最大宽度

3. 该参数可以由下列标识中的一个或多个组成:
 

含义

FORMAT_MESSAGE_ALLOCATE_BUFFER
(0x00000100)

1. 此标识可让该函数分配一个足够大的缓冲区来保存格式化的消息。并且让该函数在被 lpBuffer 参数指定的地址中放置一个指向被分配的缓冲区的指针。IpBuffer 参数是一个指向一个 LPTSTR 的指针;你必须让该指针指向一个LPTSTR(例如 (LPTSTR)&lpBuffer)。nSize 参数指定分配给输出消息缓冲区的TCHARs的最小数。当该参数不再被需要时,调用者应该使用 LocalFree 函数来释放缓冲区

2. 如果格式化消息的长度超过了 128K 字节。那么 FormatMessage 函数将会运行失败并且随后对GetLastError 函数的调用将会返回 ERROR_MORE_DATA

3. 在 Windows 的早期版本中。当编写 Windows 商店应用程序时该标识是不可用的。在 Windows10 中,该标识是可用的

4. Windows Server 2003 and Windows XP:如果格式化消息的长度超过了 128K 字节。FormatMessag 函数将不会以带有 ERROR_MORE_DATA 错误的方式自动运行失败

5. Windows 10:LocalFree 函数不在 SDK 模块中。所以 LocalFree 函数不能用于释放结果缓冲区。作为替代,可以用HeapFree(GetProcessHeap().allocateMessage)函数。在这种情况下,调用 HeapFree 函数与在内存中调用 LocalFree 函数相同

6. 要点:LocalAlloc 函数有不同的选项:LMEM_FIXED 和 LMEM_MOVABLE.FormatMessage 函数使用了 LMEM_FIXED,HeapFree 函数就能够被使用。如果 LMEM_MOVABLE 被使用了,则 HeapFree 函数不能被使用

FORMAT_MESSAGE_ARGUMENT_ARRAY
(0x00002000)

该标识表明 Arguments 参数不是一个 va_list 结构。但是是一个指向数组的值代表参数的数组的指针。此标识不能使用 64 位整数值。如果你要用64位整数,你必须要用 va_list 结构

FORMAT_MESSAGE_FROM_HMODULE
(0x00000800)

1. 该标识表明 IpSource 参数是一个包含要被搜索的消息表资源的模块句柄。如果 IpSource 句柄是空的。当前进程的应用程序映像文件将被搜索。该标识不能与 FORMAT_MESSAGE_FROM_STRING 标识一起使用

2. 如果该模块没有消息表资源,该函数将以带有 ERROR_RESOURCE_TYPE_NOT_FOUND 标识的方式运行失败

FORMAT_MESSAGE_FROM_STRING
(0x00000400)

该标识表明 IpSource 参数是一个指向零终止字符串的指针,该零终止字符串包含一个消息定义。该消息定义可能包含插入序列。就像在消息表资源中的消息文本可能的一样。该标识不能与 FORMAT_MESSAGE_FROM_HMODULE 标识或 FORMAT_MESSAGE_FROM_SYSTEM 标识一起使用

FORMAT_MESSAGE_FROM_SYSTEM
(0x00001000)

1. 如果该标识被 FORMAT_MESSAGE_FROM_HMODUL 标识指定,则该函数应该在系统信息表资源中搜索被请求的信息。如果该信息没有在 IpSource 参数指定的模块中发现,那么该函数会搜索系统消息表。该标识不能与 FORMAT_MESSAGE_FROM_STRING 标识一起使用

2. 如果指定了该标识,一个应用程序可以通过GetLastError 函数结果来获取对于错误消息文本的消息定义

FORMAT_MESSAGE_IGNORE_INSERTS
(0x00000200)

该标识使消息定义中的插入序列被忽略,并使该序列在未改变的情况下被传递到输出缓冲区。该标识可用于获取稍后格式化的消息。如果未设置此标识,则忽略 Arguments 参数


4. dwFlags 参数的低字节可以指定格式化输出行的最大宽度。以下是低阶字节可能的值:
 

含义

0

该值表明这里没有输出行宽度限制。该函数会将在消息定义文本中的行中断存储到输出缓冲区

FORMAT_MESSAGE_MAX_WIDTH_MASK
(0x000000FF)

该值表明该函数会忽略在消息定义文本中常规的行中断。该函数会将在消息定义文本中的硬编码行中断存储到输出缓冲区中。该函数不会产生新的行中断


5. 如果低位字节是一个与 FORMAT_MESSAGE_MAX_WIDTH_MASK 标识不同的非零值,该低位字节将指定输出行中的最大字符数。且该函数会忽略消息定义文本中常规的行中断。在一个行中断中,该函数永远不会拆分一个由空格分隔的字符串。该函数会将在消息定义文本中的硬编码行中断存储到输出缓冲区。硬编码行中断被用“%n”转义序列进行编码

lpSource

1. 该参数表示消息定义的位置。这个参数的类型取决于在 dwFlags 参数中的设置:
 

dwFlags 参数设置

含义

FORMAT_MESSAGE_FROM_HMODULE
(0x00000800)

该标识表示一个包含要搜索的消息表的模块句柄

FORMAT_MESSAGE_FROM_STRING
(0x00000400)

该标识表示一个包含未被格式化的消息文本的字符串的指针。为了相应的插入和格式化,该指针将被扫描


2. 如果这些标识没有一个在 dwFlags 参数里被设置。那么 Ipsource 参数将被忽略

dwMessageId

该参数表示被请求消息的消息标识符。如果 dwFlags 参数包含 FORMAT_MESSAGE_FROM_STRING 标识,那么该参数被忽略

dwLanguageId

1. 该参数表示被请求消息的语言标识符。如果 dwFlags 参数包含 FORMAT_MESSAGE_FROM_STRING 标识,那么该参数被忽略

2. 如果你传送一个特定的 LANGID 到这个参数,FormatMessage 函数将只会为该 LANGID 返回一个消息。如果该函数不能为该 LANGID 找到一个消息,它将把最后一个错误设置为ERROR_RESOURCE_LANG_NOT_FOUND。如果你将该 LANGID 传送进 0 里,FormatMessage 函数会为 LANGIDs 按下列顺序寻找一个消息:

 

1.    中性语言

2.    线程 LANGID,基于线程的区域值

3.    用户默认 LANGID,基于用户的默认区域值

4.    系统默认 LANGID,基于系统的默认区域值

5.    美式英语


3. 如果 FormatMessage 函数不对任何先前的 LANGIDs 确定一个消息,它则返出现的任何语言消息字符串。如果失败了,它则返回 ERROR_RESOURCE_LANG_NOT_FOUND

lpBuffer

1. 该参数表示指向接收格式化消息的空终止字符串缓冲区的指针。如果 dwFlags 函数包含 FORMAT_MESSAGE_ALLOCATE_BUFFER 标识,那么该函数会用 LocalAlloc 函数分配一个缓冲区,并且将指针放到该缓冲区中 IpBuffer 函数指定的地址

2. 该缓冲区不能大于 64K 字节

nSize

1. 如果没有设置 FORMAT_MESSAGE_ALLOCATE_BUFFER 标识,那么该参数会在 TCHARS 里指定输出缓冲区的大小。如果设置了 FORMAT_MESSAGE_ALLOCATE_BUFFER 标识。该参数指定一个 TCHARs 最小数,用来分配给输出缓冲区

2. 输出缓冲区不能大于 64K 字节

Arguments

1. 该参数表示用于在格式化消息中作为插入值的一组值。在格式化字符串中的 A%1 表示在 Arguments 字符串中的第一个值,a%2 表示第二个参数,以此类推

2. 每个值的解释取决于与消息定义中的插入相关的格式信息。默认是把每个值作为指向一个空终止字符串的指针

3. 默认情况下,Arguments 参数是 va_list* 类型。该类型是一个语言和具体的数据类型,用于描述一个参数的变量。该函数的返回之中,va_list 参数的状态没有被定义。当再次使用 va_list,可用 va_end 取消可变参数列表指针并且可用 va_start 重新初始化可变参数列表指针

4. 如果没有一个指向 va_list* 类型的指针,可指定 FORMAT_MESSAGE_ARGUMENT_ARRAY 标识并且传递一个指向 DWORD_PTR 值得数组的指针;这些值被输入到被格式化的消息中作为插入值。每一个插入在数组中必须有一个对应的插入元素



返回值:

1. 如果函数运行成功,该返回值为储存在输出缓冲区的 TCHARs 的数量,不包括终止空字符;

2. 如果函数运行失败,该返回值为 0。

想要调用更多错误信息,请访问 GetLastError 参数。


备注:

1. 在消息文本中,动态格式消息支持几个转义序列。这些转义序列和它们的含义被显示在下面的表里。所有的转义序列都以百分号(%)开始:
 

参数

含义

%0

1. 该转义序列用于终止一个末尾不带有新行字符的消息文本行

2. 该转义序列可以用于建立长行或者用于终止末尾不带有新行字符的消息本身,提示信息是有用的

%n!format string!

1. 该转义序列用于指定一个插入。n 的值可以在 1-99 的范围内。该格式字符串(必须被感叹号包围)是可选择的,并且如果未指定,默认是 !s!。更多信息,请参照 Format Specification Fields 函数

2. 该格式化字符串能包含一个对字符串的宽度和精度的说明符和一个对整数的宽度说明符。用一个星号(*)指定宽度和精度。例如 %1!*.*s! 或者 %1!*u!

3. 如果你不用这个宽度和精度说明符,那么插入数直接对应于输入的参数。例如,如果源字符串是“%1 %2 %1”并且输入参数是“Bill”和“Bob”,那么该格式输入字符串是“Bill Bob Bill”

4. 然而,如果你用一个宽度和精度说明符,那么该插入数不会直接对应输入的参数。例如,在先前的例子中,输入号可能改成“%1!*.*s! %4 %5!*s!”

5. 插入数取决于你是否使用了参数数组(FORMAT_MESSAGE_ARGUMENT_ARRAY)或者是否你使用了一个 va_list。对于一个参数数组,如果先前的格式化字符串    包含一个星号,那么下一个插入数就是 n+2,如果先前的格式化字符串被指定了两个星号,那么下一个插入数就是 n+3。对于一个 va_list,如果先前的格式化字符串包含一个星号,那么下一个插入数是 n+1;如果先前的格式化字符串包含两个星号,那么下一个插入数是 n+2

6. 就像先前的例子,如果你想要重复“Bill”,那么该参数必须包含两个“Bill”。例如,如果源字符串是“%1!*.*s! %4 %5!*s!”,那么该参数可能是 4.2.Bill.Bob.6.Bill(如果用FORMAT_MESSAGE_ARGUMENT_ARRAY标识)。然后格式化字符串可能是“Bi Bob   Bill”

7. 当源字符串包含宽度和精度说明符时,重复插入数可能不会产生预期的结果。如果你用 %1 代替 %5,那么该函数将尝试打印在地址6处的字符串(可能导致访问冲突)

8. 浮点型格式说明符 —— e, E, f, 和 g —— 是不被支持的。解决方案是用 StringCchPrintf 函数将浮点数格式化到临时缓冲区。然后用该缓冲区作为插入字符串

9. 使用 I64 前缀的插入被视为两个 32 位的参数。它们必须在之后的参数被使用之前被使用。值得注意的是使用 StingCchPrintf 函数代替该前缀对你来说可能更容易


2. 任何其它的带有百分号的非数字字符会在输出消息中格式化为不带百分号的字符。以下就是一些例子:

格式化字符串

输出结果

%%

该输出结果为一个单独的百分号

%space

该输出结果为一个单独的空白。该格式字符串可以被用于保证一个消息文本行里一定数量的结尾空白

%.

该输出结果为一个单独的句号。该格式字符串可以被用于让不带有终止消息文本定义的行开始的地方包含一个单独的句号

%!

该输出结果为一个单独的感叹号。该格式字符串可以被用于在一个没有被误认为是一个格式字符串的开始的插入之后立即包括一个感叹号

%n

该输出结果为当格式字符串出现在一行的结尾处时的一个硬换行符。当 FormatMessage 函数支持常规换行符时该格式字符串是有用的,这样,消息就符合了一定的宽度

%r

该输出结果为一个不带有换行字符的硬回车

%t

一个单独的制表键



安全备注:

如果该函数在不带有 FORMAT_MESSAGE_IGNORE_INSERTS 标识的情况下被调用,那么 Argument 参数必须包含足够的参数,以满足消息字符串中的所有插入序列。并且这些参数必须是正确的类型。因此不要使用不确定的或未知但可插入的消息字符串,因为它们可能包含比 Arguments 参数可提供的插入序列更多的插入序列。或者这些字符串可能是错误的类型。尤其是,当采用一个从 API 返回的系统错误代码和在不使用 FORMAT_MESSAGE_IGNORE_INSERTS 标识时使用 FORMAT_MESSAGE_FROM_SYSTEM 标识时是不安全的。


例子:

FormatMessage 函数能被用于获取 GetLastError 函数返回的系统错误代码的错误消息字符串。例子请参照 Retrieving the Last-Error Code

下面的示例展示了如何使用一个参数数组以及如何使用一个宽度和精度说明符:
 

#ifndef UNICODE
#define UNICODE
#endif

#include <windows.h>
#include <stdio.h>

void main(void)
{
    LPWSTR pMessage = L"%1!*.*s! %4 %5!*s!";
    DWORD_PTR pArgs[] = { (DWORD_PTR)4, (DWORD_PTR)2, (DWORD_PTR)L"Bill",  // %1!*.*s! refers back to the first insertion string in pMessage
         (DWORD_PTR)L"Bob",                                                // %4 refers back to the second insertion string in pMessage
         (DWORD_PTR)6, (DWORD_PTR)L"Bill" };                               // %5!*s! refers back to the third insertion string in pMessage
    const DWORD size = 100+1;
    WCHAR buffer[size];


    if (!FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
                       pMessage, 
                       0,
                       0,
                       buffer, 
                       size, 
                       (va_list*)pArgs))
    {
        wprintf(L"Format message failed with 0x%x\n", GetLastError());
        return;
    }

    // Buffer contains "  Bi Bob   Bill".
    wprintf(L"Formatted message: %s\n", buffer);
}


下面的示例展示如何使用 va_list 来实现前一个示例:
 

#ifndef UNICODE
#define UNICODE
#endif

#include <windows.h>
#include <stdio.h>

LPWSTR GetFormattedMessage(LPWSTR pMessage, ...);

void main(void)
{
    LPWSTR pBuffer = NULL;
    LPWSTR pMessage = L"%1!*.*s! %3 %4!*s!";

    // The variable length arguments correspond directly to the format
    // strings in pMessage.
    pBuffer = GetFormattedMessage(pMessage, 4, 2, L"Bill", L"Bob", 6, L"Bill");
    if (pBuffer)
    {
        // Buffer contains "  Bi Bob   Bill".
        wprintf(L"Formatted message: %s\n", pBuffer);
        LocalFree(pBuffer);
    }
    else
    {
        wprintf(L"Format message failed with 0x%x\n", GetLastError());
    }
}

// Formats a message string using the specified message and variable
// list of arguments.
LPWSTR GetFormattedMessage(LPWSTR pMessage, ...)
{
    LPWSTR pBuffer = NULL;

    va_list args = NULL;
    va_start(args, pMessage);

    FormatMessage(FORMAT_MESSAGE_FROM_STRING |
                  FORMAT_MESSAGE_ALLOCATE_BUFFER,
                  pMessage, 
                  0,
                  0,
                  (LPWSTR)&pBuffer, 
                  0, 
                  &args);

    va_end(args);

    return pBuffer;
}



需求:
 

Minimum supported client

Windows XP [桌面应用程序 | Windows 商店应用程序]

Minimum supported server

Windows 2003 服务器版 [桌面应用程序 | Windows 商店应用程序]

Header

WinBase.h (包含于 Windows.h)

Library

Kernel32.lib

DLL

Kernel32.dll

Unicode and ANSI names

FormatMessageW (Unicode) 和 FormatMessageA (ANSI)

提示
郴维网为您提供各类专业服务:
软件开发,电脑配件销售,WIFI路由器销售,上门电脑维修,上门安装系统,系统安装,软、硬件安装,电脑除尘清灰,显示器维修,WIFI安装调试,服务器维护,数据恢复,密码破解,网络布线,网络检修,打印机维修,打印机加碳粉,苹果电脑安装系统,苹果电脑安装双系统,监控安装维护,电脑外包,笔记本电脑维修,餐饮、美容行业软件安装 等。。。。。。
点击次数:1300 更新时间:2017-7-1 21:43:27  【打印此页

上一条:SetLastError

下一条:GetMessageTime

关键词推荐:郴州电脑城 郴州电脑维修公司 维修电脑公司 郴州软件开发 上门电脑维修 上门安装系统 笔记本电脑维修 郴州打印机维修 打印机加碳粉 电脑安装双系统 苹果电脑双系统 液晶显示器维修 联想笔记本维修 联想笔记本维修电话 戴尔笔记本维修电话 郴州戴尔笔记本维修 戴尔笔记本郴州维修点 华硕笔记本维修点 郴州华硕笔记本维修 郴州笔记本上网维修