Solving this next problem should be a snap with your nascent psychic powers:
I’m trying use
FormatMessageto load a resource string with one insertion in it, and this doesn’t work for some reason. The string is “Blah blah blah %1. Blah blah blah.” The call toFormatMessagefails, andGetLastError()returnsERROR_RESOURCE_TYPE_NOT_FOUND. What am I doing wrong?LPTSTR pszInsertion = TEXT("Sample"); LPTSTR pszResult; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, //I also tried an instance handle and NULL. GetModuleHandle(NULL), IDS_MY_CUSTOM_MESSAGE, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language (LPTSTR) &pszResult, 0, (va_list*) &pszInsertion);
Hint: Take a closer look at the parameter
IDS_MY_CUSTOM_MESSAGE.
Hint 2: What does “IDS_” tell you?
Resource identifiers that begin with “IDS_”
are typically string resource identifiers, not message resource
identifiers.
There is no strong consensus on the naming convention for
message resource identifiers,
although I’ve seen “MSG_“.
Part of the reason why there is no strong consensus on the naming
convention for message resource identifiers is that almost nobody
uses message resources!
I don’t understand why they were added to Win32, since there
was already a way of embedding strings in resources,
namely, string resources.
That’s why you’re getting ERROR_RESOURCE_TYPE_NOT_FOUND.
There is no message resource in your module.
If you’re not going to use a message resource, you’ll have to
use the FORMAT_MESSAGE_FROM_STRING flag and
pass the format string explicitly.
DWORD_PTR rgdwInsertions[1] = { (DWORD_PTR)TEXT("Sample") };
TCHAR szFormat[256];
LoadString(hInstance, IDS_MY_CUSTOM_MESSAGE, szFormat, 256);
LPTSTR pszResult;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_STRING |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
szFormat,
0,
0,
(LPTSTR) &pszResult,
0,
(va_list*) &rgdwInsertions);
I also made a slight change to the final parameter.
When you use FORMAT_MESSAGE_ARGUMENT_ARRAY,
the last parameter must be an array of DWORD_PTRs.
(The parameter must be cast to va_list* to keep
the compiler happy.)
It so happens that the original code got away with this mistake
since sizeof(DWORD_PTR) == sizeof(LPTSTR) and they
both have the same alignment requirements.
On the other hand, if the insertion were a DWORD,
passing (va_list*)&dwValue is definitely wrong
and can crash if you’re sufficiently unlucky.
(Determining the conditions under which your luck runs out
is left as an exercise.)
0 comments