Dll中SAFEARRAY内存泄漏的问题

cs_dn_net 2014-10-16 09:02:28
要写个DLL给VB调用,实现从VB中传入一个动态数组,DLL中进行处理及调整数组大小后返回。
C++中的测试代码如下:
__declspec(dllexport) long __stdcall TestArr(LPSAFEARRAY *VbArray,long nNewEle)
{
LPSAFEARRAY pSa;
SAFEARRAYBOUND iBound;
iBound.lLbound = 0; // 数组起始位
iBound.cElements = nNewEle; // 数组元素
long nPreEle(0);
if (*VbArray == NULL){
if ((pSa = SafeArrayCreate(VT_I4,1,&iBound)) == NULL) return -1;// 创建SafeArray描述符
try{
nPreEle = (*VbArray)->rgsabound->cElements;
}catch(...){
nPreEle = 0;
}
*VbArray = pSa;// 返回SafeArray描述符
}else{
if ((*VbArray)->cDims != 1) return -1;//一维数组
nPreEle = (*VbArray)->rgsabound->cElements;
}
long *pNew=(long *)malloc(nNewEle*sizeof(long));
if (pNew != NULL) {
memset(pNew,0,nNewEle*sizeof(long));
if (nPreEle>0) {//复制原数组元素
long *pData = NULL;
SafeArrayAccessData(*VbArray,(LPVOID *)&pData);
if (pData != NULL) {
if (nPreEle<=nNewEle) {
memcpy(pNew,pData,nPreEle*sizeof(long));
} else {
memcpy(pNew,pData,nNewEle*sizeof(long));
}
}
SafeArrayUnlock(*VbArray);
}
for(long i=nPreEle; i<nNewEle; i++)
pNew[i]=nNewEle-i;
SafeArrayRedim(*VbArray,&iBound);
(*VbArray)->pvData = pNew;
return 1;
}else{
return -1;
}
}


VB中的测试代码如下:

Private Declare Function TestArr Lib "ArrTest.dll" (nArr() As Long, ByVal nNewEle As Long) As Long

Private Sub Command1_Click()
Dim nArr() As Long, n As Long
n = TestArr(nArr, 15000)
Debug.Print n,
n = TestArr(nArr, 90)
Debug.Print n,
'n = TestArr(nArr, 600)
'Debug.Print n
End Sub


由于内存没有释放,VB中运行到TestArr(nArr, 600)时就崩溃了。
请问在DLL的代码中,原来(*VbArray)->pvData所指向的内存怎么释放?
...全文
188 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
redui 2014-10-17
  • 打赏
  • 举报
回复
需要重定义数组大小时,仍然使用SafeArrayCreate创建新的内存,然后把旧的数据复制过来,再让SAFEARRAY包含新内存指针,用SafeArrayDestroy释放旧内存即可
cs_dn_net 2014-10-17
  • 打赏
  • 举报
回复
LPSAFEARRAY pSa定义的这个SAFEARRAY是在传过来的*VbArray未初始化时去才创建的。 上面的代码只是测试,实际程序中根据需要数组大小可能要调整很多次,每次都要保留已有的数据,就像VB中的Redim Preserve。用malloc来分配内存,调整时就可以用realloc了。 你有更好的方法吗?
redui 2014-10-17
  • 打赏
  • 举报
回复
引用 4 楼 cs_dn_net 的回复:
我这样子处理,可以吧
	long *pNew=(long *)malloc(nNewEle*sizeof(long));
	if (pNew != NULL) {
		memset(pNew,0,nNewEle*sizeof(long));
		long *pData = NULL;
		if( SUCCEEDED( SafeArrayAccessData(*VbArray,(LPVOID *)&pData) ) ){
			if (nPreEle>0) {//复制原数组元素
				if (nPreEle<=nNewEle) {
					memcpy(pNew,pData,nPreEle*sizeof(long));
				} else {
					memcpy(pNew,pData,nNewEle*sizeof(long));
				}
			}
			SafeArrayUnlock(*VbArray);
			for(long i=nPreEle; i<nNewEle; i++)
				pNew[i]=nNewEle-i;
			SafeArrayRedim(*VbArray,&iBound);//重定大小
			if ( SUCCEEDED( SafeArrayAccessData(*VbArray,(LPVOID *)&pData) ) ) {//重获指针
				memcpy(pData,pNew,nNewEle*sizeof(long));
				nPreEle=1;
			}else{nPreEle=-1;}
		}else{nPreEle=-1;}
		SafeArrayUnaccessData(*VbArray);
		free(pNew);
		return nPreEle;
	}else{return -1;}
你这个pNew完全是多余的,为啥要多一个拷贝环节? 两个SAFEARRAY都获取到内存指针,直接对拷不行吗?
会思考的草 2014-10-17
  • 打赏
  • 举报
回复
我建议秉承两个原则: 1,谁分配,谁释放,职权清晰。既然是DLL中分配的,DLL再提供一个函数用于释放数组。 2,用什么方法分配的,就用什么方法释放,malloc和free,new和delete操作符,必须成对。这隐约呼应了第一点,假如dll中负责分配内存,在另一个模块中释放,由于dll的代码没有公开,很容易就带来问题即释放的时候不知道该用delete还是free,用错了就会带来一些很难排查的问题,尽管可以在dll的头文件函数注释中写上该用什么方法释放,但是依然会有被漏看的可能性。
cs_dn_net 2014-10-17
  • 打赏
  • 举报
回复
我这样子处理,可以吧
	long *pNew=(long *)malloc(nNewEle*sizeof(long));
	if (pNew != NULL) {
		memset(pNew,0,nNewEle*sizeof(long));
		long *pData = NULL;
		if( SUCCEEDED( SafeArrayAccessData(*VbArray,(LPVOID *)&pData) ) ){
			if (nPreEle>0) {//复制原数组元素
				if (nPreEle<=nNewEle) {
					memcpy(pNew,pData,nPreEle*sizeof(long));
				} else {
					memcpy(pNew,pData,nNewEle*sizeof(long));
				}
			}
			SafeArrayUnlock(*VbArray);
			for(long i=nPreEle; i<nNewEle; i++)
				pNew[i]=nNewEle-i;
			SafeArrayRedim(*VbArray,&iBound);//重定大小
			if ( SUCCEEDED( SafeArrayAccessData(*VbArray,(LPVOID *)&pData) ) ) {//重获指针
				memcpy(pData,pNew,nNewEle*sizeof(long));
				nPreEle=1;
			}else{nPreEle=-1;}
		}else{nPreEle=-1;}
		SafeArrayUnaccessData(*VbArray);
		free(pNew);
		return nPreEle;
	}else{return -1;}
cs_dn_net 2014-10-16
  • 打赏
  • 举报
回复
怎么改?这类API我不熟悉。
redui 2014-10-16
  • 打赏
  • 举报
回复
保证只用SafeArrayCreate之类的API来管理数组内存,千万别跟malloc之类的函数混用,它们使用了不同的堆来创建内存,一旦混用,不崩溃才是怪事

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