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。 第二,如果我们看到一个BSTR,那它应该总从由一个 SysAllocString 得到的,它总是应该用 SysFreeString 释放。

 

我们可以想像,SysAllocString 实际上做了一个malloc分配了一块内存,然后把内存长度放第一个DWORD,把这个DWORD后面位置作为BSTR返回。因为在BSTR减4的位置已经保存了块长度,所以对BSTR不应该用 wcslen 之类的方法来得到它的长度,要用 SysStringLen。这就是为什么不推荐用 BSTR p = L"Hello World!"这种方法直接给BSTR赋值,因为这样得到到BSTR不符合减4位置有块长度的规范,也不能用 SysStringLen 得到长度,也不能用 SysFreeString 来释放。乱了规矩。


又一个问题,为什么需要 SysAllocString ? 我用 new 或 malloc 不行吗?因为用ATL常常是为了写COM。而COM控件是跨语言的。你用C++写一个COM控件,可能被HTML中的一个VBSCRIPT或PHP调用。你返回的那个BSTR字串可能需要在VBSCRIPT中释放。而 new 或 malloc 等常规的C++分配内存函数,都要求内存在本模块内释放。所以,SysAllocString 分析的内存,是为了支持跨模块使用,并在外地free的。


那么 CComBSTR 又是什么呢?上面讲了,BSTR只是一个指针,它太简单了。如果我要实现字串查找,字串合并等复杂的操作就要自己写代码了。于是就有了 CComBSTR这个类。它只有一个成员 BSTR m_str 但它有大量的方法函数,足够你所可能需要的所有字串操作。

最后结论:
  * BSTR 只是一个指针,要小心使用,除了 SysAllocString 不要对它赋值。
  * 如果发现一个 BSTR, 那它一定是用 SysAllocString 得到的。一定要用 SysStringLen 来得到长度。一定要用 SysFreeString 来释放它
  * 如果需要对 BSTR 做字串操作,把它变成 CComBSTR ,总有一个现成的函数直接使用。
  * 这一系列东西,都是为了COM跨模块把字串当作返回值使用的。如果一个字串只在本模块内有效,还是用 new 或 malloc 或 CString 来得简单。 

 

BSTR是非引用计数的,两次引用同一字符串的内容必须指向两个单独的BSTR,也就是说BSTR本身实现的是深拷贝。

按照COM规则,调用者负责释放传出[out]参数的内容。

CComVariant定义了33个赋值函数,所有都有如下步骤:

  1. 释放当前资源
  2. 设置新的vt
  3. 储存数据

所以下面代码会抛出异常:

STDMETHODIMP MyClass::get_somthing (VARIANT* pVal) {
    CComVariant val;
    long i = 5;
    val = i;

    // Wrong! The following code can generate an exception,
    // corrupt your heap, and give at least seven years bad luck!
    // Detach function will clear pVal first, but it doesn't initialize,
    // because [out] parameter doesn't.
    return val.Detach (pVal);
}

正确做法应该是:

STTDMETHODIMP MyClass:get_something (VARIANT* pVal) {
    CComVariant val;
    long i = 5;
    val = i;
    
    ::VariantInit(pVal);
    // or pVal->vt = VT_EMPTY;
    return val.Detatch(pVal);
}

改编自http://bbs.pediy.com/showthread.php?t=125705

posted on 2014-09-15 15:57  lys_lys_2009  阅读(288)  评论(0编辑  收藏  举报

导航