使用:: SysFreeString()释放BSTR。更多平台依赖?

时间:2012-02-27 14:49:54

标签: visual-c++ com vc6 dcom bstr

我正在编写一个具有大量接口和方法的COM服务器。并且大多数方法具有BSTR作为参数以及用于返回的本地参数。一个片段看起来像

更新5:

真实的代码。这是根据DB填充Object数组的特定条件从一堆数据中获取的。

STDMETHODIMP CApplication::GetAllAddressByName(BSTR bstrParamName, VARIANT *vAdddresses)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState())

//check the Database server connection

COleSafeArray saAddress;
HRESULT hr;

// Prepare the SQL Strings dan Query the DB

long lRecCount = table.GetRecordCount();

 if (lRecCount > 0)
 {
    //create one dimension safe array for putting  details
    saAddress.CreateOneDim(VT_DISPATCH,lRecCount);

    IAddress *pIAddress = NULL; 
    //retrieve details 
    for(long iRet = table.MoveFirst(),iCount=0; !iRet; iRet = table.MoveNext(),iCount++)
    {
        CComObject<CAddress> *pAddress;
        hr = CComObject<CAddress>::CreateInstance(&pAddress);
        if (SUCCEEDED(hr))
        {   
            BSTR bstrStreet = ::SysAllocString(table.m_pRecordData->Street);
            pAddress->put_StreetName(bstrStreet);

            BSTR bstrCity = ::SysAllocString(table.m_pRecordData->City);
            pAddress->put_CityName(bstrCity);
        }
        hr = pAddress->QueryInterface(IID_IAddress, (void**)&pIAddress);
        if(SUCCEEDED(hr)) 
        {
            saAddress.PutElement(&iCount,pIAddress); 
        }
    }
    *vAdddresses=saAddress.Detach(); 
}
table.Close(); 
return S_OK;
}


STDMETHODIMP CAddress::put_CityName(BSTR bstrCityName)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState())
    // m_sCityName is of CComBSTR Type
    m_sCityName.Empty();//free the old string 
    m_sCityName = ::SysAllocString(bstrCityName);//create the memory for the new string
    return S_OK;
}

问题出在Memory Freeing部分。代码在任何Win XP机器上都能正常工作,但是当涉及到WIN2K8 R2和WIN7时,代码崩溃并指向:: SysFreeString()作为罪魁祸首。 MSDN不适合解决方案。

有人可以帮助找到合适的解决方案吗?

提前多多感谢:)

更新1:

我已尝试按照原始BSTR位置的建议使用CComBSTR,使用直接CString初始化并排除SysFreeString()。但是对于我的麻烦,在超出范围时系统调用SysFreeString()再次导致崩溃:(

更新2: 使用相同的CComBSTR,我尝试使用SysAllocString()进行分配,问题仍然存在:(

更新3: 我厌倦了所有的选择,在和平中,我只有一个问题

  

是否有必要通过SysFreeString()释放BSTR   使用SysAllocString()/ string.AllocSysString()?

分配

更新4: 我错过了提供有关崩溃的信息。当我尝试调试COM服务器崩溃时出现错误

  

“可能的堆腐败”

。请帮助我离开这里.. :(

2 个答案:

答案 0 :(得分:2)

// Now All Things are packed in to the Object
obj.Name = bstrName;
obj.Name2 = bstrname2;

我不太明白你说的是什么意思,因为你只是复制指向字符串的指针,并且当你调用SysFreeString obj.Name和obj.Name2指向无效时记忆块。虽然这段代码不安全,但看起来你的问题来源是CFoo类。您应该向我们展示您的代码的更多细节

我建议您使用CComBSTR类,它将负责释放内存。

<强>更新

#include <atlbase.h>
using namespace ATL;
...
{
    CComBSTR bstrname(_T("Some Name")); 
    CComBSTR bstrname2(_T("Another Name"));
    // Here one may work with these variables if needed
    ...
    // Copy the local values to the Obj's member Variable 
    bstrname.Copy(&obj.Name); 
    bstrname2.Copy(&obj.Name2);
}

<强> UPDATE2 首先,应该使用SysFreeString释放bstrCity和bstrStreetName,或者在此块中使用CComBSTR:

if (SUCCEEDED(hr))
{   
    BSTR bstrStreet = ::SysAllocString(table.m_pRecordData->Street);
    pAddress->put_StreetName(bstrStreet);

    BSTR bstrCity = ::SysAllocString(table.m_pRecordData->City);
    pAddress->put_CityName(bstrCity);

    // SysFreeString(bstrStreet)
    // SysFreeString(bstrCity)
} 

考虑放大循环的条件!iRet与iCount&lt; lRecCount。

for(...; !iRet /* && (iCount < lRecCount) */; ...)

另外,这里:

m_sCityName = ::SysAllocString(bstrCityName);

你分配内存但从未在内部发布CComBSTR&amp; operator =(OLESTR ..)自己分配一个新存储。应该重写如下:

m_sCityName = bstrCityName;

其他一切,对我来说都很好

<强> UPDATE3 好吧,堆损坏通常是在分配的内存块之外写入一些值的结果。假设你分配一个长度为5的数组并将一些值放到第6个位置

答案 1 :(得分:1)

最后,我找到了代码中发生的堆腐败的真正原因。

IAddress / CAddress的put_StreetName / put_CityName按以下方式设计。

STDMETHODIMP CAddress::put_CityName(BSTR bstrCityName)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState())

    m_sCityName.Empty();
    TrimBSTR(bstrCityName);
    m_sCityName = ::SysAllocString(bstrCityName);

    return S_OK;
}

BSTR CAddress::TrimBSTR(BSTR bstrString)
{
    CString sTmpStr(bstrString);
    sTmpStr.TrimLeft();
    sTmpStr.TrimRight();
    SysReAllocString(&bstrString,sTmpStr);  // The Devilish Line
}

恶魔的代码行是造成记忆地狱的真正罪魁祸首。

是什么造成了麻烦?

在这行代码中,作为参数传递的BSTR字符串来自另一个应用程序,而实际内存位于另一个域中。所以系统正在尝试重新分配字符串。无论是否成功,都会尝试从原始应用程序/域中的内存中清除,从而导致崩溃。

还有什么尚未解决?

  

为什么同一段代码在Win XP和Windows XP中没有崩溃一次   旧系统? :(

感谢所有花时间回答并解决问题的人:)