[c++]记录Windows程序“应用程序错误”到异常日志

时间:2021-02-23 19:49:40

客户反应,程序在运行中经常发生“非法操作”的错误,0x00XXXXXX的内存不能为读之类的错误。

这断代码的作用就是 将这些 异常 保存到日志文件, 对照MAP文件可以找到源代码的出错行。

#include "Shlwapi.h"
#pragma comment( lib,"Shlwapi.lib")

 
#include
std::vector g_vErrCode;

CString GetNow()
{
 CHAR szData[MAX_PATH] = {'/0'};
 CHAR szTime[MAX_PATH] = {'/0'};
 _strdate( szData );
 _strtime( szTime );

 CString strRet;
 strRet.Format( "£¨%s£©%s", szData, szTime);
 strRet.Replace( "/", "_");
 strRet.Replace( ":", "£º");
 return strRet;
}


CString GetAppPath()
{
 TCHAR tszBuf[MAX_PATH] = {'/0'};
 GetModuleFileName( NULL, tszBuf, MAX_PATH);

 CString strDir, tmpDir;
 tmpDir = tszBuf;
 strDir = tmpDir.Left( tmpDir.ReverseFind('//') );

 return strDir;
}


#define EXE_NAME "XVODNew.exe"

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
  CString strPath;
 strPath.Format( "%s//%s", GetAppPath(), EXE_NAME);

 if( !PathFileExists(strPath) )
 {
  MessageBox( NULL, "Ç뽫µ÷ÊÔ³ÌÐò·ÅÔÚ±»µ÷ÊÔ³ÌÐòͬһĿ¼Ï£¡", NULL, MB_OK );
  return -1;
 }


 STARTUPINFO si = {'/0'};
 si.cb = sizeof(si);
 si.dwFlags = STARTF_USESHOWWINDOW;
 si.wShowWindow = SW_SHOW;
    PROCESS_INFORMATION pi = {'/0'};
 
 if( !CreateProcess( (LPSTR)(LPCSTR)strPath
  , NULL
  , NULL           
        , NULL           
        , FALSE          
        , DEBUG_PROCESS//CREATE_SUSPENDED
        , NULL           
        , GetAppPath()   
        , &si            
        , &pi   
  ) )
    {
  MessageBox( NULL, "Æô¶¯½ø³Ìʧ°Ü!", NULL, MB_OK );
  return -2;
    }
/* 
 if( !DebugActiveProcess(pi.dwProcessId) )
 {
  MessageBox( NULL, "µ÷ÊÔ½ø³Ìʧ°Ü", NULL, MB_OK );
  return -3;
 }

 if( ::ResumeThread( pi.hThread ) == (DWORD)-1 )
 {
  MessageBox( NULL, "¼¤»î½ø³Ìʧ°Ü", NULL, MB_OK );
  return -4;
 }
 */


 CString strDir;
 strDir.Format( "%s//Log"
  , GetAppPath()
  );
 CreateDirectory( strDir, NULL); 
 
 CString strLog;
 strLog.Format( "%s//Log//%s.log"
  , GetAppPath()
  , GetNow()
  );
 
 CFile file;
 if( file.Open( strLog
  , CFile::modeCreate | CFile::modeReadWrite
  , NULL
  ) == 0 )
 {
  MessageBox( NULL, "´´½¨ÈÕÖ¾Îļþʧ°Ü", NULL, MB_OK );
  return -4;
 }

 DEBUG_EVENT de;
 BOOL bContinue = TRUE;
 DWORD dwContinueStatus = 0;
 
 while( bContinue )
 {
  bContinue = WaitForDebugEvent( &de, INFINITE);
  
  switch( de.dwDebugEventCode )
  {
  case EXCEPTION_DEBUG_EVENT:
   {
    EXCEPTION_DEBUG_INFO info = de.u.Exception;
    BOOL bExist = FALSE;

    // ÊÇ·ñÊǵÚÒ»´Î³ö´í
    std::vector ::iterator iter;
    for( iter = g_vErrCode.begin(); iter != g_vErrCode.end(); iter++)
    {
     if( (LPVOID)(*iter) == info.ExceptionRecord.ExceptionAddress )
     {
      bExist = TRUE;
      break;
     }
    }

    if( !bExist )
    {
     g_vErrCode.push_back(info.ExceptionRecord.ExceptionAddress);
     
     CString strMsg;
     strMsg.Format( "%s/r/n"
      "/t/t/t/tFirstChance:%d/t/r/n"
      "/t/t/t/tExceptionCode:0x%X/r/n"
      "/t/t/t/tExceptionFlags:%d/r/n"
      "/t/t/t/tExceptionAddress:0x%X/r/n"
      "/t/t/t/tNumberParameters:%d/r/n"
      "/t/t/t/tIsWrite:%d/r/n"
      "/t/t/t/tAccessAddress:0x%X/r/n"
      "/r/n"
      , GetNow()
      , info.dwFirstChance
      , info.ExceptionRecord.ExceptionCode
      , info.ExceptionRecord.ExceptionFlags
      , info.ExceptionRecord.ExceptionAddress
      , info.ExceptionRecord.NumberParameters
      , info.ExceptionRecord.ExceptionInformation[0]
      , info.ExceptionRecord.ExceptionInformation[1]
      );
     file.Write( strMsg.GetBuffer(0), strMsg.GetLength());
     strMsg.ReleaseBuffer();
     file.Flush();
    }
    else
    {
     if( MessageBox( NULL, "µÚ¶þ´ÎÔÚÏàͬλÖóö´í£¡,ÊÇ·ñÍ˳ö?", NULL, MB_YESNO) == IDYES )
     {
      bContinue = FALSE;
      break;
     }
    }

    dwContinueStatus = DBG_CONTINUE;
    break;
   }

   
  case EXIT_PROCESS_DEBUG_EVENT:
   {
    bContinue = FALSE;
    break;
   }
   
  default:
   {
    dwContinueStatus = DBG_CONTINUE;
    break;
   }
  }
  
  ContinueDebugEvent(de.dwProcessId, de.dwThreadId, dwContinueStatus);
 }

 file.Flush();
 file.Close();


 return 0;
}