1. BSTR使用注意事项
1.1 BSTR是什么?
l BSTR的定义
typedef OLECHAR *BSTR;
从定义看,BSTR实质就是一个指向字符串的指针,它指向字符串的首地址。在32位Windows系统中,BSTR指向的是以NULL为结束的Unicode字符串。
l BSTR的内存结构
与一般的字符串不一样的是,BSTR指向的字符串是带前缀的,前缀是一个DWORD(32位)的内存空间,保存的是字符串的字节长度(注意,不是字符串的长度,并且不包括NULL结束符占用的空间),这个长度值是利用BSTR专用的函数族分配空间的同时填写的。
1.2 BSTR的特殊性
l BSTR字符串可以内嵌零个或多个NULL,因为决定其长度的不是NULL,而是其前缀保存的数值,所以不能以NULL来判断字符串的结束。;
l 必须用SysAllocString()和SysFreeString()函数族来分配和释放,用SysStringLen()等取得字符串的长度;
1.3 BSTR相关函数族
l 内存分配和重分配函数
SysAllocString
SysAllocStringLen
SysAllocStringByteLen
SysReAllocString
SysReAllocStringLen
注:通过以上函数分配空间的同时将根据字符串实际占用的字节数填写前缀
l 字符串释放函数
SysFreeString
注:这个函数的参数可以传入NULL,即在调用此函数时可以不用判断参数是否为NULL
l 字符串(占用空间)长度函数
SysStringLen
SysStringByteLen
1.4 如何避免BSTR造成的内存泄漏
l 对于BSTR的管理(申请、释放和计算长度)严格使用上述对应的函数族,不要使用new、delete、CoTaskMemAlloc、CoTaskMemFree、sizeof 等。
l 不要在BSTR字符串中嵌入NULL
l 定义BSTR时要赋初值NULL
BSTR bstr = NULL;
l 调用SysFreeString后要给bstr赋NULL
SysFreeString(bstr);
bstr = NULL;
l 不要给BSTR直接初始化字符串
BSTR bstr = L“kkkkkk”; -à BSTR bstr = SysAllocString (L“kkkkkk”);
因为直接初始化字符串时前缀的值可能是一个随机数,这样的话,其他地方使用这个BSTR时将无法决定出字符串的长度,特别在跨进程传送数据时将会出现致命错误。
l 在给一个BSTR赋值前,如果不能确定它目前是否指向一个有效的空间,最好先调一下SysFreeString,如:
SysFreeString(bstr);
bstr = SysAllocString(L“kkkkkk”);
l 不要将一个BSTR通过“=”赋给另一个BSTR
bstr1 = bstr2 -à bstr1 = SysAllocString(bstr2);
避免调用SysFreeString(bstr1)和SysFreeString(bstr2)对同一块内存空间释放两次。
l 参数为[out]的BSTR注意点
比如函数GetBSTR([out] BSTR* bstr)
1、 对于客户端
BSTR bstr = NULL;// 传入的bstr必须为NULL
GetBSTR(&bstr);
。。。。。。
SysFreeString(bstr);// 使用完bstr后别忘了释放
bstr = NULL;
2、 对于服务端
HRESULT GetBSTR(BSTR* bstr)
{
// 一般来说,传入的bstr不指向任何空间应该由客户端保证的,所以下面的判断和释放不是必须的,但有的话可能更安全。
if ( NULL != *bstr )
SysFreeString(*bstr);
// 创建成员变量的拷贝,不要将其值直接给出去(特别对于进程内组件)
*bstr = m_bstr; -à *bstr = SysAllocString( m_str );
}
l 参数为[in]的BSTR注意点
HRESULT SetBSTR(/*[in]*/ BSTR bstr){
// 如果服务器需要保存传入的bstr供以后使用,必须将成员变量释放,然后重新分配。
SysFreeString(m_bstr);
m_bstr = bstr; -à m_bstr = SysAllocString( bstr );
}
l 参数为[out]的数据结构中包含BSTR的注意点
typedef struct kk{
long i;
BSTR bstr;
} KK;
KK param;
param.bstr = NULL;
GetKK(¶m);
。。。。。。
SysFreeString(param .bstr);// 这种内嵌在结构体内的BSTR非常容易忽略释放
param .bstr = NULL;
l BSTR作为SysAllocString或SysReAllocString的参数时的注意点
如果bstr作为SysAllocString或SysReAllocString的参数传入,并且不确定这个传入的bstr是否包含内嵌NULL时,为保险起见,请务必改用下面两函数。
SysAllocStringLen
SysReAllocStringLen
原因:因为上述4个函数的参数类型都是OLECHAR FAR* 而不是BSTR,但后两个函数多了传入数量的参数。
1.5 BSTR的ATL封装类CCOMBSTR
建议:必须在非常清楚CComBSTR各个函数(特别是赋值操作符和构造函数)如何使用和注意事项的情况下才使用它,否则建议使用BSTR,因为使用不慎非常容易造成内存泄漏。
1.1 BSTR是什么?
l BSTR的定义
typedef OLECHAR *BSTR;
从定义看,BSTR实质就是一个指向字符串的指针,它指向字符串的首地址。在32位Windows系统中,BSTR指向的是以NULL为结束的Unicode字符串。
l BSTR的内存结构
与一般的字符串不一样的是,BSTR指向的字符串是带前缀的,前缀是一个DWORD(32位)的内存空间,保存的是字符串的字节长度(注意,不是字符串的长度,并且不包括NULL结束符占用的空间),这个长度值是利用BSTR专用的函数族分配空间的同时填写的。
1.2 BSTR的特殊性
l BSTR字符串可以内嵌零个或多个NULL,因为决定其长度的不是NULL,而是其前缀保存的数值,所以不能以NULL来判断字符串的结束。;
l 必须用SysAllocString()和SysFreeString()函数族来分配和释放,用SysStringLen()等取得字符串的长度;
1.3 BSTR相关函数族
l 内存分配和重分配函数
SysAllocString
SysAllocStringLen
SysAllocStringByteLen
SysReAllocString
SysReAllocStringLen
注:通过以上函数分配空间的同时将根据字符串实际占用的字节数填写前缀
l 字符串释放函数
SysFreeString
注:这个函数的参数可以传入NULL,即在调用此函数时可以不用判断参数是否为NULL
l 字符串(占用空间)长度函数
SysStringLen
SysStringByteLen
1.4 如何避免BSTR造成的内存泄漏
l 对于BSTR的管理(申请、释放和计算长度)严格使用上述对应的函数族,不要使用new、delete、CoTaskMemAlloc、CoTaskMemFree、sizeof 等。
l 不要在BSTR字符串中嵌入NULL
l 定义BSTR时要赋初值NULL
BSTR bstr = NULL;
l 调用SysFreeString后要给bstr赋NULL
SysFreeString(bstr);
bstr = NULL;
l 不要给BSTR直接初始化字符串
BSTR bstr = L“kkkkkk”; -à BSTR bstr = SysAllocString (L“kkkkkk”);
因为直接初始化字符串时前缀的值可能是一个随机数,这样的话,其他地方使用这个BSTR时将无法决定出字符串的长度,特别在跨进程传送数据时将会出现致命错误。
l 在给一个BSTR赋值前,如果不能确定它目前是否指向一个有效的空间,最好先调一下SysFreeString,如:
SysFreeString(bstr);
bstr = SysAllocString(L“kkkkkk”);
l 不要将一个BSTR通过“=”赋给另一个BSTR
bstr1 = bstr2 -à bstr1 = SysAllocString(bstr2);
避免调用SysFreeString(bstr1)和SysFreeString(bstr2)对同一块内存空间释放两次。
l 参数为[out]的BSTR注意点
比如函数GetBSTR([out] BSTR* bstr)
1、 对于客户端
BSTR bstr = NULL;// 传入的bstr必须为NULL
GetBSTR(&bstr);
。。。。。。
SysFreeString(bstr);// 使用完bstr后别忘了释放
bstr = NULL;
2、 对于服务端
HRESULT GetBSTR(BSTR* bstr)
{
// 一般来说,传入的bstr不指向任何空间应该由客户端保证的,所以下面的判断和释放不是必须的,但有的话可能更安全。
if ( NULL != *bstr )
SysFreeString(*bstr);
// 创建成员变量的拷贝,不要将其值直接给出去(特别对于进程内组件)
*bstr = m_bstr; -à *bstr = SysAllocString( m_str );
}
l 参数为[in]的BSTR注意点
HRESULT SetBSTR(/*[in]*/ BSTR bstr){
// 如果服务器需要保存传入的bstr供以后使用,必须将成员变量释放,然后重新分配。
SysFreeString(m_bstr);
m_bstr = bstr; -à m_bstr = SysAllocString( bstr );
}
l 参数为[out]的数据结构中包含BSTR的注意点
typedef struct kk{
long i;
BSTR bstr;
} KK;
KK param;
param.bstr = NULL;
GetKK(¶m);
。。。。。。
SysFreeString(param .bstr);// 这种内嵌在结构体内的BSTR非常容易忽略释放
param .bstr = NULL;
l BSTR作为SysAllocString或SysReAllocString的参数时的注意点
如果bstr作为SysAllocString或SysReAllocString的参数传入,并且不确定这个传入的bstr是否包含内嵌NULL时,为保险起见,请务必改用下面两函数。
SysAllocStringLen
SysReAllocStringLen
原因:因为上述4个函数的参数类型都是OLECHAR FAR* 而不是BSTR,但后两个函数多了传入数量的参数。
1.5 BSTR的ATL封装类CCOMBSTR
建议:必须在非常清楚CComBSTR各个函数(特别是赋值操作符和构造函数)如何使用和注意事项的情况下才使用它,否则建议使用BSTR,因为使用不慎非常容易造成内存泄漏。