使用FormatMessage时如果对一些参数不仔细研究,那么就会出错误,首先说下这个函数
1 函数描述
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 );
<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.
例如:
LPWSTR pMessage = L"%1!*.*s! %4 %5!*s!"; DWORD_PTR pArgs[] = { (DWORD_PTR)4, (DWORD_PTR)1, (DWORD_PTR)L"Bill", (DWORD_PTR)L"Bob", (DWORD_PTR)5, (DWORD_PTR)L"Bill" }; const DWORD size = 100+1; WCHAR buffer[size]; if (!FormatMessageW(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; }
这里面pArgs的4代表第一个插入元素的宽度,1代表精度(即Bill中的一个元素B)。6代表元素的宽度,每一个字符串之间都是以空格为间隔,上面的程序运行得到的buffer就是“ B Bob Bill”
7 再看两个例子区分下
<1>
LPSTR buf; LONG x1 = RegCreateKey(HKEY_LOCAL_MACHINE,TEXT("sofware\\VC++MFC\\adminss"),&hKey); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL , x1, MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), (LPTSTR)&buf, 3, NULL); LocalFree(buf);
注意这里buf以及参数dwFlags
<2>
TCHAR buf[100] = {0}; LONG x1 = RegCreateKey(HKEY_LOCAL_MACHINE,TEXT("sofware\\VC++MFC\\adminss"),&hKey); FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL , x1, MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), (LPTSTR)buf, 100, NULL);
注意这里的buf以及参数dwFlags
8 VS提供的查看错误的工具
VS,工具-》错误查找,就可以打开错误对话框,然后在Key中输入值就可以查找错误ID对应的文字描述了。这里的错误ID是可以是10进制,也可以是16进制,但是不管10进制还是16进制,只要其对应的值相等那么错误描述就一样。
FormatMessage函数的用法