ホーム ソリューション ソフトウェア ライブラリ サポート 送金 書籍紹介 リンク
秀まるおのソフト開発者向け情報
 この情報は斉藤秀夫が勝手に発信している情報です。この情報についての質問にはたぶんお答えできません。
 保護違反で死んだ時にログを出す! (2001.4.6)
一般保護違反で死んでしまった時、WindowsNT/2000ならワトソン博士のログが出るのでいいんですが、Windows95/98系だとあまり詳しい情報が出てくれないのでデバッグ作業が手こずってしまいます。そこで、__try / __except を使って一般保護違反を横取りし、独自にログを出しましょう。
 また、内部的なエラーチェック時にもスタックトレースを出力するととても便利です。

以下、参考ソースコードです。(そのままでは使えません)
int WINAPI WinMain( ... ) {
#ifndef _DEBUG
    PEXCEPTION_POINTERS pInfo;
    __try {
#endif
        ...
        ... WinMainの処理 ...
        ...
#ifndef _DEBUG
    }
    __except( pInfo = GetExceptionInformation(), TRUE ) {
        StartDump( "Exception" );
        DumpContext( pInfo->ContextRecord );
        EndDump();
        MessageBox( NULL, "××ソフトのプロセスで保護違反が発生しました。××ソフトは異常終了します。\n\n"
                        "××ソフトの異常終了についての詳細情報は、dump.txtファイルに出力されています。"
                        "そのファイル内容を作者に連絡ください。"
                , NULL, MB_OK | MB_ICONHAND | MB_SYSTEMMODAL );
        return TRUE;
    }
#endif
}

////////////////////////////////////////////////////////

static HANDLE   hfileDump;

void DumpOut( char* psz ) {
    DWORD   cbWritten;
    WriteFile( hfileDump, psz, strlen(psz), &cbWritten, NULL );
}

void StartDump( char* pszTitle ) {
    hfileDump = CreateFile( "dump.txt", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE
                    , NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL );
    SetFilePointer( hfileDump, 0, NULL, FILE_END );
    SYSTEMTIME  st;
    GetLocalTime( &st );
    char    sz[256];
    wsprintf( sz, "********** %02u/%02u/%02u %02u:%02u:%02u.%03u ××ソフト V1.00  "
            , st.wYear % 100, st.wMonth, st.wDay
            , st.wHour, st.wMinute, st.wSecond, st.wMilliseconds );
    DumpOut( sz );
    DumpOut( pszTitle );
    DumpOut( "\r\n" );
}

void EndDump() {
    DumpOut( "\r\n\r\n" );
    CloseHandle( hfileDump );
}

void DumpContext( CONTEXT* pcont ) {
    char    sz[256];
    wsprintf( sz, "eax=%08X ebx=%08X ecx=%08X edx=%08X esi=%08X edi=%08X ebp=%08X esp=%08X eip=%08X\r\n"
        , pcont->Eax, pcont->Ebx, pcont->Ecx, pcont->Edx, pcont->Esi, pcont->Edi, pcont->Ebp, pcont->Esp, pcont->Eip );
    DumpOut( sz );
    DumpOut( "Stack Dump\r\n" );
    int i;
    DWORD*  esp = (DWORD*)pcont->Esp;
    for( i = 0; i < 8; i++ ) {
        if( IsBadReadPtr( esp, 8 * 4 ) ) {
            break;
        }
        wsprintf( sz, "%08X %08X %08X %08X %08X %08X %08X %08X\r\n"
                , esp[0], esp[1], esp[2], esp[3], esp[4], esp[5], esp[6], esp[7] );
        DumpOut( sz );
        esp += 8;
    }

    DumpOut( "FramePtr ReturnAd Param#1  Param#2  Param#3  Param#4  Param#5  Param#6  Param#7  Param#8  Param#9  Param#10 MachineCode\r\n" );
    i = 0;
    DWORD*  ebp = (DWORD*)pcont->Ebp;
    while( i < 80 && !IsBadReadPtr( ebp, 4 * (10 + 1 + 1) ) ) {
        wsprintf( sz, "%08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X "
                , ebp[0], ebp[1], ebp[2], ebp[3], ebp[4], ebp[5], ebp[6], ebp[7], ebp[8], ebp[9], ebp[10], ebp[11], ebp[12] );
        DumpOut( sz );
        BYTE*   pbCode = (BYTE*)(ebp[1]);
        if( !IsBadReadPtr( pbCode, 8 ) ) {
            wsprintf( sz, "%02X %02X %02X %02X %02X %02X %02X %02X"
                    , pbCode[0], pbCode[1], pbCode[2], pbCode[3], pbCode[4], pbCode[5], pbCode[6], pbCode[7] );
            DumpOut( sz );
        }
        DumpOut( "\r\n" );
        i ++;
        ebp = (DWORD*)*ebp;
    }
    DumpOut( "\r\n" );
}

 もちろん、レジスターやスタックトレース、さらには逆アセンブルリストを理解できることが前提ですが…。あ、そうそう、ここで出てくるマシンコードのアドレスは、.mapファイル上では0x00401000引いた値が該当するようです。

『戻る』