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 服务器时,出现错误提示
“可能的堆损坏”
. 请帮我离开这里.. :(
最后我找到了代码中发生堆损坏的真正原因。
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 和旧系统中一次不会崩溃?:(
感谢所有花时间回答和解决我的问题的人:)