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

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);

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.

C++ Combine 2 Tchar

I'm trying to combine 2 tchar.
char username[UNLEN+1];
DWORD username_len = UNLEN+1;
GetUserName(username, &username_len);
TCHAR* appdatapath ="C:\\Users\\"+username+"\\AppData";
But I get error error at appdatapath line. How can I combine 2 tchar? Thanks
Have a look at strcat and wcscat. You can't add char pointer with char array.
If you are on a windows machine, you can use _tcscat which will redirect to the right function to use depending on _UNICODE and _MBCS defines.
Might want to use the safe versions as well by appending _s to the function name.
As pointed in the comments, you can also use snprintf like so:
const size_t concatenated_size = 256;
char concatenated[concatenated_size];
snprintf(concatenated, concatenated_size, "C:\\Users\\%s\\AppData", username);
Since you have string literals before and after the runtime string, it is probably a better approach.
To answer the question in the title: you concatenate two TCHAR strings using the _tcscat function.
However, there are other issues in your code related to this: GetUserName expects a LPTSTR, i.e. a pointer to a buffer TCHAR characters. Furthermore, there's another TCHAR usage in
TCHAR* appdatapath ="C:\\Users\\"+username+"\\AppData";
The issue with this is that the type to which TCHAR expands changes depending on whether _UNICODE is defined. In particular, if you set it, TCHAR (eventually) expands to wchar and hence GetUserName expects a wchar_t* but you pass a char*. Another issue is that you cannot concatenate C arrays using the + operator.
I suggest to stop worrying about TCHAR in the first place and always just compile with _UNICODE defined - and use wchar throughout your code. Also, since you're using C++, just use std::wstring:
wchar username[UNLEN+1];
DWORD username_len = UNLEN+1;
GetUserNameW(username, &username_len);
std::wstring appdatapath = L"C:\\Users\\";
appdatapath += username;
appdatapath += L"\\AppData";
Last but not least: your entire code can probably be replaced with a call to the SHGetSpecialFolderPath function - pass CSIDL_APPDATA to it to get the "AppData" path.
#include <tchar.h>
const size_t stringSize= 20;
TCHAR value[stringSize] = { 0 };
_tcscat_s(value, stringSize, TEXT("appendMe"));
MSDN: _tcscat_s

Concatenate two WCHAR_T arrays in C++

Dealing with these insane strings and arrays is giving me a headache...
Here's my code so far
wchar_t mypath[MAX_PATH];
wchar_t temppath[MAX_PATH];
GetModuleFileName(0, mypath, MAX_PATH);
GetTempPath(MAX_PATH, temppath);
CreateDirectory(???, NULL);
The first two windows API functions use the LPWSTR variable. The third uses LPCWSTR. What's the major difference? After I get the path for the TEMP directory, I want to create a new directory inside it called "test". This means I need to append (L"test") to my "temppath" variable. Can someone give me some tips on how to use these arrays. This is what makes C++ a pain. Why couldn't everyone just settle on one data type for strings. How is wchar_t even useful? It's so hard to use and manipulate.
Thanks guys!
The first two windows API functions use the LPWSTR variable. The third uses LPCWSTR. What's the major difference?
LPCWSTR is a const version of LPWSTR:
From LPCWSTR:
typedef const wchar_t* LPCWSTR;
From LPWSTR:
typedef wchar_t* LPWSTR, *PWSTR;
I want to create a new directory inside it called "test". This means I need to append (L"test") to my "temppath" variable.
Use a std::wostringstream:
std::wostringstream wos;
wos << temppath << L"\\test";
std::wstring fullpath(wos.str());
or just a std::wstring (as suggested by chris in the comments):
std::wstring fullpath(std::wstring(temppath) + L"\\test");
to produce a concatenated version. Then use c_str() as the argument to CreateDirectory():
if (CreateDirectory(fullpath.c_str(), NULL) ||
ERROR_ALREADY_EXISTS == GetLastError())
{
// Directory created or already existed.
}
else
{
// Failed to create directory.
}
Use PathCombine(), eg:
wchar_t temppath[MAX_PATH+1] = {0};
GetTempPath(MAX_PATH, temppath);
wchar_t mypath[MAX_PATH+8] = {0};
PathCombineW(mypath, temppath, L"test");
CreateDirectoryW(mypath, NULL);

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.

How to convert std::wstring to a TCHAR*?

How to convert a std::wstring to a TCHAR*? std::wstring.c_str() does not work since it returns a wchar_t*.
How do I get from wchar_t* to TCHAR*, or from std::wstring to TCHAR*?
use this :
wstring str1(L"Hello world");
TCHAR * v1 = (wchar_t *)str1.c_str();
#include <atlconv.h>
TCHAR *dst = W2T(src.c_str());
Will do the right thing in ANSI or Unicode builds.
TCHAR* is defined to be wchar_t* if UNICODE is defined, otherwise it's char*. So your code might look something like this:
wchar_t* src;
TCHAR* result;
#ifdef UNICODE
result = src;
#else
//I think W2A is defined in atlbase.h, and it returns a stack-allocated var.
//If that's not OK, look at the documenation for wcstombs.
result = W2A(src);
#endif
in general this is not possible since wchar_t may not be the same size as TCHAR.
several solutions are already listed for converting between character sets. these can work if the character sets overlap for the range being converted.
I prefer to sidestep the issue entirely wherever possible and use a standard string that is defined on the TCHAR character set as follows:
typedef std::basic_string<TCHAR> tstring;
using this you now have a standard library compatible string that is also compatible with the windows TCHAR macro.
You can use:
wstring ws = L"Testing123";
string s(ws.begin(), ws.end());
// s.c_str() is what you're after
Assuming that you are operating on Windows.
If you are in Unicode build configuration, then TCHAR and wchar_t are the same thing. You might need a cast depending on whether you have /Z set for wchar_t is a type versus wchar_t is a typedef.
If you are in a multibyte build configuration, you need MultiByteToWideChar (and vica versa).