Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Visual C++/MFC/WTL > [MVS2008] Отловить падение программы


Автор: MuForum 10.8.2010, 13:28
Доброго времени суток.
Работаю на "Microsoft Visual Studio 2008", язык программирования "C++".

Есть программа которая использует MFC.

# Задача: Отловить падение/crash программы и определить имя или индекс модуля и если возможно имя функции.



P.S. -> Прошу помочь с проблемой, готов заплатить деньги за помощь.

Автор: SenkraD 10.8.2010, 13:35
MuForum,  глянь http://www.codeproject.com/KB/threads/StackWalker.aspx, если не ещё не смотрел.
И ещё может http://www.codeproject.com/KB/applications/leakfinder.aspx поможет

Автор: MuForum 10.8.2010, 13:54
1. Программа запускается не под отладчиком, а на другом компьютере.
2. Программа написана на VC++, а не на .NET VC++.

Автор: SenkraD 10.8.2010, 14:01
Цитата(MuForum @  10.8.2010,  13:54 Найти цитируемый пост)
1. Программа запускается не под отладчиком, а на другом компьютере.
тогда может crash dump с последующей отладкой (к примеру, http://www.rsdn.ru/article/files/libs/crashrpt.xml)

Цитата(MuForum @  10.8.2010,  13:54 Найти цитируемый пост)
2. Программа написана на VC++, а не на .NET VC++.
StackWalker без .NET пашет

Автор: jonie 10.8.2010, 17:16
а я бы использовал просто ntsd.exe и просил бы дамп высылать....

Автор: MuForum 10.8.2010, 23:24
Благодарю за помощь принявших участие.

Я решил следующим образом.
1. В самой программе при падение делаю дамп.
Код


typedef BOOL (*MINIDUMPWRITEDUMP)
(
    IN HANDLE hProcess,
    IN DWORD ProcessId,
    IN HANDLE hFile,
    IN MINIDUMP_TYPE DumpType,
    IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL
    IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL
    IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL
);
//---------------------------------------------------------------------------

void SetExceptionHook();
LONG TopLevelFilter(struct _EXCEPTION_POINTERS * pExceptionInfo);
//---------------------------------------------------------------------------

void SetExceptionHook()
{
    ::SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)TopLevelFilter);
}
//---------------------------------------------------------------------------

