Is this the right size to hold a integer value on 64-bit machine plus a unicode string? or am I missing something?
DWORD errorMessageID = GetLastError();
const wchar_t msgFmt[] = L"foo baaa. Error code = %d";
wchar_t bufferMsg[sizeof(msgFmt) + // room for fmt message string itself
21 + // enough to hold numbers up to 64-bits
sizeof(wchar_t) // byte-terminattor
];
int nBytesWritten = swprintf_s(bufferMsg,
msgFmt,
sizeof(msgFmt),
errorMessageID);
MessageBox(NULL,
bufferMsg,
TEXT("Copy to clipboard failed"),
MB_OK | MB_ICONERROR);
In addition to the problems with the arguments passed to swsprintf_s()
mentioned in Kirill Kobelev's answer , there are at least a few more things that aren't quite right, even if not all of them would result in a defect:
DWORD
in the Windows SDK is 32-bits, even when building for a 64-bit target. Reserving 21 characters for formatting it is a small bit of overkill, but not a bug. However, it's an indication of a misunderstanding that might result in other problems. DWORD
is an unsigned type, so using "%d" to format it isn't quite right No, this is not correct. The right code should look like:
const wchar_t msgFmt[] = L"foo baaa. Error code = %d";
wchar_t bufferMsg[sizeof(msgFmt)/sizeof(wchar_t) + // room for fmt message string itself
21 + // enough to hold numbers up to 64-bits
1 // symbol-terminator
];
int nBytesWritten = swprintf_s(bufferMsg,
sizeof(bufferMsg)/sizeof(wchar_t),
msgFmt,
errorMessageID);
In both cases you used the byte-size instead of the number of elements plus the order of params is wrong. You call of the MessageBox()
function is correct.
Manually calculating the required buffer size for the destination of an sprintf
call is difficult to maintain. It is easier and safer to have the system perform the calculation for you. The CRT that ships with Visual Studio provides the _scprintf
family of functions for this.
The following code illustrates its usage. It implements a function that takes a format string and a variable number of arguments and returns a string that is the result of formatting:
std::wstring FormatString( const wchar_t* a_Format, ... ) {
std::wstring text;
va_list argList;
va_start( argList, a_Format );
// Calculate required buffer size
size_t size = _vscwprintf( a_Format, argList ) + 1;
va_end( argList );
if ( size > 0 ) {
// Dynamically construct buffer with the correct size
std::vector<wchar_t> buffer( size );
va_start( argList, a_Format );
int count = _vsnwprintf_s( buffer.data(), size, size - 1,
a_Format, argList );
va_end( argList );
if ( count >= 0 ) {
// Construct return value
text = std::wstring( buffer.data(), count + 1 );
}
}
return text;
}
This function returns a std::wstring
object. Just like the std::vector
used in the implementation, it automatically manages memory for you, and no explicit cleanup code is required. To use it with Windows API calls that require an LPCWSTR
argument call its c_str()
member.
Using this function in your original code condenses it down to the following:
DWORD errorMessageID = GetLastError();
MessageBoxW(NULL,
FormatString( L"foo baaa. Error code = %u", errorMessageID ).c_str(),
L"Copy to clipboard failed",
MB_OK | MB_ICONERROR);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.