Cannot convert CString to BYTE array - c++

I need to convert CString to BYTE array. I don't know why, but everything that I found in internet does not work :(
For example, I have
CString str = _T("string");
I've been trying so
1)
BYTE *pbBuffer = (BYTE*)(LPCTSTR)str;
2)
BYTE *pbBuffer = new BYTE[str.GetLength()+1];
memcpy(pbBuffer, (VOID*)(LPCTSTR)StrRegID, str.GetLength());
3)
BYTE *pbBuffer = (BYTE*)str.GetString();
And always pbBuffer contains just first letter of str
DWORD dwBufferLen = strlen((char *)pbBuffer)+1;
is 2
But if I use const string:
BYTE *pbBuffer = (BYTE*)"string";
pbBuffer contains whole string
Where is my mistake?

Your CString is Unicode (two bytes per character) and you try to interpret it as ANSI (one byte per character). This leads to results you don't expect.
Instead of casting the underlying buffer into char* you need to convert the data. Use WideCharToMultiByte() for that.

You are probably compiling with unicode. This means that your CString contains wchar_t instead of char. Converting a wchar_t pointer to a char pointer causes you to interpret the second byte of the first wchar_t as a string terminator (since that by is 0 for the most common characters)
When using visual studio you should always use _T() to declare string literals and TCHAR as your character type. In your case:
BYTE* pBuffer = (BYTE*)(LPCTSTR)str;
You get the buffer, but every other byte is most probably zero.
Use a CStringA if you need an ANSI string. (But then skip the _T() when initializing it)

Related

Converting a TCHAR to wstring

TCHAR path[_MAX_PATH+1];
std::wstring ws(&path[0], sizeof(path)/sizeof(path[0]));
or
TCHAR path[_MAX_PATH];
std::wstring ws(&path[0]);
While converting a TCHAR to wstring both are correct?
I'm asking just for clarification, I'm in doubt if I'm converting it correctly.
The code is problematic in several ways.
First, std::wstring is a string of wchar_t (aka WCHAR) while TCHAR may be either CHAR or WCHAR, depending on configuration. So either use WCHAR and std::wstring, or TCHAR and std::basic_string<TCHAR> (remembering that std::wstring is just a typedef for std::basic_string<WCHAR>).
Second, the problem is with string length. This snippet:
WCHAR path[_MAX_PATH];
std::wstring ws(&path[0], sizeof(path)/sizeof(path[0]));
will create a string of length exactly _MAX_PATH + 1, plus a terminating null (and likely with embedded nulls, C++ strings allow that). Likely not what you want.
The other one:
WCHAR path[_MAX_PATH+1];
...
std::wstring ws(&path[0]);
expects that path holds a null-terminated string by the time ws is constructed, and copies it into ws. If path happens to be not null-terminated, UB ensues (usually, either garbage in ws or access violation).
If your path is either null-terminated or contains _MAX_PATH-length string, I suggest using it like this:
WCHAR path[_MAX_PATH+1];
... // fill up to _MAX_PATH characters
path[_MAX_PATH] = L'0'; // ensure it is null-terminated
std::wstring ws(path); // construct from a null-terminated string
Or if you know the actual length, just pass it:
WCHAR path[_MAX_PATH];
size_t length = fill_that_path(path);
std::wstring ws(path, length); // length shouldn’t include the null terminator, if any
See the docs (it’s the same for string and wstring except of different char type).
It depends on the content of path. If it is an arbitrary char array that can contain null characters, then you should use the first version which explicitely gives the size. But if is contains a null terminated string (and only contains unused values after the first null), then you should use the second one which will stop on the terminating null character.

Why wstring can accept WCHAR[] while string doesn't accept UCHAR[]

