lundi 2 mars 2015

How to populate the va_list for system error messages using the FormatMessage function?

I am unsure if I have made a fundamental issue in my implementation or there is a bug in the Windows API with regards to formatting system error messages.


I have a Windows API wrapper method for the FormatMessage function. My implementation allows the caller to pass in additional parameters to allow for the formatting of system error messages.


The method signature is as follows:


bool setFormattedMessage(int arguments, ...)


Within this method I have the following block of code that doesn't appear to work for all my unit tests:



if (arguments)
{
va_list argumentsList;
va_start(argumentsList, arguments);

size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, language, (LPWSTR)&buffer, 0,
&argumentsList);

va_end(argumentsList);
}


Note: code and language are members of the class set in the instantiation list (using GetLastError and LANGIDFROMLCID(GetThreadLocale()).


Here are some unit tests that pass without any problems:


If I create an instance of the class for an error code of 34 I will get the following if I call the method as test.setFormattedMessage(0) (note that this doesn't go into the block of code I posted due to the if (arguments) line):



The wrong diskette is in the drive. Insert %2 (Volume Serial Number: %3) into drive %1.`



If I call the method as test.setFormattedMessage(3, L"C:", L"disk 2", L"ABC123") I get the following:



The wrong diskette is in the drive. Insert disk 2 (Volume Serial Number: ABC123) into drive C:.;



However, for error messages that include such examples as %hs or %08lx I run into problems attempting to format the text.


Take the example of error code 573. When passing an argument of 0 into the method I get the following text (as expected):



{Missing System File} The required system file %hs is bad or missing.



But, if I pass in (1, "test") I end up with:



{Missing System File} The required system file hs is bad or missing.



In fact, I have found that regardless of whether I pass in "test", L"test", a copy of char, wchar_t etc I always end up with the error message above. The message created is the same as passing (0) with the exception of having the % dropped from the string.


I am finding the same problem for all other parameters unless they are numbered (such as %1). I am completely stuck at this point as to whether I have made a fundamental error or there really is a shortcoming in the FormatMessage function.


I was under the impression that I could pass in a replacement for the %hs placeholder in the same way I would do it for swprintf:



char * t = "file 123";
wchar_t a[2000];
int v = swprintf(a, 2000, L"Blah blah %hs", t);
std::wstring someText(a, v);



Blah blah file 123



Aucun commentaire:

Enregistrer un commentaire