I'm working on a win32 project with CStrings (console application), and I noticed something odd when I want to pass to a function (like strtok_s for example) a LPSTR pointer from a CString with the method GetBuffer(), this last one instead of giving me a LPSTR, it gave me a LPWSTR (a pointer to a wide string)... CString is supposed to store 8 bit chars isn't it ?
I'm obliged in some cases to use CStringA for example to be able for example to use the method Find() because with a CString my input string must be a wide one. But in other another project (windowed program), I don't have this problem, i'm suspecting the headers (when I use afxstr.h "Find" works with a normal string, but not with afxcoll.h...)
Usually I work with std::string that's why I'm lost.
CString is a typdef, declared as (afxstr.h):
typedef ATL::CStringT< TCHAR, StrTraitMFC< TCHAR > > CString;
// Or, when using the MFC DLL
typedef ATL::CStringT< TCHAR, StrTraitMFC_DLL< TCHAR > > CString;
Depending on what TCHAR is, a CString stores either an ANSI (MBCS) or Unicode string. There are also explicit instantiations of the CStringT template: CStringW and CStringA.
Either type has a conversion constructor, taking a constant pointer to the respective other character encoding. In other words: You can construct a CStringW from an ANSI (MBCS) string, as well as a CStringA from a UTF-16LE-encoded Unicode string.
If you need to be explicit about the character encoding, use either CStringW or CStringA.
Full documentation for CString is available at CStringT Class.
Related
I am trying to use a DLL with an ANSI C compiler. One of the DLL functions takes a void pointer. In some sample Windows code that was provided with the DLL, the struct that gets passed to the function is defined as having three CString entities. I have told the author of the DLL that they should not be passing MFC classes through their DLL functions. They have told me just to replace the CString declarations in the struct with char arrays and it should be fine. I'm 99% sure that's wrong, but since I don't have VC++ and don't have any experience with MFC, and since I've seen some posts saying LPTSTR can be used in place of CString (What is `CString`?), I'm starting to wonder if I'm wrong.
Can someone please confirm for me that CString and LPTSTR are not interchangeable as arguments to a function? If you can provide the source for the definition of the CString class, that would be helpful so I can send it to the DLL's author and explain that the memory footprint of a char array is not the same as a CString class, and that you can't pass a pointer to a struct that was defined with char arrays and then treat it as a bunch of CString objects.
CString is an alias of the CStringT class template. Objects of this class are really better not to pass to the DLL. The character type of the string class can be TCHAR (for both ANSI and Unicode character strings - see explanation below). The definition of CString (and CStringT) can most likely be found in the atlstr.h header file.
LPTSTR is a regular pointer to a sequence of characters. The data type (TCHAR*) depends on the settings of the development environment: if the "Use Unicode Character set" option is selected, the TCHAR data type will be wchar_t (and LPTSTR will be wchar_t*, respectively). If the "Use Multi-byte character set" is selected, the TCHAR will be defined as char (and LPTSTR will be char*).
So the question about interchangeability between CString and LPTSTR is not so simple. It also depends on how the DLL is written. If the DLL was designed with the same environment settings as the main program, then CString and LPTSTR can really be interchangeable.
Also, remember that CStirng is a class with many methods, while LPTSTR is just a pointer.
I'm working for crossplatrofm project in c++ and I have variable with type std::string and need convert it to const TCHAR * - what is proper way, may be functions from some library ?
UPD 1: - as I see in function definition there is split windows and non-Windows implementations:
#if defined _MSC_VER || defined __MINGW32__
#define _tinydir_char_t TCHAR
#else
#define _tinydir_char_t char
#endif
- so is it a really no way for non spliting realization for send parameter from std::string ?
Proper way crossplatfom convert from std::string to 'const TCHAR *'
TCHAR should not be used in cross platform programs at all; Except of course, when interacting with windows API calls, but those need to be abstracted away from the rest of the program or else it won't be cross-platform. So, you only need to convert between TCHAR strings and char strings in windows specific code.
The rest of the program should use char, and preferably assume that it contains UTF-8 encoded strings. If user input, or system calls return strings that are in a different encoding, you need to figure out what that encoding is, and convert accordingly.
Character encoding conversion functionality of the C++ standard library is rather weak, so that is not of much use. You can implement the conversion according the encoding specification or you can use a third party implementation, as always.
may be functions from some library ?
I recommend this.
as I see in function definition there is split windows and non-Windows implementations
The library that you use doesn't provide a uniform API to different platforms, so it cannot be used in a truly cross-platform way. You can write a wrapper library with uniform function declarations that handles the character encoding conversion on platforms that need it.
Or, you can use another library, which provides a uniform API and converts the encoding transparently.
TCHAR are Windows type and it defined in this way:
#ifdef UNICODE
typedef wchar_t TCHAR, *PTCHAR;
#else
typedef char TCHAR, *PTCHAR;
#endif
UNICODE macro is typically defined in project settings (in case when your use Visual Studio project on Windows).
You can get the const TCHAR* from std::string (which is ASCII or UTF8 in most cases) in this way:
std::string s("hello world");
const TCHAR* pstring = nullptr;
#ifdef UNICODE
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::wstring wstr = converter.from_bytes(s);
pstring = wstr.data();
#else
pstring = s.data();
#endif
pstring will be the result.
But it's highly not recommended to use the TCHAR on other platforms. It's better to use the UTF8 strings (char*) within std::string
I came across boost.nowide the other day. I think it will do exactly what you want.
http://cppcms.com/files/nowide/html/
As others have pointed out, you should not be using TCHAR except in code that interfaces with the Windows API (or libraries modeled after the Windows API).
Another alternative is to use the character conversion classes/macros defined in atlconv.h. CA2T will convert an 8-bit character string to a TCHAR string. CA2CT will convert to a const TCHAR string (LPCTSTR). Assuming your 8-bit strings are UTF-8, you should specify CP_UTF8 as the code page for the conversion.
If you want to declare a variable containing a TCHAR copy of a std::string:
CA2T tstr(stdstr.c_str(), CP_UTF8);
If you want to call a function that takes an LPCTSTR:
FunctionThatTakesString(CA2CT(stdsr.c_str(), CP_UTF8));
If you want to construct a std::string from a TCHAR string:
std::string mystdstring(CT2CA(tstr, CP_UTF8));
If you want to call a function that takes an LPTSTR then maybe you should not be using these conversion classes. (But you can if you know that the function you are calling does not modify the string outside its current length.)
So I am trying to move a file that the user specifies by using cin and MoveFile(). But the thing is MoveFile() parameters take LPCTSTR variables but cin doesnt take those variable types can anyone help me with a conversion from a char myChars[] table to a LPCTSTR variable? Any help is appreciated.
LPCTSTR is a typedef. It's actually another type: It's a long pointer to a const TCHAR string. Or, in other words, it's a const TCHAR*.
A TCHAR is also a typedef, but it's either a char or a wide character, depending on whether your project is using Unicode or ASCII. They usually default to Unicode.
You can use MoveFileA to force ASCII. Then, a LPCTSTR is literally a const char*.
I have to feed a LPCTSTR in to CreateProcess.
The short question is how do I convert a std::string into a LPCTSTR?
( LPCTSTR lpApplicationName = (LPCTSTR)FilePath.c_str(); does not work, CreateProcess simply ignores it, I know the path etc. I'm using is right because it works perfectly if I put in LPCTSTR lpApplicationName = L"a//test//path//and//file";).
The long question (why I need to do this) is: This LPCTSTR has to contain the path to, and name of, a file I wish to run.
The process is:
To get the path into the right format for CreateProcess I am having
to perform character replace (replacing single \ with double \ ) on
the output from GetModuleFileName. This output starts off as a
WCHAR buffer and I then convert into a std::string.
I then also need to concatenate this string with the final file name
which could be in any variable type (I define it in the program).
The finished string goes into the CreateProcess LPCTSTR.
I have tried using other sorts of string, but so far I haven't found any that the concatenate and character replace will work on.
Every solution I have seen does not work in Visual Studio 2010, which is what I'm using. All advice gratefully received.
LPCTSTR is a pointer to a const TCHAR*, not a const char*. Depending on your UNICODE and _UNICODE settings you will need either a std::wstring or a std::string. If you are stuck with std::string then you need to convert the char* returned by c_str() to a wchar_t* string (or not depending on UNICODE).
To make life a little easier on yourself I recommend:
#ifdef _UNICODE
typedef std::wstring tstring;
#else
typedef std::string tstring;
#endif
I have downloaded an sample code, so there are some CString variables in that code which are passed to the sscanf() function as char* the compiler implicitly converts those CString and the code complie fine.the code which works fine is here:
CString m_strVersionXFS;
m_strVersionXFS = _T("00029903");
DWORD nVersion;
sscanf(m_strVersionXFS,"%08X",&nVersion);
the problem is here when i tried to write my own simple code which tries to manipulate a CString variable in the same way but the compiler says which can't convert a CString to a cahr*
I suspect that your own code is using unicode (UNICODE constant defined). This means that CString is using wide characters, and will implicitly convert to wchar_t*, but not to char*.
If that is the case, there are three possible solutions:
Use swscanf, the wide character version of sscanf (recommended);
Explicitly use CStringA instead of CString so you're using the ANSI version of CString;
Change your project to use multi-byte characters rather than unicode (this can be done from the project properties in Visual Studio).