Error in converting BSTR to CString - c++

I using Visual C++ 2008 and ADO to access a database and obtain a field value like this:
_variant_t vtValue;
AfxVariantInit(&vtValue);
vtValue = m_pRecordset->Fields->GetItem(_variant_t(strFieldName))->GetValue();
If (vtValue.vt == VT_BSTR)
{
strValue = vtValue.bstrVal;
TRACE(_T(“Field value is %s.\r\n”), strValue); // Cause CrtDbgReport: String too long or IO Error
}
else
{
.. other codes…
}
The TRACE statement for strValue will cause the following error:
“CrtDbgReport: String too long or IO Error”
I just check strValue and found it is a Chinese string with only 6 characters, nothing special. Why it will cause the error?
Thanks

A BSTR is a composite data type that consists of a length prefix, a data string, and a terminator, you can not assign it to CString directly as CString doesn't have the length prefix.
You can use the smart point class _bstr_t to do the conversion.
strValue = (TCHAR*)(_bstr_t)vtValue;

Related

C++ dll for VBA - problem with reading/encoding strings

I need to read entries from old-fashioned INI-file with a DLL and after some manipulation export them to VBA code.
The c++ code for the function looks like this:
BSTR __stdcall GetSectionEntry(LPCSTR sSection, LPCSTR sEntry)
{
LPCTSTR gszINIfilename = "C:\\test\\test.ini";
TCHAR localStr[64];
GetFileAttributes(gszINIfilename);
if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(gszINIfilename) && GetLastError() == ERROR_FILE_NOT_FOUND) {
bstr_t bstrt = "";
return bstrt;
} else {
GetPrivateProfileStringA(sSection, sEntry, "", localStr, sizeof(localStr), gszINIfilename);
//_bstr_t bstrt(localStr);
CComBSTR bstrt(localStr);
return bstrt;
}
}
The VBA (Word 2016):
Declare PtrSafe Function GetSectionEntry Lib "test.dll" (ByVal sSection As String, ByVal sEntry As String) As String
For i = 0 To 5
Debug.Print ("Name = " & StrConv(GetSectionEntry("Name", CStr(i)), vbFromUnicode))
Next i
End finally the INI-file:
[Name]
0=123456789012345678901234567
1=1234567890123456789012345678
2=1234567890123456789012345678901234567890123456789012345678901
3=12345678901234567890123456789012345678901234567890123456789012
I compiled the DLL using VS2019 with either "Character Set" set to "Not Set" or to "Use Multi-Byte Character Set".
Debugging in VS shows that the strings are properly formatted (for example for 1 it's L"1234567890123456789012345678"). I tested it with different sizes of localStr (64..1024). I tried bstr_t and CComBSTR and a few more. In all cases print.debug in VBA shows following result:
Name = 123456789012345678901234567
Name = ?????????????? ????????????
Name = ??????????????????????????????1 ?? ??????????????yu ? rg|A ?
Name = 12345678901234567890123456789012345678901234567890123456789012
Any string that is longer than 27 and shorter than 62 characters is not properly encoded. When I checked them without StrConv(string, vbFromUnicode) they were missing all even null-characters.
For that reason they are then encoded as some Asian characters:
The same happens for string that are 13--14 character long:
I'm very sure that I'm doing something trivial and stupid but I never had to write any C/C++ for windows. I would be grateful if anyone could point my mistake and correct me.
CComBSTR bstrt(localStr);
return bstrt;
This return statement converts the CComBSTR to a BSTR, and returns that, and then destroys the CComBSTR since it's no longer in scope. When the CComBSTR object is destroyed the string is freed.
Try return bstrt.Detach(); which detaches the string from the CComBSTR object so it won't be freed by the destructor.
After you return it, the string "belongs" to VBA and it's VBA's job to free it, which I assume it does automatically.

How to get a readable string from SetupDiGetDeviceRegistryProperty?

I'm trying to get a human readable string from SetupDiGetDeviceRegistryPropertyA() function.
My code is:
size_t strSize = RequiredSize / sizeof(wchar_t) + 1;
wchar_t* DevName = new wchar_t[strSize];
Name = new CHAR[strSize];
Result = SetupDiGetDeviceRegistryPropertyA(InfoSet, &InfoData, SPDRP_DEVICEDESC, &Type, reinterpret_cast<PBYTE>(DevName), RequiredSize, &RequiredSize);
If Result is true, I want to convert the DevName value to a string using the following code:
size_t sizeCon;
wcstombs_s(&sizeCon, Name, strSize, DevName, strSize);
But in "Name" I always get null and sizeCon is always '0'.
If I use a wide string (for example: wchar_t b[] = L"984567";) instead of the parameter DevName, I get a correct translation of the wide string to a character string.
In the Documenation of SetupDiGetDeviceRegistryPropertyA the PropertyBuffer parameter is described as a PBYTE.
In all code examples, which I saw, the code examples uses a wchar variable. This wchar variable which will be casted to a PBYTE, like I do.
Now I am confused.
Why in the code examples is a wchar variable used, when the type of PropertyBuffer is PBYTE?
What is the correct type to use in SetupDiGetDeviceRegistryPropertyA to get a string?
If I need to use a wchar variable, why the wcstombs_s function cannot convert the wchar variable to a char string?
Can someone help me to get the correct string from SetupDiGetDeviceRegistryPropertyA?
Thank you.

How to convert fetched string data to character array?

I am doing this IoT based project on displaying data to connected display( I've used the MAX7219 module, in this case) with the help of nodeMCU. The idea here is that the string which is stored in my firebase database is to be display on the led display.
I've had no trouble in getting the value from the database to my nodeMCU but there is this little problem with converting that string to char array since the code i am using( Max72xx_Message_serial, which was available as an example with the max72xx library) has used char array but i can only fetch the stored data in string format. I've modified that code so as to connect with firebase but the main issue is to convert the string fetched from the database to char array.
I tried toCharArray() but it still shows conversion error.
void readfromfirebase(void)
{
static uint8_t putIndex = 0;
int n=1;
while (Firebase.available())
{
newMessage[putIndex] = (char)Firebase.getString("Submit Message"); // this line produces the error
if ((newMessage[putIndex] == '\n') || (putIndex >= BUF_SIZE-3)) // end of message character or full buffer
{
// put in a message separator and end the string
newMessage[putIndex++] = ' ';
newMessage[putIndex] = '\0';
// restart the index for next filling spree and flag we have a message waiting
putIndex = 0;
newMessageAvailable = true;
}
else if (newMessage[putIndex] != '\r')
// Just save the next char in next location
{putIndex++;}
n++;
}
}
I think you are confusing the types
getString returns a String object wich can be converted to a char[] using the methods of the String class.
I assume your newMessage is of type char[] or char*.
Then I would advise you to go for the String.c_str() method, because it returns a C style null-terminated string, meaning a char*.
See https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/c_str/ for reference.
It also sets the last character of the string to 0. So methods like strlen, strcmp etc will work.
! be carefull not to modify the array returned by c_str(), if you want to modify it you chould copy the char[] or use string.toCharArray(buf, len).
Your Code might then look like the following.
String msg = Firebase.getString("Submit Message");
newMessage = msg.c_str();
// rest of your code
If newMessage is a buffer storing multiple messages, meaning char* newMessage[3].
String msg = Firebase.getString("Submit Message");
newMessage[putIndex] = msg.c_str();
// rest of your code
Be careful, because you are storing multiple characters in an array, so use strcmp to compare these arrays!
If you are new to C I would recommend reading.
https://www.cprogramming.com/tutorial/c/lesson9.html
https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/ (as pointed out by #gre_gor)

Windows Universal app (XAML): textBlock->Text cannot be called with the given argument list

I'm trying to set the textBlock equal to the result of some calculations, but for some reason i'm getting the following error: "cannot be called with the given argument list" total is an int.
string Result;
ostringstream convert;
convert << total;
Result = convert.str();
textBlock->Text = Result;
The error message means that you are passing a parameter of a wrong type to the textBlock's Text property, which expects a Platform::String, but you pass a std::string. The MSDN page Strings(C++/CX) contains more details on string construction and conversions - also you need to be aware of ANSI and UNICODE when dealing with strings.
Below is the modified code. Noted that I have changed string to wstring (wide string, 16-bit Unicode) so that I can construct a Platform:String with it.
wostringstream convert;
convert << total;
wstring str = convert.str();
String^ Result = ref new String(str.c_str());
tb1->Text = Result;

How to convert win32 CHAR(char) type to std string?

Im using the win32 function ReadFile:
CHAR lpBuffer[256];
DWORD nBytesRead;
DWORD nCharsWritten;
ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer),
&nBytesRead,NULL) || !nBytesRead)
now im catcing the response from stdout in to lpBuffer with this i like to convert it to std string , the problem is when i do simple :
std::string szReturnlpBuffer(lpBuffer);
the value of the szReturnlpBuffer contains alot of garbege carecthers after the real string:
its looks like this the szReturnlpBuffer value :
"Im stdout from the Qt
applicationÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ"
what im doing wrong here ?
You need to specify the size of the string:
std::string szReturnlpBuffer(lpBuffer, nBytesRead);
because otherwise it reads till it finds a null character, which causes undefined behavior when it gets outside lpBuffer's memory.
You need to terminate the string with a null character:
lpBuffer[nBytesread] = '\0';