I am trying to print the returned value of NtQueryValueKey which is UCHAR Data[1]; i have tried printf, cout, and string(Data, DataLengh), with the first two printing only 1 character and the last one throws an exception... Basically if i changed the Data Type to WCHAR Data[1] and used wstring(Data) it accepts it normally without any complain... also wprintf prints the value normally.
Edit: I meant NtQueryValueKey using the KEY_VALUE_PARTIAL_INFORMATION, I am using VS 2015 btw...
You must have mixed something up. You did not specify what value from the KEY_NAME_INFORMATION enumeration you are using for the second parameter to specify the data type, but a quick look at MSDN shows that all of the structures contain WCHAR Name[1]; or something similar as the last member (which I guess is the one you are interested in). Can you elaborate and provide the link or other means of documentation that states you actually need to use UCHAR ?
WCHAR is an alias for wchar_t. std::wstring operates with wchar_t elements. A WCHAR[] can decay to a wchar_t*, and thus can be assigned directly to a std::wstring.
UCHAR is an alias for unsigned char. std::string operates with char elements instead. A UCHAR[]/UCHAR* cannot be assigned directly to a std::string without a type-cast to char*, as char and unsigned char are distinct data types.
unsigned char is commonly used to represent 8bit bytes (it is the same data type used for BYTE).
NtQueryKey() returns strings as UTF-16LE encoded bytes using WCHAR[] character arrays, not UCHAR[] byte arrays. So your code is declaring things wrong if you are using UCHAR[] to begin with. But even so, you can use UCHAR if you pay attention to the encoding and byte length, and use appropriate type-casts.
Any associated Length value reported by NtQueryKey() is expressed in bytes, not characters. sizeof(UCHAR) is 1 and sizeof(WCHAR) is 2. So every 2 UCHARs represents 1 WCHAR. And the strings are not null-terminated, so you have to take the Length into account when printing or converting.
In Latin-based languages, most commonly used Unicode characters will be <= U+00FF, and thus every other UCHAR in UTF-16LE will usually be 0. That is interpreted as a null terminator when UTF-16 is printed with printf() or std::cout. You need to use wprintf() or std::wcout instead.
Converting Data to a std::string is a valid operation and should not be raising an exception:
std::string((char*)Data, DataLength)
Provided that:
Data is a valid pointer.
DataLength is an accurate byte count.
The only way this could raise an exception is if either:
Data is not pointing at valid memory.
the value of DataLength is more than the actual number of bytes allocated for Data.
available memory is too low to allocate std::string's internal buffer.
memory is corrupted.
Assigning Data by itself to a std::wstring without taking DataLength into account is not a valid operation because the strings are not null-terminated. You must specify the length:
std::wstring(Data, DataLength / sizeof(WCHAR))
If Data is UCHAR then use a type-cast:
std::wstring((WCHAR*)Data, DataLength / sizeof(WCHAR))
When printing Data directly with wprintf(), you must pass DataLength as an input parameter:
wprintf(L"%.*s", DataLength / sizeof(WCHAR), Data);
When printing Data directly with std::wcout, you should use write() instead of operator<< so you can pass DataLength as an input parameter:
std::wcout.write(Data, DataLength / sizeof(WCHAR));
If Data is UCHAR then use a type-cast:
std::wcout.write((WCHAR*)Data, DataLength / sizeof(WCHAR));

memcpy only copying one byte over c++

I'm trying to use memcpy to convert a TCHAR array into a BYTE array but the memcpy function is only copying 1 TCHAR from the tchar array into the byte array.
I have no idea why this is happening.
Here is a code snippet.
TCHAR test[] = L"This is a test string, its purpose is to do some testing!";
DWORD testSizeBytes = sizeof(TCHAR) * lstrlen(test);
LPBYTE byteArray = new BYTE[testSizeBytes+1];
memcpy(byteArray,test,testSizeBytes);
If I used this snippet the byteArray would just contain 'T';
Any help would be appreciated.
EDIT: I fixed the issue (It was a typo). The code I wrote here works flawlessly. My compiler is in a windows VM so I had to retype it here and unknowingly fixed the typo.
TCHAR test[] = L"This is a test string, its purpose is to do some testing!";
This is a wide character (wchar_t) string. On Windows, with UNICODE defined, that is UTF-16. In UTF-16, the character 'T' is 2 bytes. The first byte corresponds to the ASCII value of 'T' (decimal 84). The second byte is a 0. So when you copy this over to your byte array, it looks like a null terminated c-string with 1 character. The other characters are there, but they come after the end of the apparent c-string, so your debugger is apparently ignoring them.
As the comment from ajshort mentioned, your debugger probably does not realize you are dealing with an array.
If you can use your debugger to look at memory, try to look at the memory location byteArray + 1 and byteArray + 2, etc.
I am not on Windows, so I cannot tell you how to do that, but the equivalent gdb command would be x byteArray + 1.

