Fix exception handler to obey UAC on windows machines.
It will write the crash report file to CSIDL_PERSONAL (c:\Users\user name\Documents\logs\warzone2100.rpt) *All* platforms will now always have --debug-file enable as a default. This will write the logs to <configdir>/logs/WZlog*.txt When a user overrides the configdir, then we will try to use that directory instead of the default as well. refs ticket:1759 2.3: r10532 git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/trunk@10538 4a71c877-e1ca-e34f-864e-861f7616d084master
parent
43b6c72448
commit
1c4c1cc5bd
|
@ -72,7 +72,7 @@ case ${host_os} in
|
|||
*mingw32*)
|
||||
host_os_mingw32=yes
|
||||
AC_CHECK_TOOL([WINDRES], [windres], AC_MSG_ERROR([windres not found]))
|
||||
WIN32_LIBS='-ldbghelp -lshfolder -lwinmm -lws2_32'
|
||||
WIN32_LIBS='-ldbghelp -lshfolder -lshlwapi -lpsapi -lshell32 -lwinmm -lws2_32'
|
||||
AC_SUBST([WIN32_LIBS], [${WIN32_LIBS}])
|
||||
;;
|
||||
*openbsd*)
|
||||
|
|
|
@ -212,7 +212,7 @@ static std::string getProgramPath(const char* programCommand)
|
|||
}
|
||||
else
|
||||
{
|
||||
debug(LOG_WARNING, "Could not retrieve full path to %s, will not create extended backtrace", programCommand);
|
||||
debug(LOG_INFO, "Could not retrieve full path to %s, will not create extended backtrace", programCommand);
|
||||
}
|
||||
|
||||
return programPath;
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
#include "dumpinfo.h"
|
||||
|
||||
#if defined(WZ_OS_WIN)
|
||||
#include <tchar.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
# include "dbghelp.h"
|
||||
# include "exchndl.h"
|
||||
|
@ -33,6 +36,7 @@ static LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionHandler = NULL;
|
|||
/**
|
||||
* Exception handling on Windows.
|
||||
* Ask the user whether he wants to safe a Minidump and then dump it into the temp directory.
|
||||
* NOTE: This is only for MSVC compiled programs.
|
||||
*
|
||||
* \param pExceptionInfo Information on the exception, passed from Windows
|
||||
* \return whether further exception handlers (i.e. the Windows internal one) should be invoked
|
||||
|
@ -703,3 +707,43 @@ void setupExceptionHandler(int argc, char * argv[])
|
|||
setFatalSignalHandler(posixExceptionHandler);
|
||||
#endif // WZ_OS_*
|
||||
}
|
||||
bool OverrideRPTDirectory(char *newPath)
|
||||
{
|
||||
# if defined(WZ_CC_MINGW)
|
||||
TCHAR buf[MAX_PATH];
|
||||
|
||||
if (!MultiByteToWideChar(CP_UTF8, 0, newPath, strlen(newPath), buf, 0))
|
||||
{
|
||||
//conversion failed-- we won't use the user's directory.
|
||||
|
||||
LPVOID lpMsgBuf;
|
||||
LPVOID lpDisplayBuf;
|
||||
DWORD dw = GetLastError();
|
||||
TCHAR szBuffer[4196];
|
||||
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
dw,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0, NULL );
|
||||
|
||||
wsprintf(szBuffer, _T("Exception handler failed setting new directory with error %d: %s\n"), dw, lpMsgBuf);
|
||||
MessageBox(MB_ICONEXCLAMATION, szBuffer, _T("Error"), MB_OK);
|
||||
|
||||
LocalFree(lpMsgBuf);
|
||||
LocalFree(lpDisplayBuf);
|
||||
|
||||
return false;
|
||||
}
|
||||
_tcscpy(buf, newPath);
|
||||
PathRemoveFileSpec(buf);
|
||||
_tcscat(buf, _T("\\logs\\")); // stuff it in the logs directory
|
||||
_tcscat(buf, _T("Warzone2100.RPT"));
|
||||
ResetRPTDirectory(buf);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -21,5 +21,5 @@
|
|||
#define __INCLUDED_LIB_EXCEPTIONHANDLER_EXCEPTIONHANDLER_H__
|
||||
|
||||
extern void setupExceptionHandler(int argc, char * argv[]);
|
||||
|
||||
extern bool OverrideRPTDirectory(char *newPath);
|
||||
#endif // __INCLUDED_LIB_EXCEPTIONHANDLER_EXCEPTIONHANDLER_H__
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
along with Warzone 2100; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if (_WIN32_WINNT < 0x0500) // must force win 2k or higher
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0500
|
||||
#endif
|
||||
#include "lib/framework/frame.h"
|
||||
#include "dumpinfo.h"
|
||||
#include "exchndl.h"
|
||||
|
@ -32,7 +35,8 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
#if !defined(WZ_CC_MSVC)
|
||||
#define HAVE_BFD 1
|
||||
|
@ -1072,7 +1076,7 @@ void GenerateExceptionReport(PEXCEPTION_POINTERS pExceptionInfo)
|
|||
rprintf(_T("\r\n\r\n"));
|
||||
|
||||
#endif
|
||||
|
||||
// FIXME: We *never* return from the below call!
|
||||
StackBackTrace(GetCurrentProcess(), GetCurrentThread(), pContext);
|
||||
|
||||
rprintf(_T("\r\n\r\n"));
|
||||
|
@ -1106,6 +1110,32 @@ LONG WINAPI TopLevelExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
|
|||
FILE_FLAG_WRITE_THROUGH,
|
||||
0
|
||||
);
|
||||
if (hReportFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
// Retrieve the system error message for the last-error code
|
||||
|
||||
LPVOID lpMsgBuf;
|
||||
LPVOID lpDisplayBuf;
|
||||
DWORD dw = GetLastError();
|
||||
TCHAR szBuffer[4196];
|
||||
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
dw,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0, NULL );
|
||||
|
||||
wsprintf(szBuffer, _T("Exception handler failed with error %d: %s\n"), dw, lpMsgBuf);
|
||||
MessageBox(MB_ICONEXCLAMATION, szBuffer, _T("Error"), MB_OK);
|
||||
|
||||
LocalFree(lpMsgBuf);
|
||||
LocalFree(lpDisplayBuf);
|
||||
debug(LOG_ERROR, "Exception handler failed to create file!");
|
||||
}
|
||||
|
||||
#ifdef HAVE_BFD
|
||||
bfd_set_error_handler((bfd_error_handler_type) rprintf);
|
||||
|
@ -1113,28 +1143,43 @@ LONG WINAPI TopLevelExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
|
|||
|
||||
if (hReportFile)
|
||||
{
|
||||
TCHAR szBuffer[4196];
|
||||
int err;
|
||||
|
||||
SetFilePointer(hReportFile, 0, 0, FILE_END);
|
||||
|
||||
// FIXME: We don't return from the below function call
|
||||
GenerateExceptionReport(pExceptionInfo);
|
||||
|
||||
CloseHandle(hReportFile);
|
||||
|
||||
wsprintf(szBuffer, _T("Warzone has crashed.\r\nSee %s for more details\r\n"), szLogFileName);
|
||||
err = MessageBox(MB_ICONERROR, szBuffer, _T("Warzone Crashed!"), MB_OK | MB_ICONERROR);
|
||||
if (err == 0)
|
||||
{
|
||||
LPVOID lpMsgBuf;
|
||||
LPVOID lpDisplayBuf;
|
||||
DWORD dw = GetLastError();
|
||||
TCHAR szBuffer[4196];
|
||||
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
dw,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0, NULL );
|
||||
|
||||
wsprintf(szBuffer, _T("Exception handler failed with error %d: %s\n"), dw, lpMsgBuf);
|
||||
MessageBox(MB_ICONEXCLAMATION, szBuffer, _T("Error"), MB_OK);
|
||||
|
||||
LocalFree(lpMsgBuf);
|
||||
LocalFree(lpDisplayBuf);
|
||||
debug(LOG_ERROR, "Exception handler failed to create file!");
|
||||
}
|
||||
hReportFile = 0;
|
||||
}
|
||||
|
||||
if(fuOldErrorMode & SEM_NOGPFAULTERRORBOX)
|
||||
{
|
||||
TCHAR szBuffer[4196];
|
||||
|
||||
wsprintf(szBuffer, _T("An unhandled exception ocurred\r\nSee %s for more details\r\n"), szLogFileName);
|
||||
|
||||
MessageBox(
|
||||
NULL,
|
||||
szBuffer,
|
||||
_T("Error"),
|
||||
MB_OK | MB_ICONERROR
|
||||
);
|
||||
}
|
||||
|
||||
SetErrorMode(fuOldErrorMode);
|
||||
}
|
||||
|
||||
|
@ -1146,35 +1191,46 @@ LONG WINAPI TopLevelExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
|
|||
|
||||
void ExchndlSetup()
|
||||
{
|
||||
# if defined(WZ_CC_MINGW)
|
||||
TCHAR miniDumpPath[PATH_MAX] = {'\0'};
|
||||
// Install the unhandled exception filter function
|
||||
prevExceptionFilter = SetUnhandledExceptionFilter(TopLevelExceptionFilter);
|
||||
|
||||
// Retrieve the current version
|
||||
formattedVersionString = strdup(version_getFormattedVersionString());
|
||||
|
||||
// Figure out what the report file will be named, and store it away
|
||||
if(GetModuleFileName(NULL, szLogFileName, MAX_PATH))
|
||||
// Because of UAC on vista / win7 we use this to write our dumps to (unless we override it via OverrideRPTDirectory())
|
||||
// NOTE: CSIDL_PERSONAL = C:\Users\user name\Documents
|
||||
if ( SUCCEEDED( SHGetFolderPathA( NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, miniDumpPath ) ))
|
||||
{
|
||||
LPTSTR lpszDot;
|
||||
PathAppend( miniDumpPath, TEXT( "Warzone 2100 2.3\\logs" ) );
|
||||
|
||||
// Look for the '.' before the "EXE" extension. Replace the extension
|
||||
// with "RPT"
|
||||
if((lpszDot = _tcsrchr(szLogFileName, _T('.'))))
|
||||
if( !PathFileExists( miniDumpPath ) )
|
||||
{
|
||||
lpszDot++; // Advance past the '.'
|
||||
_tcscpy(lpszDot, _T("RPT")); // "RPT" -> "Report"
|
||||
if( ERROR_SUCCESS != SHCreateDirectoryEx( NULL, miniDumpPath, NULL ) )
|
||||
{
|
||||
_tcscpy(miniDumpPath, _T("c:\\temp"));
|
||||
}
|
||||
}
|
||||
else
|
||||
_tcscat(szLogFileName, _T(".RPT"));
|
||||
}
|
||||
else if(GetWindowsDirectory(szLogFileName, MAX_PATH))
|
||||
{
|
||||
_tcscat(szLogFileName, _T("EXCHNDL.RPT"));
|
||||
else
|
||||
{ // should never fail, but if it does, we fall back to this
|
||||
_tcscpy(miniDumpPath, _T("c:\\temp"));
|
||||
}
|
||||
|
||||
_tcscat(szLogFileName, _T("Warzone2100.RPT"));
|
||||
_tcscat(miniDumpPath, _T("\\"));
|
||||
_tcscat(miniDumpPath,szLogFileName);
|
||||
_tcscpy(szLogFileName, miniDumpPath);
|
||||
|
||||
atexit(ExchndlShutdown);
|
||||
#endif
|
||||
}
|
||||
void ResetRPTDirectory(char *newPath)
|
||||
{
|
||||
debug(LOG_WZ, "New RPT directory is %s, was %s", newPath, szLogFileName);
|
||||
_tcscpy(szLogFileName, newPath);
|
||||
}
|
||||
|
||||
void ExchndlShutdown(void)
|
||||
{
|
||||
if (prevExceptionFilter)
|
||||
|
|
|
@ -23,5 +23,5 @@
|
|||
|
||||
extern void ExchndlSetup(void);
|
||||
extern void ExchndlShutdown(void);
|
||||
|
||||
void ResetRPTDirectory(char *newPath);
|
||||
#endif // __INCLUDED_LIB_EXCEPTIONHANDLER_EXCHNDL_H__
|
||||
|
|
|
@ -73,7 +73,7 @@ CC:=gcc
|
|||
CXX:=g++
|
||||
WINDRES:=windres
|
||||
WZ_CPPFLAGS+=-DWIN32
|
||||
WZ_LDFLAGS+=-mwindows -lmingw32 -lSDLmain -lSDL -lpng12 -lphysfs -lz -lvorbisfile -lvorbis -logg -lpopt -lintl -lGLC -lglu32 -lopengl32 -lopenal32 -ldbghelp -lshfolder -lwinmm -lws2_32 -lbfd -liberty -liconv -lz -lfreetype -lfontconfig -lexpat -ltheora
|
||||
WZ_LDFLAGS+=-mwindows -lmingw32 -lSDLmain -lSDL -lpng12 -lphysfs -lz -lvorbisfile -lvorbis -logg -lpopt -lintl -lGLC -lglu32 -lopengl32 -lopenal32 -ldbghelp -lshfolder -lwinmm -lshlwapi -lpsapi -lshell32 -lws2_32 -lbfd -liberty -liconv -lz -lfreetype -lfontconfig -lexpat -ltheora
|
||||
|
||||
|
||||
# Import environment variables
|
||||
|
|
|
@ -342,6 +342,7 @@ bool ParseCommandLineEarly(int argc, const char** argv)
|
|||
return false;
|
||||
}
|
||||
debug_register_callback( debug_callback_file, debug_callback_file_init, debug_callback_file_exit, (void*)token );
|
||||
customDebugfile = true;
|
||||
break;
|
||||
|
||||
case CLI_FLUSHDEBUGSTDERR:
|
||||
|
@ -418,7 +419,7 @@ bool ParseCommandLine(int argc, const char** argv)
|
|||
break;
|
||||
|
||||
case CLI_CHEAT:
|
||||
printf(" ** DEBUG MODE UNLOCKED! **\n");
|
||||
//printf(" ** DEBUG MODE UNLOCKED! **\n");
|
||||
bAllowDebugMode = true;
|
||||
break;
|
||||
|
||||
|
|
28
src/main.c
28
src/main.c
|
@ -75,6 +75,7 @@
|
|||
#include "map.h"
|
||||
#include "parsetest.h"
|
||||
#include "keybind.h"
|
||||
#include <time.h>
|
||||
|
||||
/* Always use fallbacks on Windows */
|
||||
#if defined(WZ_OS_WIN)
|
||||
|
@ -114,6 +115,7 @@ bool use_override_mods = false;
|
|||
|
||||
char * loaded_mods[MAX_MODS] = { NULL };
|
||||
char * mod_list = NULL;
|
||||
bool customDebugfile = false; // Default false: user has NOT specified where to store the stdout/err file.
|
||||
int num_loaded_mods = 0;
|
||||
|
||||
|
||||
|
@ -485,6 +487,15 @@ static void initialize_ConfigDir(void)
|
|||
tmpstr, PHYSFS_getLastError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// NOTE: This is currently only used for mingw builds for now.
|
||||
#if defined (WZ_CC_MINGW)
|
||||
if (!OverrideRPTDirectory(tmpstr))
|
||||
{
|
||||
// since it failed, we just use our default path, and not the user supplied one.
|
||||
debug(LOG_ERROR, "Error setting exception hanlder to use directory %s", tmpstr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// User's home dir first so we allways see what we write
|
||||
|
@ -1045,7 +1056,22 @@ int main(int argc, char *argv[])
|
|||
* directory.
|
||||
*/
|
||||
initialize_ConfigDir();
|
||||
if (!customDebugfile)
|
||||
{
|
||||
// there was no custom debug file specified (--debug-file=blah)
|
||||
// so we use our write directory to store our logs.
|
||||
time_t aclock;
|
||||
struct tm *newtime;
|
||||
char buf[PATH_MAX];
|
||||
|
||||
time( &aclock ); // Get time in seconds
|
||||
newtime = localtime( &aclock ); // Convert time to struct
|
||||
// Note: We are using fopen(), and not physfs routines to open the file
|
||||
// log name is logs/(or \)WZlog-MMDD_HHMMSS.txt
|
||||
snprintf(buf, sizeof(buf), "%slogs%sWZlog-%02d%02d_%02d%02d%02d.txt", PHYSFS_getWriteDir(), PHYSFS_getDirSeparator(),
|
||||
newtime->tm_mon, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec );
|
||||
debug_register_callback( debug_callback_file, debug_callback_file_init, debug_callback_file_exit, buf );
|
||||
}
|
||||
debug(LOG_WZ, "Warzone 2100 - %s", version_getFormattedVersionString());
|
||||
|
||||
/*** Initialize directory structure ***/
|
||||
|
@ -1053,7 +1079,7 @@ int main(int argc, char *argv[])
|
|||
make_dir(SaveGamePath, "savegame", NULL);
|
||||
PHYSFS_mkdir("maps"); // MUST have this to prevent crashes when getting map
|
||||
PHYSFS_mkdir("music");
|
||||
PHYSFS_mkdir("logs"); // a place to hold our netplay logs
|
||||
PHYSFS_mkdir("logs"); // a place to hold our netplay, mingw crash reports & WZ logs
|
||||
make_dir(MultiPlayersPath, "multiplay", NULL);
|
||||
make_dir(MultiPlayersPath, "multiplay", "players");
|
||||
make_dir(MultiCustomMapsPath, "multiplay", "custommaps");
|
||||
|
|
|
@ -35,7 +35,7 @@ typedef enum {
|
|||
//flag to indicate when initialisation is complete
|
||||
extern BOOL gameInitialised;
|
||||
extern BOOL bDisableLobby;
|
||||
|
||||
extern bool customDebugfile;
|
||||
extern GS_GAMEMODE GetGameMode(void) WZ_DECL_PURE;
|
||||
extern void SetGameMode(GS_GAMEMODE status);
|
||||
|
||||
|
|
Loading…
Reference in New Issue