5

私はたくさんのインターフェースとメソッドを備えた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;
}

問題はメモリ解放の部分にあります。コードはどのWinXPマシンでも非常に正常に機能しますが、WIN2K8 R2およびWIN7になると、コードがクラッシュし、:: SysFreeString()が原因として示されます。MSDNはソリューションに十分ではありません。

誰かが正しい解決策を見つけるのを手伝ってもらえますか?

よろしくお願いします:)

アップデート1:

生のBSTRの代わりに提案に従ってCComBSTRを使用してみましたが、直接CStringを使用して初期化され、SysFreeString()が除外されました。しかし、私の問題のために、スコープから外れると、システムはSysFreeString()を呼び出し、これが再びクラッシュを引き起こします:(

更新2: SysAllocString()を使用して割り当てようとした同じCComBSTRで、問題は同じままです:(

更新3: 私はすべてのオプションにうんざりしていて、安心して質問だけを念頭に置いています

SysAllocString()/ string.AllocSysString()を使用して割り当てられたSysFreeString()を介してBSTRを解放する必要がありますか?

更新4: クラッシュに関する情報を提供できませんでした。COMサーバーをデバッグしようとすると、次のようなエラーでクラッシュしました

「ヒープの破損の可能性」

。ここから私を助けてください..:(

4

2 に答える 2

4
// 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 まず、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<lRecCountで増幅することを検討してください。

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

ここもまた:

m_sCityName = ::SysAllocString(bstrCityName);

メモリを割り当てますが、内部的にCComBSTR&operator =(OLESTR ..)が新しいストレージ自体を割り当てるため、メモリを解放することはありません。書き直す必要があるのは次のとおりです。

m_sCityName = bstrCityName;

他のすべては、私にとってよさそうだ

UPDATE3 ええと、ヒープの破損は、割り当てられたメモリブロックの外にいくつかの値を書き込んだ結果であることがよくあります。長さ5の配列を割り当て、6番目の位置に値を設定するとします。

于 2012-02-27T14:56:20.547 に答える
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
}

Devilish Line of codeは、Memoryを地獄に追いやった本当の原因です。

何が問題を引き起こしたのですか?

このコード行では、パラメーターとして渡されるBSTR文字列は別のアプリケーションからのものであり、実メモリーは別のレルムにあります。そのため、システムは文字列を再割り当てしようとしています。成功するかどうかにかかわらず、同じものが元のアプリケーション/レルムのメモリからクリアされようとするため、クラッシュが発生します。

まだ解決されていないものは何ですか?

Win XP以前のシステムで同じコードが一度もクラッシュしないのはなぜですか?:(

私の問題に答えて解決するために時間を割いてくれたすべての人に感謝します:)

于 2013-07-26T12:22:09.847 に答える