Converting a TCHAR to wstring - c++

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.

Related

Assign variable wstring to Char array in C++

I have char array as follows:
TCHAR name[256] = L"abc";
Also I have another wstring vector as follows,
std::vector<std::wstring> nameList;
nameList.push_back(L"cde");
nameList.push_back(L"fgh");
I want to assign nameList vector first element to name array,
Can any one help for that me?
You can use std::copy; name is an array with a bound, but it's usage as a function argument decays to a pointer to it's first element, which satisfies the requirements for an output iterator.
So you can:
wchar_t name[256] = L"abc";
std::vector<std::wstring> nameList;
nameList.push_back(L"cde");
nameList.push_back(L"fgh");
std::copy(nameList.front().begin(), nameList.front().end(), name);
Note that: this will not add any trailing \0 terminator to the buffer; If you wanted to replace/overwrite name, you should as well just use std::wstring and save yourself some hassles
Given your question and the assumption that you must use an array instead of a wstring, your best bet may be to use either std::copy or even an old fashioned memcpy. However these are dangerous for the following two reasons:
If TCHAR is not actually a wchar_t there are likely be to memory errors.
If nameList contains a string that is longer than 255 TCHAR characters you will have a buffer overflow.
That said, you can do this safely with the following:
if (nameList[0].size() >= 256) {
throw std::length_error("string too long");
}
std::copy(nameList[0].begin(), nameList[0].end(), name);
name[nameList[0].size()] = TCHAR(0);
You could also add a static_assert to force a compiler error if TCHAR is not a wchar_t, but it probably isn't necessary as the copy would perform any implicit conversion on a character by character basis.

C++ How can I convert wchar_t* to TCHAR [] (not TCHAR*)

I wants to add a small additional options to a big unit, so I do not want to process a large amount of code.
TCHAR szTempFileName[MAX_PATH];
TCHAR lpTempPathBuffer[MAX_PATH];
int uRetVal = 0;
GetTempPath(MAX_PATH, // length of the buffer
lpTempPathBuffer); // buffer for path
GetTempFileName(lpTempPathBuffer, // directory for tmp files
TEXT("QRCode_"), // temp file name prefix
0, // create unique name
szTempFileName); // buffer for name
I want to change szTempFileName to optional wstring/std::string/wchar_t* parametr .
Solution:
change TCHAR to wchar_t
wcscpy(wchar_t[], wchat_t*);
Typically, there's no reason to use TCHARs at all. If you're working with wchar_t anyway, simply call the Unicode variants of the Winapi functions directly by adding a W suffix:
// Use wchar_t instead of TCHAR.
wchar_t szTempFileName[MAX_PATH];
wchar_t lpTempPathBuffer[MAX_PATH];
int uRetVal = 0;
// Call GetTempPathW directly.
GetTempPathW(MAX_PATH, lpTempPathBuffer);
// Use L"..." instead of TEXT("...").
GetTempFileNameW(lpTempPathBuffer, L"QRCode_", 0, szTempFileName);
Stick with what you have and convert to the appropriate string type at the end. Getting windows to play nicely and correctly with the C++ string types will probably turn your hair grey.
Use the following typedef to create your string type that you can use throughout your code instead of std::string or std::wstring:
typedef std::basic_string<TCHAR> tstring;
Construct your string from the buffer directly:
tstring RealFileName(szTempFileName);

CreateFileMapping() name

Im creating a DLL that shares memory between different applications.
The code that creates the shared memory looks like this:
#define NAME_SIZE 4
HANDLE hSharedFile;
create(char[NAME_SIZE] name)
{
hSharedFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, (LPCSTR)name);
(...) //Other stuff that maps the view of the file etc.
}
It does not work. However if I replace name with a string it works:
SharedFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, (LPCSTR)"MY_TEST_NAME");
How can I get this to work with the char array?
I have a java background where you would just use string all the time, what is a LPCSTR? And does this relate to whether my MS VC++ project is using Unicode or Multi-Byte character set
I suppose you should increase NAME_SIZE value.
Do not forget that array must be at least number of chars + 1 to hold \0 char at the end, which shows the end of the line.
LPCSTR is a pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters and defined as follows:
LPCSTR defined as typedef __nullterminated CONST CHAR *LPCSTR;
For example even if you have "Hello world" constant and it has 11 characters it will take 12 bytes in the memory.
If you are passing a string constant as an array you must add '\0' to the end like {'T','E','S','T', '\0'}
If you look at the documentation, you'll find that most Win32 functions take an LPCTSTR, which represents a string of TCHAR. Depending on whether you use Unicode (the default) or ANSI, TCHAR will expand to either wchar_t or char. Also, LPCWSTR and LPCSTR explicitly represent Unicode and ANSI strings respectively.
When you're developing for Win32, in most cases, it's best to follow suit and use LPCTSTR wherever you need strings, instead of explicit char arrays/pointers. Also, use the TEXT("...") macro to create the correct kind of string literals instead of just "...".
In your case though, I doubt this is causing a problem, since both your examples use only LPCSTR. You have also defined NAME_SIZE to be 4, could it be that your array is too small to hold the string you want?

How can I substring a TCHAR

I have a TCHAR and value as below:
TCHAR szDestPathRoot[MAX_PATH]="String This";
Now I want the 1st three character from TCHAR , like below:
szDestPathRoot.substring(0,2);
How can I do this.
TCHAR[] is a simple null-terminated array (rather than a C++ class). As a result, there's no ".substring()" method.
TCHAR[] (by definition) can either be a wide character string (Unicode) or a simple char string (ASCII). This means there are wcs and str equivalents for each string function (wcslen() vs strlen(), etc etc). And an agnostic, compile-time TCHAR equivalent that can be either/or.
The TCHAR equivalent of strncpy() is tcsncpy().
Final caveat: to declare a TCHARliteral, it's best to use the _T() macro, as shown in the following snippet:
TCHAR szDestPathRoot[MAX_PATH] = _T("String This");
TCHAR szStrNew[4];
_tcsncpy (str_new, szTestPathRoot, 3);
You may find these links to be of interest:
http://msdn.microsoft.com/en-us/library/xdsywd25%28VS.71%29.aspx
http://www.i18nguy.com/unicode/c-unicode.html
http://msdn.microsoft.com/en-us/library/5dae5d43(VS.80).aspx (for using the secure _tcsncpy_s)
TCHAR szDestPathRoot[MAX_PATH]="String This";
TCHAR substringValue[4] = {0};
memcpy(substringValue, szDestPathRoot, sizeof(TCHAR) * 3);
As you have tagged your question with "C++" you can use the string classes of the std library:
std::wstring strDestPathRoot( _T("String This") );
strDestPathRoot.substr( 0, 2 );
This is somewhat ugly but if you know for sure that:
The string holds at least 4 TCHAR (3 chars plus the terminating NUL)
The content of the string can be modified (which is the case in your example).
You don't have to keep the original string intact
You could just put a terminating NUL at the 4th position to make the string 3 char long.
szDestPathRoot[3] = _T('\0');
Note that this operation is destructive to the original string
You should really be using a string class in C++ code though.

Cannot convert CString to BYTE array

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)