封装了一个类库,类库中调用一个webservice的atl代理类,程序退出时,会出现内存不能为读错误,大家帮忙!谢谢

小小的一株含羞草 2007-05-24 11:18:13
大概思路是这样的:
我们的用户鉴权功能是由C#写的一个Web Service提供,为了方便VC的客户端使用,打算将对WebService的引用封装在一个类库中。
但是偶用vc写的一个自测程序去调用封装后的类库,在退出时就会出现“内存不能为读”的错误提示;

偶试了两种情况:
1、如果直接在自测程序中添加Web引用,然后直接调用自动生成的WebService的ATL代理类,退出时就不会出现这样的错误;
2、在类库中调用这个ATL代理类时,如果输出参数传递一个NULL,退出时也不会出现这个错误。

所以,初步确定应该是输出参数的释放有问题,但偶试了好久,也还是有“内存不能为读”的错误提示,不知道错在哪里了?大家帮忙看看,谢谢

封装的类库中的部分代码如下:
其中,m_pWS是atl代理类指针,在类库构造时创建,析构时释放;


// ***************************************************************
// 函数名称:CheckUser
// 功能描述:验证用户登录
// 访问的表:无
// 修改的表:无
// 输入参数:const CString& sUserid - 用户名称
// const CString& sUserpwd - 用户密码
// BYTE nSysfuncid - 是否能登录该子系统的系统功能编号
// 输出参数:bool* bRtn - 执行是否成功
// 返回值:CString - 输出信息
// 其它说明:无
// ***************************************************************
CString CAuthority::CheckUser(const CString& sUserid, const CString& sUserpwd , BYTE nSysfuncid, bool* bRtn)
{
HRESULT hr = S_OK;
CComBSTR bstrUserid = sUserid;
CComBSTR bstrUserpwd = sUserpwd;
CComBSTR bstrMsg = NULL;//static_cast< LPCOLESTR>(NULL);
bstrMsg.Empty();

hr = m_pWS->CheckUser(bstrUserid, bstrUserpwd, nSysfuncid, bRtn, &bstrMsg);

// 获取返回值
CString sMsg(bstrMsg == NULL ? L"" : bstrMsg);

return sMsg;
}
...全文
426 点赞 收藏 11
写回复
11 条回复
编程乐趣 2011年08月13日
无意看到这个帖子,我的程序也会偶尔,出现“内存不能为读”的错误提示。

我也是直接delete,马上更改。。
回复 点赞
小小的一株含羞草 2007年05月26日
To samsun2000(美女都结婚了) :
你太有才了,确实是这个问题,释放时改成如下两句:
// 释放WebService服务代理对象
m_pWS->Release();
m_pWS = NULL;

问题解决啦,^_^,多谢各位的鼎立相助!
回复 点赞
samsun2000 2007年05月25日
我不确定你通过new来生成代理对象是合理的。不过根据他在delete(就是说被析构)时调用Release()方法实现,说明它是一个COM智能指针类型。对COM中的东西都不该直接调用delete,应该通过调用Release()让他自己析构,智能指针也可以通过附NULL值间接调用Release()。

我给你分析一下违规内存访问的发生原因:
m_pWS是个智能指针(可参考CComPtr地实现,很可能他根本就是个CComPtr)。它内部维护着真正的代理对象的指针,就是你上面Release()方法里面的p呀。因为智能指针类型有个operator T()实现,所以你可以拿他当它内部的p用。你调用delete m_pWS;其实是调用的delete p,如此真正的对象就析构了(永远不要对智能指针调用delete),但智能指针m_pWS不知道。然后你有调用了m_pWS = NULL;你可以参考CComPtr的operator = (null)方法,他会去调用Release(),就是你最后列出来的void Release() throw(){}。可见,这时候pTemp是无效的内存,所以报了错误。


前面你讲的字符串问题是偶然的。就算你传空的输出参数结果不出错,只能说明微软现在的系统做得比较安全了。你可以尝试拿你的代码去Win98上跑,即使传空的输出参数怕也会报错。XP估计也会报错。

无论如何,你delete m_pWS;是绝对错误的操作。
回复 点赞
ys19011 2007年05月25日
确定你的m_pWS在delete之前是有效的吗?
还有你说到的输出参数是在调用程序还是DLL中分配、释放?
回复 点赞
wshcdr 2007年05月24日
MK
回复 点赞
fairyprince 2007年05月24日
一般来说在退出时报错,是由内存泄漏引起的

你的类库在处理,宽字符是否有问题,缓冲是否够用。
MultiByteToWideChar 不自动加大利\0 这个要注意
回复 点赞
小小的一株含羞草 2007年05月24日
构造函数:
CAuthority::CAuthority(void)
{
try
{
// WebService代理对象
m_pWS = new CWSAuthority;
}
catch(...)
{
}

// 可以调用SetUrl动态设置Web服务地址
CString strUrl = theApp.GetWebServiceUrl();
m_pWS->SetUrl(strUrl);
}

析构函数:
CAuthority::~CAuthority(void)
{
try
{
// 释放WebService服务代理对象
delete m_pWS;
m_pWS = NULL;
}
catch(...)
{
}
}

退出时是跟踪到delete m_pWS;这句出错,出错位置定位到atlcomcli.h文件中pTemp->Release();这句:
atlcomcli.h文件部分内容:
...
// Release the interface and set to NULL
void Release() throw()
{
T* pTemp = p;
if (pTemp)
{
p = NULL;
pTemp->Release();
}
}
...
回复 点赞
小小的一株含羞草 2007年05月24日
To: fairyprince(精灵王子)
检查过,应该是正确的,返回的信息都是正确的。
回复 点赞
teli_eurydice 2007年05月24日
看看是不是析构函数里面调用了虚函数
回复 点赞
fairyprince 2007年05月24日
hr = m_pWS->CheckUser(bstrUserid, bstrUserpwd, nSysfuncid, bRtn, &bstrMsg);
&bstrMsg 这里传的是CComBSTR指针,检查是否正确
回复 点赞
小小的一株含羞草 2007年05月24日
偶也觉得应该是有内存泄漏,但是就是不知道该怎么做才能不泄漏,呵呵
Web Service的代理类是.net自动生成的,偶自己封装的类中只是调用了一下,然后把输出参数转成CString返回,仅此而已,而且CComBSTR是智能指针,应该会自己释放内存的,好郁闷...
回复 点赞
发动态
发帖子
ATL
创建于2007-09-28

3025

社区成员

4.8w+

社区内容

ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。
社区公告
暂无公告