diff options
author | Kyle Machulis <qdot@lindenlab.com> | 2007-11-20 23:42:48 +0000 |
---|---|---|
committer | Kyle Machulis <qdot@lindenlab.com> | 2007-11-20 23:42:48 +0000 |
commit | 2e7c0d973ed28d732ea19762099ed3c55123780e (patch) | |
tree | 36b04301d325e07075880a8a64166c5284d1d61f /indra/win_crash_logger | |
parent | 5356b917545d43df5537128245ee5b786b705b90 (diff) |
svn merge -r74104:74124 svn+ssh://svn/svn/linden/branches/crash-logger-cleanup-merge-6
Diffstat (limited to 'indra/win_crash_logger')
-rw-r--r-- | indra/win_crash_logger/StdAfx.h | 2 | ||||
-rw-r--r-- | indra/win_crash_logger/llcrashloggerwindows.cpp | 348 | ||||
-rw-r--r-- | indra/win_crash_logger/llcrashloggerwindows.h | 59 | ||||
-rw-r--r-- | indra/win_crash_logger/resource.h | 34 | ||||
-rw-r--r-- | indra/win_crash_logger/win_crash_logger.cpp | 874 | ||||
-rw-r--r-- | indra/win_crash_logger/win_crash_logger.rc | 65 |
6 files changed, 490 insertions, 892 deletions
diff --git a/indra/win_crash_logger/StdAfx.h b/indra/win_crash_logger/StdAfx.h index 6f046f9820..d954823c74 100644 --- a/indra/win_crash_logger/StdAfx.h +++ b/indra/win_crash_logger/StdAfx.h @@ -52,6 +52,8 @@ #include <malloc.h> #include <memory.h> #include <tchar.h> +#include <atlbase.h> + // Local Header Files diff --git a/indra/win_crash_logger/llcrashloggerwindows.cpp b/indra/win_crash_logger/llcrashloggerwindows.cpp new file mode 100644 index 0000000000..007e2b0ed5 --- /dev/null +++ b/indra/win_crash_logger/llcrashloggerwindows.cpp @@ -0,0 +1,348 @@ +/** +* @file llcrashloggerwindows.cpp +* @brief Windows crash logger implementation +* +* $LicenseInfo:firstyear=2003&license=viewergpl$ +* +* Copyright (c) 2003-2007, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlife.com/developers/opensource/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at http://secondlife.com/developers/opensource/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#include "stdafx.h" +#include "resource.h" +#include "llcrashloggerwindows.h" + +#include <sstream> + +#include "boost/tokenizer.hpp" + +#include "dbghelp.h" +#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME +#include "llerror.h" +#include "llfile.h" +#include "lltimer.h" +#include "llstring.h" +#include "lldxhardware.h" +#include "lldir.h" +#include "llsdserialize.h" + +#define MAX_LOADSTRING 100 +const char* const SETTINGS_FILE_HEADER = "version"; +const S32 SETTINGS_FILE_VERSION = 101; + +// Windows Message Handlers + +// Global Variables: +HINSTANCE hInst= NULL; // current instance +TCHAR szTitle[MAX_LOADSTRING]; /* Flawfinder: ignore */ // The title bar text +TCHAR szWindowClass[MAX_LOADSTRING]; /* Flawfinder: ignore */ // The title bar text + +HWND gHwndReport = NULL; // Send/Don't Send dialog +HWND gHwndProgress = NULL; // Progress window +HCURSOR gCursorArrow = NULL; +HCURSOR gCursorWait = NULL; +BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialog? +std::stringstream gDXInfo; + +void write_debug(const char *str) +{ + gDXInfo << str; /* Flawfinder: ignore */ +} + +void write_debug(std::string& str) +{ + write_debug(str.c_str()); +} + +void show_progress(const char* message) +{ + std::wstring msg = wstring_to_utf16str(utf8str_to_wstring(message)); + if (gHwndProgress) + { + SendDlgItemMessage(gHwndProgress, // handle to destination window + IDC_LOG, + WM_SETTEXT, // message to send + FALSE, // undo option + (LPARAM)msg.c_str()); + } +} + +void update_messages() +{ + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + { + exit(0); + } + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +void sleep_and_pump_messages( U32 seconds ) +{ + const U32 CYCLES_PER_SECOND = 10; + U32 cycles = seconds * CYCLES_PER_SECOND; + while( cycles-- ) + { + update_messages(); + ms_sleep(1000 / CYCLES_PER_SECOND); + } +} + +// Include product name in the window caption. +void LLCrashLoggerWindows::ProcessCaption(HWND hWnd) +{ + TCHAR templateText[1024]; /* Flawfinder: ignore */ + TCHAR finalText[2048]; /* Flawfinder: ignore */ + GetWindowText(hWnd, templateText, sizeof(templateText)); + swprintf(finalText, sizeof(CA2T(mProductName.c_str())), templateText, CA2T(mProductName.c_str())); /* Flawfinder: ignore */ + SetWindowText(hWnd, finalText); +} + + +// Include product name in the diaog item text. +void LLCrashLoggerWindows::ProcessDlgItemText(HWND hWnd, int nIDDlgItem) +{ + TCHAR templateText[1024]; /* Flawfinder: ignore */ + TCHAR finalText[2048]; /* Flawfinder: ignore */ + GetDlgItemText(hWnd, nIDDlgItem, templateText, sizeof(templateText)); + swprintf(finalText, sizeof(CA2T(mProductName.c_str())), templateText, CA2T(mProductName.c_str())); /* Flawfinder: ignore */ + SetDlgItemText(hWnd, nIDDlgItem, finalText); +} + +bool handle_button_click(WORD button_id) +{ + USES_CONVERSION; + // Is this something other than Send or Don't Send? + if (button_id != IDOK + && button_id != IDCANCEL) + { + return false; + } + + // See if "do this next time" is checked and save state + S32 crash_behavior = CRASH_BEHAVIOR_ASK; + LRESULT result = SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_GETCHECK, 0, 0); + if (result == BST_CHECKED) + { + if (button_id == IDOK) + { + crash_behavior = CRASH_BEHAVIOR_ALWAYS_SEND; + } + else if (button_id == IDCANCEL) + { + crash_behavior = CRASH_BEHAVIOR_NEVER_SEND; + } + ((LLCrashLoggerWindows*)LLCrashLogger::instance())->saveCrashBehaviorSetting(crash_behavior); + } + + // We're done with this dialog. + gFirstDialog = FALSE; + + // Send the crash report if requested + if (button_id == IDOK) + { + WCHAR wbuffer[20000]; + GetDlgItemText(gHwndReport, // handle to dialog box + IDC_EDIT1, // control identifier + wbuffer, // pointer to buffer for text + 20000 // maximum size of string + ); + LLString user_text(T2CA(wbuffer)); + // Activate and show the window. + ShowWindow(gHwndProgress, SW_SHOW); + // Try doing this second to make the progress window go frontmost. + ShowWindow(gHwndReport, SW_HIDE); + ((LLCrashLoggerWindows*)LLCrashLogger::instance())->setUserText(user_text); + ((LLCrashLoggerWindows*)LLCrashLogger::instance())->sendCrashLogs(); + } + // Quit the app + LLApp::setQuitting(); + return true; +} + + +LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + switch( message ) + { + case WM_CREATE: + return 0; + + case WM_COMMAND: + if( gFirstDialog ) + { + WORD button_id = LOWORD(wParam); + bool handled = handle_button_click(button_id); + if (handled) + { + return 0; + } + } + break; + + case WM_DESTROY: + // Closing the window cancels + LLApp::setQuitting(); + PostQuitMessage(0); + return 0; + } + + return DefWindowProc(hwnd, message, wParam, lParam); +} + + +LLCrashLoggerWindows::LLCrashLoggerWindows(void) +{ +} + +LLCrashLoggerWindows::~LLCrashLoggerWindows(void) +{ +} + +bool LLCrashLoggerWindows::init(void) +{ + bool ok = LLCrashLogger::init(); + if(!ok) return false; + + /* + mbstowcs(gProductName, mProductName.c_str(), sizeof(gProductName)/sizeof(gProductName[0])); + gProductName[ sizeof(gProductName)/sizeof(gProductName[0]) - 1 ] = 0; + swprintf(gProductName, L"Second Life"); + */ + + llinfos << "Loading dialogs" << llendl; + + // Initialize global strings + LoadString(mhInst, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); + LoadString(mhInst, IDC_WIN_CRASH_LOGGER, szWindowClass, MAX_LOADSTRING); + + gCursorArrow = LoadCursor(NULL, IDC_ARROW); + gCursorWait = LoadCursor(NULL, IDC_WAIT); + + // Register a window class that will be used by our dialogs + WNDCLASS wndclass; + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = DLGWINDOWEXTRA; // Required, since this is used for dialogs! + wndclass.hInstance = mhInst; + wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE( IDI_WIN_CRASH_LOGGER ) ); + wndclass.hCursor = gCursorArrow; + wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = szWindowClass; + RegisterClass( &wndclass ); + + return true; +} + +void LLCrashLoggerWindows::gatherPlatformSpecificFiles() +{ + updateApplication("Gathering hardware information. App may appear frozen."); + // DX hardware probe blocks, so we can't cancel during it + //Generate our dx_info.log file + SetCursor(gCursorWait); + // At this point we're responsive enough the user could click the close button + SetCursor(gCursorArrow); + mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo(); + mFileMap["CrashLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLifeException.log"); +} + +bool LLCrashLoggerWindows::mainLoop() +{ + + USES_CONVERSION; + + // Note: parent hwnd is 0 (the desktop). No dlg proc. See Petzold (5th ed) HexCalc example, Chapter 11, p529 + // win_crash_logger.rc has been edited by hand. + // Dialogs defined with CLASS "WIN_CRASH_LOGGER" (must be same as szWindowClass) + + gHwndProgress = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROGRESS), 0, NULL); + ProcessCaption(gHwndProgress); + ShowWindow(gHwndProgress, SW_HIDE ); + + if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND) + { + ShowWindow(gHwndProgress, SW_SHOW ); + sendCrashLogs(); + } + else if (mCrashBehavior == CRASH_BEHAVIOR_ASK) + { + gHwndReport = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PREVREPORTBOX), 0, NULL); + + // Include the product name in the caption and various dialog items. + ProcessCaption(gHwndReport); + ProcessDlgItemText(gHwndReport, IDC_STATIC_MSG); + + // Update the header to include whether or not we crashed on the last run. + TCHAR header[2048]; + CA2T product(mProductName.c_str()); + if (mCrashInPreviousExec) + { + swprintf(header, _T("%s appears to have crashed or frozen the last time it ran."), product); /* Flawfinder: ignore */ + } + else + { + swprintf(header, _T("%s appears to have crashed."), product); /* Flawfinder: ignore */ + } + SetDlgItemText(gHwndReport, IDC_STATIC_HEADER, header); + ShowWindow(gHwndReport, SW_SHOW ); + + MSG msg; + while (!LLApp::isQuitting() && GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return msg.wParam; + } + else + { + llwarns << "Unknown crash behavior " << mCrashBehavior << llendl; + return 1; + } + return 0; +} + +void LLCrashLoggerWindows::updateApplication(LLString message) +{ + LLCrashLogger::updateApplication(); + if(message != "") show_progress(message.c_str()); + update_messages(); +} + +bool LLCrashLoggerWindows::cleanup() +{ + if(mSentCrashLogs) show_progress("Done"); + else show_progress("Could not connect to servers, logs not sent"); + sleep_and_pump_messages(3); + + PostQuitMessage(0); + return true; +} + diff --git a/indra/win_crash_logger/llcrashloggerwindows.h b/indra/win_crash_logger/llcrashloggerwindows.h new file mode 100644 index 0000000000..1f5a216947 --- /dev/null +++ b/indra/win_crash_logger/llcrashloggerwindows.h @@ -0,0 +1,59 @@ +/** +* @file llcrashloggerwindows.h +* @brief Windows crash logger definition +* +* $LicenseInfo:firstyear=2003&license=viewergpl$ +* +* Copyright (c) 2003-2007, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlife.com/developers/opensource/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at http://secondlife.com/developers/opensource/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#ifndef LLCRASHLOGGERWINDOWS_H +#define LLCRASHLOGGERWINDOWS_H + +#include "linden_common.h" +#include "llcrashlogger.h" +#include "windows.h" +#include "llstring.h" + +class LLCrashLoggerWindows : public LLCrashLogger +{ +public: + LLCrashLoggerWindows(void); + ~LLCrashLoggerWindows(void); + virtual bool init(); + virtual bool mainLoop(); + virtual void updateApplication(LLString message = ""); + virtual bool cleanup(); + virtual void gatherPlatformSpecificFiles(); + //void annotateCallStack(); + void setHandle(HINSTANCE hInst) { mhInst = hInst; } +private: + void ProcessDlgItemText(HWND hWnd, int nIDDlgItem); + void ProcessCaption(HWND hWnd); + HINSTANCE mhInst; + +}; + +#endif diff --git a/indra/win_crash_logger/resource.h b/indra/win_crash_logger/resource.h index ee6bf3d575..f1ef850f76 100644 --- a/indra/win_crash_logger/resource.h +++ b/indra/win_crash_logger/resource.h @@ -1,3 +1,34 @@ +/** +* @file resource.h +* @brief Windows crash logger windows resources +* +* $LicenseInfo:firstyear=2003&license=viewergpl$ +* +* Copyright (c) 2003-2007, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlife.com/developers/opensource/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at http://secondlife.com/developers/opensource/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by win_crash_logger.rc @@ -22,6 +53,7 @@ #define IDC_STATIC_HEADER 1007 #define IDC_STATIC_WHATINFO 1008 #define IDC_STATIC_MOTIVATION 1009 +#define IDC_STATIC_MSG 1010 #define IDC_STATIC -1 // Next default values for new objects @@ -30,7 +62,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 131 #define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 1010 +#define _APS_NEXT_CONTROL_VALUE 1011 #define _APS_NEXT_SYMED_VALUE 110 #endif #endif diff --git a/indra/win_crash_logger/win_crash_logger.cpp b/indra/win_crash_logger/win_crash_logger.cpp index 266940741b..c6b4ff1c34 100644 --- a/indra/win_crash_logger/win_crash_logger.cpp +++ b/indra/win_crash_logger/win_crash_logger.cpp @@ -35,98 +35,22 @@ // Must be first include, precompiled headers. #include "stdafx.h" -#include "linden_common.h" -#include "llcontrol.h" -#include "resource.h" +#include <stdlib.h> -#include <direct.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <wininet.h> +#include "llcrashloggerwindows.h" -#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME -#include "llerror.h" -#include "lltimer.h" -#include "lldir.h" -#include "llstring.h" -#include "lldxhardware.h" - -LLControlGroup gCrashSettings; // saved at end of session - -// Constants -#define MAX_LOADSTRING 100 -const char* const SETTINGS_FILE_HEADER = "version"; -const S32 SETTINGS_FILE_VERSION = 101; - -// Functions -LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); -bool handle_button_click(WORD button_id); -S32 load_crash_behavior_setting(); -bool save_crash_behavior_setting(S32 crash_behavior); -void send_crash_report(); -void write_debug(const char *str); -void write_debug(std::string& str); - -// Global Variables: -HINSTANCE hInst= NULL; // current instance -TCHAR szTitle[MAX_LOADSTRING]; /* Flawfinder: ignore */ // The title bar text -TCHAR szWindowClass[MAX_LOADSTRING]; /* Flawfinder: ignore */ // The title bar text - -LLString gUserText; // User's description of the problem -time_t gStartTime = 0; -HWND gHwndReport = NULL; // Send/Don't Send dialog -HWND gHwndProgress = NULL; // Progress window -HCURSOR gCursorArrow = NULL; -HCURSOR gCursorWait = NULL; -BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialog? -BOOL gCrashInPreviousExec = FALSE; -FILE *gDebugFile = NULL; -LLString gUserserver; -WCHAR gProductName[512]; // // Implementation // -// Include product name in the window caption. -void ProcessCaption(HWND hWnd) -{ - TCHAR templateText[1024]; /* Flawfinder: ignore */ - TCHAR finalText[2048]; /* Flawfinder: ignore */ - GetWindowText(hWnd, templateText, sizeof(templateText)); - swprintf(finalText, templateText, gProductName); /* Flawfinder: ignore */ - SetWindowText(hWnd, finalText); -} - - -// Include product name in the diaog item text. -void ProcessDlgItemText(HWND hWnd, int nIDDlgItem) -{ - TCHAR templateText[1024]; /* Flawfinder: ignore */ - TCHAR finalText[2048]; /* Flawfinder: ignore */ - GetDlgItemText(hWnd, nIDDlgItem, templateText, sizeof(templateText)); - swprintf(finalText, templateText, gProductName); /* Flawfinder: ignore */ - SetDlgItemText(hWnd, nIDDlgItem, finalText); -} - int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { llinfos << "Starting crash reporter" << llendl; - // We assume that all the logs we're looking for reside on the current drive - gDirUtilp->initAppDirs("SecondLife"); - - // Default to the product name "Second Life" (this is overridden by the -name argument) - swprintf(gProductName, L"Second Life"); /* Flawfinder: ignore */ - - gCrashSettings.declareS32(CRASH_BEHAVIOR_SETTING, CRASH_BEHAVIOR_ASK, "Controls behavior when viewer crashes " - "(0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)"); - - llinfos << "Loading crash behavior setting" << llendl; - S32 crash_behavior = load_crash_behavior_setting(); // In Win32, we need to generate argc and argv ourselves... // Note: GetCommandLine() returns a potentially return a LPTSTR @@ -139,7 +63,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, const S32 MAX_ARGS = 100; int argc = 0; - char *argv[MAX_ARGS]; /* Flawfinder: ignore */ + char *argv[MAX_ARGS]; char *token = NULL; if( cmd_line_including_exe_name[0] == '\"' ) @@ -159,7 +83,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, { argv[argc++] = token; /* Get next token: */ - if (*(token + strlen(token) + 1) == '\"') /* Flawfinder: ignore */ + if (*(token + strlen(token) + 1) == '\"') { token = strtok( NULL, "\""); } @@ -169,784 +93,32 @@ int APIENTRY WinMain(HINSTANCE hInstance, } } - S32 i; - for (i=0; i<argc; i++) - { - if(!strcmp(argv[i], "-previous")) - { - llinfos << "Previous execution did not remove SecondLife.exec_marker" << llendl; - gCrashInPreviousExec = TRUE; - } - - if(!strcmp(argv[i], "-dialog")) - { - llinfos << "Show the user dialog" << llendl; - crash_behavior = CRASH_BEHAVIOR_ASK; - } - - if(!strcmp(argv[i], "-user")) - { - if ((i + 1) < argc) - { - i++; - gUserserver = argv[i]; - llinfos << "Got userserver " << gUserserver << llendl; - } - } - - if(!strcmp(argv[i], "-name")) - { - if ((i + 1) < argc) - { - i++; - - mbstowcs(gProductName, argv[i], sizeof(gProductName)/sizeof(gProductName[0])); - gProductName[ sizeof(gProductName)/sizeof(gProductName[0]) - 1 ] = 0; - llinfos << "Got product name " << argv[i] << llendl; - } - } - } - - // If user doesn't want to send, bail out - if (crash_behavior == CRASH_BEHAVIOR_NEVER_SEND) - { - llinfos << "Crash behavior is never_send, quitting" << llendl; - return 0; - } - - // Get the current time - time(&gStartTime); - - llinfos << "Loading dialogs" << llendl; - - // Store instance handle in our global variable - hInst = hInstance; - - // Initialize global strings - LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); - LoadString(hInstance, IDC_WIN_CRASH_LOGGER, szWindowClass, MAX_LOADSTRING); - - gCursorArrow = LoadCursor(NULL, IDC_ARROW); - gCursorWait = LoadCursor(NULL, IDC_WAIT); - - // Register a window class that will be used by our dialogs - WNDCLASS wndclass; - wndclass.style = CS_HREDRAW | CS_VREDRAW; - wndclass.lpfnWndProc = WndProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = DLGWINDOWEXTRA; // Required, since this is used for dialogs! - wndclass.hInstance = hInst; - wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE( IDI_WIN_CRASH_LOGGER ) ); - wndclass.hCursor = gCursorArrow; - wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - wndclass.lpszMenuName = NULL; - wndclass.lpszClassName = szWindowClass; - RegisterClass( &wndclass ); - - // Note: parent hwnd is 0 (the desktop). No dlg proc. See Petzold (5th ed) HexCalc example, Chapter 11, p529 - // win_crash_logger.rc has been edited by hand. - // Dialogs defined with CLASS "WIN_CRASH_LOGGER" (must be same as szWindowClass) - - gHwndProgress = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROGRESS), 0, NULL); - ProcessCaption(gHwndProgress); - ShowWindow(gHwndProgress, SW_HIDE ); - - if (crash_behavior == CRASH_BEHAVIOR_ALWAYS_SEND) - { - ShowWindow(gHwndProgress, SW_SHOW ); - send_crash_report(); - return 0; - } - - if (crash_behavior == CRASH_BEHAVIOR_ASK) - { - gHwndReport = CreateDialog(hInst, MAKEINTRESOURCE(IDD_REPORT), 0, NULL); - - // Include the product name in the caption and various dialog items. - ProcessCaption(gHwndReport); - ProcessDlgItemText(gHwndReport, IDC_STATIC_WHATINFO); - ProcessDlgItemText(gHwndReport, IDC_STATIC_MOTIVATION); - - // Update the header to include whether or not we crashed on the last run. - WCHAR header[2048]; - if (gCrashInPreviousExec) - { - swprintf(header, L"%s appears to have crashed or frozen the last time it ran.", gProductName); /* Flawfinder: ignore */ - } - else - { - swprintf(header, L"%s appears to have crashed.", gProductName); /* Flawfinder: ignore */ - } - SetDlgItemText(gHwndReport, IDC_STATIC_HEADER, header); - ShowWindow(gHwndReport, SW_SHOW ); - - MSG msg; - while (GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return msg.wParam; - } - else - { - llwarns << "Unknown crash behavior " << crash_behavior << llendl; - return 1; - } -} - - -LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) -{ - switch( message ) - { - case WM_CREATE: - return 0; - - case WM_COMMAND: - if( gFirstDialog ) - { - WORD button_id = LOWORD(wParam); - bool handled = handle_button_click(button_id); - if (handled) - { - return 0; - } - } - break; - - case WM_DESTROY: - // Closing the window cancels - PostQuitMessage(0); - return 0; - } - - return DefWindowProc(hwnd, message, wParam, lParam); -} - - -bool handle_button_click(WORD button_id) -{ - // Is this something other than Send or Don't Send? - if (button_id != IDOK - && button_id != IDCANCEL) - { - return false; - } - - // See if "do this next time" is checked and save state - S32 crash_behavior = CRASH_BEHAVIOR_ASK; - LRESULT result = SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_GETCHECK, 0, 0); - if (result == BST_CHECKED) - { - if (button_id == IDOK) - { - crash_behavior = CRASH_BEHAVIOR_ALWAYS_SEND; - } - else if (button_id == IDCANCEL) - { - crash_behavior = CRASH_BEHAVIOR_NEVER_SEND; - } - } - bool success = save_crash_behavior_setting(crash_behavior); - if (!success) - { - llwarns << "Failed to save crash settings" << llendl; - } - - // We're done with this dialog. - gFirstDialog = FALSE; - - // Send the crash report if requested - if (button_id == IDOK) - { - // Don't let users type anything. They believe the reports - // get read by humans, and get angry when we don't respond. JC - //WCHAR wbuffer[20000]; - //GetDlgItemText(gHwndReport, // handle to dialog box - // IDC_EDIT1, // control identifier - // wbuffer, // pointer to buffer for text - // 20000 // maximum size of string - // ); - //gUserText = wstring_to_utf8str(utf16str_to_wstring(wbuffer)).c_str(); - //llinfos << gUserText << llendl; - - // Activate and show the window. - ShowWindow(gHwndProgress, SW_SHOW); - // Try doing this second to make the progress window go frontmost. - ShowWindow(gHwndReport, SW_HIDE); - - send_crash_report(); - } - - // Quit the app - PostQuitMessage(0); - - return true; -} - - -class LLFileEncoder -{ -public: - LLFileEncoder(const char *formname, const char *filename); - ~LLFileEncoder(); - - BOOL isValid() const { return mIsValid; } - LLString encodeURL(const S32 max_length = 0); -public: - BOOL mIsValid; - LLString mFilename; - LLString mFormname; - S32 mBufLength; - U8 *mBuf; -}; - -LLString encode_string(const char *formname, const LLString &str); - -void update_messages() -{ - MSG msg; - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - { - exit(0); - } - TranslateMessage(&msg); - DispatchMessage(&msg); - } -} - -void sleep_and_pump_messages( U32 seconds ) -{ - const U32 CYCLES_PER_SECOND = 10; - U32 cycles = seconds * CYCLES_PER_SECOND; - while( cycles-- ) + LLCrashLoggerWindows app; + bool ok = app.parseCommandOptions(argc, argv); + if(!ok) { - update_messages(); - ms_sleep(1000 / CYCLES_PER_SECOND); - } -} - - -void show_progress(const char* message) -{ - std::wstring msg = wstring_to_utf16str(utf8str_to_wstring(message)); - if (gHwndProgress) - { - SendDlgItemMessage(gHwndProgress, // handle to destination window - IDC_LOG, - WM_SETTEXT, // message to send - FALSE, // undo option - (LPARAM)msg.c_str()); - } -} - - -void send_crash_report() -{ - update_messages(); - show_progress("Starting up..."); - update_messages(); - - const S32 SL_MAX_SIZE = 100000; // Maximum size of the Second Life log file. - - update_messages(); - - // Lots of silly variable, replicated for each log file. - std::string db_file_name; // debug.log - std::string sl_file_name; // SecondLife.log - std::string md_file_name; // minidump (SecondLife.dmp) file name - std::string st_file_name; // stats.log file - std::string si_file_name; // settings.ini file - std::string ml_file_name; // message.log file - - LLFileEncoder *db_filep = NULL; - LLFileEncoder *sl_filep = NULL; - LLFileEncoder *st_filep = NULL; - LLFileEncoder *md_filep = NULL; - LLFileEncoder *si_filep = NULL; - LLFileEncoder *ml_filep = NULL; - - // DX hardware probe blocks, so we can't cancel during it - SetCursor(gCursorWait); - - // Need to do hardware detection before we grab the files, otherwise we don't send the debug log updates - // to the server (including the list of hardware). - update_messages(); - show_progress("Detecting hardware, please wait..."); - update_messages(); - gDXHardware.setWriteDebugFunc(write_debug); - gDXHardware.getInfo(FALSE); - update_messages(); - gDXHardware.dumpDevices(); - update_messages(); - fclose(gDebugFile); - gDebugFile = NULL; - - // At this point we're responsive enough the user could click the close button - SetCursor(gCursorArrow); - - /////////////////////////////////// - // - // We do the parsing for the debug_info file first, as that will - // give us the location of the SecondLife.log file. - // - - // Figure out the filename of the debug log - db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log"); - db_filep = new LLFileEncoder("DB", db_file_name.c_str()); - - // Get the filename of the SecondLife.log file - // *NOTE: This buffer size is hard coded into scanf() below. - char tmp_sl_name[256]; /* Flawfinder: ignore */ - tmp_sl_name[0] = '\0'; - - update_messages(); - show_progress("Looking for files..."); - update_messages(); - - // Look for it in the debug_info.log file - if (db_filep->isValid()) - { - sscanf( - (const char*)db_filep->mBuf, - "SL Log: %255[^\r\n]", - tmp_sl_name); - } - else - { - delete db_filep; - db_filep = NULL; - } - - if (gCrashInPreviousExec) - { - // If we froze, the crash log this time around isn't useful. Use the - // old one. - sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.old"); - } - else if (tmp_sl_name[0]) - { - // If debug_info.log gives us a valid log filename, use that. - sl_file_name = tmp_sl_name; - llinfos << "Using log file from debug log " << sl_file_name << llendl; - } - else - { - // Figure out the filename of the default second life log - sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log"); - } - - // Now we get the SecondLife.log file if it's there - sl_filep = new LLFileEncoder("SL", sl_file_name.c_str()); - if (!sl_filep->isValid()) - { - delete sl_filep; - sl_filep = NULL; - } - - update_messages(); - show_progress("Looking for stats file..."); - update_messages(); - - st_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log"); - st_filep = new LLFileEncoder("ST", st_file_name.c_str()); - if (!st_filep->isValid()) - { - delete st_filep; - st_filep = NULL; - } - - si_file_name = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.ini"); - si_filep = new LLFileEncoder("SI", si_file_name.c_str()); - if (!si_filep->isValid()) - { - delete si_filep; - si_filep = NULL; - } - - // Now we get the minidump - md_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.dmp"); - md_filep = new LLFileEncoder("MD", md_file_name.c_str()); - if (!md_filep->isValid()) - { - delete md_filep; - md_filep = NULL; - } - - // Now we get the message log - ml_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"message.log"); - ml_filep = new LLFileEncoder("ML", ml_file_name.c_str()); - if (!ml_filep->isValid()) - { - delete ml_filep; - ml_filep = NULL; - } - - LLString post_data; - LLString tmp_url_buf; - - // Append the userserver - tmp_url_buf = encode_string("USER", gUserserver); - post_data += tmp_url_buf; - llinfos << "PostData:" << post_data << llendl; - - if (gCrashInPreviousExec) - { - post_data.append(1, '&'); - tmp_url_buf = encode_string("EF", "Y"); - post_data += tmp_url_buf; - } - - update_messages(); - show_progress("Encoding data"); - update_messages(); - if (db_filep) - { - post_data.append(1, '&'); - tmp_url_buf = db_filep->encodeURL(); - post_data += tmp_url_buf; - llinfos << "Sending DB log file" << llendl; - } - else - { - llinfos << "Not sending DB log file" << llendl; - } - show_progress("Encoding data."); - update_messages(); - - if (sl_filep) - { - post_data.append(1, '&'); - tmp_url_buf = sl_filep->encodeURL(SL_MAX_SIZE); - post_data += tmp_url_buf; - llinfos << "Sending SL log file" << llendl; - } - else - { - llinfos << "Not sending SL log file" << llendl; - } - show_progress("Encoding data.."); - update_messages(); - - if (st_filep) - { - post_data.append(1, '&'); - tmp_url_buf = st_filep->encodeURL(SL_MAX_SIZE); - post_data += tmp_url_buf; - llinfos << "Sending stats log file" << llendl; - } - else - { - llinfos << "Not sending stats log file" << llendl; - } - show_progress("Encoding data..."); - update_messages(); - - if (md_filep) - { - post_data.append(1, '&'); - tmp_url_buf = md_filep->encodeURL(); - post_data += tmp_url_buf; - llinfos << "Sending minidump log file" << llendl; - } - else - { - llinfos << "Not sending minidump log file" << llendl; - } - show_progress("Encoding data...."); - update_messages(); - - if (si_filep) - { - post_data.append(1, '&'); - tmp_url_buf = si_filep->encodeURL(); - post_data += tmp_url_buf; - llinfos << "Sending settings log file" << llendl; - } - else - { - llinfos << "Not sending settings.ini file" << llendl; - } - show_progress("Encoding data...."); - update_messages(); - - if (ml_filep) - { - post_data.append(1, '&'); - tmp_url_buf = ml_filep->encodeURL(SL_MAX_SIZE); - post_data += tmp_url_buf; - llinfos << "Sending message log file" << llendl; - } - else - { - llinfos << "Not sending message.log file" << llendl; - } - show_progress("Encoding data...."); - update_messages(); - - if (gUserText.size()) - { - post_data.append(1, '&'); - tmp_url_buf = encode_string("UN", gUserText); - post_data += tmp_url_buf; - } - - delete db_filep; - db_filep = NULL; - delete sl_filep; - sl_filep = NULL; - delete md_filep; - md_filep = NULL; - - // Post data to web server - const S32 BUFSIZE = 65536; - HINTERNET hinet, hsession, hrequest; - char data[BUFSIZE]; /* Flawfinder: ignore */ - unsigned long bytes_read; - - llinfos << "Connecting to crash report server" << llendl; - update_messages(); - show_progress("Connecting to server..."); - update_messages(); - - // Init wininet subsystem - hinet = InternetOpen(L"LindenCrashReporter", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); - if (hinet == NULL) - { - llinfos << "Couldn't open connection" << llendl; - sleep_and_pump_messages( 5 ); -// return FALSE; - } - - hsession = InternetConnect(hinet, - L"secondlife.com", - INTERNET_DEFAULT_HTTP_PORT, - NULL, - NULL, - INTERNET_SERVICE_HTTP, - NULL, - NULL); - - if (!hsession) - { - llinfos << "Couldn't talk to crash report server" << llendl; - } - - hrequest = HttpOpenRequest(hsession, L"POST", L"/cgi-bin/viewer_crash_reporter2", NULL, L"", NULL, 0, 0); - if (!hrequest) - { - llinfos << "Couldn't open crash report URL!" << llendl; + llwarns << "Unable to parse command line." << llendl; } - llinfos << "Transmitting data" << llendl; - llinfos << "Bytes: " << (post_data.size()) << llendl; - - update_messages(); - show_progress("Transmitting data..."); - update_messages(); - - BOOL ok = HttpSendRequest(hrequest, NULL, 0, (void *)(post_data.c_str()), post_data.size()); - if (!ok) - { - llinfos << "Error posting data!" << llendl; - sleep_and_pump_messages( 5 ); - } - - llinfos << "Response from crash report server:" << llendl; - do - { - if (InternetReadFile(hrequest, data, BUFSIZE, &bytes_read)) - { - if (bytes_read == 0) - { - // If InternetFileRead returns TRUE AND bytes_read == 0 - // we've successfully downloaded the entire file - break; - } - else - { - data[bytes_read] = 0; - llinfos << data << llendl; - } - } - else - { - llinfos << "Couldn't read file!" << llendl; - sleep_and_pump_messages( 5 ); -// return FALSE; - } - } while(TRUE); - - InternetCloseHandle(hrequest); - InternetCloseHandle(hsession); - InternetCloseHandle(hinet); - update_messages(); - show_progress("Done."); - sleep_and_pump_messages( 3 ); -// return TRUE; -} - -LLFileEncoder::LLFileEncoder(const char *form_name, const char *filename) -{ - mFormname = form_name; - mFilename = filename; - mIsValid = FALSE; - mBuf = NULL; - - int res; - - llstat stat_data; - res = LLFile::stat(mFilename.c_str(), &stat_data); - if (res) - { - llwarns << "File " << mFilename << " is missing!" << llendl; - return; - } - - FILE *fp = NULL; - S32 buf_size = 0; - S32 count = 0; - while (count < 5) - { - buf_size = stat_data.st_size; - fp = LLFile::fopen(mFilename.c_str(), "rb"); /* Flawfinder: ignore */ - if (!fp) - { - llwarns << "Can't open file " << mFilename << ", wait for a second" << llendl; - // Couldn't open the file, wait a bit and try again - count++; - ms_sleep(1000); - } - else - { - break; - } - } - if (!fp) - { - return; - } - U8 *buf = new U8[buf_size + 1]; - fread(buf, 1, buf_size, fp); - fclose(fp); - - mBuf = buf; - mBufLength = buf_size; - - mIsValid = TRUE; -} - -LLFileEncoder::~LLFileEncoder() -{ - if (mBuf) - { - delete mBuf; - mBuf = NULL; - } -} - -LLString LLFileEncoder::encodeURL(const S32 max_length) -{ - LLString result = mFormname; - result.append(1, '='); - - S32 i = 0; - - if (max_length) - { - if (mBufLength > max_length) - { - i = mBufLength - max_length; - } - } - - S32 url_buf_size = 3*mBufLength + 1; - char *url_buf = new char[url_buf_size]; - - S32 cur_pos = 0; - for (; i < mBufLength; i++) + app.setHandle(hInstance); + ok = app.init(); + if(!ok) { - S32 byte_val = mBuf[i]; - sprintf(url_buf + cur_pos, "%%%02x", byte_val); - cur_pos += 3; + llwarns << "Unable to initialize application." << llendl; + return -1; } - url_buf[i*3] = 0; - result.append(url_buf); - delete[] url_buf; - return result; -} - -LLString encode_string(const char *formname, const LLString &str) -{ - LLString result = formname; - result.append(1, '='); - // Not using LLString because of bad performance issues - S32 buf_size = str.size(); - S32 url_buf_size = 3*str.size() + 1; - char *url_buf = new char[url_buf_size]; + // Run the application main loop + if(!LLApp::isQuitting()) app.mainLoop(); - S32 cur_pos = 0; - S32 i; - for (i = 0; i < buf_size; i++) + if (!app.isError()) { - sprintf(url_buf + cur_pos, "%%%02x", str[i]); - cur_pos += 3; + // + // We don't want to do cleanup here if the error handler got called - + // the assumption is that the error handler is responsible for doing + // app cleanup if there was a problem. + // + app.cleanup(); } - url_buf[i*3] = 0; - - result.append(url_buf); - delete[] url_buf; - return result; -} - -void write_debug(const char *str) -{ - if (!gDebugFile) - { - std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log"); - llinfos << "Opening debug file " << debug_filename << llendl; - gDebugFile = LLFile::fopen(debug_filename.c_str(), "a+"); /* Flawfinder: ignore */ - if (!gDebugFile) - { - fprintf(stderr, "Couldn't open %s: debug log to stderr instead.\n", debug_filename.c_str()); - gDebugFile = stderr; - } - } - fprintf(gDebugFile, str); /* Flawfinder: ignore */ - fflush(gDebugFile); -} - -void write_debug(std::string& str) -{ - write_debug(str.c_str()); -} - -S32 load_crash_behavior_setting() -{ - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); - - gCrashSettings.loadFromFile(filename); - - S32 value = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING); - - if (value < CRASH_BEHAVIOR_ASK || CRASH_BEHAVIOR_NEVER_SEND < value) return CRASH_BEHAVIOR_ASK; - - return value; -} - -bool save_crash_behavior_setting(S32 crash_behavior) -{ - if (crash_behavior < CRASH_BEHAVIOR_ASK) return false; - if (crash_behavior > CRASH_BEHAVIOR_NEVER_SEND) return false; - - gCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior); - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); - - gCrashSettings.saveToFile(filename, FALSE); - - return true; + return 0; } diff --git a/indra/win_crash_logger/win_crash_logger.rc b/indra/win_crash_logger/win_crash_logger.rc index 2c46859b95..2819722f63 100644 --- a/indra/win_crash_logger/win_crash_logger.rc +++ b/indra/win_crash_logger/win_crash_logger.rc @@ -56,13 +56,13 @@ END // Dialog // -IDD_PROGRESS DIALOG 100, 100, 186, 33 +IDD_PROGRESS DIALOGEX 100, 100, 234, 33 STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU CAPTION "%s Crash Logger" CLASS "WIN_CRASH_LOGGER" -FONT 8, "MS Sans Serif" +FONT 8, "MS Sans Serif", 0, 0, 0x0 BEGIN - LTEXT "Static",IDC_LOG,7,7,172,8 + LTEXT "Static",IDC_LOG,7,7,220,8 END IDD_REPORT DIALOGEX 100, 100, 297, 125 @@ -73,48 +73,33 @@ FONT 8, "MS Sans Serif", 0, 0, 0x0 BEGIN DEFPUSHBUTTON "Send",IDOK,198,104,45,15,WS_GROUP PUSHBUTTON "Don't Send",IDCANCEL,247,104,45,15,WS_GROUP - LTEXT "%s appears to have crashed.",IDC_STATIC_HEADER,4,4,288, - 14 - LTEXT "This crash reporter collects information about your computer's hardware, operating system, and some %s logs, which are used for debugging purposes only.", - IDC_STATIC_WHATINFO,4,23,288,19,NOT WS_GROUP - CONTROL "Remember this choice",IDC_CHECK_AUTO,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,4,106,89,13 - LTEXT "Sending crash reports is the best way to help us improve the quality of %s.", - IDC_STATIC_MOTIVATION,4,38,288,8 - LTEXT "If you continue to experience this problem, please try:", - IDC_STATIC,4,57,251,8 - LTEXT "- Contacting support by visiting http://www.secondlife.com/support", - IDC_STATIC,4,67,231,8 + LTEXT "%s appears to have crashed.",IDC_STATIC_HEADER,4,4,288,14 + LTEXT "This crash reporter collects information about your computer's hardware, operating system, and some %s logs, which are used for debugging purposes only.",IDC_STATIC_WHATINFO,4,23,288,19,NOT WS_GROUP + CONTROL "Remember this choice",IDC_CHECK_AUTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,106,89,13 + LTEXT "Sending crash reports is the best way to help us improve the quality of %s.",IDC_STATIC_MOTIVATION,4,43,288,8 + LTEXT "If you continue to experience this problem, please try:",IDC_STATIC,4,57,251,8 + LTEXT "- Contacting support by visiting http://www.secondlife.com/support",IDC_STATIC,4,67,231,8 END -IDD_PREVREPORTBOX DIALOG 100, 100, 232, 213 +IDD_PREVREPORTBOX DIALOGEX 100, 100, 232, 213 STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU CAPTION "%s Crash Logger" CLASS "WIN_CRASH_LOGGER" -FONT 8, "MS Sans Serif" +FONT 8, "MS Sans Serif", 0, 0, 0x0 BEGIN - DEFPUSHBUTTON "OK",IDOK,131,193,45,15,WS_GROUP - EDITTEXT IDC_EDIT1,4,102,223,89,ES_MULTILINE | ES_WANTRETURN | - WS_VSCROLL - PUSHBUTTON "Cancel",IDCANCEL,181,193,45,15,WS_GROUP - LTEXT "%s appears to have crashed or frozen the last time it ran.", - IDC_STATIC,4,4,214,8 - LTEXT "This crash reporter collects information about your computer's", - IDC_STATIC,4,17,201,8 - LTEXT "hardware configuration, operating system, and some %s", - IDC_STATIC,4,25,212,8 - LTEXT "logs, all of which are used for debugging purposes only.", - IDC_STATIC,4,33,210,8 - LTEXT "In the space below, please briefly describe what you were doing", - IDC_STATIC,3,48,208,8 - LTEXT "or trying to do just prior to the crash.",IDC_STATIC,3, - 56,204,8 - LTEXT "If you don't wish to send Linden Lab a crash report, press Cancel.", - IDC_STATIC,3,90,214,8 - LTEXT "This report is NOT read by customer support. If you have billing or", - IDC_STATIC,3,68,208,8 - LTEXT "other questions, please go to: www.secondlife.com/support", - IDC_STATIC,3,76,206,8 + DEFPUSHBUTTON "Send Report",IDOK,131,193,45,15,WS_GROUP + EDITTEXT IDC_EDIT1,3,100,223,89,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL + PUSHBUTTON "Don't Send",IDCANCEL,181,193,45,15,WS_GROUP + LTEXT "%s appears to have crashed or frozen the last time it ran.",IDC_STATIC_HEADER,4,4,214,8 + LTEXT "This crash reporter collects information about your computer's",IDC_STATIC,4,17,201,8 + LTEXT "hardware configuration, operating system, and some %s",IDC_STATIC_MSG,4,25,212,8 + LTEXT "logs, all of which are used for debugging purposes only.",IDC_STATIC,4,33,210,8 + LTEXT "In the space below, please briefly describe what you were doing",IDC_STATIC,3,48,208,8 + LTEXT "or trying to do just prior to the crash.",IDC_STATIC,3,56,204,8 + LTEXT "If you don't wish to send Linden Lab a crash report, press Don't Send.",IDC_STATIC,3,90,223,8 + LTEXT "This report is NOT read by customer support. If you have billing or",IDC_STATIC,3,68,208,8 + LTEXT "other questions, please go to: www.secondlife.com/support",IDC_STATIC,3,76,206,8 + CONTROL "Remember this choice",IDC_CHECK_AUTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,193,89,13 END @@ -158,7 +143,7 @@ BEGIN IDD_PROGRESS, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 179 + RIGHTMARGIN, 227 TOPMARGIN, 7 BOTTOMMARGIN, 26 END |