0

最近、オペレーティング システムを Windows XP から Windows 7 SP1 64 ビットにアップグレードしました。Visual Studio 2008 Professional Edition と Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64 ビット製品を使用しています。

このコードを実行しようとすると、以下の例外が発生します

{ CDatabase *pDatabase = CDatabaseConnection::getDatabaseConnectionProcessLog(); を試してください。

    ORSProcessLog rsProcessLog(pDatabase);
    CString strFilter = _T("SELECT PROCESS_ID, MESSAGE FROM OP_PROCESS_LOG");
    rsProcessLog.SetRowsetSize(1);
    if( !rsProcessLog.Open(CRecordset::dynaset, strFilter, CRecordset::appendOnly) )        
        return;

    if( !rsProcessLog.CanAppend() )
        return; 

    rsProcessLog.AddNew();          

    rsProcessLog.m_PROCESS_ID = gcsProcessID;
    rsProcessLog.m_MESSAGE = csMessageA;

    rsProcessLog.Update();
    rsProcessLog.Close();
}
catch ( CDBException* pEx )
{
    bException = true;
    pEx->GetErrorMessage(szCause, 255);
} 
catch( CException* pEx )
{
    bException = true;
    pEx->GetErrorMessage(szCause, 255);
} 

ここで、rsProcessLog は、正常に接続されたデータベース ポインター pDatabase を使用する CRecordset オブジェクトです。

32 ビット デバッグ バージョンでは、rsProcessLog.Close(); にメッセージ ボックスが表示されます。以下のテキストで デバッグエラー

プログラム: ...\Test.exe

ヒープ破損が検出されました: 0x0087F628 の通常ブロック (#506) の後。CRT は、アプリケーションがヒープ バッファーの終了後にメモリに書き込んだことを検出しました。

f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\dbcore.cpp(2626) に割り当てられたメモリ

(アプリケーションのデバッグを再試行してください)

32 ビット リリース バージョンでは、rsProcessLog.Close(); にメッセージ ボックスが表示されます。以下のテキストで Windows は Test.exe でブレークポイントをトリガーしました

これはヒープの破損が原因である可能性があります。これは、Test.exe またはそれがロードした DLL のバグを示しています。

これは、Test.exe にフォーカスがあるときにユーザーが F12 キーを押したことが原因である可能性もあります。

出力ウィンドウには、より多くの診断情報が表示される場合があります。

上記のコードは Windows XP で動作するコードであり、残りの env は同じままであり、Windows XP でも引き続き実行されますが、Windows 7 では実行されません。

4

1 に答える 1

0

MFC クラスを分析した結果、ヒープに割り当てられた配列が破損した場所CRecordestを呼び出した後に問題が発生することに気付きました (ヒープにさらに 1 バイトが書き込まれます)。::SqlSetPosm_rgRowStatus

問題に対する最初のクリーンなアプローチは、クラスに関数CRecordsetの代わりに update/delete SQL ステートメントを使用させることです。::SqlSetPosこれを実現するには、OpenExメソッドとCDatabase::userCursorLibオプションを使用してデータベースを開く必要があります。

CDatabase db;
db.OpenEx(ConnectionString, CDatabase:useCursorLib);

これにより、一部の CRecordset 機能が変更されます。詳細については、http: //msdn.microsoft.com/en-us/library/c689y99f.aspxを参照してください。

2番目のアプローチ(ダーティ)は、m_rgRowStatusフィールドを再割り当てし、ヒープでより多くのメモリを使用するため、への呼び出しは::SqlSetPos割り当てられていないメモリに書き込みません。

CRecordset::PreBindFieldsこれを行う 1 つの方法は、関数をオーバーライドすることです。

void CMyDerivedRecordset::PreBindFields()
{
    if  ( ! (m_dwOptions & useMultiRowFetch) )
    {
        delete [] m_rgRowStatus;
        m_rgRowStatus = new WORD[2];
    }

    CRecordset::PreBindFields();
}

すべての派生クラスでこれを行うことも、既存のすべての派生クラスの基本クラスになるCRecordset新しい派生クラスを 1 つ作成することもできます。CRecordsetCRecordset

于 2014-03-04T09:28:36.620 に答える