在COM中,除了IUnknown的AddRef,Release(返回ULONG参数)特殊外,其它的任何函数都必须返回HRESULT.
所以就有了传入参数,传出参数.
如果传入传出的仅仅是基本类型的数据,如int,long,BYTE等,那也没有资源释放问题(由本地栈解决了).
如果传入传出的是一些Pointer,如BSTR,IDispatch&等那就存在一个资源释放的问题,可是它们该由那一方释放啊,还是双方都要释放.就像编译器指令__stdcall一样,规定了参数栈该由那一方恢复.下面举一个例子:
A组件:
idl片段:
HRESULT Hello([out]BSTR* bstrOut);
实现:
HRESULT Hello(BSTR* bstrOut){
*bstrOut=SysAllocString(OLESTR("Hello")); //需要释放该BSTR资源吗? 还是由调用者释放?
//SysFreeString(*bstrOut);
return S_OK;
} B组件:
idl片段:
HRESULT Goodbye([in]BSTR bstrIn); 实现:
HRESULT Goodbye(BSTR bstrIn){
....
//该方法调用者在方法返回时是否也要释放该资源?
SysFreeString(bstrIn);
return S_OK;
}请教各位大侠........
所以就有了传入参数,传出参数.
如果传入传出的仅仅是基本类型的数据,如int,long,BYTE等,那也没有资源释放问题(由本地栈解决了).
如果传入传出的是一些Pointer,如BSTR,IDispatch&等那就存在一个资源释放的问题,可是它们该由那一方释放啊,还是双方都要释放.就像编译器指令__stdcall一样,规定了参数栈该由那一方恢复.下面举一个例子:
A组件:
idl片段:
HRESULT Hello([out]BSTR* bstrOut);
实现:
HRESULT Hello(BSTR* bstrOut){
*bstrOut=SysAllocString(OLESTR("Hello")); //需要释放该BSTR资源吗? 还是由调用者释放?
//SysFreeString(*bstrOut);
return S_OK;
} B组件:
idl片段:
HRESULT Goodbye([in]BSTR bstrIn); 实现:
HRESULT Goodbye(BSTR bstrIn){
....
//该方法调用者在方法返回时是否也要释放该资源?
SysFreeString(bstrIn);
return S_OK;
}请教各位大侠........
BSTR的原形为: typedef OLECHAR *BSTR;
它是一个Pointer,如果作为COM方法的传出参数,那么传出的其实就是一个32位long值,该值指向一个OLECHAR的数组首地址.对于局部的方法而言,方法执行完后,会pop回该方所用的所有地址空间也就是说那个32位的long值释放了,但是它指向的资源却依旧没有释放也就是说发生了Memory Leak!
HRESULT Hello(/* [out]BSTR* */ BSTR* bstrOut){
*bstrOut=SysAllocString(OLESTR("Hello")); return S_OK;
}上面方法中的bstrOut是一个传出参数.
*bstrOut=SysAllocString(OLESTR("Hello")); SysAllocString(OLESTR("Hello"))该语句从操作系统获得一个BSTR资源,也就是说如下内存
结构不是在Hello方法的栈中分配的."Hello"的BSTR结构如下(其中的地址仅做假设):
040FF01 0
040FF02 o
040FF03 l
040FF04 l
040FF05 e
040FF06 H
040FF07 5
SysAllocString(OLESTR("Hello"))返回一个32位long值(又操作系统分配的),并将该值赋给
bstrOut.当方法结束时,bstrOut是会释放的,但是由操作系统分配的空间是不会自动释放的.
对于[out]参数,COM里面有个约定,由COM分配内存,由调用者来释放。
IInterface->Hello(&bstrOut);
//...
::SysFreeString(bstrOut); //显示释放或者:
BSTR bstrOut;
IInterface->Hello(&bstrOut);
//...
_bstr_t bstr(bstrOut, false); //由_bstr_t析构时来释放
非常感谢LeeZi,这个问题累我几天了.
对于out参数,组件用任务分配器分配,客户也要用任务分配器释放任务分配器是一个专门用于管理由组件分配的内存需要客户释放的问题,它是一个实现了IMalloc接口的组件。COM提供一个已有的实现。具体用法是:
组件内使用CoTaskMemAlloc,然后在客户端使用CoTaskMemFree(如果客户端是VB,运行时解释器自动调用)
如果要重新分配[in, out]参数的内存大小,组件内不要使用CoTaskMemAlloc而应使用CoTaskMemRealloc
对于BSTR类型,有专用的函数SysAllocString和SysFreeString