aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/win_crash_logger/llcrashloggerwindows.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:45:19 -0500
committerJacek Antonelli2008-08-15 23:45:19 -0500
commitb235c59d60472f818a9142c0886b95a0ff4191d7 (patch)
treed323c55587584b19cc43a03f58a178823f12d3cd /linden/indra/win_crash_logger/llcrashloggerwindows.cpp
parentSecond Life viewer sources 1.18.5.3 (diff)
downloadmeta-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.cpp378
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
52const char* const SETTINGS_FILE_HEADER = "version";
53const S32 SETTINGS_FILE_VERSION = 101;
54
55// Windows Message Handlers
56
57// Global Variables:
58HINSTANCE hInst= NULL; // current instance
59TCHAR szTitle[MAX_LOADSTRING]; /* Flawfinder: ignore */ // The title bar text
60TCHAR szWindowClass[MAX_LOADSTRING]; /* Flawfinder: ignore */ // The title bar text
61
62LLString gProductName;
63HWND gHwndReport = NULL; // Send/Don't Send dialog
64HWND gHwndProgress = NULL; // Progress window
65HCURSOR gCursorArrow = NULL;
66HCURSOR gCursorWait = NULL;
67BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialog?
68std::stringstream gDXInfo;
69bool 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
75void 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
90void write_debug(const char *str)
91{
92 gDXInfo << str; /* Flawfinder: ignore */
93}
94
95void write_debug(std::string& str)
96{
97 write_debug(str.c_str());
98}
99
100void 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
113void 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
127void 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.
139void 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.
152void 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
163bool 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
215LRESULT 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
245LLCrashLoggerWindows::LLCrashLoggerWindows(void)
246{
247}
248
249LLCrashLoggerWindows::~LLCrashLoggerWindows(void)
250{
251}
252
253bool 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
290void 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
302bool 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
358void LLCrashLoggerWindows::updateApplication(LLString message)
359{
360 LLCrashLogger::updateApplication();
361 if(message != "") show_progress(message.c_str());
362 update_messages();
363}
364
365bool 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