how to convert or cast CString to LPWSTR?

I tried to use this code:
USES_CONVERSION;
LPWSTR temp = A2W(selectedFileName);
but when I check the temp variable, just get the first character
thanks in advance
If I recall correctly, CString is typedef'd to either CStringA or CStringW, depending on whether you're building Unicode or not.
LPWSTR is a "Long Pointer to a Wide STRing" -- aka: wchar_t*
If you want to pass a CString to a function that takes LPWSTR, you can do:
some_function(LPWSTR str);
// if building in unicode:
some_function(selectedFileName);
// if building in ansi:
some_function(CA2W(selectedFileName));
// The better way, especially if you're building in both string types:
some_function(CT2W(selectedFileName));
HOWEVER LPWSTR is non-const access to a string. Are you using a function that tries to modify the string? If so, you want to use an actual buffer, not a CString.
Also, when you "check" temp -- what do you mean? did you try cout << temp? Because that won't work (it will display just the first character):
char uses one byte per character. wchar_t uses two bytes per character. For plain english, when you convert it to wide strings, it uses the same bytes as the original string, but each character gets padded with a zero. Since the NULL terminator is also a zero, if you use a poor debugger or cout (which is uses ANSI text), you will only see the first character.
If you want to print a wide string to standard out, use wcout.
In short: You cannot. If you need a non-const pointer to the underlying character buffer of a CString object you need to call GetBuffer.
If you need a const pointer you can simply use static_cast<LPCWSTR>(selectedFilename).
I know this is a decently old question, but I had this same question and none of the previous answers worked for me.
This, however, did work for my unicode build:
LPWSTR temp = (LPWSTR)(LPCWSTR)selectedFileName;
LPWSTR is a "Long Pointer to a Wide String". It is like wchar*.
CString strTmp = "temp";
wchar* szTmp;
szTmp = new WCHAR[wcslen(strTmp) + 1];
wcscpy_s(szTmp, wcslen(strTmp) + 1, strTmp);

MFC: How to i convert DWORD and BYTE to LPCTSTR in order to display in MessageBox

I'm using VS2005 with "using Unicode Character Set" option
typedef unsigned char BYTE;
typedef unsigned long DWORD;
BYTE m_bGeraet[0xFF];
DWORD m_dwAdresse[0xFF];
How do i make the code work?
MessageBox (m_bGeraet[0], _T("Display Content"));
MessageBox (m_dwAdresse[0], _T("Display Content"));
It looks like you might need some help with the C language itself, and I recommend you find a beginner's book on C that is not about Windows programming.
MessageBox() only displays C-style strings which are arrays of type char which contain a character with ASCII value 0. This zero character is the NUL character, and such strings are said to be "NUL-terminated" or "Zero-terminated." Only the characters prior to the NUL are displayed when the string is printed, or copied when the string is concatenated. However, if there is no NUL character in the array, then the string is not properly terminated and an attempt to display it could lead to a crash, or to "garbage" being displayed, as in: "Can I have a beer?#BT&I10)aaX?.
The szTitle and szText arguments to MessageBox() expect char * which are pointers to this type of string.
If you attempt to pass a BYTE instead of a char *, the value of the BYTE will be mistakenly treated as an address. MessageBox() will attempt to access memory at the value "specified" by the BYTE and an Access Violation will occur.
One solution to this problem is to allocate a buffer of type char and use snprintf_s to transcribe your data values to string representations.
For example:
char output_buffer[1024];
snprintf_s(output_buffer, dimensionof(output_buffer), "Geraet = 0x%02X", m_bGeraet[i]);
MessageBox(hwnd_parent, output_buffer, "Message from me:", MB_OK);
Would display a MessageBox with a message reading something like "Geraet = 0x35".
If it's essential that BYTE is 1-byte then you have to (optionally) convert your byte strings to wide strings using mbstowcs.
//easy way for bytes is to do this
CString sTemp;
sTemp.Format("my byte = %d", bySomeVal);
MessageBox(sTemp);
//for a DWORD try
sTemp.Format("Dword is %lu", dwSomeVal);
MessageBox(sTemp);
if you using MessageBox, i would suggest soetming like AfxMessageBox...