in source/shared/FormattedPrint.cpp [1404:1493]
DWORD FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPTSTR lpBuffer, DWORD nSize, va_list *Arguments)
{
DWORD chars_printed = 0;
// XPLAT_ODBC_TODO VSTS 718708 Localization by handling FORMAT_MESSAGE_FROM_HMODULE and dwLanguageId param
if ( dwFlags & FORMAT_MESSAGE_FROM_STRING )
{
// Format specification allows for reordering of insertions relative to var arg position
// This means we need to walk thru the format specification to find the types of the var args in var arg order
// We extract the var args in order based on the identified types
// Finally, we re-walk the format specfication and perform the insertions
// First pass thru the format string to determine all args and their types
// This first pass also validates the format string and will return an error
// if it is invalid. This allows FormatMessageToBuffer to have less error
// checking.
std::vector< vararg_t > args;
// Based on quick scan of RC files, the largest arg count was 7 so reserve 8 slots to reduce allocations
args.reserve(8);
if ( GetFormatMessageArgsA( reinterpret_cast<const char *>(lpSource), &args, Arguments ) )
{
if ( dwFlags == (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING) )
{
*((char**)lpBuffer) = NULL;
const DWORD max_size = 64000;
char local_buf[max_size] = {'\0'};
chars_printed = FormatMessageToBufferA( reinterpret_cast<const char *>(lpSource), local_buf, max_size, args );
if ( 0 < chars_printed )
{
size_t buf_size = std::min( max_size, std::max(nSize, (chars_printed+1)) );
char * return_buf = (char *)LocalAlloc(0, buf_size * sizeof(char));
if ( NULL == return_buf )
{
errno = ENOMEM;
}
else
{
mplat_cscpy(return_buf, local_buf);
*((char**)lpBuffer) = return_buf;
}
}
}
else if ( dwFlags == FORMAT_MESSAGE_FROM_STRING )
{
chars_printed = FormatMessageToBufferA( reinterpret_cast<const char *>(lpSource), lpBuffer, std::min(nSize, (DWORD)64000), args );
}
}
}
else if ( dwFlags & FORMAT_MESSAGE_FROM_SYSTEM )
{
// Since we don't have the Windows system error messages available use a fixed message
// Can not use a message ID for this since this same code is used by driver and tools,
// each having their own RLL file. Don't think we should be reserving an ID across all RLLs.
const char systemMsg[] = "Error code 0x%X";
if ( dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER )
{
*((char**)lpBuffer) = NULL;
// Add 9 for up to 8 hex digits plus null term (ignore removal of format specs)
const size_t msgsize = (9 + sizeof(systemMsg)/sizeof(systemMsg[0]));
char * return_buf = (char *)LocalAlloc(0, msgsize * sizeof(char));
if ( NULL == return_buf )
{
errno = ENOMEM;
}
else
{
chars_printed = mplat_snprintf_s( return_buf, msgsize, msgsize, systemMsg, dwMessageId );
// Assert that we did our buffer size math right
assert( chars_printed < msgsize );
if ( 0 < chars_printed )
{
*((char**)lpBuffer) = return_buf;
}
else
{
LocalFree( return_buf );
errno = EINVAL;
}
}
}
else
{
chars_printed = mplat_snprintf_s( lpBuffer, nSize, nSize, systemMsg, dwMessageId );
}
}
return chars_printed;
}