String Data Types, Conversion Classes, and Helper Functions
对于字符串表示,不同的系统有不同的方法
C/C++使用在字串末尾加Nul
VB,Java,Pascal在字串头部标识字串长度
COM使用OLECHAR作为字符类型,COM的字符串为Nul结尾的OLECHARs,用LPOLESTR表示。如果向COM interface传递text参数,应该使用LPOLESTR
Unicode,=wchar_t, 16-bit,L()宏
MBCS,=unsigned char,1~2Bytes
ANSI,=[signed] char
TCHAR/_TCHAR,由编译条件决定定义类型,_T()宏
OLECHAR,Win32=wchar_t,Win16=char,Mac OS=char,Solaris OS=wchar_t
BSTR,头部标识长度的OLECHAR串,无法使用转换宏,转换类进行变换
使用转换类防止内存提前释放
LPOLESTR ConvertString(LPTSTR lpsz) { return CT2OLE(lpsz);}
转换宏,转换类区别
转换类都有C开头
转换宏永远使用栈分配,更快,需要USE_CONVERSION宏,可能在loop中造成程序内存崩溃
转换类更加安全
The CComBSTR Smart BSTR Class
BSTR特点
对于非C语言交互,应该使用BSTR作为字符串参数
BSTR包括一串字符串和一个前置整数,BSTR指向字符串,字符串以Nul结尾,前置整数为字符串Byte长度,不包括末尾Nul
BSTR必须使用SysAllocString,SysFreeString,copy必须真实复制字符串而不仅仅是指针
BSTR=NULL表示一个空的字符串
The CComBSTR Class
CComBSTR() { m_str = NULL; } ~CComBSTR() { ::SysFreeString(m_str); }
构造函数变形
CComBSTR(LPCOLESTR pSrc) { if (pSrc == NULL) m_str = NULL; else { m_str = ::SysAllocString(pSrc); if (m_str == NULL) AtlThrow(E_OUTOFMEMORY); } }
CComBSTR(int nSize, LPCOLESTR sz);
nSize为目标字符串的字符数,不包含末尾Nul
CComBSTR(const CComBSTR& src) { m_str = src.Copy(); ... }
BSTR Copy() const { if (!*this) { return NULL; } return ::SysAllocStringByteLen((char*)m_str, ::SysStringByteLen(m_str)); }
CComBSTR(LPCSTR pSrc) { ... m_str = A2WBSTR(pSrc); ... } CComBSTR(int nSize, LPCSTR sz) { ... m_str = A2WBSTR(sz, nSize); ... }
CComBSTR(REFGUID src);例子
// Define a GUID as a binary constant static const GUID GUID_Sample = { 0x8a44e110, 0xf134, 0x11d1, { 0x96, 0xb1, 0xBA, 0xDB, 0xAD, 0xBA, 0xDB, 0xAD } }; // Convert the binary GUID to its string representation CComBSTR str6 (GUID_Sample) ; // str6 contains "{8A44E110-F134-11d1-96B1-BADBADBADBAD}"
Assignment
CComBSTR& operator=(const CComBSTR& src) { if (m_str != src.m_str) { ::SysFreeString(m_str); m_str = src.Copy(); if (!!src && !*this) { AtlThrow(E_OUTOFMEMORY); } } return *this; }
CComBSTR& operator=(LPCOLESTR pSrc) { if (pSrc != m_str) { ::SysFreeString(m_str); if (pSrc != NULL) { m_str = ::SysAllocString(pSrc); if (!*this) { AtlThrow(E_OUTOFMEMORY); } } else { m_str = NULL; } } return *this; }
HRESULT AssignBSTR(const BSTR bstrSrc) { HRESULT hr = S_OK; if (m_str != bstrSrc) { ::SysFreeString(m_str); if (bstrSrc != NULL) { m_str = ::SysAllocStringByteLen((char*)bstrSrc, ::SysStringByteLen(bstrSrc)); if (!*this) { hr = E_OUTOFMEMORY; } } else { m_str = NULL; } } return hr; }
CComBSTR& operator=(LPCSTR pSrc) { ::SysFreeString(m_str); m_str = A2WBSTR(pSrc); if (!*this && pSrc != NULL) { AtlThrow(E_OUTOFMEMORY); } return *this; }
bool LoadString(HINSTANCE hInst, UINT nID) ; bool LoadString(UINT nID) ;
CComBSTR Operations
operator BSTR() const { return m_str; }
#ifndef ATL_CCOMBSTR_ADDRESS_OF_ASSERT // Temp disable CComBSTR::operator& Assert #define ATL_NO_CCOMBSTR_ADDRESS_OF_ASSERT #endif BSTR* operator&() { #ifndef ATL_NO_CCOMBSTR_ADDRESS_OF_ASSERT ATLASSERT(!*this); #endif return &m_str; }
HRESULT CopyTo(BSTR* pbstr);
BSTR Detach() { BSTR s = m_str; m_str = NULL; return s; }
void Attach(BSTR src) { if (m_str != src) { ::SysFreeString(m_str); m_str = src; } }
void Empty() { ::SysFreeString(m_str); m_str = NULL; }
HRESULT BSTRToArray(LPSAFEARRAY *ppArray) { return VectorFromBstr(m_str, ppArray); } HRESULT ArrayToBSTR(const SAFEARRAY *pSrc) { ::SysFreeString(m_str); return BstrFromVector((LPSAFEARRAY)pSrc, &m_str); }
String Concatenation Using CComBSTR
HRESULT Append(LPCOLESTR lpsz, int nLen); HRESULT Append(LPCOLESTR lpsz); HRESULT Append(LPCSTR); HRESULT Append(char ch); HRESULT Append(wchar_t ch); HRESULT Append(const CComBSTR& bstrSrc); CComBSTR& operator+=(const CComBSTR& bstrSrc); HRESULT AppendBSTR(BSTR p); HRESULT AppendBytes(const char* lpsz, int nLen);
注意AppendBytes does not perform a conversion from ANSI to Unicode.
Character Case Conversion
HRESULT ToLower() { if (m_str != NULL) { #ifdef _UNICODE // Convert in place CharLowerBuff(m_str, Length()); #else UINT _acp = _AtlGetConversionACP(); ... int nRet = WideCharToMultiByte( _acp, 0, m_str, Length(), pszA, _convert, NULL, NULL); ... CharLowerBuff(pszA, nRet); nRet = MultiByteToWideChar(_acp, 0, pszA, nRet, pszW, _convert); ... BSTR b = ::SysAllocStringByteLen( (LPCSTR) (LPWSTR) pszW, nRet * sizeof(OLECHAR)); if (b == NULL) return E_OUTOFMEMORY; SysFreeString(m_str); m_str = b; #endif } return S_OK; }
CComBSTR Comparison Operators
bool operator!() const { return (m_str == NULL); }
bool operator<(const CComBSTR& bstrSrc) const { return VarBstrCmp(m_str, bstrSrc.m_str, LOCALE_USER_DEFAULT, 0) == VARCMP_LT; }
bool operator>(LPCSTR pszSrc) const { CComBSTR bstr2(pszSrc); return operator>(bstr2); }
bool operator<(LPCOLESTR pszSrc) const { CComBSTR bstr2(pszSrc); return operator>(bstr2); }
bool operator>(LPOLESTR pszSrc) const { return operator>((LPCOLESTR)pszSrc); }
CComBSTR Persistence Support
HRESULT WriteToStream(IStream* pStream) { ATLASSERT(pStream != NULL); if(pStream == NULL) return E_INVALIDARG; ULONG cb; ULONG cbStrLen = ULONG(m_str ? SysStringByteLen(m_str)+sizeof(OLECHAR) : 0); HRESULT hr = pStream->Write((void*) &cbStrLen, sizeof(cbStrLen), &cb); if (FAILED(hr)) return hr; return cbStrLen ? pStream->Write((void*) m_str, cbStrLen, &cb) : S_OK; }
HRESULT ReadFromStream(IStream* pStream) { ATLASSERT(pStream != NULL); ATLASSERT(!*this); // should be empty ULONG cbStrLen = 0; HRESULT hr = pStream->Read((void*) &cbStrLen, sizeof(cbStrLen), NULL); if ((hr == S_OK) && (cbStrLen != 0)) { //subtract size for terminating NULL which we wrote out //since SysAllocStringByteLen overallocates for the NULL m_str = SysAllocStringByteLen(NULL, cbStrLen-sizeof(OLECHAR)); if (!*this) hr = E_OUTOFMEMORY; else hr = pStream->Read((void*) m_str, cbStrLen, NULL); ... } if (hr == S_FALSE) hr = E_FAIL; return hr; }
注意在Read前,应该保证obj为Empty
CComBSTR注意点
typedef /* [wire_marshal] */ OLECHAR __RPC_FAR *BSTR;两者有时可以混用
将BSTR数据传入LPOLESTR的输入函数中,会导致字串缩短
将BSTR传给[out]OLECHAR**函数,会导致内存泄漏
不要将OLESTR*传给[in]BSTR,因为SysStringLen无法工作正确
将BSTR传给CComBSTR构造函数应该注意
BSTR bstrInput =
SysAllocStringLen (
OLESTR ("This is part one\0and here's part two"),
36) ;
CComBSTR str8 (bstrInput) ; // Wrong! Unexpected behavior here
// Note: str2 contains only
// "This is part one"
CComBSTR str9 (::SysStringLen (bstrInput),
bstrInput); // Correct!
// str9 contains "This is part one\0and here's part two"
同理Assignment应该注意
// BSTR bstrInput contains
// "This is part one\0and here's part two"
CComBSTR str10;
str10 = bstrInput; // Wrong! Unexpected behavior here
// str10 now contains "This is part one"
str10.Empty(); // Insure object is initially empty str10.AppendBSTR (bstrInput); // This works!
The CString Class
大部分和MFC中一样
Working with BSTRs and CString
BSTR AllocSysString() const { BSTR bstrResult = StringTraits::AllocSysString( GetString(), GetLength() ); if( bstrResult == NULL ) { ThrowMemoryException(); } return( bstrResult ); } BSTR SetSysString( BSTR* pbstr ) const { ATLASSERT( AtlIsValidAddress( pbstr, sizeof( BSTR ) ) ); if( !StringTraits::ReAllocSysString( GetString(), pbstr, GetLength() ) ) { ThrowMemoryException(); } ATLASSERT( *pbstr != NULL ); return( *pbstr ); }
注意2个函数都是const,对CString中的数据没有影响