llcrashloggerwindows.cpp

Go to the documentation of this file.
00001 
00032 #include "stdafx.h"
00033 #include "resource.h"
00034 #include "llcrashloggerwindows.h"
00035 
00036 #include <sstream>
00037 
00038 #include "boost/tokenizer.hpp"
00039 
00040 #include "dbghelp.h"
00041 #include "indra_constants.h"    // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME
00042 #include "llerror.h"
00043 #include "llfile.h"
00044 #include "lltimer.h"
00045 #include "llstring.h"
00046 #include "lldxhardware.h"
00047 #include "lldir.h"
00048 #include "llsdserialize.h"
00049 
00050 #define MAX_LOADSTRING 100
00051 #define MAX_STRING 2048
00052 const char* const SETTINGS_FILE_HEADER = "version";
00053 const S32 SETTINGS_FILE_VERSION = 101;
00054 
00055 // Windows Message Handlers
00056 
00057 // Global Variables:
00058 HINSTANCE hInst= NULL;                                  // current instance
00059 TCHAR szTitle[MAX_LOADSTRING];                          /* Flawfinder: ignore */                // The title bar text
00060 TCHAR szWindowClass[MAX_LOADSTRING];            /* Flawfinder: ignore */                // The title bar text
00061 
00062 LLString gProductName;
00063 HWND gHwndReport = NULL;        // Send/Don't Send dialog
00064 HWND gHwndProgress = NULL;      // Progress window
00065 HCURSOR gCursorArrow = NULL;
00066 HCURSOR gCursorWait = NULL;
00067 BOOL gFirstDialog = TRUE;       // Are we currently handling the Send/Don't Send dialog?
00068 std::stringstream gDXInfo;
00069 bool gSendLogs = false;
00070 
00071 
00072 //Conversion from char* to wchar*
00073 //Replacement for ATL macros, doesn't allocate memory
00074 //For more info see: http://www.codeguru.com/forum/showthread.php?t=337247
00075 void ConvertLPCSTRToLPWSTR (const char* pCstring, WCHAR* outStr)
00076 {
00077     if (pCstring != NULL)
00078     {
00079         int nInputStrLen = strlen (pCstring);
00080         // Double NULL Termination
00081         int nOutputStrLen = MultiByteToWideChar(CP_ACP, 0, pCstring, nInputStrLen, NULL, 0) + 2;
00082         if (outStr)
00083         {
00084             memset (outStr, 0x00, sizeof (WCHAR)*nOutputStrLen);
00085             MultiByteToWideChar (CP_ACP, 0, pCstring, nInputStrLen, outStr, nInputStrLen);
00086         }
00087     }
00088 }
00089 
00090 void write_debug(const char *str)
00091 {
00092         gDXInfo << str;         /* Flawfinder: ignore */
00093 }
00094 
00095 void write_debug(std::string& str)
00096 {
00097         write_debug(str.c_str());
00098 }
00099 
00100 void show_progress(const char* message)
00101 {
00102         std::wstring msg = wstring_to_utf16str(utf8str_to_wstring(message));
00103         if (gHwndProgress)
00104         {
00105                 SendDlgItemMessage(gHwndProgress,       // handle to destination window 
00106                                                         IDC_LOG,
00107                                                         WM_SETTEXT,                     // message to send
00108                                                         FALSE,                          // undo option
00109                                                         (LPARAM)msg.c_str());
00110         }
00111 }
00112 
00113 void update_messages()
00114 {
00115         MSG msg;
00116         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
00117         {
00118                 if (msg.message == WM_QUIT)
00119                 {
00120                         exit(0);
00121                 }
00122                 TranslateMessage(&msg);
00123                 DispatchMessage(&msg);
00124         }
00125 }
00126 
00127 void sleep_and_pump_messages( U32 seconds )
00128 {
00129         const U32 CYCLES_PER_SECOND = 10;
00130         U32 cycles = seconds * CYCLES_PER_SECOND;
00131         while( cycles-- )
00132         {
00133                 update_messages();
00134                 ms_sleep(1000 / CYCLES_PER_SECOND);
00135         }
00136 }
00137 
00138 // Include product name in the window caption.
00139 void LLCrashLoggerWindows::ProcessCaption(HWND hWnd)
00140 {
00141         TCHAR templateText[MAX_STRING];         /* Flawfinder: ignore */
00142         TCHAR header[MAX_STRING];
00143         std::string final;
00144         GetWindowText(hWnd, templateText, sizeof(templateText));
00145         final = llformat(ll_convert_wide_to_string(templateText).c_str(), gProductName.c_str());
00146         ConvertLPCSTRToLPWSTR(final.c_str(), header);
00147         SetWindowText(hWnd, header);
00148 }
00149 
00150 
00151 // Include product name in the diaog item text.
00152 void LLCrashLoggerWindows::ProcessDlgItemText(HWND hWnd, int nIDDlgItem)
00153 {
00154         TCHAR templateText[MAX_STRING];         /* Flawfinder: ignore */
00155         TCHAR header[MAX_STRING];
00156         std::string final;
00157         GetDlgItemText(hWnd, nIDDlgItem, templateText, sizeof(templateText));
00158         final = llformat(ll_convert_wide_to_string(templateText).c_str(), gProductName.c_str());
00159         ConvertLPCSTRToLPWSTR(final.c_str(), header);
00160         SetDlgItemText(hWnd, nIDDlgItem, header);
00161 }
00162 
00163 bool handle_button_click(WORD button_id)
00164 {
00165         // Is this something other than Send or Don't Send?
00166         if (button_id != IDOK
00167                 && button_id != IDCANCEL)
00168         {
00169                 return false;
00170         }
00171 
00172         // See if "do this next time" is checked and save state
00173         S32 crash_behavior = CRASH_BEHAVIOR_ASK;
00174         LRESULT result = SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_GETCHECK, 0, 0);
00175         if (result == BST_CHECKED)
00176         {
00177                 if (button_id == IDOK)
00178                 {
00179                         crash_behavior = CRASH_BEHAVIOR_ALWAYS_SEND;
00180                 }
00181                 else if (button_id == IDCANCEL)
00182                 {
00183                         crash_behavior = CRASH_BEHAVIOR_NEVER_SEND;
00184                 }
00185                 ((LLCrashLoggerWindows*)LLCrashLogger::instance())->saveCrashBehaviorSetting(crash_behavior);
00186         }
00187         
00188         // We're done with this dialog.
00189         gFirstDialog = FALSE;
00190 
00191         // Send the crash report if requested
00192         if (button_id == IDOK)
00193         {
00194                 gSendLogs = TRUE;
00195                 WCHAR wbuffer[20000];
00196                 GetDlgItemText(gHwndReport, // handle to dialog box
00197                                                 IDC_EDIT1,  // control identifier
00198                                                 wbuffer, // pointer to buffer for text
00199                                                 20000 // maximum size of string
00200                                                 );
00201                 LLString user_text(ll_convert_wide_to_string(wbuffer));
00202                 // Activate and show the window.
00203                 ShowWindow(gHwndProgress, SW_SHOW); 
00204                 // Try doing this second to make the progress window go frontmost.
00205                 ShowWindow(gHwndReport, SW_HIDE);
00206                 ((LLCrashLoggerWindows*)LLCrashLogger::instance())->setUserText(user_text);
00207                 ((LLCrashLoggerWindows*)LLCrashLogger::instance())->sendCrashLogs();
00208         }
00209         // Quit the app
00210         LLApp::setQuitting();
00211         return true;
00212 }
00213 
00214 
00215 LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
00216 {
00217         switch( message )
00218         {
00219         case WM_CREATE:
00220                 return 0;
00221 
00222         case WM_COMMAND:
00223                 if( gFirstDialog )
00224                 {
00225                         WORD button_id = LOWORD(wParam);
00226                         bool handled = handle_button_click(button_id);
00227                         if (handled)
00228                         {
00229                                 return 0;
00230                         }
00231                 }
00232                 break;
00233 
00234         case WM_DESTROY:
00235                 // Closing the window cancels
00236                 LLApp::setQuitting();
00237                 PostQuitMessage(0);
00238                 return 0;
00239         }
00240 
00241         return DefWindowProc(hwnd, message, wParam, lParam);
00242 }
00243 
00244 
00245 LLCrashLoggerWindows::LLCrashLoggerWindows(void)
00246 {
00247 }
00248 
00249 LLCrashLoggerWindows::~LLCrashLoggerWindows(void)
00250 {
00251 }
00252 
00253 bool LLCrashLoggerWindows::init(void)
00254 {       
00255         bool ok = LLCrashLogger::init();
00256         if(!ok) return false;
00257 
00258         /*
00259         mbstowcs(gProductName, mProductName.c_str(), sizeof(gProductName)/sizeof(gProductName[0]));
00260         gProductName[ sizeof(gProductName)/sizeof(gProductName[0]) - 1 ] = 0;
00261         swprintf(gProductName, L"Second Life");
00262         */
00263 
00264         llinfos << "Loading dialogs" << llendl;
00265 
00266         // Initialize global strings
00267         LoadString(mhInst, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
00268         LoadString(mhInst, IDC_WIN_CRASH_LOGGER, szWindowClass, MAX_LOADSTRING);
00269 
00270         gCursorArrow = LoadCursor(NULL, IDC_ARROW);
00271         gCursorWait = LoadCursor(NULL, IDC_WAIT);
00272 
00273         // Register a window class that will be used by our dialogs
00274         WNDCLASS wndclass;
00275         wndclass.style = CS_HREDRAW | CS_VREDRAW;
00276         wndclass.lpfnWndProc = WndProc;
00277         wndclass.cbClsExtra = 0;
00278         wndclass.cbWndExtra = DLGWINDOWEXTRA;  // Required, since this is used for dialogs!
00279         wndclass.hInstance = mhInst;
00280         wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE( IDI_WIN_CRASH_LOGGER ) );
00281         wndclass.hCursor = gCursorArrow;
00282         wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
00283         wndclass.lpszMenuName = NULL;
00284         wndclass.lpszClassName = szWindowClass;
00285         RegisterClass( &wndclass );
00286         
00287         return true;
00288 }
00289 
00290 void LLCrashLoggerWindows::gatherPlatformSpecificFiles()
00291 {
00292         updateApplication("Gathering hardware information. App may appear frozen.");
00293         // DX hardware probe blocks, so we can't cancel during it
00294         //Generate our dx_info.log file 
00295         SetCursor(gCursorWait);
00296         // At this point we're responsive enough the user could click the close button
00297         SetCursor(gCursorArrow);
00298         mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo();
00299         mFileMap["CrashLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLifeException.log");
00300 }
00301 
00302 bool LLCrashLoggerWindows::mainLoop()
00303 {       
00304 
00305         // Note: parent hwnd is 0 (the desktop).  No dlg proc.  See Petzold (5th ed) HexCalc example, Chapter 11, p529
00306         // win_crash_logger.rc has been edited by hand.
00307         // Dialogs defined with CLASS "WIN_CRASH_LOGGER" (must be same as szWindowClass)
00308         gProductName = mProductName;
00309 
00310         gHwndProgress = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROGRESS), 0, NULL);
00311         ProcessCaption(gHwndProgress);
00312         ShowWindow(gHwndProgress, SW_HIDE );
00313 
00314         if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND)
00315         {
00316                 ShowWindow(gHwndProgress, SW_SHOW );
00317                 sendCrashLogs();
00318         }
00319         else if (mCrashBehavior == CRASH_BEHAVIOR_ASK)
00320         {
00321                 gHwndReport = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PREVREPORTBOX), 0, NULL);
00322                 // Ignore result
00323                 (void) SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_SETCHECK, 1, 0);
00324                 // Include the product name in the caption and various dialog items.
00325                 ProcessCaption(gHwndReport);
00326                 ProcessDlgItemText(gHwndReport, IDC_STATIC_MSG);
00327 
00328                 // Update the header to include whether or not we crashed on the last run.
00329                 std::string headerStr;
00330                 TCHAR header[MAX_STRING];
00331                 if (mCrashInPreviousExec)
00332                 {
00333                         headerStr = llformat("%s appears to have crashed or frozen the last time it ran.", mProductName.c_str());
00334                 }
00335                 else
00336                 {
00337                         headerStr = llformat("%s appears to have crashed.", mProductName.c_str());
00338                 }
00339                 ConvertLPCSTRToLPWSTR(headerStr.c_str(), header);
00340                 SetDlgItemText(gHwndReport, IDC_STATIC_HEADER, header);         
00341                 ShowWindow(gHwndReport, SW_SHOW );
00342                 
00343                 MSG msg;
00344                 msg.wParam = 0;
00345                 while (!LLApp::isQuitting() && GetMessage(&msg, NULL, 0, 0))
00346                 {
00347                         TranslateMessage(&msg);
00348                         DispatchMessage(&msg);
00349                 }
00350                 return msg.wParam;
00351         }
00352         else
00353         {
00354                 llwarns << "Unknown crash behavior " << mCrashBehavior << llendl;
00355                 return 1;
00356         }
00357         return 0;
00358 }
00359 
00360 void LLCrashLoggerWindows::updateApplication(LLString message)
00361 {
00362         LLCrashLogger::updateApplication();
00363         if(message != "") show_progress(message.c_str());
00364         update_messages();
00365 }
00366 
00367 bool LLCrashLoggerWindows::cleanup()
00368 {
00369         if(gSendLogs)
00370         {
00371                 if(mSentCrashLogs) show_progress("Done");
00372                 else show_progress("Could not connect to servers, logs not sent");
00373                 sleep_and_pump_messages(3);
00374         }
00375         PostQuitMessage(0);
00376         return true;
00377 }
00378 
00379 
00380 

Generated on Fri May 16 08:34:32 2008 for SecondLife by  doxygen 1.5.5