Освобождение BSTR с помощью :: SysFreeString (). Больше зависит от платформы? - PullRequest
2 голосов
/ 27 февраля 2012

Я пишу COM-сервер, который имеет множество интерфейсов и методов.И большинство методов имеют BSTR как параметры и как локальные параметры, используемые для возврата.Фрагмент выглядит как

Обновление 5:

Реальный код.Он извлекается из набора данных на основе конкретного условия БД для заполнения массива объектов.

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;
}

Проблема заключается в части освобождения памяти.Код работает очень хорошо на любых машинах с Win XP, но когда дело доходит до WIN2K8 R2 и WIN7, код падает и указывает на виновника :: SysFreeString ().MSDN не подходит для решения.

Может ли кто-нибудь помочь в поиске правильного решения?

Заранее большое спасибо:)

Обновление 1:

Я пытался использовать CComBSTR в соответствии с предложением вместо необработанного BSTR, инициализируется с использованием прямых CString и исключает SysFreeString ().Но из-за моей проблемы при выходе из области видимости система вызывает SysFreeString (), что снова вызывает сбой: (* ​​1020 *

Обновление 2: С тем же CComBSTR, который я пытался выделить с помощьюSysAllocString (), проблема остается той же: (

Обновление 3: Я устал от всех вариантов, и в мире я имею в виду только вопрос

Нужно ли освобождать BSTR через SysFreeString (), который был выделен с помощью SysAllocString () / string.AllocSysString ()?

Обновление 4: Я пропустил, чтобы предоставить информациюо сбое. Когда я попытался отладить сбой COM-сервера с ошибкой, говорящей

«Возможное повреждение кучи»

. Пожалуйста, помогите мне отсюда ..:(

Ответы [ 2 ]

2 голосов
/ 27 февраля 2012
// 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);
}

ОБНОВЛЕНИЕ2 Прежде всего следует освободить bstrCity и bstrStreetName с помощью SysFreeString или использовать 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

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

Кроме того, здесь:

m_sCityName = ::SysAllocString(bstrCityName);

вы выделяете память, но никогда не освобождаете ее, так каквнутренне CComBSTR & operator = (OLESTR ..) выделяет само новое хранилище.Нужно переписать следующее:

m_sCityName = bstrCityName;

Все остальное выглядит хорошо для меня

UPDATE3 Что ж, повреждение кучи часто является следствием записи некоторых значений за пределамивыделенный блок памяти.Допустим, вы выделили массив длиной 5 и поместили какое-то значение в 6-ю позицию

1 голос
/ 26 июля 2013

Наконец, я нашел реальную причину повреждения кучи, произошедшего в коде.

put_StreetName / put_CityName для IAddress / CAddress сконструировано следующим образом.

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 и более старых системах?: (

Спасибо всем, кто нашел время, чтобы ответить и решить мою проблему:)

...