使用与返回SafeArrays(一)

原创: Jeff Louie 摘自:http://www.geocities.com/ 翻译:叉叉(kchjxx)

好像再也没有比SafeArrays更易混淆的概念了。首先,这方面的文档相当稀缺;其次,SafeArrays 可以盛放指向系统堆上分配的资源的指针。你可以把SafeArrays当作一个可以包含数组信息的VB Array,当然,你也可以把SafeArrays 当作一个高安全级别的封装类。在ASP COM编程中,SafeArrays可以封装数据给脚本使用,在从COM组件向ASP或脚本对象传值时非常有用,列表(List)可以得到有效的传递了。下面是一些例子(带有注释),这些例子是经过我对文档和源码精心研究后得出了,它们表达了我对SafeArrays及其内存分配最好的理解。

SafeArrayPutElements构建SafeArray

你可以通过SafeArrayPutElements把元素放进SafeArray中,这样简化了数据访问,但是增大了构建数组的开销。常用到的是构建一个VT_BSTR型的VARIANTSafeArray,这样一个复杂的结构需要与各种脚本语言兼容。要想让这样一个结构被脚本使用,还是有点困难。

在下面的例子中,我构建了一个拥有10个元素的SafeArray,把元素索引用 ltoa()转换ANSI编码字符串,然后再通过ATL转换宏A2WANSI编码字符串转成Unicode编码的,最后通过字符串长度,在系统堆上分配确定长度的内存空间,把Unicode转成BSTR,并返回该字符串指针。这也可以通过A2BSTR得到,但是这个宏隐藏了内存的分配,因为我要演示内存的分配。

这个很重要的指针是COM组件中BSTR在内存中的地址。当作为[out, retval]返回时,调用了脚本引擎去释放字符串在系统中的真实内存。你可以把BSTR当作在COM组建中调用new()和在脚本中调用delete()。这个例子是创建一个BSTR VARIANTsSafeArray的复杂的过程。

USES_CONVERSION;
char  buffer[ 20 ];
HRESULT hr
=  S_OK;

//  Create SafeArray of VARIANT BSTRs
SAFEARRAY  * pSA;
SAFEARRAYBOUND aDim[
1 ];
aDim[
0 ].lLbound =   0 ;
aDim[
0 ].cElements =   10 ;
pSA
=  SafeArrayCreate(VT_VARIANT, 1 ,aDim);
if  (pSA  !=  NULL)  {
    _variant_t vOut;
    
for (long l= aDim[0].lLbound; l< (aDim[0].cElements + aDim[0].lLbound); l++{
        ltoa(l,buffer,
10);
        vOut
= A2W(buffer);  // assignment operator automates memory allocation for BSTR
        if (hr= SafeArrayPutElement(pSA, &l, &vOut)) {
            SafeArrayDestroy(pSA); 
// does a deep destroy on error
            return hr;
        }

    }

}

//  clean up here only if you do not return SafeArray as an [out, retval]
SafeArrayDestroy(pSA);  //  again does a deep destroy

根据我所阅读的文档,这个重要的指针就是SafeArrayPutElement正确拷贝这个VARIANTSafeArray中了,估计是通过对BSTR的深拷贝。所有SafeArray中存在的元素都会被合理的释放。为了避免内存泄漏,你必须在每次PUT之后,从源VARIANT上调用VariantClear()来回收分配给源BSTR的内存。

_variant_t类是类似于CComVariant的一个自动内存管理的包装类。既然重载运算符可以将Unicode字符串转成BSTR,那么使用_variant_t可以大大的简化上面的代码。


      
_variant_t& operator=(const wchar_t* pSrc) throw(_com_error); // Assign a VT_BSTR


    
为了使用_variant_t类,你必须在头文件中加入#include <comdef.h>。我在简化的版本中消除了the array of longs,在我阅读了Shelley Powers "Developing ASP Components Second Edition",构建了下面的代码:

USES_CONVERSION;   //  enables use of ATL conversion macro A2W
char  buffer[ 20 ];   //  used to store ANSI string
HRESULT hr =  S_OK;

//  Create SafeArray of VARIANT BSTRs
SAFEARRAY  * pSA;
SAFEARRAYBOUND aDim[
1 ];     //  a one dimensional array
aDim[ 0 ].lLbound =   0 ;   //  Visual Basic arrays start with index 0
aDim[ 0 ].cElements =   10 ;
pSA
=  SafeArrayCreate(VT_VARIANT, 1 ,aDim);   //  create a 1D SafeArray of VARIANTS
if  (pSA  !=  NULL)  {
    
long aLong[1];
    
// iterate over array adding VARIANTs of type VT_BSTR
    for (long l= aDim[0].lLbound; l< (aDim[0].cElements + aDim[0].lLbound); l++{
        VARIANT vOut;
        VariantInit(
&vOut);
        vOut.vt
= VT_BSTR;  // set type
        ltoa(l,buffer,10);  // convert long to ANSI string value
        vOut.bstrVal= ::SysAllocString(A2W(buffer)); // system wide "new"
        aLong[0]= l;  // set index value
        if (hr= SafeArrayPutElement(pSA, aLong, &vOut)) // "correctly" copies VARIANT
            VariantClear(&vOut);  // release BSTR from memory on error
            SafeArrayDestroy(pSA); // does a deep destroy on error
            return hr;
        }

        VariantClear(
&vOut);  // does a deep destroy of source VARIANT
    }
 // end iteration
}

//  clean up here only if you do not return SafeArray as an [out, retval]
SafeArrayDestroy(pSA);  //  again does a deep destroy
< 未完待续 >

转载请注明出处

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值