123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #if defined( TORQUE_MINIDUMP ) && defined( TORQUE_RELEASE )
- #include "platformWin32/platformWin32.h"
- #include "platformWin32/minidump/winStackWalker.h"
- #include "core/fileio.h"
- #include "core/strings/stringFunctions.h"
- #include "console/console.h"
- #include "app/net/serverQuery.h"
- #pragma pack(push,8)
- #include <DbgHelp.h>
- #include <time.h>
- #pragma pack(pop)
- #pragma comment(lib, "dbghelp.lib")
- extern Win32PlatState winState;
- //Forward declarations for the dialog functions
- BOOL CALLBACK MiniDumpDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam);
- LRESULT DisplayMiniDumpDialog(HINSTANCE hinst, HWND hwndOwner);
- LPWORD lpwAlign(LPWORD lpIn);
- char gUserInput[4096];
- //Console variables
- extern StringTableEntry gMiniDumpDir;
- extern StringTableEntry gMiniDumpUser;
- extern StringTableEntry gMiniDumpExec;
- extern StringTableEntry gMiniDumpParams;
- extern StringTableEntry gMiniDumpExecDir;
- char* dStrrstr(char* dst, const char* src, const char* findStr, char* replaceStr)
- {
- //see if str contains findStr, if not then return
- const char* findpos = strstr(src, findStr);
- if(!findpos)
- {
- strcpy(dst, src);
- }
- else
- {
- //copy the new string to the buffer
- dst[0]='\0';
- strncat(dst, src, findpos-src);
- strcat(dst, replaceStr);
- const char* cur = findpos + strlen(findStr);
- strcat(dst, cur);
- }
- return dst;
- }
- //-----------------------------------------------------------------------------------------------------------------------------------------
- // CreateMiniDump()
- //-----------------------------------------------------------------------------------------------------------------------------------------
- INT CreateMiniDump( LPEXCEPTION_POINTERS ExceptionInfo)
- {
- //Get any information we can from the user and store it in gUserInput
- try
- {
- while(ShowCursor(TRUE) < 0);
- DisplayMiniDumpDialog(winState.appInstance, winState.appWindow);
- }
- catch(...)
- {
- //dSprintf(gUserInput, 4096, "The user could not enter a description of what was occurring.\n\n\n");
- }
- //Build a Game, Date and Time stamped MiniDump folder
- time_t theTime;
- time(&theTime);
- tm* pLocalTime = localtime(&theTime);
- char crashFolder[2048];
- dSprintf(crashFolder, 2048, "%s_%02d.%02d_%02d.%02d.%02d",
- Platform::getExecutableName(),
- pLocalTime->tm_mon+1, pLocalTime->tm_mday,
- pLocalTime->tm_hour, pLocalTime->tm_min, pLocalTime->tm_sec);
- //Builed the fully qualified MiniDump path
- char crashPath[2048];
- char fileName[2048];
- if(gMiniDumpDir==NULL)
- {
- dSprintf(crashPath, 2048, "%s/MiniDump/%s", Platform::getCurrentDirectory(), crashFolder);
- }
- else
- {
- dSprintf(crashPath, 2048, "%s/%s", gMiniDumpDir, crashFolder);
- }
- dSprintf(fileName, 2048, "%s/Minidump.dmp",crashPath);
- if (!Platform::createPath (fileName))return false; //create the directory
- //Save the minidump
- File fileObject;
- if(fileObject.open(fileName, File::Write) == File::Ok)
- {
- MINIDUMP_EXCEPTION_INFORMATION DumpExceptionInfo;
- DumpExceptionInfo.ThreadId = GetCurrentThreadId();
- DumpExceptionInfo.ExceptionPointers = ExceptionInfo;
- DumpExceptionInfo.ClientPointers = true;
- MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), (HANDLE)fileObject.getHandle(), MiniDumpNormal, &DumpExceptionInfo, NULL, NULL );
- fileObject.close();
- }
- //copy over the log file
- char fromFile[2048];
- dSprintf(fromFile, 2048, "%s/%s", Platform::getCurrentDirectory(), "console.log" );
- dSprintf(fileName, 2048, "%s/console.log", crashPath);
- Con::setLogMode(3); //ensure that the log file is closed (so it can be copied)
- dPathCopy(fromFile, fileName, true);
- //copy over the exe file
- char exeName[1024];
- dSprintf(exeName, 1024, Platform::getExecutableName());
- exeName[dStrlen(exeName)-4]=0;
- dSprintf(fromFile, 2048, "%s/%s.dll", Platform::getCurrentDirectory(), exeName );
- dSprintf(fileName, 2048, "%s/%s.dll", crashPath, exeName );
- dPathCopy(fromFile, fileName, true);
- //copy over the pdb file
- char pdbName[1024];
- dStrcpy(pdbName, exeName, 1024);
- dStrncat(pdbName, ".pdb", 4);
- dSprintf(fromFile, 2048, "%s/%s", Platform::getCurrentDirectory(), pdbName );
- dSprintf(fileName, 2048, "%s/%s", crashPath, pdbName );
- dPathCopy(fromFile, fileName, true);
- //save the call stack
- char traceBuffer[65536];
- traceBuffer[0] = 0;
- dGetStackTrace( traceBuffer, *static_cast<const CONTEXT *>(ExceptionInfo->ContextRecord) );
- //save the user input and the call stack to a file
- char crashlogFile[2048];
- dSprintf(crashlogFile, 2048, "%s/crash.log", crashPath);
- if(fileObject.open(crashlogFile, File::Write) == File::Ok)
- {
- fileObject.write(strlen(gUserInput), gUserInput);
- fileObject.write(strlen(traceBuffer), traceBuffer);
- fileObject.close();
- }
- //call the external program indicated in script
- if(gMiniDumpExec!= NULL)
- {
- //replace special variables in gMiniDumpParams
- if(gMiniDumpParams)
- {
- char updateParams[4096];
- char finalParams[4096];
- dStrrstr(finalParams, gMiniDumpParams, "%crashpath%", crashPath);
- dStrrstr(updateParams, finalParams, "%crashfolder%", crashFolder);
- dStrrstr(finalParams, updateParams, "%crashlog%", crashlogFile);
- ShellExecuteA(NULL, "", gMiniDumpExec, finalParams, gMiniDumpExecDir ? gMiniDumpExecDir : "", SW_SHOWNORMAL);
- }
- else
- {
- ShellExecuteA(NULL, "", gMiniDumpExec, "", gMiniDumpExecDir ? gMiniDumpExecDir : "", SW_SHOWNORMAL);
- }
- }
- return EXCEPTION_EXECUTE_HANDLER;
- }
- //-----------------------------------------------------------------------------------------------------------------------------------------
- // MiniDumpDialogProc - Used By DisplayMiniDumpDialog
- //-----------------------------------------------------------------------------------------------------------------------------------------
- const S32 ID_TEXT=200;
- const S32 ID_USERTEXT=300;
- const S32 ID_DONE=400;
- BOOL CALLBACK MiniDumpDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
- {
- char text[128]= "";
- switch (message)
- {
- case WM_INITDIALOG :
- SetDlgItemTextA ( hwndDlg, ID_USERTEXT, text );
- return TRUE ;
- case WM_COMMAND:
- switch (LOWORD(wParam))
- {
- case ID_DONE:
- if( !GetDlgItemTextA(hwndDlg, ID_USERTEXT, gUserInput, 4096) ) gUserInput[0]='\0';
- strcat(gUserInput, "\n\n\n");
- EndDialog(hwndDlg, wParam);
- return TRUE;
- default:
- return TRUE;
- }
- }
- return FALSE;
- }
- //-----------------------------------------------------------------------------------------------------------------------------------------
- // Helper function to DWORD align the Dialog Box components (Used in DisplayMiniDumpDialog()
- //-----------------------------------------------------------------------------------------------------------------------------------------
- LPWORD lpwAlign(LPWORD lpIn)
- {
- ULONG ul;
- ul = (ULONG)lpIn;
- ul ++;
- ul >>=1;
- ul <<=1;
- return (LPWORD)ul;
- }
- //-----------------------------------------------------------------------------------------------------------------------------------------
- // Create the Dialog Box to get input from the user
- //-----------------------------------------------------------------------------------------------------------------------------------------
- LRESULT DisplayMiniDumpDialog(HINSTANCE hinst, HWND hwndOwner)
- {
- HGLOBAL hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024);
- if (!hgbl) return -1;
- //-----------------------------------------------------------------
- // Define the dialog box
- //-----------------------------------------------------------------
- LPDLGTEMPLATE lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
- lpdt->style = WS_POPUP | WS_BORDER | DS_MODALFRAME | WS_CAPTION;
- lpdt->cdit = 3; // Number of controls
- lpdt->x = 100;
- lpdt->y = 100;
- lpdt->cx = 300;
- lpdt->cy = 90;
- LPWORD lpw = (LPWORD)(lpdt + 1);
- *lpw++ = 0; // No menu
- *lpw++ = 0; // Predefined dialog box class (by default)
- LPWSTR lpwsz = (LPWSTR)lpw;
- S32 nchar = 1 + MultiByteToWideChar(CP_ACP, 0, "MiniDump Crash Report", -1, lpwsz, 50);
- lpw += nchar;
- //-----------------------------------------------------------------
- // Define a static text message
- //-----------------------------------------------------------------
- lpw = lpwAlign(lpw); // Align DLGITEMTEMPLATE on DWORD boundary
- LPDLGITEMTEMPLATE lpdit = (LPDLGITEMTEMPLATE)lpw;
- lpdit->x = 10;
- lpdit->y = 10;
- lpdit->cx = 290;
- lpdit->cy = 10;
- lpdit->id = ID_TEXT; // Text identifier
- lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
- lpw = (LPWORD)(lpdit + 1);
- *lpw++ = 0xFFFF;
- *lpw++ = 0x0082; // Static class
- LPSTR msg = "The program has crashed. Please describe what was happening:";
- for (lpwsz = (LPWSTR)lpw; *lpwsz++ = (WCHAR)*msg++;);
- lpw = (LPWORD)lpwsz;
- *lpw++ = 0; // No creation data
- //-----------------------------------------------------------------
- // Define a DONE button
- //-----------------------------------------------------------------
- lpw = lpwAlign(lpw); // Align DLGITEMTEMPLATE on DWORD boundary
- lpdit = (LPDLGITEMTEMPLATE)lpw;
- lpdit->x = 265;
- lpdit->y = 75;
- lpdit->cx = 25;
- lpdit->cy = 12;
- lpdit->id = ID_DONE; // OK button identifier
- lpdit->style = WS_CHILD | WS_VISIBLE | WS_TABSTOP;// | BS_DEFPUSHBUTTON;
- lpw = (LPWORD)(lpdit + 1);
- *lpw++ = 0xFFFF;
- *lpw++ = 0x0080; // Button class
- lpwsz = (LPWSTR)lpw;
- nchar = 1 + MultiByteToWideChar(CP_ACP, 0, "Done", -1, lpwsz, 50);
- lpw += nchar;
- *lpw++ = 0; // No creation data
- //-----------------------------------------------------------------
- // Define a text entry message
- //-----------------------------------------------------------------
- lpw = lpwAlign(lpw); // Align DLGITEMTEMPLATE on DWORD boundary
- lpdit = (LPDLGITEMTEMPLATE)lpw;
- lpdit->x = 10;
- lpdit->y = 22;
- lpdit->cx = 280;
- lpdit->cy = 50;
- lpdit->id = ID_USERTEXT; // Text identifier
- lpdit->style = ES_LEFT | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE;
- lpw = (LPWORD)(lpdit + 1);
- *lpw++ = 0xFFFF;
- *lpw++ = 0x0081; // Text edit class
- *lpw++ = 0; // No creation data
- GlobalUnlock(hgbl);
- LRESULT ret = DialogBoxIndirect( hinst,
- (LPDLGTEMPLATE)hgbl,
- hwndOwner,
- (DLGPROC)MiniDumpDialogProc);
- GlobalFree(hgbl);
- return ret;
- }
- #endif
|