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"
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
00056
00057
00058 HINSTANCE hInst= NULL;
00059 TCHAR szTitle[MAX_LOADSTRING];
00060 TCHAR szWindowClass[MAX_LOADSTRING];
00061
00062 LLString gProductName;
00063 HWND gHwndReport = NULL;
00064 HWND gHwndProgress = NULL;
00065 HCURSOR gCursorArrow = NULL;
00066 HCURSOR gCursorWait = NULL;
00067 BOOL gFirstDialog = TRUE;
00068 std::stringstream gDXInfo;
00069 bool gSendLogs = false;
00070
00071
00072
00073
00074
00075 void ConvertLPCSTRToLPWSTR (const char* pCstring, WCHAR* outStr)
00076 {
00077 if (pCstring != NULL)
00078 {
00079 int nInputStrLen = strlen (pCstring);
00080
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;
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,
00106 IDC_LOG,
00107 WM_SETTEXT,
00108 FALSE,
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
00139 void LLCrashLoggerWindows::ProcessCaption(HWND hWnd)
00140 {
00141 TCHAR templateText[MAX_STRING];
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
00152 void LLCrashLoggerWindows::ProcessDlgItemText(HWND hWnd, int nIDDlgItem)
00153 {
00154 TCHAR templateText[MAX_STRING];
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
00166 if (button_id != IDOK
00167 && button_id != IDCANCEL)
00168 {
00169 return false;
00170 }
00171
00172
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
00189 gFirstDialog = FALSE;
00190
00191
00192 if (button_id == IDOK)
00193 {
00194 gSendLogs = TRUE;
00195 WCHAR wbuffer[20000];
00196 GetDlgItemText(gHwndReport,
00197 IDC_EDIT1,
00198 wbuffer,
00199 20000
00200 );
00201 LLString user_text(ll_convert_wide_to_string(wbuffer));
00202
00203 ShowWindow(gHwndProgress, SW_SHOW);
00204
00205 ShowWindow(gHwndReport, SW_HIDE);
00206 ((LLCrashLoggerWindows*)LLCrashLogger::instance())->setUserText(user_text);
00207 ((LLCrashLoggerWindows*)LLCrashLogger::instance())->sendCrashLogs();
00208 }
00209
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
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
00260
00261
00262
00263
00264 llinfos << "Loading dialogs" << llendl;
00265
00266
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
00274 WNDCLASS wndclass;
00275 wndclass.style = CS_HREDRAW | CS_VREDRAW;
00276 wndclass.lpfnWndProc = WndProc;
00277 wndclass.cbClsExtra = 0;
00278 wndclass.cbWndExtra = DLGWINDOWEXTRA;
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
00294
00295 SetCursor(gCursorWait);
00296
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
00306
00307
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
00323 (void) SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_SETCHECK, 1, 0);
00324
00325 ProcessCaption(gHwndReport);
00326 ProcessDlgItemText(gHwndReport, IDC_STATIC_MSG);
00327
00328
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