看流星社区

 找回密码
 注册账号
查看: 1692|回复: 0

BSTR原理及CComBSTR源码

[复制链接]

该用户从未签到

发表于 2014-6-14 16:01:00 | 显示全部楼层 |阅读模式
BSTR 是一个指向 UNICODE 字符串的指针,且 BSTR 向前的4个字节中,使用DWORD保存着这个字符串的字节长度( 没有含字符串的结束符)。因此系统就能够正确处理并传送这个字符串到“地球另一 边”了。特别需要注意的是,由于BSTR的指针就是指向 UNICODE 串,因此 BSTR 和 LPOLESTR (LPCOLESTR类型,是一个OLECHAR字符数组的常量指针。即该指针所指向的内容不能被修改)可以在一定程度上混用,但一定要注意:

有函数 fun(LPCOLESTR lp),则你调用 BSTR p=...; fun(p); 正确
有函数 fun(const BSTR bstr),则你调用 LPCOLESTR p=...; fun(p); 错误!!!(会提示:cannot convert parameter 1 from 'const unsigned short *' to 'unsigned short *const)。const BSTR bstr说明bstr是一个常量指针其指向不能改变,LPCOLESTR是一个指向常量的指针其指向的内容是常量。

有关 BSTR 的处理函数:

众所周知BSTR具有如下属性:
1.           BSTR是指向一个带有长度前缀的OLECHAR字符数组的指针。
2.           BSTR是指针数据类型,它指向字符数组的第一个字符。其长度是以整数存储在数组中第一个字符前面的位置(4个字节)。
3.           字符数组以NUL字符结束。
4.           前缀长度是指的字节长度,不包含结束符NUL。
5.           字符数组内部可能包含有效的NUL字符。

但是我们直接使用BSTR比较麻烦,需要自己手动分配释放内存,由如下两个函数完成:
str = ::SysAllocString() ,::SysFreeString(str),例如:
#include <iostream>
#include <atlbase.h>
using namespace std;
int main()
{
       BSTR p = ::SysAllocString(L"Hello,你好");
       return 0;
}
断点执行,然后观察p的内存)


含义如下:

为此我们可以考虑使用ATL提供的智能指针CComBSTR,在include\atlbase.h中可以找到其定义,如下:
// CComBSTR
我仅分析部分代码
class CComBSTR
{
public:  
       BSTR m_str;//被包装的BSTR成员

       CComBSTR()//默认构造函数
       {
              m_str = NULL;
       }

// explicit防止但参数构造函数的类型转换功能
//分配nSize+4字节的空间(未初始化)并把字符串首地址赋给m_str
       /*explicit*/ CComBSTR(int nSize)
       {
              m_str = ::SysAllocStringLen(NULL, nSize);
       }

//分配nSize+4字节的空间(初始化为sz)并把字符串首地址赋给m_str
       /*explicit*/ CComBSTR(int nSize, LPCOLESTR sz)
       {
              m_str = ::SysAllocStringLen(sz, nSize);
       }

       /*explicit*/ CComBSTR(LPCOLESTR pSrc)
       {
              m_str = ::SysAllocString(pSrc);
       }

//拷贝构造函数
//调用Copy()成员函数完成,典型的把公共操作封装为一个函数
       /*explicit*/ CComBSTR(const CComBSTR& src)
       {
              m_str = src.Copy();
       }

//将GUID转换成CComBSTR,见code2
       /*explicit*/ CComBSTR(REFGUID src)
       {
              LPOLESTR szGuid;
              StringFromCLSID(src, &szGuid);//将GUID转换成可打印的字符串
              m_str = ::SysAllocString(szGuid);
              CoTaskMemFree(szGuid);//释放StringFromCLSID中分配的内存
       }

//赋值运算符,注意返回的是一个引用,从而使得连续赋值成为可能
       CComBSTR& operator=(const CComBSTR& src)
       {
//如果=左右的值是一样就直接返回没有必要做其他步骤
              if (m_str != src.m_str)
              {
                     if (m_str)
                            ::SysFreeString(m_str);
                     m_str = src.Copy();
              }
              return *this;
       }

//下面的=运算符使得可以把一个LPCOLESTR赋值给CComBSTR
       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);
       }

//类型转换符,把一个CComBSTR强制转换成BSTR成为可能
       operator BSTR() const
       {
              return m_str;
       }

//重载的取地址运算符
       BSTR* operator&()
       {
              return &m_str;
       }

//辅助函数,一个公共操作函数
       BSTR Copy() const
       {
              return ::SysAllocStringLen(m_str, ::SysStringLen(m_str));
       }

//把智能指针CComBSTR所包裹的BSTR字符串拷贝到*pbstr中
       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;
       }

//让指针指针指向一个新的BSTR
       void Attach(BSTR src)
       {
              ATLASSERT(m_str == NULL);
              m_str = src;
       }

//把智能指针CComBSTR所包裹的BSTR指针取出来返回并把智能指针置空
       BSTR Detach()
       {
              BSTR s = m_str;
              m_str = NULL;
              return s;
       }
//置空
       void Empty()
       {
              ::SysFreeString(m_str);
              m_str = NULL;
       }

//重载的!运算符判断CComBSTR是否为空
       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;
        }
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-5-29 02:30

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表