Torque3D Documentation / _generateds / winMiniDump.cpp

winMiniDump.cpp

Engine/source/platformWin32/minidump/winMiniDump.cpp

More...

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#if defined( TORQUE_MINIDUMP ) && defined( TORQUE_RELEASE )
 25
 26#include "platformWin32/platformWin32.h"
 27#include "platformWin32/minidump/winStackWalker.h"
 28#include "core/fileio.h"
 29#include "core/strings/stringFunctions.h"
 30#include "console/console.h"
 31#include "app/net/serverQuery.h"
 32
 33#pragma pack(push,8)
 34#include <DbgHelp.h>
 35#include <time.h>
 36#pragma pack(pop)
 37
 38#pragma comment(lib, "dbghelp.lib")
 39
 40extern Win32PlatState winState;
 41
 42//Forward declarations for the dialog functions
 43BOOL CALLBACK MiniDumpDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam);
 44LRESULT DisplayMiniDumpDialog(HINSTANCE hinst, HWND hwndOwner);
 45LPWORD lpwAlign(LPWORD lpIn);
 46char gUserInput[4096];
 47
 48//Console variables
 49extern StringTableEntry gMiniDumpDir;
 50extern StringTableEntry gMiniDumpUser;
 51extern StringTableEntry gMiniDumpExec;
 52extern StringTableEntry gMiniDumpParams;
 53extern StringTableEntry gMiniDumpExecDir;
 54
 55
 56char* dStrrstr(char* dst, const char* src, const char* findStr, char* replaceStr)
 57{
 58   //see if str contains findStr, if not then return
 59   const char* findpos = strstr(src, findStr);
 60   if(!findpos) 
 61   {
 62      strcpy(dst, src);
 63   }
 64   else
 65   {
 66      //copy the new string to the buffer
 67      dst[0]='\0';
 68      strncat(dst, src, findpos-src);
 69      strcat(dst, replaceStr);
 70      const char* cur = findpos + strlen(findStr);
 71      strcat(dst, cur);
 72   }
 73
 74   return dst;
 75}
 76
 77
 78//-----------------------------------------------------------------------------------------------------------------------------------------
 79//  CreateMiniDump()
 80//-----------------------------------------------------------------------------------------------------------------------------------------
 81INT CreateMiniDump( LPEXCEPTION_POINTERS ExceptionInfo)
 82{
 83   //Get any information we can from the user and store it in gUserInput
 84   try
 85   {
 86      while(ShowCursor(TRUE) < 0);
 87      DisplayMiniDumpDialog(winState.appInstance, winState.appWindow);
 88   }
 89   catch(...)
 90   {
 91      //dSprintf(gUserInput, 4096, "The user could not enter a description of what was occurring.\n\n\n");
 92   }
 93
 94   //Build a Game, Date and Time stamped MiniDump folder
 95   time_t theTime;
 96   time(&theTime);
 97   tm* pLocalTime = localtime(&theTime);
 98   char crashFolder[2048];
 99   dSprintf(crashFolder, 2048, "%s_%02d.%02d_%02d.%02d.%02d", 
100      Platform::getExecutableName(),
101      pLocalTime->tm_mon+1, pLocalTime->tm_mday,
102      pLocalTime->tm_hour, pLocalTime->tm_min, pLocalTime->tm_sec);
103
104   //Builed the fully qualified MiniDump path
105   char crashPath[2048];
106   char fileName[2048];
107   if(gMiniDumpDir==<a href="/coding/file/types_8lint_8h/#types_8lint_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a>)
108   {
109      dSprintf(crashPath, 2048, "%s/MiniDump/%s", Platform::getCurrentDirectory(), crashFolder);
110   }
111   else
112   {
113      dSprintf(crashPath, 2048, "%s/%s", gMiniDumpDir, crashFolder);
114   }
115
116   dSprintf(fileName, 2048, "%s/Minidump.dmp",crashPath);
117   if (!Platform::createPath (fileName))return false;  //create the directory
118
119   //Save the minidump
120   File fileObject;
121   if(fileObject.open(fileName, File::Write) == File::Ok)
122   {
123      MINIDUMP_EXCEPTION_INFORMATION DumpExceptionInfo;
124      DumpExceptionInfo.ThreadId = GetCurrentThreadId();
125      DumpExceptionInfo.ExceptionPointers = ExceptionInfo;
126      DumpExceptionInfo.ClientPointers = true;
127      MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), (HANDLE)fileObject.getHandle(), MiniDumpNormal, &DumpExceptionInfo, NULL, NULL );
128      fileObject.close();
129   }
130
131   //copy over the log file
132   char fromFile[2048];
133   dSprintf(fromFile, 2048, "%s/%s", Platform::getCurrentDirectory(), "console.log" );
134   dSprintf(fileName, 2048, "%s/console.log", crashPath);
135   Con::setLogMode(3); //ensure that the log file is closed (so it can be copied)
136   dPathCopy(fromFile, fileName, true);
137
138   //copy over the exe file
139   char exeName[1024];
140   dSprintf(exeName, 1024, Platform::getExecutableName());
141   exeName[dStrlen(exeName)-4]=0;
142   dSprintf(fromFile, 2048, "%s/%s.dll", Platform::getCurrentDirectory(), exeName );
143   dSprintf(fileName, 2048, "%s/%s.dll", crashPath, exeName );
144   dPathCopy(fromFile, fileName, true);
145
146   //copy over the pdb file
147   char pdbName[1024];
148   dStrcpy(pdbName, exeName, 1024); 
149   dStrncat(pdbName, ".pdb", 4);
150   dSprintf(fromFile, 2048, "%s/%s", Platform::getCurrentDirectory(), pdbName );
151   dSprintf(fileName, 2048, "%s/%s", crashPath, pdbName );
152   dPathCopy(fromFile, fileName, true);
153
154   //save the call stack
155   char traceBuffer[65536];
156   traceBuffer[0] = 0;
157   dGetStackTrace( traceBuffer, *static_cast<const CONTEXT *>(ExceptionInfo->ContextRecord) );
158
159   //save the user input and the call stack to a file
160   char crashlogFile[2048];
161   dSprintf(crashlogFile, 2048, "%s/crash.log", crashPath);
162   if(fileObject.open(crashlogFile, File::Write) == File::Ok)
163   {
164      fileObject.write(strlen(gUserInput), gUserInput);
165      fileObject.write(strlen(traceBuffer), traceBuffer);
166      fileObject.close();
167   }
168
169   //call the external program indicated in script
170   if(gMiniDumpExec!= NULL)
171   {
172      //replace special variables in gMiniDumpParams
173      if(gMiniDumpParams)
174      {
175         char updateParams[4096];
176         char finalParams[4096];
177         dStrrstr(finalParams, gMiniDumpParams, "%crashpath%", crashPath);
178         dStrrstr(updateParams, finalParams, "%crashfolder%", crashFolder);
179         dStrrstr(finalParams, updateParams, "%crashlog%", crashlogFile);
180         ShellExecuteA(NULL, "", gMiniDumpExec, finalParams, gMiniDumpExecDir ? gMiniDumpExecDir : "", SW_SHOWNORMAL);
181      }
182      else
183      {
184         ShellExecuteA(NULL, "", gMiniDumpExec, "", gMiniDumpExecDir ? gMiniDumpExecDir : "", SW_SHOWNORMAL);
185      }
186   }
187
188   return EXCEPTION_EXECUTE_HANDLER;
189}
190
191
192//-----------------------------------------------------------------------------------------------------------------------------------------
193//  MiniDumpDialogProc - Used By DisplayMiniDumpDialog
194//-----------------------------------------------------------------------------------------------------------------------------------------
195const S32 ID_TEXT=200;
196const S32 ID_USERTEXT=300;
197const S32 ID_DONE=400;
198BOOL CALLBACK MiniDumpDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) 
199{ 
200   char text[128]= "";
201
202   switch (message) 
203   { 
204   case WM_INITDIALOG :
205      SetDlgItemTextA ( hwndDlg, ID_USERTEXT, text );
206      return TRUE ;
207
208   case WM_COMMAND: 
209      switch (LOWORD(wParam)) 
210      { 
211      case ID_DONE:
212         if( !GetDlgItemTextA(hwndDlg, ID_USERTEXT, gUserInput, 4096) )  gUserInput[0]='\0'; 
213         strcat(gUserInput, "\n\n\n");
214         EndDialog(hwndDlg, wParam); 
215         return TRUE; 
216      default:
217         return TRUE;
218      } 
219   } 
220   return FALSE; 
221} 
222
223
224//-----------------------------------------------------------------------------------------------------------------------------------------
225//  Helper function to DWORD align the Dialog Box components (Used in DisplayMiniDumpDialog()
226//-----------------------------------------------------------------------------------------------------------------------------------------
227LPWORD lpwAlign(LPWORD lpIn)
228{
229   ULONG ul;
230
231   ul = (ULONG)lpIn;
232   ul ++;
233   ul >>=1;
234   ul <<=1;
235   return (LPWORD)ul;
236}
237
238
239//-----------------------------------------------------------------------------------------------------------------------------------------
240//  Create the Dialog Box to get input from the user
241//-----------------------------------------------------------------------------------------------------------------------------------------
242LRESULT DisplayMiniDumpDialog(HINSTANCE hinst, HWND hwndOwner)
243{
244   HGLOBAL hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024);
245   if (!hgbl) return -1;
246
247   //-----------------------------------------------------------------
248   // Define the dialog box
249   //-----------------------------------------------------------------
250   LPDLGTEMPLATE lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
251   lpdt->style = WS_POPUP | WS_BORDER | DS_MODALFRAME | WS_CAPTION;
252   lpdt->cdit = 3;         // Number of controls
253   lpdt->x  = 100;  
254   lpdt->y  = 100;
255   lpdt->cx = 300; 
256   lpdt->cy = 90;
257
258   LPWORD lpw = (LPWORD)(lpdt + 1);
259   *lpw++ = 0;             // No menu
260   *lpw++ = 0;             // Predefined dialog box class (by default)
261
262   LPWSTR lpwsz = (LPWSTR)lpw;
263   S32 nchar = 1 + MultiByteToWideChar(CP_ACP, 0, "MiniDump Crash Report", -1, lpwsz, 50);
264   lpw += nchar;
265
266   //-----------------------------------------------------------------
267   // Define a static text message
268   //-----------------------------------------------------------------
269   lpw = lpwAlign(lpw);    // Align DLGITEMTEMPLATE on DWORD boundary
270   LPDLGITEMTEMPLATE lpdit = (LPDLGITEMTEMPLATE)lpw;
271   lpdit->x  = 10; 
272   lpdit->y  = 10;
273   lpdit->cx = 290; 
274   lpdit->cy = 10;
275   lpdit->id = ID_TEXT;    // Text identifier
276   lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
277
278   lpw = (LPWORD)(lpdit + 1);
279   *lpw++ = 0xFFFF;
280   *lpw++ = 0x0082;        // Static class
281
282   LPSTR msg = "The program has crashed.  Please describe what was happening:";
283   for (lpwsz = (LPWSTR)lpw; *lpwsz++ = (WCHAR)*msg++;);
284   lpw = (LPWORD)lpwsz;
285
286   *lpw++ = 0;             // No creation data        
287
288   //-----------------------------------------------------------------
289   // Define a DONE button
290   //-----------------------------------------------------------------
291   lpw = lpwAlign(lpw);    // Align DLGITEMTEMPLATE on DWORD boundary
292   lpdit = (LPDLGITEMTEMPLATE)lpw;
293   lpdit->x  = 265; 
294   lpdit->y  = 75;
295   lpdit->cx = 25; 
296   lpdit->cy = 12;
297   lpdit->id = ID_DONE;       // OK button identifier
298   lpdit->style = WS_CHILD | WS_VISIBLE | WS_TABSTOP;// | BS_DEFPUSHBUTTON;
299
300   lpw = (LPWORD)(lpdit + 1);
301   *lpw++ = 0xFFFF;
302   *lpw++ = 0x0080;        // Button class
303
304   lpwsz = (LPWSTR)lpw;
305   nchar = 1 + MultiByteToWideChar(CP_ACP, 0, "Done", -1, lpwsz, 50);
306   lpw += nchar;
307   *lpw++ = 0;             // No creation data
308
309   //-----------------------------------------------------------------
310   // Define a text entry message
311   //-----------------------------------------------------------------
312   lpw = lpwAlign(lpw);    // Align DLGITEMTEMPLATE on DWORD boundary
313   lpdit = (LPDLGITEMTEMPLATE)lpw;
314   lpdit->x  = 10; 
315   lpdit->y  = 22;
316   lpdit->cx = 280; 
317   lpdit->cy = 50;
318   lpdit->id = ID_USERTEXT;    // Text identifier
319   lpdit->style = ES_LEFT | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE;
320
321   lpw = (LPWORD)(lpdit + 1);
322   *lpw++ = 0xFFFF;
323   *lpw++ = 0x0081;        // Text edit class
324
325   *lpw++ = 0;             // No creation data
326
327
328
329   GlobalUnlock(hgbl); 
330   LRESULT ret = DialogBoxIndirect( hinst, 
331      (LPDLGTEMPLATE)hgbl, 
332      hwndOwner, 
333      (DLGPROC)MiniDumpDialogProc); 
334   GlobalFree(hgbl); 
335   return ret; 
336}
337
338#endif
339