wostringstream to LPWSTR for MessageBoxW function - c++

I seem to be missing something in regards to converting a wostringstream to a LPCWSTR.
void counter_error(const wstring& input) {
wostringstream tempss;
tempss << L"Cannot find counter " << input;
LPCWSTR temp = tempss.str().c_str();
MessageBoxW(0, temp, L"ERROR", 0);
}
The "ERROR" caption shows up fine but the text below is garbled. I thought that it might be the c_str() function returning a regular char array instead of a wchar array but intellisense is telling me it returns a wchar array.

This line looks problematic:
LPCWSTR temp = tempss.str().c_str();
tempss.str() creates a temporary string which is destroyed at the end.
Try
void counter_error(const wstring& input) {
wostringstream tempss;
tempss << L"Cannot find counter " << input;
wstring temp_str = tempss.str();
LPCWSTR temp = temp_str.c_str();
MessageBoxW(0, temp, L"ERROR", 0);
}
Or, as #JoachimPileborg suggested, consider
MessageBoxW(0, (wstring(L"Cannot find counter " + input).c_str(), ...)
It still creates a temporary variable, but it is not going to be destroyed before returning from MessageBoxW.

Related

Cannot convert from 'WCHAR [256]' to 'WCHAR'

I have this function which uses the winscard.h function SCardGetReaderDeviceInstanceId.
WCHAR SCardInstanceId(SCARDCONTEXT phContext, LPTSTR szReaderName) {
WCHAR szDeviceInstanceId[256];
DWORD cchDeviceInstanceId = 256;
long lReturn = SCardGetReaderDeviceInstanceId(phContext, szReaderName, szDeviceInstanceId, &cchDeviceInstanceId);
if (lReturn != SCARD_S_SUCCESS) {
cout << "Failed SCardGetReaderDeviceInstanceId, errorcode: " << std::hex << std::setfill('0') << std::setw(8) << lReturn << endl;
exit(1);
}
return szDeviceInstanceId;
}
But it gives me a wierd error message on the return line.
E0120 return value type does not match the function type
and
Error C2440 'return': cannot convert from 'WCHAR [256]' to 'WCHAR'
What can be the issue here? and how do I solve it?
I can't change the function type to WCHAR [256], it that even a type?
The function return type is WCHAR. You are trying to return a C-style array of WCHARs. This isn't possible. You can instead return an std::wstring object, so your code would look like this:
#include <string>
std::wstring SCardInstanceId(SCARDCONTEXT phContext, LPTSTR szReaderName) {
std::wstring szDeviceInstanceId;
DWORD cchDeviceInstanceId = 255;
szDeviceInstanceId.resize(cchDeviceInstanceId);
// I think it is safer to resize to 255 chars as it is implementation defined if the internal array has the null-terminator.
// If it does and you resize to 256, you will end up with a 257-element array...
long lReturn = SCardGetReaderDeviceInstanceId(phContext, szReaderName, szDeviceInstanceId.data(), &cchDeviceInstanceId); // from c++17
// long lReturn = SCardGetReaderDeviceInstanceId(phContext, szReaderName, &szDeviceInstanceId[0], &cchDeviceInstanceId);
// before c++17 'data' returns const reference, so SCardGetReaderDeviceInstanceId couldn't modify the buffer (compilation error)
szDeviceInstanceId.resize(cchDeviceInstanceId-1); // shrink the string length to the length actually occupied by characters
// -1 because cchDeviceInstanceId is length including null-terminator (according to docs), and resize expects length excluding null
if (lReturn != SCARD_S_SUCCESS) {
cout << "Failed SCardGetReaderDeviceInstanceId, errorcode: " << std::hex << std::setfill('0') << std::setw(8) << lReturn << endl;
exit(1);
}
return szDeviceInstanceId;
}
If the 4th parameter of SCardGetReaderDeviceInstanceId didn't output any data, you could just pass szDeviceInstanceId.size()+1 (+1 for null).
Also note, that the buffer will be allocated on the heap, unless SSO occurs (which is implementation defined, yet I don't think it would occur in any implementation in case of this long string).
As you can see the code is somewhat complex because of the differences in the management of the null-terminator. To make it simpler (but less beautiful in the C++ context) you can use std::wstring only to return the string:
std::wstring SCardInstanceId(SCARDCONTEXT phContext, LPTSTR szReaderName) {
WCHAR szDeviceInstanceId[255];
DWORD cchDeviceInstanceId = 255;
long lReturn = SCardGetReaderDeviceInstanceId(phContext, szReaderName, szDeviceInstanceId, &cchDeviceInstanceId);
if (lReturn != SCARD_S_SUCCESS) {
cout << "Failed SCardGetReaderDeviceInstanceId, errorcode: " << std::hex << std::setfill('0') << std::setw(8) << lReturn << endl;
exit(1);
}
return std::wstring(szDeviceInstanceId);
}
Please note, that doing it like this might be a bit less performant as you have to allocate both WCHAR[255] array and std::wstring array. It isn't going to matter most of the time, but it might be worth using the first method in a very performance-sensitive context.
You can return the array in the C manner as well, however it isn't recommended to do that in C++.

Assert a BSTR with string

I have a test function as follow:
[TestMethod]
void RipMichaelJacksonTest()
{
string expected = "Hello";
BSTR actual = SysAllocString(L"Hello");
Assert::AreEqual(expected, actual);
}
The assert part will of course fail.
Is there any Assert function that i can use?
Im new to VC++.
The problem is that you are doing a AreEqual. Passing in two parameters will force AreEqual(Object^, Object^) which:
Verifies that two specified objects are equal. The assertion fails if the objects are not equal.
What you are actually looking for is the comparison of a wchar* and a char*. There is not a direct comparison function between the two so it will be necessary to convert from a string to a wstring. There are lots of examples of how to do that, such as: https://stackoverflow.com/a/7159944/2642059 and you'll need to do something similar, for example:
wstring get_wstring(const string& s) {
wstring buf;
const char* cs = s.c_str();
const size_t wn = mbsrtowcs(nullptr, &cs, 0, nullptr);
if (wn == string::npos) {
cout << "Error in mbsrtowcs(): " << errno << endl;
} else {
buf.resize(wn + 1);
if(mbsrtowcs(&*buf.begin(), &cs, wn + 1, nullptr) == string::npos) {
cout << "Error in mbsrtowcs(): " << errno << endl;
buf.resize(0);
}
}
return buf;
}
The return of get_wstring(expected) and actual will now both be wchars and can thereby be compared in the using AreEqual(String^, String^, bool)

C++ - Read data from Buffer

How can i read data from my memory buffer?
const char *buf
and then print it out like this
MessageBoxA(NULL, "Buf: " + buf, " ", MB_OK);
std::string str = "Buf: ";
str += buf; // I assume buf is a null terminated string
MessageBoxA(NULL, str.c_str(), " ", MB_OK);
You can't apply + on string literals and/or char*. One of the operands has to be a std::string to be able to take advantage of std::string's operator+ overload.
If your buf is a char array, then something like this could work:
std::string("Buf: ") + buf
This requires that buf is null-terminated.
If buf isn't null-terminated however, Tony D's solution should work.

C++ String to byte error

So, I converted the string to byte in C++, but when it goes to add it into registry, it's stripping off the exe part but keeping the ., I have no idea what's wrong with it.
If you're wondering what NXS is, the value of it is "noerrorsplease.exe", type is char.
char szFinal[] = "";
strcat(szFinal, (const char *)ExtractDirectory(filepath).c_str());
//Not needed: strcat(szFinal, "");
strcat(szFinal, nxs);
strcat(szFinal, ".exe");
CString str;
str = szFinal;
str += ".exe";
cout << str.GetString() << endl;
const BYTE* pb = reinterpret_cast<const BYTE*>(str.GetString());
cout << pb << endl;
DWORD pathLenInBytes = *szFinal * sizeof(*szFinal);
if(RegSetValueEx(newValue, TEXT("Printing Device"), 0, REG_SZ, (LPBYTE)pb, pathLenInBytes) != ERROR_SUCCESS)
{
RegCloseKey(newValue);
cout << "error" << endl;
}
cout << "Possibly worked." << endl;
RegCloseKey(newValue);
This code
char szFinal[] = "";
strcat(szFinal, (const char *)ExtractDirectory(filepath).c_str());
is already invalid. You defined array szFina having only one character that is the terminating zero. You may not use it for copying in it any string. In these situations you should use an object of type std::string.

C++ string to fixed sized char array possible?

Hi i have the following code:
char msg[10000];
string mystr = "hello";
I want to put mystr into msg. Is there a way to do that? I tried all sorts of methods, but keep getting:
incompatible types in assignment of 'const char*' to char [10000]'
I tried:
msg = mystr.c_str();
and
msg = (char[10000])mystr;
to no avail.
You can try std::copy for this. Something like:
std::copy(mystr.begin(), mystr.end(), msg);
I would avoid C string functions like mempcy and strcpy in C++.
Take a look at string::copy - it takes a string an puts it into an array.
In your case it would be:
std::size_t length = mystr.copy(msg,10000);
msg[length]='\0';
char msg[10000];
string mystr = "hello";
strcpy(msg, mystr.c_str());
cout<<msg;
Use copy member function of std::string:
size_t len = mystr.copy(msg, (sizeof msg)-1);
msg[len] = 0;
String assignment in C is different. You have to copy the bytes into your destination string.
memcpy_s(msg, 1000, mystr.c_str(), mystr.length()) // safe windows version
memcpy(msg, mystr.c_str(), mystr.length()) // unix version
Use strcpy function :
http://www.cplusplus.com/reference/clibrary/cstring/strncpy/
strncpy(msg, mystr.c_str(), sizeof msg / sizeof msg[0]);
msg[sizeof msg / sizeof msg[0] - 1] = 0; // null-terminate in case of truncation
Compilers sometimes produce wonky error messages for array types.
Here's an accumulation of previous answers into a paste-and-compile program.
#include <string>
#include <iostream>
#if 1
int main(int argc, char **argv)
{
using std::cout;
using std::endl;
char msg[1000] = {0}; // initialize to 0 here since we're printing below
// the <type> <array-name>[<size>] = {0} just fills a POD struct or an array with 0s
std::string mystr = "hello";
// if, at some point, you have things changing "mystr"
// you'll need to make sure that it will fit in msg[]
cout << "Before strcpy: \"" << msg << "\"" << endl;
// I'll just finish the statement in mystr...
mystr += " world!";
if(mystr.length() < sizeof(msg)){
strcpy(
msg, // <- put in here until we find a '\0'
mystr.c_str() // <- take from here (which could be a temporary buffer)
);
}
//MSC will complain about strcpy being unsafe
//
// you can use the below instead (if you really feel the need to), which is
// the MS-specific equivalent to the above.
/*
strcpy_s(
msg, // <- put in here until we find a '\0' or the size limit is reached
sizeof(msg), // <- don't put any more than this many chars in msg
mystr.c_str() // <- take from here
);
*/
cout << "After strcpy: \"" << msg << "\"" << endl;
return 0;
}
#else
// Similarly, using wchar_t (a usually non-byte-sized character type)
//
// note where the divisions occurr
int main(int argc, char **argv)
{
using std::wcout;
using std::endl;
wchar_t msg[1000] = {0};
std::wstring mystr = L"hello";
wcout << "Before strcpy: \"" << msg << "\"" << endl;
mystr += L" world";
if(mystr.length() < (sizeof(msg)/sizeof(wchar_t))){
// mystr wil fit!
wcscpy(
msg, // <- put in here until we find a '\0'
mystr.c_str() // <- take from here (which could be a temporary buffer)
);
}
// Similar to the char case in the first preprocessor block
/*
wcscpy_s(
msg, // <- put in here until we find a '\0' or the size limit is reached
sizeof(msg)/sizeof(wchar_t), // <- don't put any more than this many wchar_ts in msg
mystr.c_str() // <- take from here
);
*/
wcout << "After strcpy: \"" << msg << "\"" << endl;
return 0;
}
#endif
I shall leave it to you to read the documentation on all related functions.