Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / WinMobile

WTL CString Class Implemented with the Standard C++ Library

4.25/5 (8 votes)
28 Sep 2006CPL4 min read 2   776  
Plug-in CodeProject's CStdString as WTL::CString and get the WTL CString support with a Standard C++ Library implementation.

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.

//  FILE:  StdString.h
//  Changes tagged with '// AR' copyright (c) Alain Rist 2006:
//  AUTHOR: Joe O'Leary (with outside help noted in comments) 
//... 

template <CT>class CStdStr : public std::basic_string<CT> 
//... 

typedef std::basic_string<TCHAR> tstring; 
//... 

typedef CStdStr<char> CStdStringA; // a better std::string 

typedef CStdStr<wchar_t> CStdStringW; // a better std::wstring 

typedef CStdStr<OLECHAR> CStdStringO; // almost always CStdStringW 

//... 

#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"); // as with WTL::CString no _T() needed 

CStdStringW sw = ss; // no WTL::CStringW and WTL::CStringA available

CStdStringA sa = "àáâãäåæçèéêëìíîïñòóôõöøùúûüýþÿ";
sw = sa; // different character widths

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)); // construct from resource ID

ss1.LoadString(IDS_MYSTRING); // load from resource 

CWindow(hWnd).SetDlgItemText(ID_MYCONTROL, ss1); // use (LPCTSTR)cast

ss1.MakeLower(); // change content

CStdString ss2 = ss1.Right(1); // extraction

if (!ss1.IsEmpty()) // anything here?
    ss2.Replace(ss1[ss1.GetLength() -1], '?'); // just to play

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);  // was ::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:

  1. WTL::CString is not compiled if you #define _WTL_NO_CSTRING before #include<atlmisc.h>
  2. You will get ATL::CString support if you #include<atlstr.h> before #include<atlapp.h>
  3. When ATL::CString is supported, WTL::CString should not be compiled.
  4. If rule 2 does not apply, you will get WTL::CString support for classes defined after #define _WTL_USE_CSTRING
  5. 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:

// MyWindow.h
// ...

CFindFile ff;
ff.FindFile(_T("C:*.*"));
CListBox lb = GetDlgItem(ID_MYLB);
//

CString sText = ff.GetFileName();
// actually returns a _CSTRING_NS::CString  

lb.GetText(0, sText);
// actually requires a _CSTRING_NS::CString&

// 

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:

  1. #include "StdString.h" (note the quoted file name),
  2. define or declare in the WTL namespace, a class CString built on ::CStdString,
  3. 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.

/////////////////////////////////////////////////////////////
// Recommended stdafx.h layout
//...
// Change these values to use different versions
//...


#define _CRT_SECURE_NO_DEPRECATE // avoid StdString.h deprecation warnings

#include <atlbase.h>


//#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 <atlapp.h>


extern CAppModule _Module;

#include <atlwin.h>


//#include <atlmisc.h> // uncomment AND comment next line for original 

                       // WTL:CString defintion

#include <atlssmisc.h> // CStdString based WTL:CString definition and support

//...

/////////////////////////////////////////////////////////////
  • 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:

// stdafx.h: Wizard97Test WTL sample

//...

// Includes

#include "resource.h"

#include <atlbase.h>

/********************************* comment or cut from here
#if (_ATL_VER >= 0x0700)
#include <atlstr.h>
#include <atltypes.h>
#endif
// WTL related preprocessor definitions
#if (_ATL_VER >= 0x0700)
#define _WTL_NO_WTYPES
#define _WTL_NO_UNION_CLASSES
#define _WTL_NO_CSTRING
#endif
**************************************         to here   */
#define _WTL_NEW_PAGE_NOTIFY_HANDLERS
#include <atlapp.h>

extern CAppModule _Module;
#include <atlwin.h>

#include <atlcom.h>

#include <atlssmisc.h>     // instead of <atlmisc.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 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!

License

This article, along with any associated source code and files, is licensed under The Common Public License Version 1.0 (CPL)