LONG TopLevelFilter(struct _EXCEPTION_POINTERS * pExceptionInfo)
{
    // По умолчанию завершим процесс стандартным образом;
    LONG retval        = EXCEPTION_CONTINUE_SEARCH;
    // ---- 
    // Сначала попробуем загрузить библиотеку рядом с EXE, т.к.
    // В System32 может быть старая версия.
    HMODULE hDll            = NULL;
    // ----
    TCHAR szDbgHelpPath[_MAX_PATH];
    memset(szDbgHelpPath, 0, _MAX_PATH);
    // ----
    if ( GetModuleFileName(NULL, szDbgHelpPath, _MAX_PATH) != 0 )
    {
        TCHAR * pSlash        = _tcsrchr(szDbgHelpPath, '\\');
        // ----
        if ( pSlash != 0 )
        {
            _tcscpy(pSlash + 1, _T("DBGHELP.DLL"));
            // ----
            hDll            = ::LoadLibrary(szDbgHelpPath);
        }
    }
    // ----
    if ( hDll == NULL )
    {
        // Если загрузка не удалась,
        // Пробуем загрузить любую доступную версию;
        hDll            = ::LoadLibrary( _T("DBGHELP.DLL"));
    }
    // ----
    LPCTSTR szResult    = NULL;
    // ----
    if ( hDll == NULL )
    {
        szResult        = _T("DBGHELP.DLL не найдена");
        // ----
        MessageBox(NULL, szResult, _T("eGameServer"), MB_OK);
        // ----
        return retval;
    }
    // ----
    // Если библиотека загружена - получаем адрес MiniDumpWriteDump();
    MINIDUMPWRITEDUMP pDump    = (MINIDUMPWRITEDUMP)GetProcAddress(hDll, "MiniDumpWriteDump");
    // ----
    if ( pDump == NULL )
    {
        szResult = _T("DBGHELP.DLL старая");
        // ----
        MessageBox(NULL, szResult, _T("eGameServer"), MB_OK);
        // ----
        return retval;
    }
    // ----
    TCHAR        szDumpPath[_MAX_PATH];
    memset(szDumpPath, 0, _MAX_PATH);
    // ----
    TCHAR        szScratch[_MAX_PATH];
    memset(szScratch, 0, _MAX_PATH);
    // ----
    // Будем записывать файл во временную папку;
    // ----
    SYSTEMTIME SysTime;
    GetLocalTime( & SysTime);
    // ----
    char lpCurDir[_MAX_PATH];
    memset(lpCurDir, 0, _MAX_PATH);
    // ----
    GetCurrentDirectory(_MAX_PATH - 1, lpCurDir);
    // ----
    sprintf(szDumpPath, "%s\\GameServer_Dump_%02d-%02d-%02d_%02d.%02d.%04d.dmp\0",
        lpCurDir,
        SysTime.wHour, SysTime.wMinute, SysTime.wSecond,
        SysTime.wDay, SysTime.wMonth, SysTime.wYear);
    // ----
    // Сообщаем пользователю, что процесс на грани смерти и
    // предлагаем сохранить дамп;
    // ----
    // Создаём файл;
    HANDLE hFile = ::CreateFile(szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, 
                                CREATE_ALWAYS,
                                FILE_ATTRIBUTE_NORMAL, NULL);
    // ----
    if ( hFile == INVALID_HANDLE_VALUE )
    {
        _stprintf(szScratch,
            _T("Ошибка создания диагностического файла '%s' (код %d)"),
            szDumpPath, GetLastError() );
        // ----
        szResult    = szScratch;
        // ----
        return retval;
    }
    // ----
    _MINIDUMP_EXCEPTION_INFORMATION ExInfo;
    // ----
    ExInfo.ThreadId                = ::GetCurrentThreadId();
    ExInfo.ExceptionPointers    = pExceptionInfo;
    ExInfo.ClientPointers        = NULL;
    // ----
    // И записать в него дамп;
    BOOL bOK        = pDump(GetCurrentProcess(), GetCurrentProcessId(),
                            hFile, MiniDumpNormal, & ExInfo, NULL, NULL);
    // ----
    if ( bOK != 0 )
    {
        _stprintf(szScratch, _T("Файл сохранен в: '%s'"), szDumpPath);
        // ----
        szResult        = szScratch;
        // ----
        retval            = EXCEPTION_EXECUTE_HANDLER;
    }
    else
    {
        _stprintf(szScratch,
            _T("Ошибка сохранения '%s' (код %d)"),
            szDumpPath, GetLastError());
        // ----
        szResult        = szScratch;
    }
    // ----
    ::CloseHandle(hFile);
    // ----
    return retval;
}
//---------------------------------------------------------------------------

// # Write in function;
SetExceptionHook();
//---------------------------------------------------------------------------



Затем при помощи WinDbg (WDK Windows Driver Kit), окрываем Crash log и смотрим что не так.


P.S. -> Необходимо установить |symbols path".

Автор: Abyx 10.8.2010, 23:28
MuForum, вам наверное за строчки кода платят...

Автор: Rad87 11.8.2010, 09:24
Серьезно smile
Какой практический смысл имеет отделение строчек этим "// ----"?

Автор: MuForum 11.8.2010, 09:42
Цитата(Rad87 @ 11.8.2010,  09:24)
Серьезно smile
Какой практический смысл имеет отделение строчек этим "// ----"?

Практического смысла нет, но мне так работать удобнее.
- Код лично для меня, намного читабельнее.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)