我们写程序,调试出错时用的一个重要函数是 GetLastError(),它会返回一个非负数字给我们,在VS的工具--错误查找里面看相应的描述。
FormatMessage函数的功能是格式化一个消息字符串。函数需要一个消息定义(message definition)作为输入。这个消息定义可以通过一个缓冲区或一个已经加载了的消息资源表模块传入本函数。调用者还可以通过搜索系统消息资源表来传入这个消息定义。
FormatMessage函数在一个消息资源表中是通过一个消息标识符和一个语言标识符来找到一个消息定义。函数如果被调用,则通过复制格式化的消息文本到一个输出缓冲区中来处理任何嵌入式插入序列(processing any embedded insert sequences if requested)。
FormatMessage函数,能够自动将错误代码转换成自定义的格式(简单的来说)
函数原型:
DWORD WINAPI
FormatMessageW(
_In_ DWORD dwFlags,
_In_opt_ LPCVOID lpSource,
_In_ DWORD dwMessageId,
_In_ DWORD dwLanguageId,
_Out_ LPWSTR lpBuffer,
_In_ DWORD nSize,
_In_opt_ va_list *Arguments
);
参数说明:
<1>dwFlags
格式化选项。这个參数主要用来影响lpSource以及lpBuffer。须要注意的是FORMAT_MESSAGE_ALLOCATE_BUFFER,当指定它的时候。是系统为你分配内存。这个时候的lpBuffer參数须要做一些处理,假设传递的是LPSTR buf的话,则传递的參数应该是&buf(这里涉及到了函数栈的销毁问题,在《C++高质量编程中有过》解释)。假设没有指定FORMAT_MESSAGE_ALLOCATE_BUFFER的话,那么传递的就是一个字符数组。
<2>lpSource
消息定义的位置。依赖于dwFlags的设置,有两种情况
FORMAT_MESSAGE_FROM_HMODULE:
0x00000800 A handle to the module that contains the message table to search.
FORMAT_MESSAGE_FROM_STRING:
0x00000400 Pointer to a string that consists of unformatted message text. It will be scanned for inserts and formatted accordingly.
假设这两个都没有指定的话,那么lpSource參数就会被忽略
<3>dwMessageId
错误ID。假设dwFlags中指定了FORMAT_MESSAGE_FROM_STRING,那么该值就会被忽略
<4>dwLanguageId
语言ID,假设假设dwFlags中指定了FORMAT_MESSAGE_FROM_STRING,那么该值就会被忽略。
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) //设置为本地默认语言 MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US) //设置为美语 MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED) //简体中文
全部的语言宏定义都是在WinNT.h中能够看到。
<5>lpBuffer
输出的缓冲区,注意事项在dwFlags中说了,主要是根据FORMAT_MESSAGE_ALLOCATE_BUFFER来对应变化
<6>nSize
输出缓冲区的大小,假设没有指定FORMAT_MESSAGE_ALLOCATE_BUFFER,则是缓冲区自身的大小,假设指定了
FORMAT_MESSAGE_ALLOCATE_BUFFER,能够任意设置,设置为0也没事。
<7>Arguments
这个參数第一次是用的时候感觉是尤其复杂。这个參数跟dwFlags,lpSource都有关系。所以才是有点复杂。參数类型是va_list*,首先假设參数不是一个va_list*的指针,那么就得在dwFlags中使用FORMAT_MESSAGE_ARGUMENT_ARRAY ,而且传递一个DWORD_PTR类型的数组作为參数。
%n!string!的使用方法:
当中n是1-99的整数,假设不加后面的!string!的话就直接表示第一个,第二个參数。以此类推。
当加上!string!时,要注意中间的string是有一个*还是有两个*,在指定FORMAT_MESSAGE_ARGUMENT_ARRAY的时候。一个*则下一个元素是n+2,两个*的话就是n+3。在没有指定FORMAT_MESSAGE_ARGUMENT_ARRAY 的情况下,一个*就是n+1,两个星就是n+2.
示例:
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
using namespace std;
void Search();
int main()
{
setlocale(LC_ALL, "Chinese-simplified"); //汉语显示
Search();
return 0;
}
void Search()
{
DWORD dwError = 0;
printf("请输入要查找的错误号码:\r\n");
cin >> dwError;
HANDLE LocaleHandle = NULL;
// MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) 汉语
// MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) 英语
DWORD LocaleSystem = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
// 获得文本描述
// typedef int BOOL;
BOOL bOk = FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, dwError, LocaleSystem,
(PTSTR)&LocaleHandle, 0, NULL);
if (!bOk)
{
// 可能是网络错误
HMODULE hDll = LoadLibraryEx(TEXT("netmsg.dll"), NULL, DONT_RESOLVE_DLL_REFERENCES);
if (hDll != NULL)
{
bOk = FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
hDll, dwError, LocaleSystem,
(PTSTR)&LocaleHandle, 0, NULL);
FreeLibrary(hDll);
}
}
if (bOk && (LocaleHandle != NULL))
{
LPVOID v1 = LocalLock(LocaleHandle);
printf("错误类型描述: %ls\r\n", v1);
LocalFree(LocaleHandle);
}
else
{
MessageBox(0, L"No text found for this error number.", 0, 0);
}
}
从各个地方摘抄的