談ATL(六)--BSTR和CComBSTR類

在我寫的談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不能經過?

怎麼樣,棒極了吧!

相關文章
相關標籤/搜索