Introduction
Before going any further, you should read CString-clone Using Standard C++: A Drop-In replacement for CString that builds on the Standard C++ Library's basic_string template by Joe O'Leary. You can get some more info about the CStdString here.
This article shows how CStdString, initially designed to replace the MFC CString, may as well smoothly replace WTL:CString, in any WTL project, including WinCE projects compiled with eVC4 SP4 or VS2005. The attached StdString.h is adapted from the last original revision dated 2005-Jan-10 for full WTL:CString and WinCE compliance.
The CStdString[X] classes
When including the attached StdString.h in your project, you access the class CStdString actually defined as either CStdStringA or CStdStringW, depending on your project Unicode/MBCS settings.
template <CT>class CStdStr : public std::basic_string<CT>
typedef std::basic_string<TCHAR> tstring;
typedef CStdStr<char> CStdStringA;
typedef CStdStr<wchar_t> CStdStringW;
typedef CStdStr<OLECHAR> CStdStringO;
#ifdef UNICODE
typedef CStdStringW CStdString;
#else
typedef CStdStringA CStdString;
So, you have four CStdString[X] classes deriving from std::basic_string at your fingertips. Each can safely be static_casted to and from one of std::string or std::wstring.
Both character widths together
These classes have all possibly needed type constructors and assignment operators so that the following code will compile without errors and produce the same result in UNICODE and MBCS builds:
CStdString ss("My standard string");
CStdStringW sw = ss;
CStdStringA sa = "àáâãäåæçèéêëìíîïñòóôõöøùúûüýþÿ";
sw = sa;
Note that getting rid of the _T() macros may be very handy for lazy typers like me, but costs, at runtime, the price of conversion if both side types are different.
Same WTL::CString interface
As defined in the attached StdString.h, CStdString exposes all WTL::CString constructors, operators, and function members with one difference: the CStdString[X] constructors that take a character and a count takes them in the order (count, value), which is the opposite of the order WTL::CString(TCHAR ch, int nLength) declares them.
Except for this constructor, call on CStdString any WTL::CString member, operator, and (LPCTSTR) cast, for instance:
CStdString ss1(MAKEINTRESOURCE(IDR_MYID));
ss1.LoadString(IDS_MYSTRING);
CWindow(hWnd).SetDlgItemText(ID_MYCONTROL, ss1);
ss1.MakeLower();
CStdString ss2 = ss1.Right(1);
if (!ss1.IsEmpty()) ss2.Replace(ss1[ss1.GetLength() -1], '?');
CStdString integration in WTL projects
To use CStdString in WTL projects, unzip the WtlStdString.zip files to some place accessible by your compiler through angle brackets, and:
#include <StdString.h> in your project,
- VS2005 or VC Express:
#define _CRT_SECURE_NO_DEPRECATE before the inclusion of atlbase.h to avoid deprecation warnings.
- WinCE projects: use only the eVC4 or VS2005 provided Standard C++ Library
- eVC4 SP4: set the /GX compiler flag: enable unwind semantics for the C++ exception handler,
- VS2005: patch the <Microsoft Visual Studio 8>\VC\ce\include\comdef.h line#3240 to:
int nLen = lstrlen(m_pszMsg);
WTL CString support
WTL 7.0 and over is designed to support one of ATL::CString or WTL::CString depending on the compile time conditions, some macro definitions, and the inclusion order of the headers; ATL::CString comes with ATL version 7.0; and VC++7.0 and over, eVC, and VCExpress/Platform SDK use ATL 3.0 and do not get it.
The following rules apply when _ATL_NO_AUTOMATIC_NAMESPACE and _WTL_NO_AUTOMATIC_NAMESPACE are both undefined:
WTL::CString is not compiled if you #define _WTL_NO_CSTRING before #include<atlmisc.h>
You will get ATL::CString support if you #include<atlstr.h> before #include<atlapp.h>
- When
ATL::CString is supported, WTL::CString should not be compiled.
- If rule 2 does not apply, you will get
WTL::CString support for classes defined after #define _WTL_USE_CSTRING
- If rule 2 does not apply, you will get
WTL::CString support for classes defined after #include<atlmisc.h>
Depending on rule 2, the _CSTRING_NS macro defined in atlapp.h will expand to ATL or WTL and silently map the application CString to WTL::CString or ATL::CString. So, we can write code like:
CFindFile ff;
ff.FindFile(_T("C:*.*"));
CListBox lb = GetDlgItem(ID_MYLB);
CString sText = ff.GetFileName();
lb.GetText(0, sText);
Plug-in CStdString as WTL::CString
To benefit the CStdString implementation of WTL::CString and WTL CString support, unzip WtlStdString.zip files to a directory accessible by your compiler through angle brackets. The included atlssmisc.h will:
#include "StdString.h" (note the quoted file name),
- define or declare in the
WTL namespace, a class CString built on ::CStdString,
- compile atlmisc.h without
WTL::CString code but with WTL::CString support (using some #define hacking).
Note that atlssmisc.h relies on the implementation details in atlmisc.h and atlapp.h, so do not compile with WTL over version 7.5.
For existing projects using WTL::CString
Change #include <atlmisc.h> to #include <atlssmisc.h> in the headers, and check the CStdString integration in WTL projects requirements. That's all.
Experiment it with the WTL samples Alpha (Win32) and ImageView (WinCE).
For new projects
Paste the following template to stdafx.h, and adjust the commented lines for your needs.
#define _CRT_SECURE_NO_DEPRECATE
#include <span class="code-keyword"><atlbase.h></span>
//#include <atlstr.h> // uncomment for WTL ATL::CString support
//#define _WTL_NO_CSTRING // uncomment for WTL ATL::CString support
// or no WTL CString suppport
//#define _WTL_USE_CSTRING // uncomment for CMenuT<> and CDCT<>
// WTL::CString support
#include <span class="code-keyword"><atlapp.h></span>
extern CAppModule _Module;
#include <span class="code-keyword"><atlwin.h></span>
//#include <atlmisc.h> // uncomment AND comment next line for original
// WTL:CString defintion
#include <span class="code-keyword"><atlssmisc.h> // CStdString based WTL:CString definition and support</span>
//...
/////////////////////////////////////////////////////////////
- With this exact layout, the project will have
WTL::CString support except for CMenuT<>::GetMenuString() and CDCT<>::GetTextFace(), and WTL::CString will be declared as: typedef ::CStdString CString;.
- If you uncomment
#define _WTL_USE_CSTRING , the project will have complete WTL::CString support, and WTL::CString will be defined as class CString: public ::CStdString.
For WinCE projects, check the CStdString integration in WTL projects requirements.
For existing projects using ATL::CString
Edit stdafx.h to get WTL::CString support, and #include <atlssmisc.h> first after atlwin.h. Check the CStdString integration in WTL projects requirements.
For instance, to plug CStdString based WTL::CString into the great Wizard97Test sample with a VC71 compiler, edit stdafx.h like this:
#include <span class="code-string">"resource.h"</span>
#include <span class="code-keyword"><atlbase.h></span>
#define _WTL_NEW_PAGE_NOTIFY_HANDLERS
#include <span class="code-keyword"><atlapp.h></span>
extern CAppModule _Module;
#include <span class="code-keyword"><atlwin.h></span>
#include <span class="code-keyword"><atlcom.h></span>
#include <span class="code-keyword"><atlssmisc.h> // instead of <atlmisc.h></span>
Conclusion
There is some dispute about the compared efficiencies of std::basic_string, ATL::CString, and other implementations of stringish objects in C++. I will not argue there.
With CStdString based WTL::CString:
- A WTL app linking external code based on
std::basic_string will build with shared string implementation code.
- Implementation of both character sizes (such as ANSI
chars coming from a network in a Unicode app) is easier.
- Old programmers like me, who followed the Fortran->Basic->C->C++->MFC->WTL path, may feel more comfortable with the
CString interface when using std::string objects.
Thanks again to Joe O'Leary who did all the real work here, and enjoy WTL!