在我寫的談ATL(四)--VARIANT和CComVariant中詳細分析了VARAINT類型的本質,並詳細說明了CComVariant爲何能夠徹底替代VARAINT的理由,下面我打算把BSTR和CComBSTR也詳細的說明一下,不過與VARAINT和CComVariant的關係不一樣的是,CComVariant是VARAINT的子類,在傳遞參數時,利用的是子類對象is-a父類的概念。BSTR和CComBSTR是否是也是這種關係呢?不是的!咱們先來看看BSTR的定義:app
typedef OLECHAR __RPC_FAR *BSTR;ide
typedef WCHAR OLECHAR;函數
typedef wchar_t WCHAR;學習
typedef unsigned short wchar_t;ui
經過這一系列的宏定義,能夠清楚的看出BSTR的本質,可見它並非結構體,更不是類,而是一個穿了幾層馬甲的內置數據類型,從這咱們也能夠斷言CComBSTR類確定不是BSTR的子類,那CComBSTR怎麼能作到完美的替代BSTR呢?咱們仍是先看看CComBSTR的定義吧,說實話,這些代碼真的像藝術品同樣。this
// CComBSTRspa
class CComBSTR
{
public:
BSTR m_str;
CComBSTR()
{
m_str = NULL;
}
CComBSTR(int nSize)
{
m_str = ::SysAllocStringLen(NULL, nSize);
}
CComBSTR(int nSize, LPCOLESTR sz)
{
m_str = ::SysAllocStringLen(sz, nSize);
}
CComBSTR(LPCOLESTR pSrc)
{
m_str = ::SysAllocString(pSrc);
}
CComBSTR(const CComBSTR& src)
{
m_str = src.Copy();
}
CComBSTR(REFGUID src)
{
LPOLESTR szGuid;
StringFromCLSID(src, &szGuid);
m_str = ::SysAllocString(szGuid);
CoTaskMemFree(szGuid);
}
CComBSTR& operator=(const CComBSTR& src)
{
if (m_str != src.m_str)
{
if (m_str)
::SysFreeString(m_str);
m_str = src.Copy();
}
return *this;
}對象
CComBSTR& operator=(LPCOLESTR pSrc)
{
::SysFreeString(m_str);
m_str = ::SysAllocString(pSrc);
return *this;
}繼承
~CComBSTR()
{
::SysFreeString(m_str);
}
unsigned int Length() const
{
return (m_str == NULL)? 0 : SysStringLen(m_str);
}
operator BSTR() const
{
return m_str;
}
BSTR* operator&()
{
return &m_str;
}
BSTR Copy() const
{
return ::SysAllocStringLen(m_str, ::SysStringLen(m_str));
}
HRESULT CopyTo(BSTR* pbstr)
{
ATLASSERT(pbstr != NULL);
if (pbstr == NULL)
return E_POINTER;
*pbstr = ::SysAllocStringLen(m_str, ::SysStringLen(m_str));
if (*pbstr == NULL)
return E_OUTOFMEMORY;
return S_OK;
}
void Attach(BSTR src)
{
ATLASSERT(m_str == NULL);
m_str = src;
}
BSTR Detach()
{
BSTR s = m_str;
m_str = NULL;
return s;
}
void Empty()
{
::SysFreeString(m_str);
m_str = NULL;
}
bool operator!() const
{
return (m_str == NULL);
}
HRESULT Append(const CComBSTR& bstrSrc)
{
return Append(bstrSrc.m_str, SysStringLen(bstrSrc.m_str));
}
HRESULT Append(LPCOLESTR lpsz)
{
return Append(lpsz, ocslen(lpsz));
}
// a BSTR is just a LPCOLESTR so we need a special version to signify
// that we are appending a BSTR
HRESULT AppendBSTR(BSTR p)
{
return Append(p, SysStringLen(p));
}
HRESULT Append(LPCOLESTR lpsz, int nLen)
{
int n1 = Length();
BSTR b;
b = ::SysAllocStringLen(NULL, n1+nLen);
if (b == NULL)
return E_OUTOFMEMORY;
memcpy(b, m_str, n1*sizeof(OLECHAR));
memcpy(b+n1, lpsz, nLen*sizeof(OLECHAR));
b[n1+nLen] = NULL;
SysFreeString(m_str);
m_str = b;
return S_OK;
}
HRESULT ToLower()
{
USES_CONVERSION;
if (m_str != NULL)
{
LPTSTR psz = CharLower(OLE2T(m_str));
if (psz == NULL)
return E_OUTOFMEMORY;
BSTR b = T2BSTR(psz);
if (psz == NULL)
return E_OUTOFMEMORY;
SysFreeString(m_str);
m_str = b;
}
return S_OK;
}
HRESULT ToUpper()
{
USES_CONVERSION;
if (m_str != NULL)
{
LPTSTR psz = CharUpper(OLE2T(m_str));
if (psz == NULL)
return E_OUTOFMEMORY;
BSTR b = T2BSTR(psz);
if (psz == NULL)
return E_OUTOFMEMORY;
SysFreeString(m_str);
m_str = b;
}
return S_OK;
}
bool LoadString(HINSTANCE hInst, UINT nID)
{
USES_CONVERSION;
TCHAR sz[512];
UINT nLen = ::LoadString(hInst, nID, sz, 512);
ATLASSERT(nLen < 511);
SysFreeString(m_str);
m_str = (nLen != 0) ? SysAllocString(T2OLE(sz)) : NULL;
return (nLen != 0);
}
bool LoadString(UINT nID)
{
return LoadString(_pModule->m_hInstResource, nID);
}ci
CComBSTR& operator+=(const CComBSTR& bstrSrc)
{
AppendBSTR(bstrSrc.m_str);
return *this;
}
bool operator<(BSTR bstrSrc) const
{
if (bstrSrc == NULL && m_str == NULL)
return false;
if (bstrSrc != NULL && m_str != NULL)
return wcscmp(m_str, bstrSrc) < 0;
return m_str == NULL;
}
bool operator==(BSTR bstrSrc) const
{
if (bstrSrc == NULL && m_str == NULL)
return true;
if (bstrSrc != NULL && m_str != NULL)
return wcscmp(m_str, bstrSrc) == 0;
return false;
}
bool operator<(LPCSTR pszSrc) const
{
if (pszSrc == NULL && m_str == NULL)
return false;
USES_CONVERSION;
if (pszSrc != NULL && m_str != NULL)
return wcscmp(m_str, A2W(pszSrc)) < 0;
return m_str == NULL;
}
bool operator==(LPCSTR pszSrc) const
{
if (pszSrc == NULL && m_str == NULL)
return true;
USES_CONVERSION;
if (pszSrc != NULL && m_str != NULL)
return wcscmp(m_str, A2W(pszSrc)) == 0;
return false;
}
#ifndef OLE2ANSI
CComBSTR(LPCSTR pSrc)
{
m_str = A2WBSTR(pSrc);
}
CComBSTR(int nSize, LPCSTR sz)
{
m_str = A2WBSTR(sz, nSize);
}
void Append(LPCSTR lpsz)
{
USES_CONVERSION;
LPCOLESTR lpo = A2COLE(lpsz);
Append(lpo, ocslen(lpo));
}
CComBSTR& operator=(LPCSTR pSrc)
{
::SysFreeString(m_str);
m_str = A2WBSTR(pSrc);
return *this;
}
#endif
HRESULT WriteToStream(IStream* pStream)
{
ATLASSERT(pStream != NULL);
ULONG cb;
ULONG cbStrLen = 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(m_str == NULL); // 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 (m_str == NULL)
hr = E_OUTOFMEMORY;
else
hr = pStream->Read((void*) m_str, cbStrLen, NULL);
}
if (hr == S_FALSE)
hr = E_FAIL;
return hr;
}
};
我把須要注意的地方都用紅色粗體標註了,經過CComBSTR的定義咱們能夠看到,CComBSTR是一個頂層類,沒有複雜的社會背景(好比一大堆的繼承和預編譯指令等),構造函數和賦值運算符提供了不少,大體能夠知足初始化和賦值操做的使用,最到位的服務是我用紅色粗體標註出來的兩個函數,一個是強制類型轉換,經過相似運算符重載的方式完成,這種語法通常的初學者比較陌生,建議再深刻學習;一個是對 & 符號的運算符重載。這兩個函數能夠起到操做CComBSTR類徹底和操做BSTR同樣的感受,也就是說你能夠這樣,假設要調用一個形以下面這個樣子的函數:
void TEST(BSTR str1, BSTR *pstr2, BSTR str3);
假設你定義了這樣的變量:
BSTR bstr;
CComBSTR coBstr1, coBstr2;
那麼調用TEST函數時就徹底能夠把coBstr1和coBstr2當作BSTR類型的變量來使用,以下:
TEST(bstr, &coBstr1, coBstr2); //該調用在VC6.0不能經過?
怎麼樣,棒極了吧!