65.9K
CodeProject 正在变化。 阅读更多。
Home

使用标准 C++ 库实现的 WTL CString 类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.25/5 (8投票s)

2006 年 9 月 29 日

CPL

4分钟阅读

viewsIcon

101796

downloadIcon

794

将 CodeProject 的 CStdString 插件化为 WTL::CString,并获得基于标准 C++ 库实现的 WTL CString 支持。

引言

在继续深入之前,您应该阅读 Joe O'Leary 的文章 《CString-clone 使用标准 C++:对 CString 的即插即用替代,构建于标准 C++ 库的 basic_string 模板之上》。您可以 在这里 获取更多关于 CStdString 的信息。

本文展示了最初旨在替代 MFC CStringCStdString,如何在任何 WTL 项目中,包括使用 eVC4 SP4VS2005 编译的 WinCE 项目中,都能顺利地替代 WTL:CString。随附的 StdString.h 是从 2005-Jan-10 的最新原始版本改编而来,以完全支持 WTL:CString 和 WinCE。

CStdString[X] 类

当在您的项目中包含随附的 StdString.h 时,您将访问 CStdString 类,该类实际被定义为 CStdStringACStdStringW,具体取决于您项目的 Unicode/MBCS 设置。

//  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; 
//...

因此,您有四个 CStdString[X] 类,它们都派生自 std::basic_string。每个类都可以安全地与 std::stringstd::wstring 进行 static_cast 转换。

同时支持两种字符宽度

这些类拥有所有可能需要的类型构造函数和赋值运算符,因此以下代码在 UNICODEMBCS 构建中都能无错误地编译并产生相同的结果

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

请注意,抛弃 _T() 宏对于像我这样懒惰的输入者来说非常方便,但运行时会付出转换的代价(如果两侧类型不同)。

相同的 WTL::CString 接口

在随附的 StdString.h 中定义的 CStdString 暴露了所有 WTL::CString 的构造函数、运算符和成员函数,但有一个**区别**:接受字符和计数的 CStdString[X] 构造函数,其参数顺序是 (count, value),这与 WTL::CString(TCHAR ch, int nLength) 的声明顺序相反。

除了这个构造函数之外,您可以对 CStdString 调用任何 WTL::CString 成员、运算符以及 (LPCTSTR) 转换,例如

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 在 WTL 项目中的集成

要在 WTL 项目中使用 CStdString,请将 WtlStdString.zip 文件解压到您的编译器可以通过尖括号访问的某个位置,然后

  • 在您的项目中,#include <StdString.h>
  • VS2005 或 VC Express:在包含 atlbase.h 之前,#define _CRT_SECURE_NO_DEPRECATE 以避免弃用警告。
  • WinCE 项目:**仅**使用 eVC4 或 VS2005 **提供的标准 C++ 库**
    • eVC4 SP4:设置 /GX 编译器标志:为 C++ 异常处理程序启用展开语义。
    • VS2005:修补 <Microsoft Visual Studio 8>\VC\ce\include\comdef.h 的第 3240 行,使其变成
    • int nLen = lstrlen(m_pszMsg);  // was ::lstrlen(m_pszMsg);

WTL CString 支持

WTL 7.0 及以上版本根据编译时条件、一些宏定义以及头文件的包含顺序,设计为支持 ATL::CStringWTL::CStringATL::CString 随 ATL 版本 7.0 一起提供;而 VC++7.0 及以上版本、eVC 和 VCExpress/Platform SDK 使用 ATL 3.0,因此不包含它。

_ATL_NO_AUTOMATIC_NAMESPACE_WTL_NO_AUTOMATIC_NAMESPACE 都未定义时,将适用以下规则:

  1. 如果您在 #include<atlmisc.h> 之前定义 #define _WTL_NO_CSTRING,则 WTL::CString 不会被编译。
  2. 如果您在 #include<atlapp.h> 之前 #include<atlstr.h>,您将获得 ATL::CString 支持。
  3. 当支持 ATL::CString 时,不应编译 WTL::CString
  4. 如果规则 2 不适用,您将在定义 #define _WTL_USE_CSTRING 之后获得 WTL::CString 支持。
  5. 如果规则 2 不适用,您将在 #include<atlmisc.h> 之后获得 WTL::CString 支持。

根据规则 2,atlapp.h 中定义的 _CSTRING_NS 宏将展开为 ATLWTL,并默默地将应用程序的 CString 映射到 WTL::CStringATL::CString。因此,我们可以这样编写代码:

// 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&

// 

插件化 CStdString 作为 WTL::CString

要利用 CStdString 实现的 WTL::CString **并**获得 WTL CString 支持,请将 WtlStdString.zip 文件解压到您的编译器可以通过尖括号访问的目录。随附的 atlssmisc.h

  1. #include "StdString.h" (注意是带引号的文件名),
  2. WTL 命名空间中定义或声明一个基于 ::CStdStringCString 类,
  3. 编译 atlmisc.h **不含** WTL::CString 代码,但**包含** WTL::CString 支持(使用一些 #define 技巧)。

请注意,atlssmisc.h 依赖于 atlmisc.hatlapp.h 中的实现细节,因此请不要使用高于 7.5 版本的 WTL 进行编译。

对于现有使用 WTL::CString 的项目

将头文件中的 #include <atlmisc.h> 更改为 #include <atlssmisc.h>,并检查 CStdString 在 WTL 项目中的集成 的要求。**仅此而已**。

尝试使用 WTL 示例 Alpha (Win32) 和 ImageView (WinCE) 进行实验。

对于新项目

将以下模板粘贴到 stdafx.h 中,并根据需要调整注释掉的行。

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

//...

/////////////////////////////////////////////////////////////
  • 采用此确切布局,项目将获得 WTL::CString 支持,但 CMenuT<>::GetMenuString()CDCT<>::GetTextFace() 除外,并且 WTL::CString 将声明为:typedef ::CStdString CString;
  • 如果您取消注释 #define _WTL_USE_CSTRING // ...,项目将获得完整的 WTL::CString 支持,并且 WTL::CString 将定义为 class CString: public ::CStdString

对于 WinCE 项目,请检查 CStdString 在 WTL 项目中的集成 的要求。

对于现有使用 ATL::CString 的项目

编辑 stdafx.h 以获得 WTL::CString 支持,并在 atlwin.h 之后**首先** #include <atlssmisc.h>。检查 CStdString 在 WTL 项目中的集成 的要求。

例如,要将基于 CStdStringWTL::CString 插件化到出色的 Wizard97Test 示例中,并使用 VC71 编译器,请按如下方式编辑 stdafx.h

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

//...

结论

关于 std::basic_stringATL::CString 和 C++ 中其他字符串对象实现的效率比较,存在一些争议。我不会在此争论。

使用基于 CStdStringWTL::CString

  • 链接外部基于 std::basic_string 的代码的 WTL 应用程序将使用共享的字符串实现代码进行构建。
  • 同时支持两种字符大小(例如,在 Unicode 应用程序中来自网络的 ANSI chars)更容易实现。
  • 像我这样遵循 Fortran->Basic->C->C++->MFC->WTL 路径的老程序员,在使用 std::string 对象时,可能会觉得 CString 接口更舒服。

再次感谢 Joe O'Leary,他完成了这里所有的实际工作,**祝您使用 WTL 愉快**!

© . All rights reserved.