谈ATL(六)--BSTR和CComBSTR类

在我写的谈ATL(四)--VARIANT和CComVariant中详细分析了VARAINT类型的本质,并详细说明了CComVariant为什么可以完全替代VARAINT的理由,下面我打算把BSTR和CComBSTR也详细的说明一下,不过与VARAINT和CComVariant的关系不同的是,CComVariant是VARAINT的子类,在传递参数时,利用的是子类对象is-a父类的概念。BSTR和CComBSTR是不是也是这种关系呢?不是的!我们先来看看BSTR的定义:

typedef OLECHAR __RPC_FAR
*BSTR;

typedef WCHAR OLECHAR;

typedef wchar_t WCHAR;

typedef unsigned short
wchar_t;

通过这一系列的宏定义,可以清楚的看出BSTR的本质,可见它并不是结构体,更不是类,而是一个穿了几层马甲的内置数据类型,从这我们也可以断言CComBSTR类肯定不是BSTR的子类,那CComBSTR怎么能做到完美的替代BSTR呢?我们还是先看看CComBSTR的定义吧,说实话,这些代码真的像艺术品一样。

// CComBSTR

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);
 }

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不能通过?

怎么样,棒极了吧!

时间: 2024-11-03 04:33:52

谈ATL(六)--BSTR和CComBSTR类的相关文章

谈ATL(二)--BSTR与CComBSTR

关于BSTR类 BSTR类型的实质是指向一个带长度前缀的OLECHAR字符数组的指针. BSTR是指针数据类型.它指向数组的第一个字符,长度是以整数存储的数据中紧接第一个字符前面的位置. BSTR中的字符数组以NUL字符结束. 前缀长度以字节单位,描述的是字符串的长度,该长度不包括终止字符NUL. 字符数组内部可以包括有效的NUL字符. BSTR必须使用SysAllocString和SysFreeString函数族进行分配和释放. NULL的BSTR指针表示空字符串.简单讲就是BSTR *p =

ATL基础BSTR CComBSTR SysAllocString

ATL提供了 BSTR 和 CComBSTR ,还有OLEAUTO32.DLL导出一个API叫SysAllocString. BSTR 是一个typedef,你可以理解为 typedef WCHAR* BSTR,它就是一个指针. BSTR p = L"Hello World!" 编译是没问题的.不过不推荐这么做.因为按MSDN,BSTR应该只接收 SysAllocString 的返回值. 就是说,第一,SysAllocString 的返回值是一个BSTR. 第二,如果我们看到一个BST

爪哇国新游记之十六----泛型单链表类

/** * 单链表节点类 * @param <T> */ class Node<T extends Object>{ protected T value; protected Node next; } /** * 单链表类 * @param <T> */ public class ChainList<T extends Object>{ private Node<T> first; public void addTail(T t){ Node&l

[ExtJS学习笔记]第六节 Extjs的类系统Class System命名规则及定义和调试

本文地址: http://blog.csdn.net/sushengmiyan/article/details/38479079 本文作者:sushengmiyan -------------------------------------------------------------资源链接----------------------------------------------------------------------- 翻译来源  Sencha Cmd官方网站:    http:

(转)Inno Setup入门(十六)——Inno Setup类参考(2)

本文转载自:http://blog.csdn.net/yushanddddfenghailin/article/details/17250967 这里将接着在前面的基础上介绍如何在自定义页面上添加按钮.按钮属于Tbutton类,该类继承自TbuttonControl,类定义如下: TButton = class(TButtonControl) property Cancel: Boolean; read write; property Caption: String; read write; p

第六周(友元类)

/* *copyright(c) 2015,烟台大学计算机学院 *All rights reserved. *文件名称:第六周(友元类) *作者:王忠 *完成日期:2015.4.14 *版本号:v1.0 * *问题描述:定义下面两个类的成员函数(为体验友元类,实际上本例并不一定是一个好的设计,将两个类的合并为一个DateTime,日期.时间都处理更好) *输入描述: *程序输出: #include <iostream> using namespace std; class Date; //对D

谈ATL(一)--说说ATL字符串转换类

大家在使用ATL技术做项目时,一定发现了非常麻烦的字符串字符集问题,下面把常用点和重点记录罗列一下,以备查. ATL提供了许多字符串转换函数,如果编译选项使得源和目的的字符类型相同,那么这些类不执行任何转换,关于设置系统编译项的问题前面windows编程的文章中已经介绍过.如果要使用ATL的字符转换类,那么必须要包含<atlconv.h>文件,转换的具体方式均是通过宏定义(宏函数)来完成,为了更好的列出这些宏函数及明确其功能,需要先说明一下都有哪些字符串类型以及他们的缩写形式: T表示一个指向

谈ATL(四)--VARIANT类型与CComVariant

ATL为了更好的让用户体验便捷并使程序的接口参数更加通用.灵活,引入了一种叫做VARIANT的数据类型,这个类型是通过一个结构体来定义的,如果不仔细阅读VARIANT结构体的定义,那么就不能体会编写者的良苦用心,更无法体会CComVariant设计的美妙,有时候用艺术的眼光欣赏程序,他们并不枯燥,相反他们真的很美. 下面是VARIANT结构体的定义,该定义在<OAIDL.h>中. typedef struct tagVARIANT VARIANT; struct  tagVARIANT   

谈ATL(五)--SAFEARRAY与CComSafeArray

在使用ATL编程的时候,常常会用到CComSafeArray类,该类是SAFEARRAY存在和使用了一段时间后才发布的,所以在VC++6.0版本的IDE环境中无法使用CComSafeArray类,在VC++6.0后来的版本中altsafe.h这个文件被添加进来,同时CComSafeArray类也随着这个文件的加入而加入到了ATL中.