写在前面
可以说CString在所有Visual C++ 程序员中占有很重要的地位,可以说是MFC Library里面最风光的一个类。据说当年还有很多程序员因为MFC中拥有好用的CString类,从其他开发工具跳槽到Visual C++来。我对CString的认识是从99年的Visual C++ 6.0中带的MFC 4.2版本中的CString类,那时候是小菜鸟,就是觉得CString好用。等变成老菜鸟的时候,发觉CString也不是那么完美的……
今天说的CString是MFC 9.0 中的CString类。照比以前MFC4.2版本的CString,功能上、性能上都改进了许多。最大的特点是自MFC7.0起CString类已经变成了一个模板类。
获取源代码
需要安装Microsoft Visual Studio 2005或者2008 ,并安装了Visual C++ 的组件。以Visual Studio2008为例,其源代码就在:\Microsoft Visual Studio 9.0\VC\atlmfc\include\ 路径下。其主要代码在cstringt.h文件和cstringt.inl 两个文件中。cstringt.h的内容是CString类的声明和实现,cstringt.inl文件包含了几个CString类常用的方法的实现,为了提高性能,这些方法被声明成了内联函数(inline)。
为什么把代码写在了cstringt.h文件中,而不是写在cstringt.cpp文件中呢?这还是要追溯到Visual C++ 6.0。在Visual C++ 6.0 以前(包括VC6),其自带的编译器MS C++(也就是cl.exe)是不支持将模板类的声明和实现分开写在.h和.cpp文件里的。所以整个的ATL库源代码都是写在.h的头文件里的。这个习俗就一直保留了下来。
不得不说的CStringData 结构
CStringData结构体是用来保存CString对象中字符串数据的结构体。也就是说,这个CStringData才是真正管理字符串缓冲区的对象。源代码在atlsimpstr.h文件中。其声明如下:
![](/Images/OutliningIndicators/ContractedBlock.gif)
struct CStringData
1
struct CStringData
2![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
3
IAtlStringMgr* pStringMgr; // String manager for this CStringData
4
int nDataLength; // Length of currently used data in XCHARs (not including terminating null)
5
int nAllocLength; // Length of allocated data in XCHARs (not including terminating null)
6
long nRefs; // Reference count: negative == locked
7
// XCHAR data[nAllocLength+1] // A CStringData is always followed in memory by the actual array of character data
8![](/Images/OutliningIndicators/InBlock.gif)
9
void* data() throw()
10![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
11
return (this+1);
12
}
13![](/Images/OutliningIndicators/InBlock.gif)
14
void AddRef() throw()
15![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
16
ATLASSERT(nRefs > 0);
17
_AtlInterlockedIncrement(&nRefs);
18
}
19
bool IsLocked() const throw()
20![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
21
return nRefs < 0;
22
}
23
bool IsShared() const throw()
24![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
25
return( nRefs > 1 );
26
}
27
void Lock() throw()
28![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
29
ATLASSERT( nRefs <= 1 );
30
nRefs--; // Locked buffers can't be shared, so no interlocked operation necessary
31
if( nRefs == 0 )
32![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
33
nRefs = -1;
34
}
35
}
36
void Release() throw()
37![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
38
ATLASSERT( nRefs != 0 );
39![](/Images/OutliningIndicators/InBlock.gif)
40
if( _AtlInterlockedDecrement( &nRefs ) <= 0 )
41![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
42
pStringMgr->Free( this );
43
}
44
}
45
void Unlock() throw()
46![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
47
ATLASSERT( IsLocked() );
48![](/Images/OutliningIndicators/InBlock.gif)
49
if(IsLocked())
50![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
51
nRefs++; // Locked buffers can't be shared, so no interlocked operation necessary
52
if( nRefs == 0 )
53![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
54
nRefs = 1;
55
}
56
}
57
}
58
};
59![](/Images/OutliningIndicators/None.gif)
如果您奇怪结构体中为什么还有方法?这个…… 简单的说一下,其实class 和 struct 的区别不大,只是默认情况下class的访问和继承权限都是私有的(private),struct的访问和集成权限都是共有的(public)。能不能包含函数,并不是class和struct的重要区别之一。他们两个关键字都是允许同时包含变量和方法的。
CStringData对象中首先包含了一个指向IAtlStringMgr对象的指针,这个指针所指向对象的主要作用是对字符串缓冲区进行内存管理。而后跟随着两个变量nDataLength 和nAllocLength 一个表示实际字符串的长度,另一个表示申请内存空间的长度。
再粗略的扫视一下CStringData的代码,有新发现了吗? 反正我看到了int nRef; AddRef()、Release()。 这是啥?了解COM技术的人都知道,这是COM技术最最根本最最基础的接口IUnknown 的成员。虽然这里CStringData没有显式的继承IUnknown接口,但实际上也是采用了引用计数的方式进行管理的。nRef的在AddRef()进行递增和Release()进行递减操作是通过_AtlInterlockedIncrement 和 _AtlInterlockedDecrement 这对儿进行的。在互斥区中访问nRef 目的是为了保证CStringData是线程安全的。不会致使nRef产生脏数据。Lock/UnLock这对儿方法,可以在单一使用者(nRef = 1)的情况下,标记字符串缓冲区是否被锁定。以便使用者可以通过独占的方式访问字符串。不过很遗憾,这两个方法并不是线程安全的。有点儿靠不住的说。
Data() 方法可以返回实际的字符串缓冲区首地址。return (this+1); this代表了指向当前CStringData对象内存首地址的指针,this + 1 就是指向在内存中紧跟CStringData对象的首地址。这里的1不是代表数值1,而是代表了1个CStringData对象。啊?为什么?答案请参照谭浩强的《C语言程序设计》有关指针操作的部分。
字符串缓冲区的管理
上面提到,在CStringData类中,包含了一个指向IAtlStringMgr接口的指针,这个IAtlStringMgr接口定义了字符串缓冲区管理的基本方法,成员如下:
Allocate 申请新的内存缓冲区
Clone 拷贝一个当前的字符串缓冲区内存管理对象。当然,所管理的内存缓冲区也被同时复制了。
Free 释放已申请的字符串缓冲区
GetNilString 清空字符串缓冲区,用’\0’填充
Reallocate 重新申请字符串缓冲区
对于这个接口,ATL库带有默认的实现,实现代码在atlstr.h文件中。有一个类CAtlStringMgr继承了IAtlStringMgr接口。代码如下:
![](/Images/OutliningIndicators/ContractedBlock.gif)
class CAtlStringMgr
1
class CAtlStringMgr :
2
public IAtlStringMgr
3![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
4
public:
5
CAtlStringMgr( _In_opt_ IAtlMemMgr* pMemMgr = NULL ) throw() :
6
m_pMemMgr( pMemMgr )
7![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
8
m_nil.SetManager( this );
9
}
10
virtual ~CAtlStringMgr() throw()
11![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
12
}
13![](/Images/OutliningIndicators/InBlock.gif)
14
void SetMemoryManager( __reserved IAtlMemMgr* pMemMgr ) throw()
15![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
16
ATLASSUME( m_pMemMgr == NULL );
17
m_pMemMgr = pMemMgr;
18
}
19![](/Images/OutliningIndicators/InBlock.gif)
20
// IAtlStringMgr
21
public:
22
_Ret_opt_bytecap_x_(sizeof(CStringData) + nChars*nCharSize) virtual CStringData* Allocate( _In_ int nChars, _In_ int nCharSize ) throw()
23![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
24
size_t nTotalSize;
25
CStringData* pData;
26
size_t nDataBytes;
27![](/Images/OutliningIndicators/InBlock.gif)
28
nChars = AtlAlignUp( nChars + 1, 8 ); // Prevent excessive reallocation. The heap will usually round up anyway.
29![](/Images/OutliningIndicators/InBlock.gif)
30
if( FAILED(::ATL::AtlMultiply(&nDataBytes, static_cast<size_t>(nChars), static_cast<size_t>(nCharSize))) ||
31
FAILED(::ATL::AtlAdd(&nTotalSize, static_cast<size_t>(sizeof( CStringData )), nDataBytes)))
32![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
33
return NULL;
34
}
35
pData = static_cast< CStringData* >( m_pMemMgr->Allocate( nTotalSize ) );
36
if( pData == NULL )
37![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
38
return( NULL );
39
}
40
pData->pStringMgr = this;
41
pData->nRefs = 1;
42
pData->nAllocLength = nChars - 1;
43
pData->nDataLength = 0;
44![](/Images/OutliningIndicators/InBlock.gif)
45
return( pData );
46
}
47
virtual void Free( _Inout_ CStringData* pData ) throw()
48![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
49
ATLASSERT( pData->pStringMgr == this );
50
m_pMemMgr->Free( pData );
51
}
52
_Ret_opt_bytecap_x_(sizeof(CStringData) + nChars*nCharSize) virtual CStringData* Reallocate( _Inout_ CStringData* pData, _In_ int nChars, _In_ int nCharSize ) throw()
53![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
54
CStringData* pNewData;
55
ULONG nTotalSize;
56
ULONG nDataBytes;
57![](/Images/OutliningIndicators/InBlock.gif)
58
ATLASSERT( pData->pStringMgr == this );
59
nChars = AtlAlignUp( nChars+1, 8 ); // Prevent excessive reallocation. The heap will usually round up anyway.
60![](/Images/OutliningIndicators/InBlock.gif)
61
if( FAILED(::ATL::AtlMultiply(&nDataBytes, static_cast<ULONG>(nChars), static_cast<ULONG>(nCharSize))) ||
62
FAILED(::ATL::AtlAdd(&nTotalSize, static_cast<ULONG>(sizeof( CStringData )), nDataBytes)))
63![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
64
return NULL;
65
}
66
pNewData = static_cast< CStringData* >( m_pMemMgr->Reallocate( pData, nTotalSize ) );
67
if( pNewData == NULL )
68![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
69
return NULL;
70
}
71
pNewData->nAllocLength = nChars - 1;
72![](/Images/OutliningIndicators/InBlock.gif)
73
return pNewData;
74
}
75
virtual CStringData* GetNilString() throw()
76![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
77
m_nil.AddRef();
78
return &m_nil;
79
}
80
virtual IAtlStringMgr* Clone() throw()
81![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
82
return this;
83
}
84![](/Images/OutliningIndicators/InBlock.gif)
85
protected:
86
IAtlMemMgr* m_pMemMgr;
87
CNilStringData m_nil;
88
};
89![](/Images/OutliningIndicators/None.gif)
我们先从Allocate() 说起。nChars = AtlAlignUp( nChars+1, 8 ); 这行代码调用了ATL内存管理的一个AtlAlignUp函数。这个函数的原型在atlmem.h文件中,其作用是将给定的长度(N n)按照规定的布局(ULONG nAlign)凑齐对应的字节,请看:
template< typename N >
inline N WINAPI AtlAlignUp( N n, ULONG nAlign ) throw()
{
return( N( (n+(nAlign-1))&~(N( nAlign )-1) ) );
}
这行代码要是换我写,我就直接让n+nAlign 再除以nAlign取商了。但是MS的工程师没有那么做,而是通过位运算实现。这无疑提高了这个模板函数的运算性能。快,就一个字。
而后,函数中使用了AtlMultply和AtlAdd方法进行了要申请的总字节数的计算。使用这两个方法进行乘、加运算,是为了避免运算结果超界带来不必要的麻烦。把AtlAdd摆出来看看:
![](/Images/OutliningIndicators/ContractedBlock.gif)
AtlAdd
1
template<>
2
class AtlLimits<int _ATL_W64>
3![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
4
public:
5
static const int _Min=INT_MIN;
6
static const int _Max=INT_MAX;
7
};
8![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//* generic version */
9
template<typename T>
10
inline HRESULT AtlAdd(T* ptResult, T tLeft, T tRight)
11![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
12
if(::ATL::AtlLimits<T>::_Max-tLeft < tRight)
13![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
14
return E_INVALIDARG;
15
}
16
*ptResult= tLeft + tRight;
17
return S_OK;
18
}
19![](/Images/OutliningIndicators/None.gif)
AtlMultply的代码也大同小异,如想更深入了解,可在atlalloc.h文件中看到函数的原型。有意思的是这个AtlMultply函数还曾经有一个bug,请参考http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=119531 意思是说,原始版本中如果tLeft参数传入0,为了避免出现除零的情况,直接返回S_OK,但返回前,没有给ptResult赋值,以致出现野指针的情况。呵呵,有兴趣的可以通过上面的链接了解到更多的信息,反正我安装的Visual Studio 2008 中的ATL代码已经修正了这个问题(多了一行 *ptResult = 0; 搞定!)。
在计算好实际要申请的字节后,使用位于atlmem.h文件中的CCRTHeap类(这个类实现了IAtlMemMgr接口)的Allocate()方法申请了存放字符串的内存。代码如下:
virtual void* Allocate( size_t nBytes ) throw()
{
return( malloc( nBytes ) );
}
看到malloc() 倍感亲切呀,哈哈。我也总算是一杆子杵到底了。看明白了上面的内容,对于CAtlStringMgr的Free、Reallocate就一通百通了,到了最后,就是依靠调用CRT的Free和Reallocate实现的。这里不再赘述。
根据CAtlStringMgr的内存管理代码,我们了解到以下内容:
1) 申请字符串缓冲区空间时,实际是以8个字符进行了对齐的。例如申请50个字符的空间时,实际申请的内存会是56个字符的空间;
2) 对缓冲区内存的管理最底层是通过CRT的内存管理函数实现的。这样一来申请内存就要遵照CRT定义的阀值。记得《Visual C++技术内
幕》上写的CRT的阀值是480个字节,不知道当前版本的CRT阀值有没有改变;
3) 申请的内存大小应该是CStringData结构体的大小 + 字符个数以8对气候 * 字符所占空间的字节数;
ChTraitsBase 和 ChTraitsCRT
![](/Images/OutliningIndicators/ContractedBlock.gif)
ChTraitsBase
1
ChTraitsBase :
2
template< typename BaseType = char >
3
class ChTraitsBase
4![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
5
public:
6
typedef char XCHAR;
7
typedef LPSTR PXSTR;
8
typedef LPCSTR PCXSTR;
9
typedef wchar_t YCHAR;
10
typedef LPWSTR PYSTR;
11
typedef LPCWSTR PCYSTR;
12
};
13![](/Images/OutliningIndicators/None.gif)
这个类中没有任何的成员变量和成员函数,而是定义了一些数据类型,简单的typedef就不用多说了吧。
ChTraitsCRT 继承了ChTraitsBase ,并实现了n多个静态的工具函数,包括判断字符是否是数字的、字符是否是空格的、以及字符串查找的、字符串比较的、格式化字符串的…… 这些静态方法,构成了CString类的字符串操作函数。这个chTraitsCRT类在cstringt.h文件中提供了两个版本,一个版本是char类型的,另一个是wchar_t类型的,也就是说CString类可以分别处理ansi字符和unicode字符。虽然有点儿长,但还是值得把代码贴一下,因为使用者比较看重的字符串操作方法的实现全都在这里了:
这个类中没有任何的成员变量和成员函数,而是定义了一些数据类型,简单的typedef就不用多说了吧。
ChTraitsCRT 继承了ChTraitsBase ,并实现了n多个静态的工具函数,包括判断字符是否是数字的、字符是否是空格的、以及字符串查找的、字符串比较的、格式化字符串的…… 这些静态方法,构成了CString类的字符串操作函数。这个chTraitsCRT类在cstringt.h文件中提供了两个版本,一个版本是char类型的,另一个是wchar_t类型的,也就是说CString类可以分别处理ansi字符和unicode字符。虽然有点儿长,但还是值得把代码贴一下,因为使用者比较看重的字符串操作方法的实现全都在这里了:
![](/Images/OutliningIndicators/ContractedBlock.gif)
class ChTraitsCRT
1
template< typename _CharType = char >
2
class ChTraitsCRT :
3
public ChTraitsBase< _CharType >
4![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
5
public:
6
static char* __cdecl CharNext( _In_z_ const char* p ) throw()
7![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
8
return reinterpret_cast< char* >( _mbsinc( reinterpret_cast< const unsigned char* >( p ) ) );
9
}
10![](/Images/OutliningIndicators/InBlock.gif)
11
static int __cdecl IsDigit( _In_ char ch ) throw()
12![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
13
return _ismbcdigit( ch );
14
}
15![](/Images/OutliningIndicators/InBlock.gif)
16
static int __cdecl IsSpace( _In_ char ch ) throw()
17![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
18
return _ismbcspace( ch );
19
}
20![](/Images/OutliningIndicators/InBlock.gif)
21
static int __cdecl StringCompare( _In_z_ LPCSTR pszA, _In_z_ LPCSTR pszB ) throw()
22![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
23
return _mbscmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB ) );
24
}
25![](/Images/OutliningIndicators/InBlock.gif)
26
static int __cdecl StringCompareIgnore( _In_z_ LPCSTR pszA, _In_z_ LPCSTR pszB ) throw()
27![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
28
return _mbsicmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB ) );
29
}
30![](/Images/OutliningIndicators/InBlock.gif)
31
static int __cdecl StringCollate( _In_z_ LPCSTR pszA, _In_z_ LPCSTR pszB ) throw()
32![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
33
return _mbscoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB ) );
34
}
35![](/Images/OutliningIndicators/InBlock.gif)
36
static int __cdecl StringCollateIgnore( _In_z_ LPCSTR pszA, _In_z_ LPCSTR pszB ) throw()
37![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
38
return _mbsicoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB ) );
39
}
40![](/Images/OutliningIndicators/InBlock.gif)
41
static LPCSTR __cdecl StringFindString( _In_z_ LPCSTR pszBlock, _In_z_ LPCSTR pszMatch ) throw()
42![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
43
return reinterpret_cast< LPCSTR >( _mbsstr( reinterpret_cast< const unsigned char* >( pszBlock ),
44
reinterpret_cast< const unsigned char* >( pszMatch ) ) );
45
}
46![](/Images/OutliningIndicators/InBlock.gif)
47
static LPSTR __cdecl StringFindString( _In_z_ LPSTR pszBlock, _In_z_ LPCSTR pszMatch ) throw()
48![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
49
return( const_cast< LPSTR >( StringFindString( const_cast< LPCSTR >( pszBlock ), pszMatch ) ) );
50
}
51![](/Images/OutliningIndicators/InBlock.gif)
52
static LPCSTR __cdecl StringFindChar( _In_z_ LPCSTR pszBlock, _In_ char chMatch ) throw()
53![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
54
return reinterpret_cast< LPCSTR >( _mbschr( reinterpret_cast< const unsigned char* >( pszBlock ), (unsigned char)chMatch ) );
55
}
56![](/Images/OutliningIndicators/InBlock.gif)
57
static LPCSTR __cdecl StringFindCharRev( _In_z_ LPCSTR psz, _In_ char ch ) throw()
58![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
59
return reinterpret_cast< LPCSTR >( _mbsrchr( reinterpret_cast< const unsigned char* >( psz ), (unsigned char)ch ) );
60
}
61![](/Images/OutliningIndicators/InBlock.gif)
62
static LPCSTR __cdecl StringScanSet( _In_z_ LPCSTR pszBlock, _In_z_ LPCSTR pszMatch ) throw()
63![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
64
return reinterpret_cast< LPCSTR >( _mbspbrk( reinterpret_cast< const unsigned char* >( pszBlock ),
65
reinterpret_cast< const unsigned char* >( pszMatch ) ) );
66
}
67![](/Images/OutliningIndicators/InBlock.gif)
68
static int __cdecl StringSpanIncluding( _In_z_ LPCSTR pszBlock, _In_z_ LPCSTR pszSet ) throw()
69![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
70
return (int)_mbsspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet ) );
71
}
72![](/Images/OutliningIndicators/InBlock.gif)
73
static int __cdecl StringSpanExcluding( _In_z_ LPCSTR pszBlock, _In_z_ LPCSTR pszSet ) throw()
74![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
75
return (int)_mbscspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet ) );
76
}
77![](/Images/OutliningIndicators/InBlock.gif)
78
_ATL_INSECURE_DEPRECATE("You must pass an output size to ChTraitsCRT::StringUppercase")
79
static LPSTR __cdecl StringUppercase( _Inout_ LPSTR psz ) throw()
80![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
81
#pragma warning (push)
82
#pragma warning(disable : 4996)
83
return reinterpret_cast< LPSTR >( _mbsupr( reinterpret_cast< unsigned char* >( psz ) ) );
84
#pragma warning (pop)
85
}
86![](/Images/OutliningIndicators/InBlock.gif)
87
_ATL_INSECURE_DEPRECATE("You must pass an output size to ChTraitsCRT::StringLowercase")
88
static LPSTR __cdecl StringLowercase( _Inout_ LPSTR psz ) throw()
89![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
90
#pragma warning (push)
91
#pragma warning(disable : 4996)
92
return reinterpret_cast< LPSTR >( _mbslwr( reinterpret_cast< unsigned char* >( psz ) ) );
93
#pragma warning (pop)
94
}
95![](/Images/OutliningIndicators/InBlock.gif)
96
static LPSTR __cdecl StringUppercase( _Inout_cap_(size) LPSTR psz, _In_ size_t size ) throw()
97![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
98
Checked::mbsupr_s(reinterpret_cast< unsigned char* >( psz ), size);
99
return psz;
100
}
101![](/Images/OutliningIndicators/InBlock.gif)
102
static LPSTR __cdecl StringLowercase( _Inout_cap_(size) LPSTR psz, _In_ size_t size ) throw()
103![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
104
Checked::mbslwr_s( reinterpret_cast< unsigned char* >( psz ), size );
105
return psz;
106
}
107![](/Images/OutliningIndicators/InBlock.gif)
108
static LPSTR __cdecl StringReverse( _Inout_ LPSTR psz ) throw()
109![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
110
return reinterpret_cast< LPSTR >( _mbsrev( reinterpret_cast< unsigned char* >( psz ) ) );
111
}
112![](/Images/OutliningIndicators/InBlock.gif)
113
static int __cdecl GetFormattedLength( _In_ _Printf_format_string_ LPCSTR pszFormat, va_list args ) throw()
114![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
115
return _vscprintf( pszFormat, args );
116
}
117![](/Images/OutliningIndicators/InBlock.gif)
118
_ATL_INSECURE_DEPRECATE("You must pass an output size to ChTraitsCRT::Format")
119
static int __cdecl Format( _Out_ LPSTR pszBuffer, _In_ _Printf_format_string_ LPCSTR pszFormat, va_list args ) throw()
120![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
121
#pragma warning (push)
122
#pragma warning(disable : 4996)
123
return vsprintf( pszBuffer, pszFormat, args );
124
#pragma warning (pop)
125![](/Images/OutliningIndicators/InBlock.gif)
126
}
127
static int __cdecl Format
128
( _Out_cap_post_count_(nlength, return) LPSTR pszBuffer, _In_ size_t nlength, _In_ _Printf_format_string_ LPCSTR pszFormat, va_list args ) throw()
129![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
130
return vsprintf_s( pszBuffer, nlength, pszFormat, args );
131
}
132![](/Images/OutliningIndicators/InBlock.gif)
133
static int __cdecl GetBaseTypeLength( _In_z_ LPCSTR pszSrc ) throw()
134![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
135
// Returns required buffer length in XCHARs
136
return int( strlen( pszSrc ) );
137
}
138![](/Images/OutliningIndicators/InBlock.gif)
139
static int __cdecl GetBaseTypeLength( _In_count_(nLength) LPCSTR pszSrc, int nLength ) throw()
140![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
141
(void)pszSrc;
142
// Returns required buffer length in XCHARs
143
return nLength;
144
}
145![](/Images/OutliningIndicators/InBlock.gif)
146
static int __cdecl GetBaseTypeLength( _In_z_ LPCWSTR pszSource ) throw()
147![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
148
// Returns required buffer length in XCHARs
149
return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, -1, NULL, 0, NULL, NULL )-1;
150
}
151![](/Images/OutliningIndicators/InBlock.gif)
152
static int __cdecl GetBaseTypeLength( _In_count_(nLength) LPCWSTR pszSource, int nLength ) throw()
153![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
154
// Returns required buffer length in XCHARs
155
return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, nLength, NULL, 0, NULL, NULL );
156
}
157![](/Images/OutliningIndicators/InBlock.gif)
158
static void __cdecl ConvertToBaseType( _Out_cap_(nDestLength) LPSTR pszDest, _In_ int nDestLength,
159
_In_z_ LPCSTR pszSrc, int nSrcLength = -1 ) throw()
160![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
161![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (nSrcLength == -1)
{ nSrcLength=1 + GetBaseTypeLength(pszSrc); }
162
// nLen is in XCHARs
163
Checked::memcpy_s( pszDest, nDestLength*sizeof( char ),
164
pszSrc, nSrcLength*sizeof( char ) );
165
}
166![](/Images/OutliningIndicators/InBlock.gif)
167
static void __cdecl ConvertToBaseType( _Out_cap_(nDestLength) LPSTR pszDest, _In_ int nDestLength,
168
_In_z_ LPCWSTR pszSrc, _In_ int nSrcLength = -1) throw()
169![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
170
// nLen is in XCHARs
171
::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL );
172
}
173![](/Images/OutliningIndicators/InBlock.gif)
174
_ATL_INSECURE_DEPRECATE("You must pass an output size to ChTraitsCRT::ConvertToOem")
175
static void ConvertToOem(_Inout_ _CharType* pstrString) throw()
176![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
177
BOOL fSuccess=::CharToOemA(pstrString, pstrString);
178
// old version can't report error
179
ATLASSERT(fSuccess);
180
}
181![](/Images/OutliningIndicators/InBlock.gif)
182
_ATL_INSECURE_DEPRECATE("You must pass an output size to ChTraitsCRT::ConvertToAnsi")
183
static void ConvertToAnsi(_Inout_ _CharType* pstrString) throw()
184![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
185
BOOL fSuccess=::OemToCharA(pstrString, pstrString);
186
// old version can't report error
187
ATLASSERT(fSuccess);
188
}
189![](/Images/OutliningIndicators/InBlock.gif)
190
static void ConvertToOem(_Inout_cap_(size) _CharType* pstrString, _In_ size_t size)
191![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
192
if(size>UINT_MAX)
193![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
194
// API only allows DWORD size
195
AtlThrow(E_INVALIDARG);
196
}
197
DWORD dwSize=static_cast<DWORD>(size);
198
BOOL fSuccess=::CharToOemBuffA(pstrString, pstrString, dwSize);
199
if(!fSuccess)
200![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
201
AtlThrowLastWin32();
202
}
203
}
204![](/Images/OutliningIndicators/InBlock.gif)
205
static void ConvertToAnsi(_Inout_cap_(size) _CharType* pstrString, _In_ size_t size)
206![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
207
if(size>UINT_MAX)
208![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
209
// API only allows DWORD size
210
AtlThrow(E_INVALIDARG);
211
}
212
DWORD dwSize=static_cast<DWORD>(size);
213
BOOL fSuccess=::OemToCharBuffA(pstrString, pstrString, dwSize);
214
if(!fSuccess)
215![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
216
AtlThrowLastWin32();
217
}
218
}
219![](/Images/OutliningIndicators/InBlock.gif)
220
static void __cdecl FloodCharacters( _In_ char ch, _In_ int nLength, _Out_capcount_(nLength) char* pch ) throw()
221![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
222
// nLength is in XCHARs
223
memset( pch, ch, nLength );
224
}
225![](/Images/OutliningIndicators/InBlock.gif)
226
static BSTR __cdecl AllocSysString( _In_count_(nDataLength) const char* pchData, int nDataLength ) throw()
227![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
228
int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength,
229
NULL, NULL );
230
BSTR bstr = ::SysAllocStringLen( NULL, nLen );
231
if( bstr != NULL )
232![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
233
::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength,
234
bstr, nLen );
235
}
236![](/Images/OutliningIndicators/InBlock.gif)
237
return bstr;
238
}
239![](/Images/OutliningIndicators/InBlock.gif)
240
static BOOL __cdecl ReAllocSysString( _In_count_(nDataLength) const char* pchData, _Out_ BSTR* pbstr, _In_ int nDataLength ) throw()
241![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
242
int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, NULL, NULL );
243
BOOL bSuccess = ::SysReAllocStringLen( pbstr, NULL, nLen );
244
if( bSuccess )
245![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
246
::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, *pbstr, nLen );
247
}
248![](/Images/OutliningIndicators/InBlock.gif)
249
return bSuccess;
250
}
251![](/Images/OutliningIndicators/InBlock.gif)
252
static DWORD __cdecl _AFX_FUNCNAME(FormatMessage)( _In_ DWORD dwFlags, LPCVOID pSource,
253
_In_ DWORD dwMessageID, _In_ DWORD dwLanguageID, _Out_cap_(nSize) LPSTR pszBuffer,
254
DWORD nSize, va_list* pArguments ) throw()
255![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
256
return ::FormatMessageA( dwFlags, pSource, dwMessageID, dwLanguageID,
257
pszBuffer, nSize, pArguments );
258
}
259![](/Images/OutliningIndicators/InBlock.gif)
260
#if defined(_AFX)
261
static DWORD __cdecl FormatMessage( _In_ DWORD dwFlags, LPCVOID pSource,
262
_In_ DWORD dwMessageID, _In_ DWORD dwLanguageID, _Out_cap_(nSize) LPSTR pszBuffer,
263
DWORD nSize, va_list* pArguments ) throw()
264![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
265
return _AFX_FUNCNAME(FormatMessage)(dwFlags, pSource, dwMessageID, dwLanguageID, pszBuffer, nSize, pArguments);
266
}
267
#endif
268![](/Images/OutliningIndicators/InBlock.gif)
269
static int __cdecl SafeStringLen( _In_opt_z_ LPCSTR psz ) throw()
270![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
271
// returns length in bytes
272
return (psz != NULL) ? int( strlen( psz ) ) : 0;
273
}
274![](/Images/OutliningIndicators/InBlock.gif)
275
static int __cdecl SafeStringLen( _In_opt_z_ LPCWSTR psz ) throw()
276![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
277
// returns length in wchar_ts
278
return (psz != NULL) ? int( wcslen( psz ) ) : 0;
279
}
280![](/Images/OutliningIndicators/InBlock.gif)
281
static int __cdecl GetCharLen( _In_z_ const wchar_t* pch ) throw()
282![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
283
(void)pch;
284
// returns char length
285
return 1;
286
}
287![](/Images/OutliningIndicators/InBlock.gif)
288
static int __cdecl GetCharLen( _In_z_ const char* pch ) throw()
289![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
290
// returns char length
291
return int( _mbclen( reinterpret_cast< const unsigned char* >( pch ) ) );
292
}
293![](/Images/OutliningIndicators/InBlock.gif)
294
static DWORD __cdecl GetEnvironmentVariable( _In_z_ LPCSTR pszVar,
295
_Out_opt_cap_(dwSize) LPSTR pszBuffer, _In_ DWORD dwSize ) throw()
296![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
297
return ::GetEnvironmentVariableA( pszVar, pszBuffer, dwSize );
298
}
299
};
300![](/Images/OutliningIndicators/None.gif)
301
// specialization for wchar_t
302
template<>
303
class ChTraitsCRT< wchar_t > :
304
public ChTraitsBase< wchar_t >
305![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
306
static DWORD __cdecl _GetEnvironmentVariableW( _In_z_ LPCWSTR pszName, _Out_opt_cap_post_count_(nSize, return) LPWSTR pszBuffer, _In_ DWORD nSize ) throw()
307![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
308
return ::GetEnvironmentVariableW( pszName, pszBuffer, nSize );
309
}
310![](/Images/OutliningIndicators/InBlock.gif)
311
public:
312
static LPWSTR __cdecl CharNext( _In_z_ LPCWSTR psz ) throw()
313![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
314
return const_cast< LPWSTR >( psz+1 );
315
}
316![](/Images/OutliningIndicators/InBlock.gif)
317
static int __cdecl IsDigit( _In_ wchar_t ch ) throw()
318![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
319
return iswdigit( static_cast<unsigned short>(ch) );
320
}
321![](/Images/OutliningIndicators/InBlock.gif)
322
static int __cdecl IsSpace( _In_ wchar_t ch ) throw()
323![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
324
return iswspace( static_cast<unsigned short>(ch) );
325
}
326![](/Images/OutliningIndicators/InBlock.gif)
327
static int __cdecl StringCompare( _In_z_ LPCWSTR pszA, _In_z_ LPCWSTR pszB ) throw()
328![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
329
return wcscmp( pszA, pszB );
330
}
331![](/Images/OutliningIndicators/InBlock.gif)
332
static int __cdecl StringCompareIgnore( _In_z_ LPCWSTR pszA, _In_z_ LPCWSTR pszB ) throw()
333![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
334
return _wcsicmp( pszA, pszB );
335
}
336![](/Images/OutliningIndicators/InBlock.gif)
337
static int __cdecl StringCollate( _In_z_ LPCWSTR pszA, _In_z_ LPCWSTR pszB ) throw()
338![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
339
return wcscoll( pszA, pszB );
340
}
341![](/Images/OutliningIndicators/InBlock.gif)
342
static int __cdecl StringCollateIgnore( _In_z_ LPCWSTR pszA, _In_z_ LPCWSTR pszB ) throw()
343![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
344
return _wcsicoll( pszA, pszB );
345
}
346![](/Images/OutliningIndicators/InBlock.gif)
347
static LPCWSTR __cdecl StringFindString( _In_z_ LPCWSTR pszBlock, _In_z_ LPCWSTR pszMatch ) throw()
348![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
349
return wcsstr( pszBlock, pszMatch );
350
}
351![](/Images/OutliningIndicators/InBlock.gif)
352
static LPWSTR __cdecl StringFindString( _In_z_ LPWSTR pszBlock, _In_z_ LPCWSTR pszMatch ) throw()
353![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
354
return( const_cast< LPWSTR >( StringFindString( const_cast< LPCWSTR >( pszBlock ), pszMatch ) ) );
355
}
356![](/Images/OutliningIndicators/InBlock.gif)
357
static LPCWSTR __cdecl StringFindChar( _In_z_ LPCWSTR pszBlock, _In_ wchar_t chMatch ) throw()
358![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
359
return wcschr( pszBlock, chMatch );
360
}
361![](/Images/OutliningIndicators/InBlock.gif)
362
static LPCWSTR __cdecl StringFindCharRev( _In_z_ LPCWSTR psz, _In_ wchar_t ch ) throw()
363![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
364
return wcsrchr( psz, ch );
365
}
366![](/Images/OutliningIndicators/InBlock.gif)
367
static LPCWSTR __cdecl StringScanSet( _In_z_ LPCWSTR pszBlock, _In_z_ LPCWSTR pszMatch ) throw()
368![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
369
return wcspbrk( pszBlock, pszMatch );
370
}
371![](/Images/OutliningIndicators/InBlock.gif)
372
static int __cdecl StringSpanIncluding( _In_z_ LPCWSTR pszBlock, _In_z_ LPCWSTR pszSet ) throw()
373![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
374
return (int)wcsspn( pszBlock, pszSet );
375
}
376![](/Images/OutliningIndicators/InBlock.gif)
377
static int __cdecl StringSpanExcluding( _In_z_ LPCWSTR pszBlock, _In_z_ LPCWSTR pszSet ) throw()
378![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
379
return (int)wcscspn( pszBlock, pszSet );
380
}
381![](/Images/OutliningIndicators/InBlock.gif)
382
_ATL_INSECURE_DEPRECATE("You must pass an output size to ChTraitsCRT::StringUppercase")
383
static LPWSTR __cdecl StringUppercase( _Inout_ LPWSTR psz ) throw()
384![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
385
#pragma warning (push)
386
#pragma warning(disable : 4996)
387
return _wcsupr( psz );
388
#pragma warning (pop)
389
}
390![](/Images/OutliningIndicators/InBlock.gif)
391
_ATL_INSECURE_DEPRECATE("You must pass an output size to ChTraitsCRT::StringLowercase")
392
static LPWSTR __cdecl StringLowercase( _Inout_ LPWSTR psz ) throw()
393![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
394
#pragma warning (push)
395
#pragma warning(disable : 4996)
396
return _wcslwr( psz );
397
#pragma warning (pop)
398
}
399![](/Images/OutliningIndicators/InBlock.gif)
400
static LPWSTR __cdecl StringUppercase( _Inout_cap_(size) LPWSTR psz, _In_ size_t size ) throw()
401![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
402
errno_t err = _wcsupr_s( psz, size );
403
return (err == 0) ? psz : NULL;
404
}
405![](/Images/OutliningIndicators/InBlock.gif)
406
static LPWSTR __cdecl StringLowercase( _Inout_cap_(size) LPWSTR psz, _In_ size_t size ) throw()
407![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
408
errno_t err = _wcslwr_s( psz, size );
409
return (err == 0) ? psz : NULL;
410
}
411![](/Images/OutliningIndicators/InBlock.gif)
412
static LPWSTR __cdecl StringReverse( _Inout_ LPWSTR psz ) throw()
413![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
414
return _wcsrev( psz );
415
}
416![](/Images/OutliningIndicators/InBlock.gif)
417
static int __cdecl GetFormattedLength( _In_ _Printf_format_string_ LPCWSTR pszFormat, va_list args) throw()
418![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
419
return _vscwprintf( pszFormat, args );
420
}
421![](/Images/OutliningIndicators/InBlock.gif)
422
_ATL_INSECURE_DEPRECATE("You must pass an output size to ChTraitsCRT::Format")
423
static int __cdecl Format( _Out_ LPWSTR pszBuffer, _In_ _Printf_format_string_ LPCWSTR pszFormat, va_list args) throw()
424![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
425
#pragma warning (push)
426
#pragma warning(disable : 4996)
427
return vswprintf( pszBuffer, pszFormat, args );
428
#pragma warning (pop)
429
}
430
static int __cdecl Format
431
( _Out_cap_(nLength) LPWSTR pszBuffer, _In_ size_t nLength, _In_ __format_string LPCWSTR pszFormat, va_list args) throw()
432![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
433
return vswprintf_s( pszBuffer, nLength, pszFormat, args );
434
}
435![](/Images/OutliningIndicators/InBlock.gif)
436
static int __cdecl GetBaseTypeLength( _In_z_ LPCSTR pszSrc ) throw()
437![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
438
// Returns required buffer size in wchar_ts
439
return ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pszSrc, -1, NULL, 0 )-1;
440
}
441![](/Images/OutliningIndicators/InBlock.gif)
442
static int __cdecl GetBaseTypeLength( _In_count_(nLength) LPCSTR pszSrc, _In_ int nLength ) throw()
443![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
444
// Returns required buffer size in wchar_ts
445
return ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pszSrc, nLength, NULL, 0 );
446
}
447![](/Images/OutliningIndicators/InBlock.gif)
448
static int __cdecl GetBaseTypeLength( _In_z_ LPCWSTR pszSrc ) throw()
449![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
450
// Returns required buffer size in wchar_ts
451
return (int)wcslen( pszSrc );
452
}
453![](/Images/OutliningIndicators/InBlock.gif)
454
static int __cdecl GetBaseTypeLength( _In_count_(nLength) LPCWSTR pszSrc, _In_ int nLength ) throw()
455![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
456
(void)pszSrc;
457
// Returns required buffer size in wchar_ts
458
return nLength;
459
}
460![](/Images/OutliningIndicators/InBlock.gif)
461
static void __cdecl ConvertToBaseType( _Out_cap_(nDestLength) LPWSTR pszDest, _In_ int nDestLength,
462
_In_z_ LPCSTR pszSrc, _In_ int nSrcLength = -1) throw()
463![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
464
// nLen is in wchar_ts
465
::MultiByteToWideChar( _AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength );
466
}
467![](/Images/OutliningIndicators/InBlock.gif)
468
static void __cdecl ConvertToBaseType( _Out_cap_(nDestLength) LPWSTR pszDest, _In_ int nDestLength,
469
_In_z_ LPCWSTR pszSrc, int nSrcLength = -1 ) throw()
470![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
471![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (nSrcLength == -1)
{ nSrcLength=1 + GetBaseTypeLength(pszSrc); }
472
// nLen is in wchar_ts
473
Checked::wmemcpy_s(pszDest, nDestLength, pszSrc, nSrcLength);
474
}
475![](/Images/OutliningIndicators/InBlock.gif)
476
static void __cdecl FloodCharacters( _In_ wchar_t ch, _In_ int nLength, _Out_capcount_(nLength) LPWSTR psz ) throw()
477![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
478
// nLength is in XCHARs
479
for( int i = 0; i < nLength; i++ )
480![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
481
psz[i] = ch;
482
}
483
}
484![](/Images/OutliningIndicators/InBlock.gif)
485
static BSTR __cdecl AllocSysString( _In_count_(nDataLength) const wchar_t* pchData, _In_ int nDataLength ) throw()
486![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
487
return ::SysAllocStringLen( pchData, nDataLength );
488
}
489![](/Images/OutliningIndicators/InBlock.gif)
490
static BOOL __cdecl ReAllocSysString( _In_count_(nDataLength) const wchar_t* pchData, _Inout_ BSTR* pbstr, _In_ int nDataLength ) throw()
491![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
492
return ::SysReAllocStringLen( pbstr, pchData, nDataLength );
493
}
494![](/Images/OutliningIndicators/InBlock.gif)
495
static int __cdecl SafeStringLen( _In_opt_z_ LPCSTR psz ) throw()
496![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
497
// returns length in bytes
498
return (psz != NULL) ? (int)strlen( psz ) : 0;
499
}
500![](/Images/OutliningIndicators/InBlock.gif)
501
static int __cdecl SafeStringLen( _In_opt_ LPCWSTR psz ) throw()
502![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
503
// returns length in wchar_ts
504
return (psz != NULL) ? (int)wcslen( psz ) : 0;
505
}
506![](/Images/OutliningIndicators/InBlock.gif)
507
static int __cdecl GetCharLen( _In_z_ const wchar_t* pch ) throw()
508![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
509
(void)pch;
510
// returns char length
511
return 1;
512
}
513![](/Images/OutliningIndicators/InBlock.gif)
514
static int __cdecl GetCharLen( _In_z_ const char* pch ) throw()
515![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
516
// returns char length
517
return (int)( _mbclen( reinterpret_cast< const unsigned char* >( pch ) ) );
518
}
519![](/Images/OutliningIndicators/InBlock.gif)
520
static DWORD __cdecl GetEnvironmentVariable( _In_z_ LPCWSTR pszVar, _Out_opt_cap_(dwSize) LPWSTR pszBuffer, _In_ DWORD dwSize ) throw()
521![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
522
return _GetEnvironmentVariableW( pszVar, pszBuffer, dwSize );
523
}
524![](/Images/OutliningIndicators/InBlock.gif)
525![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
static void __cdecl ConvertToOem( __reserved LPWSTR /**//*psz*/ )
526![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
527
ATLENSURE(FALSE); // Unsupported Feature
528
}
529![](/Images/OutliningIndicators/InBlock.gif)
530![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
static void __cdecl ConvertToAnsi( __reserved LPWSTR /**//*psz*/ )
531![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
532
ATLENSURE(FALSE); // Unsupported Feature
533
}
534![](/Images/OutliningIndicators/InBlock.gif)
535![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
static void __cdecl ConvertToOem( __reserved LPWSTR /**//*psz*/, size_t )
536![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
537
ATLENSURE(FALSE); // Unsupported Feature
538
}
539![](/Images/OutliningIndicators/InBlock.gif)
540![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
static void __cdecl ConvertToAnsi( __reserved LPWSTR /**//*psz*/, size_t )
541![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
542
ATLENSURE(FALSE); // Unsupported Feature
543
}
544![](/Images/OutliningIndicators/InBlock.gif)
545
#ifdef _UNICODE
546
public:
547
static DWORD __cdecl _AFX_FUNCNAME(FormatMessage)( _In_ DWORD dwFlags, LPCVOID pSource,
548
_In_ DWORD dwMessageID, _In_ DWORD dwLanguageID, _Out_cap_(nSize) LPWSTR pszBuffer,
549
_In_ DWORD nSize, va_list* pArguments ) throw()
550![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
551
return ::FormatMessageW( dwFlags, pSource, dwMessageID, dwLanguageID,
552
pszBuffer, nSize, pArguments );
553
}
554![](/Images/OutliningIndicators/InBlock.gif)
555
#if defined(_AFX)
556
static DWORD __cdecl FormatMessage( _In_ DWORD dwFlags, LPCVOID pSource,
557
_In_ DWORD dwMessageID, _In_ DWORD dwLanguageID, _Out_cap_(nSize) LPWSTR pszBuffer,
558
_In_ DWORD nSize, va_list* pArguments ) throw()
559![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
560
return _AFX_FUNCNAME(FormatMessage)(dwFlags, pSource, dwMessageID, dwLanguageID, pszBuffer, nSize, pArguments);
561
}
562
#endif
563![](/Images/OutliningIndicators/InBlock.gif)
564
#else
565![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
static DWORD __cdecl _AFX_FUNCNAME(FormatMessage)( DWORD /**//*dwFlags*/, LPCVOID /**//*pSource*/,
566![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
DWORD /**//*dwMessageID*/, DWORD /**//*dwLanguageID*/, __reserved LPWSTR /**//*pszBuffer*/,
567![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
DWORD /**//*nSize*/, va_list* /**//*pArguments*/ )
568![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
569
ATLENSURE(FALSE); // Unsupported Feature
570
return 0;
571
}
572![](/Images/OutliningIndicators/InBlock.gif)
573
#if defined(_AFX)
574
static DWORD __cdecl FormatMessage( DWORD dwFlags, LPCVOID pSource,
575
DWORD dwMessageID, DWORD dwLanguageID, __reserved LPWSTR pszBuffer,
576
DWORD nSize, va_list* pArguments )
577![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
578
return _AFX_FUNCNAME(FormatMessage)(dwFlags, pSource, dwMessageID, dwLanguageID, pszBuffer, nSize, pArguments);
579
}
580
#endif
581![](/Images/OutliningIndicators/InBlock.gif)
582
#endif
583![](/Images/OutliningIndicators/InBlock.gif)
584
};
585![](/Images/OutliningIndicators/None.gif)
CString类的构造函数
看过了上面的n多代码和介绍,我们终于可以看看真正的CString类了。声明如下:
template< typename BaseType, class StringTraits >
class CStringT :
public CSimpleStringT< BaseType, _CSTRING_IMPL_::_MFCDLLTraitsCheck<BaseType, StringTraits>::c_bIsMFCDLLTraits >
您可能不禁要问,不是要说CString么,怎么是CStringT呢? 其实CString实际上是一个宏而已,在afxstr.h文件中有如下定义:
typedef ATL::CStringT< wchar_t, StrTraitMFC_DLL< wchar_t > > CStringW;
typedef ATL::CStringT< char, StrTraitMFC_DLL< char > > CStringA;
typedef ATL::CStringT< TCHAR, StrTraitMFC_DLL< TCHAR > > CString;
由此,我们可以确切的知道,我们使用的CString就是CStringT模板类的一个特例。如果您是从头看到尾的话,就会知道,我们已经讲了CString的重要成员CStringData、包含了CString字符串操作的方法ChTraitsCRT。那CString里面还剩下什么没有说呢?基本上也就是构造函数、操作符重载了。一个类也就包括了这么多内容,再无其它。
先说构造函数,CString这个帅类提供了一共17种构造重载,够狠!全说没必要,要说的就是静态构造函数:
static void __cdecl Construct( CStringT* pString )
{
new( pString ) CStringT;
}
这是一个拷贝构造函数,传入一个有效的指向CString的指针,这个构造就会为你创建一个新的对象,并把这个对象的首地址赋值给传入的指针变量。
MSDN给出了构造函数使用的完整Demo:
CAtlString s1; // Empty string
CAtlString s2(_T("cat")); // From a C string literal
CAtlString s3 = s2; // Copy constructor
CAtlString s4(s2 + _T(" ") + s3); // From a string expression
CAtlString s5(_T('x')); // s5 = "x"
CAtlString s6(_T('x'), 6); // s6 = "xxxxxx"
CAtlString s7((LPCSTR)ID_FILE_NEW); // s7 = "Create a new document"
VARIANT var;
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = ::SysAllocString(L"Football is a fun sport.");
CAtlString s8(var); // s8 = "Football is a fun sport."
// The following statement does not call the assignment operator.
// The compiler considers the following statement equivalent to
// CAtlString city("Paris")
CAtlString city = _T("Paris");
关于Format函数
这个函数的奇特地方就是支持变长参数列表。在上次说道.NET下的String类时,使用的是C#的关键字Params 关键字来实现变长参数的,在C++中采用变长参数列表来实现。Format函数的声明如下:
inline void __cdecl CStringT<BaseType, StringTraits>::Format( _In_ _Printf_format_string_ PCXSTR pszFormat, ... )
这最后的… 在语法上就代表了变长参数列表。请注意,这个变长参数列表必须放在函数列表的最后声明,如写成(…,int iLength) 是不对的。
这个变长参数列表的声明在stdarg.h文件中。实际上va_list、va_start、va_end 是三个宏。代码如下:
ATLASSERT( AtlIsValidString( pszFormat ) );
va_list argList;
va_start( argList, pszFormat );
FormatV( pszFormat, argList );
va_end( argList );
LoadString 函数
这个函数也是值得一说的,正因为有了这个LoadString函数和String Table,我们才可以很容易的让我们的程序支持国际化。LoadString的代码是这样的:
_Check_return_ BOOL LoadString( _In_ HINSTANCE hInstance, _In_ UINT nID, _In_ WORD wLanguageID )
{
const ATLSTRINGRESOURCEIMAGE* pImage = AtlGetStringResourceImage( hInstance, nID, wLanguageID );
if( pImage == NULL )
{
return( FALSE );
}
int nLength = StringTraits::GetBaseTypeLength( pImage->achString, pImage->nLength );
PXSTR pszBuffer = GetBuffer( nLength );
StringTraits::ConvertToBaseType( pszBuffer, nLength, pImage->achString, pImage->nLength );
ReleaseBufferSetLength( nLength );
return( TRUE );
}
其最主要的函数是AtlGetStringResourceImage 函数,这个函数通过资源ID能够获取保存在应用程序文件或动态库中的字符串资源。AtlGetStringResourceImage 函数的功能实现最终还是通过Windows API FindResource 函数实现的。有兴趣的话,可以查看一下AtlGetStringResourceImage 函数的源代码。
写在后面
说起Windows 下的CString,那真是有说不尽的话题。比如,不同类型的字符串之间的转换,这个话题就够再写一篇博客的。本篇只能尽力起到一个抛砖引玉的作用。
我在Google上搜索到了一篇叫做《谈新手对CString的使用》一文,http://www.poptool.net/server/p52/J526413.shtml 这篇文章被n多网站转载,出处不明。文章中提到了一个问题,说“为了优化效率,就采用在系统软件内部广
泛使用的"写时复制"概念.即当从一个cstring产生另一个cstring并不复制它的字符缓
冲区内容,而只是将字符缓冲区的"引用计数"加1.当需要改写字符缓冲区内的内容时,才
分配内存,并复制内容”这部分倒是值得大家留意,这也正和前面说道的CStringData引入的引用计数机制不谋而合。