diff options
author | Jacek Antonelli | 2008-08-15 23:45:19 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:45:19 -0500 |
commit | b235c59d60472f818a9142c0886b95a0ff4191d7 (patch) | |
tree | d323c55587584b19cc43a03f58a178823f12d3cd /linden/indra/win_crash_logger/llcrashloggerwindows.cpp | |
parent | Second Life viewer sources 1.18.5.3 (diff) | |
download | meta-impy-b235c59d60472f818a9142c0886b95a0ff4191d7.zip meta-impy-b235c59d60472f818a9142c0886b95a0ff4191d7.tar.gz meta-impy-b235c59d60472f818a9142c0886b95a0ff4191d7.tar.bz2 meta-impy-b235c59d60472f818a9142c0886b95a0ff4191d7.tar.xz |
Second Life viewer sources 1.18.6.0-RC
Diffstat (limited to 'linden/indra/win_crash_logger/llcrashloggerwindows.cpp')
-rw-r--r-- | linden/indra/win_crash_logger/llcrashloggerwindows.cpp | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/linden/indra/win_crash_logger/llcrashloggerwindows.cpp b/linden/indra/win_crash_logger/llcrashloggerwindows.cpp new file mode 100644 index 0000000..5a25c17 --- /dev/null +++ b/linden/indra/win_crash_logger/llcrashloggerwindows.cpp | |||
@@ -0,0 +1,378 @@ | |||
1 | /** | ||
2 | * @file llcrashloggerwindows.cpp | ||
3 | * @brief Windows crash logger implementation | ||
4 | * | ||
5 | * $LicenseInfo:firstyear=2003&license=viewergpl$ | ||
6 | * | ||
7 | * Copyright (c) 2003-2007, Linden Research, Inc. | ||
8 | * | ||
9 | * Second Life Viewer Source Code | ||
10 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
11 | * to you under the terms of the GNU General Public License, version 2.0 | ||
12 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
13 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
14 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
15 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
16 | * | ||
17 | * There are special exceptions to the terms and conditions of the GPL as | ||
18 | * it is applied to this Source Code. View the full text of the exception | ||
19 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
20 | * online at http://secondlife.com/developers/opensource/flossexception | ||
21 | * | ||
22 | * By copying, modifying or distributing this software, you acknowledge | ||
23 | * that you have read and understood your obligations described above, | ||
24 | * and agree to abide by those obligations. | ||
25 | * | ||
26 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
27 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
28 | * COMPLETENESS OR PERFORMANCE. | ||
29 | * $/LicenseInfo$ | ||
30 | */ | ||
31 | |||
32 | #include "stdafx.h" | ||
33 | #include "resource.h" | ||
34 | #include "llcrashloggerwindows.h" | ||
35 | |||
36 | #include <sstream> | ||
37 | |||
38 | #include "boost/tokenizer.hpp" | ||
39 | |||
40 | #include "dbghelp.h" | ||
41 | #include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME | ||
42 | #include "llerror.h" | ||
43 | #include "llfile.h" | ||
44 | #include "lltimer.h" | ||
45 | #include "llstring.h" | ||
46 | #include "lldxhardware.h" | ||
47 | #include "lldir.h" | ||
48 | #include "llsdserialize.h" | ||
49 | |||
50 | #define MAX_LOADSTRING 100 | ||
51 | #define MAX_STRING 2048 | ||
52 | const char* const SETTINGS_FILE_HEADER = "version"; | ||
53 | const S32 SETTINGS_FILE_VERSION = 101; | ||
54 | |||
55 | // Windows Message Handlers | ||
56 | |||
57 | // Global Variables: | ||
58 | HINSTANCE hInst= NULL; // current instance | ||
59 | TCHAR szTitle[MAX_LOADSTRING]; /* Flawfinder: ignore */ // The title bar text | ||
60 | TCHAR szWindowClass[MAX_LOADSTRING]; /* Flawfinder: ignore */ // The title bar text | ||
61 | |||
62 | LLString gProductName; | ||
63 | HWND gHwndReport = NULL; // Send/Don't Send dialog | ||
64 | HWND gHwndProgress = NULL; // Progress window | ||
65 | HCURSOR gCursorArrow = NULL; | ||
66 | HCURSOR gCursorWait = NULL; | ||
67 | BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialog? | ||
68 | std::stringstream gDXInfo; | ||
69 | bool gSendLogs = false; | ||
70 | |||
71 | |||
72 | //Conversion from char* to wchar* | ||
73 | //Replacement for ATL macros, doesn't allocate memory | ||
74 | //For more info see: http://www.codeguru.com/forum/showthread.php?t=337247 | ||
75 | void ConvertLPCSTRToLPWSTR (const char* pCstring, WCHAR* outStr) | ||
76 | { | ||
77 | if (pCstring != NULL) | ||
78 | { | ||
79 | int nInputStrLen = strlen (pCstring); | ||
80 | // Double NULL Termination | ||
81 | int nOutputStrLen = MultiByteToWideChar(CP_ACP, 0, pCstring, nInputStrLen, NULL, 0) + 2; | ||
82 | if (outStr) | ||
83 | { | ||
84 | memset (outStr, 0x00, sizeof (WCHAR)*nOutputStrLen); | ||
85 | MultiByteToWideChar (CP_ACP, 0, pCstring, nInputStrLen, outStr, nInputStrLen); | ||
86 | } | ||
87 | } | ||
88 | } | ||
89 | |||
90 | void write_debug(const char *str) | ||
91 | { | ||
92 | gDXInfo << str; /* Flawfinder: ignore */ | ||
93 | } | ||
94 | |||
95 | void write_debug(std::string& str) | ||
96 | { | ||
97 | write_debug(str.c_str()); | ||
98 | } | ||
99 | |||
100 | void show_progress(const char* message) | ||
101 | { | ||
102 | std::wstring msg = wstring_to_utf16str(utf8str_to_wstring(message)); | ||
103 | if (gHwndProgress) | ||
104 | { | ||
105 | SendDlgItemMessage(gHwndProgress, // handle to destination window | ||
106 | IDC_LOG, | ||
107 | WM_SETTEXT, // message to send | ||
108 | FALSE, // undo option | ||
109 | (LPARAM)msg.c_str()); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | void update_messages() | ||
114 | { | ||
115 | MSG msg; | ||
116 | while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) | ||
117 | { | ||
118 | if (msg.message == WM_QUIT) | ||
119 | { | ||
120 | exit(0); | ||
121 | } | ||
122 | TranslateMessage(&msg); | ||
123 | DispatchMessage(&msg); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | void sleep_and_pump_messages( U32 seconds ) | ||
128 | { | ||
129 | const U32 CYCLES_PER_SECOND = 10; | ||
130 | U32 cycles = seconds * CYCLES_PER_SECOND; | ||
131 | while( cycles-- ) | ||
132 | { | ||
133 | update_messages(); | ||
134 | ms_sleep(1000 / CYCLES_PER_SECOND); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | // Include product name in the window caption. | ||
139 | void LLCrashLoggerWindows::ProcessCaption(HWND hWnd) | ||
140 | { | ||
141 | TCHAR templateText[MAX_STRING]; /* Flawfinder: ignore */ | ||
142 | TCHAR header[MAX_STRING]; | ||
143 | std::string final; | ||
144 | GetWindowText(hWnd, templateText, sizeof(templateText)); | ||
145 | final = llformat(ll_convert_wide_to_string(templateText).c_str(), gProductName.c_str()); | ||
146 | ConvertLPCSTRToLPWSTR(final.c_str(), header); | ||
147 | SetWindowText(hWnd, header); | ||
148 | } | ||
149 | |||
150 | |||
151 | // Include product name in the diaog item text. | ||
152 | void LLCrashLoggerWindows::ProcessDlgItemText(HWND hWnd, int nIDDlgItem) | ||
153 | { | ||
154 | TCHAR templateText[MAX_STRING]; /* Flawfinder: ignore */ | ||
155 | TCHAR header[MAX_STRING]; | ||
156 | std::string final; | ||
157 | GetDlgItemText(hWnd, nIDDlgItem, templateText, sizeof(templateText)); | ||
158 | final = llformat(ll_convert_wide_to_string(templateText).c_str(), gProductName.c_str()); | ||
159 | ConvertLPCSTRToLPWSTR(final.c_str(), header); | ||
160 | SetDlgItemText(hWnd, nIDDlgItem, header); | ||
161 | } | ||
162 | |||
163 | bool handle_button_click(WORD button_id) | ||
164 | { | ||
165 | // Is this something other than Send or Don't Send? | ||
166 | if (button_id != IDOK | ||
167 | && button_id != IDCANCEL) | ||
168 | { | ||
169 | return false; | ||
170 | } | ||
171 | |||
172 | // See if "do this next time" is checked and save state | ||
173 | S32 crash_behavior = CRASH_BEHAVIOR_ASK; | ||
174 | LRESULT result = SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_GETCHECK, 0, 0); | ||
175 | if (result == BST_CHECKED) | ||
176 | { | ||
177 | if (button_id == IDOK) | ||
178 | { | ||
179 | crash_behavior = CRASH_BEHAVIOR_ALWAYS_SEND; | ||
180 | } | ||
181 | else if (button_id == IDCANCEL) | ||
182 | { | ||
183 | crash_behavior = CRASH_BEHAVIOR_NEVER_SEND; | ||
184 | } | ||
185 | ((LLCrashLoggerWindows*)LLCrashLogger::instance())->saveCrashBehaviorSetting(crash_behavior); | ||
186 | } | ||
187 | |||
188 | // We're done with this dialog. | ||
189 | gFirstDialog = FALSE; | ||
190 | |||
191 | // Send the crash report if requested | ||
192 | if (button_id == IDOK) | ||
193 | { | ||
194 | gSendLogs = TRUE; | ||
195 | WCHAR wbuffer[20000]; | ||
196 | GetDlgItemText(gHwndReport, // handle to dialog box | ||
197 | IDC_EDIT1, // control identifier | ||
198 | wbuffer, // pointer to buffer for text | ||
199 | 20000 // maximum size of string | ||
200 | ); | ||
201 | LLString user_text(ll_convert_wide_to_string(wbuffer)); | ||
202 | // Activate and show the window. | ||
203 | ShowWindow(gHwndProgress, SW_SHOW); | ||
204 | // Try doing this second to make the progress window go frontmost. | ||
205 | ShowWindow(gHwndReport, SW_HIDE); | ||
206 | ((LLCrashLoggerWindows*)LLCrashLogger::instance())->setUserText(user_text); | ||
207 | ((LLCrashLoggerWindows*)LLCrashLogger::instance())->sendCrashLogs(); | ||
208 | } | ||
209 | // Quit the app | ||
210 | LLApp::setQuitting(); | ||
211 | return true; | ||
212 | } | ||
213 | |||
214 | |||
215 | LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) | ||
216 | { | ||
217 | switch( message ) | ||
218 | { | ||
219 | case WM_CREATE: | ||
220 | return 0; | ||
221 | |||
222 | case WM_COMMAND: | ||
223 | if( gFirstDialog ) | ||
224 | { | ||
225 | WORD button_id = LOWORD(wParam); | ||
226 | bool handled = handle_button_click(button_id); | ||
227 | if (handled) | ||
228 | { | ||
229 | return 0; | ||
230 | } | ||
231 | } | ||
232 | break; | ||
233 | |||
234 | case WM_DESTROY: | ||
235 | // Closing the window cancels | ||
236 | LLApp::setQuitting(); | ||
237 | PostQuitMessage(0); | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | return DefWindowProc(hwnd, message, wParam, lParam); | ||
242 | } | ||
243 | |||
244 | |||
245 | LLCrashLoggerWindows::LLCrashLoggerWindows(void) | ||
246 | { | ||
247 | } | ||
248 | |||
249 | LLCrashLoggerWindows::~LLCrashLoggerWindows(void) | ||
250 | { | ||
251 | } | ||
252 | |||
253 | bool LLCrashLoggerWindows::init(void) | ||
254 | { | ||
255 | bool ok = LLCrashLogger::init(); | ||
256 | if(!ok) return false; | ||
257 | |||
258 | /* | ||
259 | mbstowcs(gProductName, mProductName.c_str(), sizeof(gProductName)/sizeof(gProductName[0])); | ||
260 | gProductName[ sizeof(gProductName)/sizeof(gProductName[0]) - 1 ] = 0; | ||
261 | swprintf(gProductName, L"Second Life"); | ||
262 | */ | ||
263 | |||
264 | llinfos << "Loading dialogs" << llendl; | ||
265 | |||
266 | // Initialize global strings | ||
267 | LoadString(mhInst, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); | ||
268 | LoadString(mhInst, IDC_WIN_CRASH_LOGGER, szWindowClass, MAX_LOADSTRING); | ||
269 | |||
270 | gCursorArrow = LoadCursor(NULL, IDC_ARROW); | ||
271 | gCursorWait = LoadCursor(NULL, IDC_WAIT); | ||
272 | |||
273 | // Register a window class that will be used by our dialogs | ||
274 | WNDCLASS wndclass; | ||
275 | wndclass.style = CS_HREDRAW | CS_VREDRAW; | ||
276 | wndclass.lpfnWndProc = WndProc; | ||
277 | wndclass.cbClsExtra = 0; | ||
278 | wndclass.cbWndExtra = DLGWINDOWEXTRA; // Required, since this is used for dialogs! | ||
279 | wndclass.hInstance = mhInst; | ||
280 | wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE( IDI_WIN_CRASH_LOGGER ) ); | ||
281 | wndclass.hCursor = gCursorArrow; | ||
282 | wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); | ||
283 | wndclass.lpszMenuName = NULL; | ||
284 | wndclass.lpszClassName = szWindowClass; | ||
285 | RegisterClass( &wndclass ); | ||
286 | |||
287 | return true; | ||
288 | } | ||
289 | |||
290 | void LLCrashLoggerWindows::gatherPlatformSpecificFiles() | ||
291 | { | ||
292 | updateApplication("Gathering hardware information. App may appear frozen."); | ||
293 | // DX hardware probe blocks, so we can't cancel during it | ||
294 | //Generate our dx_info.log file | ||
295 | SetCursor(gCursorWait); | ||
296 | // At this point we're responsive enough the user could click the close button | ||
297 | SetCursor(gCursorArrow); | ||
298 | mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo(); | ||
299 | mFileMap["CrashLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLifeException.log"); | ||
300 | } | ||
301 | |||
302 | bool LLCrashLoggerWindows::mainLoop() | ||
303 | { | ||
304 | |||
305 | // Note: parent hwnd is 0 (the desktop). No dlg proc. See Petzold (5th ed) HexCalc example, Chapter 11, p529 | ||
306 | // win_crash_logger.rc has been edited by hand. | ||
307 | // Dialogs defined with CLASS "WIN_CRASH_LOGGER" (must be same as szWindowClass) | ||
308 | gProductName = mProductName; | ||
309 | |||
310 | gHwndProgress = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROGRESS), 0, NULL); | ||
311 | ProcessCaption(gHwndProgress); | ||
312 | ShowWindow(gHwndProgress, SW_HIDE ); | ||
313 | |||
314 | if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND) | ||
315 | { | ||
316 | ShowWindow(gHwndProgress, SW_SHOW ); | ||
317 | sendCrashLogs(); | ||
318 | } | ||
319 | else if (mCrashBehavior == CRASH_BEHAVIOR_ASK) | ||
320 | { | ||
321 | gHwndReport = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PREVREPORTBOX), 0, NULL); | ||
322 | |||
323 | // Include the product name in the caption and various dialog items. | ||
324 | ProcessCaption(gHwndReport); | ||
325 | ProcessDlgItemText(gHwndReport, IDC_STATIC_MSG); | ||
326 | |||
327 | // Update the header to include whether or not we crashed on the last run. | ||
328 | std::string headerStr; | ||
329 | TCHAR header[MAX_STRING]; | ||
330 | if (mCrashInPreviousExec) | ||
331 | { | ||
332 | headerStr = llformat("%s appears to have crashed or frozen the last time it ran.", mProductName.c_str()); | ||
333 | } | ||
334 | else | ||
335 | { | ||
336 | headerStr = llformat("%s appears to have crashed.", mProductName.c_str()); | ||
337 | } | ||
338 | ConvertLPCSTRToLPWSTR(headerStr.c_str(), header); | ||
339 | SetDlgItemText(gHwndReport, IDC_STATIC_HEADER, header); | ||
340 | ShowWindow(gHwndReport, SW_SHOW ); | ||
341 | |||
342 | MSG msg; | ||
343 | while (!LLApp::isQuitting() && GetMessage(&msg, NULL, 0, 0)) | ||
344 | { | ||
345 | TranslateMessage(&msg); | ||
346 | DispatchMessage(&msg); | ||
347 | } | ||
348 | return msg.wParam; | ||
349 | } | ||
350 | else | ||
351 | { | ||
352 | llwarns << "Unknown crash behavior " << mCrashBehavior << llendl; | ||
353 | return 1; | ||
354 | } | ||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | void LLCrashLoggerWindows::updateApplication(LLString message) | ||
359 | { | ||
360 | LLCrashLogger::updateApplication(); | ||
361 | if(message != "") show_progress(message.c_str()); | ||
362 | update_messages(); | ||
363 | } | ||
364 | |||
365 | bool LLCrashLoggerWindows::cleanup() | ||
366 | { | ||
367 | if(gSendLogs) | ||
368 | { | ||
369 | if(mSentCrashLogs) show_progress("Done"); | ||
370 | else show_progress("Could not connect to servers, logs not sent"); | ||
371 | sleep_and_pump_messages(3); | ||
372 | } | ||
373 | PostQuitMessage(0); | ||
374 | return true; | ||
375 | } | ||
376 | |||
377 | |||
378 | |||