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_cast
ed 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 // avoid StdString.h deprecation warnings
#include <atlbase.h>
#include <atlapp.h>
extern CAppModule _Module;
#include <atlwin.h>
#include <atlssmisc.h>
- 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 "resource.h"
#include <atlbase.h>
#define _WTL_NEW_PAGE_NOTIFY_HANDLERS
#include <atlapp.h>
extern CAppModule _Module;
#include <atlwin.h>
#include <atlcom.h>
#include <atlssmisc.h>
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
char
s 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!