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

Sat*_*uru 5 com dcom bstr visual-c++-6 visual-c++

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

更新 5:

真正的代码。这基于特定条件从 DB 的一堆数据中获取以填充对象数组。

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;
}
Run Code Online (Sandbox Code Playgroud)

问题在于内存释放部分。该代码在任何 Win XP 机器上都可以正常工作,但是当涉及到 WIN2K8 R2 和 WIN7 时,代码崩溃并指向 ::SysFreeString() 作为罪魁祸首。MSDN 不足以解决问题。

任何人都可以帮助找到正确的解决方案吗?

非常感谢提前:)

更新 1:

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

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

更新 3: 我厌倦了所有的选择,但我心里只有一个问题

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

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

“可能的堆损坏”

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

Sat*_*uru 2

最后我找到了代码中发生堆损坏的真正原因。

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
}
Run Code Online (Sandbox Code Playgroud)

恶魔般的代码行才是导致内存陷入困境的真正罪魁祸首。

是什么造成了麻烦?

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

还有什么问题没有解决?

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

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

  • 你的分析偏离了大约一英里。系统可以毫无问题地跨公寓边界对 BSTR 进行编组。您的问题是“SysReAllocString”更新了**临时**(“&amp;bstrString”)。当“TrimBSTR”返回“bstrCityName”时,它指向一个可能不再存在的字符串。要修复您的错误,可以更改“TrimBSTR”的签名以采用“BSTR*”,或者从“TrimBSTR”返回“bstrString”的更新值(它是如何编译的?)。 (5认同)