1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

New, experimental crashhandler for windows (creates minidumps).

Several minor fixes and improvements.
This commit is contained in:
Michał W. Urbańczyk 2009-07-31 20:10:22 +00:00
parent 586957b749
commit 78afb07f52
11 changed files with 169 additions and 32 deletions

View File

@ -3,7 +3,17 @@
#include "CConsoleHandler.h"
#include <boost/function.hpp>
#include <boost/thread.hpp>
#include <iomanip>
/*
* CConsoleHandler.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#ifndef _WIN32
typedef std::string TColor;
@ -17,6 +27,8 @@
#define CONSOLE_GRAY "\x1b[0;40;39m"
#else
#include <windows.h>
#include <dbghelp.h>
#pragma comment(lib, "dbghelp.lib")
typedef WORD TColor;
#define _kill_thread(a) TerminateThread(a,0)
@ -33,16 +45,101 @@
TColor defColor;
#ifdef _WIN32
void printWinError()
{
//Get error code
int error = GetLastError();
if(!error)
{
tlog0 << "No Win error information set.\n";
return;
}
tlog1 << "Error " << error << " encountered:\n";
//Get error description
char* pTemp = NULL;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, error, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), (LPSTR)&pTemp, 1, NULL);
tlog1 << pTemp << std::endl;
LocalFree( pTemp );
}
const char* exceptionName(DWORD exc)
{
#define EXC_CASE(EXC) case EXCEPTION_##EXC : return "EXCEPTION_" #EXC
switch (exc)
{
EXC_CASE(ACCESS_VIOLATION);
EXC_CASE(DATATYPE_MISALIGNMENT);
EXC_CASE(BREAKPOINT);
EXC_CASE(SINGLE_STEP);
EXC_CASE(ARRAY_BOUNDS_EXCEEDED);
EXC_CASE(FLT_DENORMAL_OPERAND);
EXC_CASE(FLT_DIVIDE_BY_ZERO);
EXC_CASE(FLT_INEXACT_RESULT);
EXC_CASE(FLT_INVALID_OPERATION);
EXC_CASE(FLT_OVERFLOW);
EXC_CASE(FLT_STACK_CHECK);
EXC_CASE(FLT_UNDERFLOW);
EXC_CASE(INT_DIVIDE_BY_ZERO);
EXC_CASE(INT_OVERFLOW);
EXC_CASE(PRIV_INSTRUCTION);
EXC_CASE(IN_PAGE_ERROR);
EXC_CASE(ILLEGAL_INSTRUCTION);
EXC_CASE(NONCONTINUABLE_EXCEPTION);
EXC_CASE(STACK_OVERFLOW);
EXC_CASE(INVALID_DISPOSITION);
EXC_CASE(GUARD_PAGE);
EXC_CASE(INVALID_HANDLE);
default:
return "UNKNOWN EXCEPTION";
}
#undef EXC_CASE
}
LONG WINAPI onUnhandledException(EXCEPTION_POINTERS* exception)
{
tlog1 << "Disaster happened.\n";
PEXCEPTION_RECORD einfo = exception->ExceptionRecord;
tlog1 << "Reason: 0x" << std::hex << einfo->ExceptionCode << " - " << exceptionName(einfo->ExceptionCode);
tlog1 << " at " << std::setfill('0') << std::setw(4) << exception->ContextRecord->SegCs << ":" << (void*)einfo->ExceptionAddress << std::endl;;
if (einfo->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
{
tlog1 << "Attempt to " << (einfo->ExceptionInformation[0] == 1 ? "write to " : "read from ")
<< "0x" << std::setw(8) << (void*)einfo->ExceptionInformation[1] << std::endl;;
}
const DWORD threadId = ::GetCurrentThreadId();
tlog1 << "Thread ID: " << threadId << " [" << std::dec << std::setw(0) << threadId << "]\n";
//exception info to be placed in the dump
MINIDUMP_EXCEPTION_INFORMATION meinfo = {threadId, exception, TRUE};
//create file where dump will be placed
char *mname = NULL;
char buffer[MAX_PATH + 1];
HMODULE hModule = NULL;
GetModuleFileNameA(hModule, buffer, MAX_PATH);
mname = strrchr(buffer, '\\');
if (mname != 0)
mname++;
else
mname = buffer;
strcat(mname, "_crashinfo.dmp");
HANDLE dfile = CreateFileA(mname, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
tlog1 << "Crash info will be put in " << dfile << std::endl;
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), dfile, MiniDumpWithDataSegs, &meinfo, 0, 0);
MessageBoxA(0, "VCMI has crashed. We are sorry. File with information about encountered problem has been created.", "VCMI Crashhandler", MB_OK | MB_ICONERROR);
return EXCEPTION_EXECUTE_HANDLER;
}
#endif
/*
* CConsoleHandler.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
void CConsoleHandler::setColor(int level)
{
@ -100,6 +197,7 @@ CConsoleHandler::CConsoleHandler()
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(handleOut,&csbi);
defColor = csbi.wAttributes;
SetUnhandledExceptionFilter(onUnhandledException);
#else
defColor = "\x1b[0m";
#endif

View File

@ -57,7 +57,8 @@
*
*/
std::string NAME = NAME_VER + std::string(" (client)"); //application name
std::string NAME_AFFIX = "client";
std::string NAME = NAME_VER + std::string(" (") + NAME_AFFIX + ')'; //application name
SDL_Surface *screen = NULL, //main screen surface
*screen2 = NULL,//and hlp surface (used to store not-active interfaces layer)
*screenBuf = screen; //points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
@ -392,6 +393,12 @@ void processCommand(const std::string &message, CClient *&client)
}
tlog0<<"\rExtracting done :)\n";
}
else if(cn=="crash")
{
int *ptr = NULL;
*ptr = 666;
//disaster!
}
else if(client && client->serv && client->serv->connected) //send to server
{
PlayerMessage pm(LOCPLINT->playerID,message);

View File

@ -309,7 +309,7 @@ CSimpleWindow * CMessage::genWindow(std::string text, int player, int Lmar, int
std::vector<std::string> * brtext = breakText(text,32,true,true);
std::vector<std::vector<SDL_Surface*> > * txtg = drawText(brtext, fontHeight);
std::pair<int,int> txts = getMaxSizes(txtg, fontHeight);
ret->bitmap = drawBox1(txts.first+Lmar+Rmar,txts.second+Tmar+Bmar,0);
ret->bitmap = drawBox1(txts.first+Lmar+Rmar,txts.second+Tmar+Bmar,player);
ret->pos.h=ret->bitmap->h;
ret->pos.w=ret->bitmap->w;
int curh = ret->bitmap->h/2 - (fontHeight*txtg->size())/2;

View File

@ -278,34 +278,36 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
if(details.result == TryMoveHero::TELEPORTATION || details.start == details.end)
return;
//initializing objects and performing first step of move
int3 hp = details.start;
if (details.result != TryMoveHero::SUCCESS) //hero failed to move
if(makingTurn && ho->tempOwner == playerID) //we are moving our hero
{
if(details.result != TryMoveHero::FAILED)
if (details.result != TryMoveHero::SUCCESS && details.result != TryMoveHero::FAILED) //hero didn't change tile but visit succeeded
{
adventureInt->paths.erase(ho);
adventureInt->terrain.currentPath = NULL;
}
else if(adventureInt->terrain.currentPath) //&& hero is moving
{
//remove one node from the path (the one we went)
adventureInt->terrain.currentPath->nodes.erase(adventureInt->terrain.currentPath->nodes.end()-1);
if(!adventureInt->terrain.currentPath->nodes.size()) //if it was the last one, remove entire path
{
adventureInt->paths.erase(ho);
adventureInt->terrain.currentPath = NULL;
}
}
}
if (details.result != TryMoveHero::SUCCESS) //hero failed to move
{
ho->isStanding = true;
stillMoveHero.setn(STOP_MOVE);
LOCPLINT->totalRedraw();
return;
}
if (adventureInt->terrain.currentPath) //&& hero is moving
{
//remove one node from the path (the one we went)
adventureInt->terrain.currentPath->nodes.erase(adventureInt->terrain.currentPath->nodes.end()-1);
if(!adventureInt->terrain.currentPath->nodes.size()) //if it was the last one, remove entire path
{
adventureInt->paths.erase(ho);
adventureInt->terrain.currentPath = NULL;
}
}
//initializing objects and performing first step of move
if(details.end.x+1 == details.start.x && details.end.y+1 == details.start.y) //tl
{
//ho->moveDir = 1;

View File

@ -361,9 +361,6 @@ void Graphics::loadHeroAnims()
loadHeroAnim("AB01_.DEF", rotations, &Graphics::boatAnims);
loadHeroAnim("AB02_.DEF", rotations, &Graphics::boatAnims);
loadHeroAnim("AB03_.DEF", rotations, &Graphics::boatAnims);
VLC->dobjinfo->gobjs[8][0]->handler = boatAnims[0];
VLC->dobjinfo->gobjs[8][1]->handler = boatAnims[1];
VLC->dobjinfo->gobjs[8][2]->handler = boatAnims[2];
}
void Graphics::loadHeroAnim( const std::string &name, const std::vector<std::pair<int,int> > &rotations, std::vector<CDefEssential *> Graphics::*dst )

View File

@ -20,6 +20,8 @@ typedef boost::int8_t si8; //signed int 8 bits (1 byte)
#endif
#define NAME_VER ("VCMI 0.72d")
extern std::string NAME; //full name
extern std::string NAME_AFFIX; //client / server
#define CONSOLE_LOGGING_LEVEL 5
#define FILE_LOGGING_LEVEL 6

View File

@ -1058,6 +1058,9 @@ void CGDwelling::newTurn() const
if(cb->getDate(1) != 1) //not first day of week
return;
//town growths are handled separately
if(ID == TOWNI_TYPE)
return;
bool change = false;

View File

@ -909,13 +909,17 @@ void Mapa::loadHero( CGObjectInstance * &nobj, unsigned char * bufor, int &i )
nhi->name = readString(bufor,i);
if(version>AB)
{
if(readChar(bufor,i))//true if hore's experience is greater than 0
if(readChar(bufor,i))//true if hero's experience is greater than 0
{ nhi->exp = readNormalNr(bufor,i); i+=4; }
else
nhi->exp = 0xffffffff;
}
else
{ nhi->exp = readNormalNr(bufor,i); i+=4; }
{
nhi->exp = readNormalNr(bufor,i); i+=4;
if(!nhi->exp) //0 means "not set" in <=AB maps
nhi->exp = 0xffffffff;
}
bool portrait=bufor[i]; ++i;
if (portrait)

View File

@ -431,6 +431,10 @@ void CMapHandler::init()
timeHandler th;
th.getDif();
CGI->dobjinfo->gobjs[8][0]->handler = graphics->boatAnims[0];
CGI->dobjinfo->gobjs[8][1]->handler = graphics->boatAnims[1];
CGI->dobjinfo->gobjs[8][2]->handler = graphics->boatAnims[2];
// Size of visible terrain.
mapW = conf.go()->ac.advmapW;
mapH = conf.go()->ac.advmapH;

View File

@ -202,6 +202,13 @@ void CGameHandler::changeSecSkill( int ID, int which, int val, bool abs/*=false*
sss.val = val;
sss.abs = abs;
sendAndApply(&sss);
if(which == 7) //Wisdom
{
const CGHeroInstance *h = getHero(ID);
if(h && h->visitedTown)
giveSpells(h->visitedTown, h);
}
}
void CGameHandler::changePrimSkill(int ID, int which, int val, bool abs)
@ -661,6 +668,9 @@ void CGameHandler::newTurn()
BOOST_FOREACH(CGHeroInstance *h, (*i).second.heroes)
{
if(h->visitedTown)
giveSpells(h->visitedTown, h);
NewTurn::Hero hth;
hth.id = h->id;
hth.move = h->maxMovePoints(gs->map->getTile(h->getPosition(false)).tertype != TerrainTile::water);
@ -1273,6 +1283,13 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
tlog5 << "Player " <<int(asker) << " wants to move hero "<< hid << " from "<< h->pos << " to " << dst << std::endl;
int3 hmpos = dst + int3(-1,0,0);
if(!gs->map->isInTheMap(hmpos))
{
tlog1 << "Destination tile os out of the map!\n";
return false;
}
TerrainTile t = gs->map->terrain[hmpos.x][hmpos.y][hmpos.z];
int cost = gs->getMovementCost(h,h->getPosition(false),CGHeroInstance::convertPosition(dst,false),h->movement);
@ -2934,4 +2951,6 @@ bool CGameHandler::buildBoat( ui32 objid )
no.subID = 1;
no.pos = tile + int3(1,0,0);
sendAndApply(&no);
return true;
}

View File

@ -25,7 +25,8 @@
#include "../lib/Interprocess.h"
#include "../lib/VCMI_Lib.h"
#include "CGameHandler.h"
std::string NAME = NAME_VER + std::string(" (server)");
std::string NAME_AFFIX = "server";
std::string NAME = NAME_VER + std::string(" (") + NAME_AFFIX + ')'; //application name
using namespace boost;
using namespace boost::asio;
using namespace boost::asio::ip;