зеркало из https://github.com/mozilla/pjs.git
Bug 358082 - Improve Mac Crashreporter UI, patch by dcamp, r=luser+me
This commit is contained in:
Родитель
843e98ad92
Коммит
4e82b2258b
|
@ -39,8 +39,11 @@
|
|||
|
||||
#include "crashreporter.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Disable exception handler warnings.
|
||||
#pragma warning( disable : 4530 )
|
||||
# pragma warning( disable : 4530 )
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
|
@ -48,8 +51,10 @@ using std::string;
|
|||
using std::istream;
|
||||
using std::ifstream;
|
||||
using std::istringstream;
|
||||
using std::ostringstream;
|
||||
using std::ostream;
|
||||
using std::ofstream;
|
||||
using std::vector;
|
||||
|
||||
StringTable gStrings;
|
||||
int gArgc;
|
||||
|
@ -61,7 +66,30 @@ static string gSettingsPath;
|
|||
|
||||
static string kExtraDataExtension = ".extra";
|
||||
|
||||
static bool ReadStrings(istream &in, StringTable &strings)
|
||||
static string Unescape(const string& str)
|
||||
{
|
||||
string ret;
|
||||
for (string::const_iterator iter = str.begin();
|
||||
iter != str.end();
|
||||
iter++) {
|
||||
if (*iter == '\\') {
|
||||
iter++;
|
||||
if (*iter == '\\'){
|
||||
ret.push_back('\\');
|
||||
} else if (*iter == 'n') {
|
||||
ret.push_back('\n');
|
||||
} else if (*iter == 't') {
|
||||
ret.push_back('\t');
|
||||
}
|
||||
} else {
|
||||
ret.push_back(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool ReadStrings(istream& in, StringTable& strings, bool unescape)
|
||||
{
|
||||
string currentSection;
|
||||
while (!in.eof()) {
|
||||
|
@ -72,6 +100,8 @@ static bool ReadStrings(istream &in, StringTable &strings)
|
|||
string key, value;
|
||||
key = line.substr(0, sep);
|
||||
value = line.substr(sep + 1);
|
||||
if (unescape)
|
||||
value = Unescape(value);
|
||||
strings[key] = value;
|
||||
}
|
||||
}
|
||||
|
@ -80,12 +110,13 @@ static bool ReadStrings(istream &in, StringTable &strings)
|
|||
}
|
||||
|
||||
static bool ReadStringsFromFile(const string& path,
|
||||
StringTable& strings)
|
||||
StringTable& strings,
|
||||
bool unescape)
|
||||
{
|
||||
ifstream f(path.c_str(), std::ios::in);
|
||||
if (!f.is_open()) return false;
|
||||
|
||||
return ReadStrings(f, strings);
|
||||
return ReadStrings(f, strings, unescape);
|
||||
}
|
||||
|
||||
static bool ReadConfig()
|
||||
|
@ -94,7 +125,7 @@ static bool ReadConfig()
|
|||
if (!UIGetIniPath(iniPath))
|
||||
return false;
|
||||
|
||||
if (!ReadStringsFromFile(iniPath, gStrings))
|
||||
if (!ReadStringsFromFile(iniPath, gStrings, true))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -125,7 +156,6 @@ static bool MoveCrashData(const string& toDir,
|
|||
string& extrafile)
|
||||
{
|
||||
if (!UIEnsurePathExists(toDir)) {
|
||||
UIError(toDir.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -134,8 +164,6 @@ static bool MoveCrashData(const string& toDir,
|
|||
|
||||
if (!UIMoveFile(dumpfile, newDump) ||
|
||||
!UIMoveFile(extrafile, newExtra)) {
|
||||
UIError(dumpfile.c_str());
|
||||
UIError(newDump.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -149,7 +177,7 @@ static bool AddSubmittedReport(const string& serverResponse)
|
|||
{
|
||||
StringTable responseItems;
|
||||
istringstream in(serverResponse);
|
||||
ReadStrings(in, responseItems);
|
||||
ReadStrings(in, responseItems, false);
|
||||
|
||||
if (responseItems.find("CrashID") == responseItems.end())
|
||||
return false;
|
||||
|
@ -190,10 +218,13 @@ bool CrashReporterSendCompleted(bool success,
|
|||
const string& serverResponse)
|
||||
{
|
||||
if (success) {
|
||||
if (!gDumpFile.empty())
|
||||
UIDeleteFile(gDumpFile);
|
||||
if (!gExtraFile.empty())
|
||||
UIDeleteFile(gExtraFile);
|
||||
const char* noDelete = getenv("MOZ_CRASHREPORTER_NO_DELETE_DUMP");
|
||||
if (!noDelete || *noDelete == '\0') {
|
||||
if (!gDumpFile.empty())
|
||||
UIDeleteFile(gDumpFile);
|
||||
if (!gExtraFile.empty())
|
||||
UIDeleteFile(gExtraFile);
|
||||
}
|
||||
|
||||
return AddSubmittedReport(serverResponse);
|
||||
}
|
||||
|
@ -228,7 +259,7 @@ int main(int argc, const char** argv)
|
|||
}
|
||||
|
||||
StringTable queryParameters;
|
||||
if (!ReadStringsFromFile(gExtraFile, queryParameters)) {
|
||||
if (!ReadStringsFromFile(gExtraFile, queryParameters, true)) {
|
||||
UIError("Couldn't read extra data");
|
||||
return 0;
|
||||
}
|
||||
|
@ -260,6 +291,19 @@ int main(int argc, const char** argv)
|
|||
// we don't need to actually send this
|
||||
queryParameters.erase("ServerURL");
|
||||
|
||||
vector<string> restartArgs;
|
||||
|
||||
ostringstream paramName;
|
||||
int i = 0;
|
||||
paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++;
|
||||
const char *param = getenv(paramName.str().c_str());
|
||||
while (param && *param) {
|
||||
restartArgs.push_back(param);
|
||||
|
||||
paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++;
|
||||
param = getenv(paramName.str().c_str());
|
||||
};
|
||||
|
||||
// allow override of the server url via environment variable
|
||||
//XXX: remove this in the far future when our robot
|
||||
// masters force everyone to use XULRunner
|
||||
|
@ -268,7 +312,29 @@ int main(int argc, const char** argv)
|
|||
sendURL = urlEnv;
|
||||
}
|
||||
|
||||
UIShowCrashUI(gDumpFile, queryParameters, sendURL);
|
||||
// rewrite some UI strings with the values from the query parameters
|
||||
char buf[4096];
|
||||
UI_SNPRINTF(buf, sizeof(buf),
|
||||
gStrings[ST_RESTART].c_str(),
|
||||
product.c_str());
|
||||
gStrings[ST_RESTART] = buf;
|
||||
|
||||
UI_SNPRINTF(buf, sizeof(buf),
|
||||
gStrings[ST_CRASHREPORTERDESCRIPTION].c_str(),
|
||||
product.c_str());
|
||||
gStrings[ST_CRASHREPORTERDESCRIPTION] = buf;
|
||||
|
||||
UI_SNPRINTF(buf, sizeof(buf),
|
||||
gStrings[ST_CHECKSUBMIT].c_str(),
|
||||
vendor.empty() ? "Mozilla" : vendor.c_str());
|
||||
gStrings[ST_CHECKSUBMIT] = buf;
|
||||
|
||||
UI_SNPRINTF(buf, sizeof(buf),
|
||||
gStrings[ST_CRASHREPORTERTITLE].c_str(),
|
||||
vendor.empty() ? "Mozilla" : vendor.c_str());
|
||||
gStrings[ST_CRASHREPORTERTITLE] = buf;
|
||||
|
||||
UIShowCrashUI(gDumpFile, queryParameters, sendURL, restartArgs);
|
||||
}
|
||||
|
||||
UIShutdown();
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
#ifndef CRASHREPORTER_H__
|
||||
#define CRASHREPORTER_H__
|
||||
|
||||
#pragma warning( push )
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning( push )
|
||||
// Disable exception handler warnings.
|
||||
#pragma warning( disable : 4530 )
|
||||
# pragma warning( disable : 4530 )
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -24,17 +28,16 @@
|
|||
|
||||
typedef std::map<std::string, std::string> StringTable;
|
||||
|
||||
#define ST_OK "Ok"
|
||||
#define ST_CANCEL "Cancel"
|
||||
#define ST_SEND "Send"
|
||||
#define ST_DONTSEND "DontSend"
|
||||
#define ST_CLOSE "Close"
|
||||
#define ST_CRASHREPORTERTITLE "CrashReporterTitle"
|
||||
#define ST_CRASHREPORTERHEADER "CrashReporterHeader"
|
||||
#define ST_CRASHREPORTERDESCRIPTION "CrashReporterDescription"
|
||||
#define ST_RADIOENABLE "RadioEnable"
|
||||
#define ST_RADIODISABLE "RadioDisable"
|
||||
#define ST_SENDTITLE "SendTitle"
|
||||
#define ST_SUBMITSUCCESS "SubmitSuccess"
|
||||
#define ST_CRASHREPORTERDEFAULT "CrashReporterDefault"
|
||||
#define ST_VIEWREPORT "ViewReport"
|
||||
#define ST_EXTRAREPORTINFO "ExtraReportInfo"
|
||||
#define ST_CHECKSUBMIT "CheckSubmit"
|
||||
#define ST_CHECKEMAIL "CheckEmail"
|
||||
#define ST_CLOSE "Close"
|
||||
#define ST_RESTART "Restart"
|
||||
#define ST_SUBMITFAILED "SubmitFailed"
|
||||
|
||||
//=============================================================================
|
||||
|
@ -62,7 +65,8 @@ void UIShowDefaultUI();
|
|||
// Run the UI for when the app was launched with a dump file
|
||||
void UIShowCrashUI(const std::string& dumpfile,
|
||||
const StringTable& queryParameters,
|
||||
const std::string& sendURL);
|
||||
const std::string& sendURL,
|
||||
const std::vector<std::string>& restartArgs);
|
||||
|
||||
void UIError(const std::string& message);
|
||||
|
||||
|
@ -74,5 +78,8 @@ bool UIEnsurePathExists(const std::string& path);
|
|||
bool UIMoveFile(const std::string& oldfile, const std::string& newfile);
|
||||
bool UIDeleteFile(const std::string& oldfile);
|
||||
|
||||
#pragma warning( pop )
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning( pop )
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
; This file is in the UTF-8 encoding
|
||||
[Strings]
|
||||
Ok=Ok
|
||||
Cancel=Cancel
|
||||
Send=Send
|
||||
DontSend=Don't Send
|
||||
CrashReporterTitle=%s Crash Reporter
|
||||
CrashReporterHeader=Crash! Bang! Boom!
|
||||
CrashReporterDescription=We're sorry, but %s hit an unexpected problem and crashed. We'll try to restore your tabs and windows when it restarts.\n\nTo help us diagnose and repair this problem, you can send us a crash report.
|
||||
CrashReporterDefault=This application is run after a crash to report the problem to the application vendor. It should not be run directly.
|
||||
ViewReport=View Report
|
||||
ExtraReportInfo=This report also contains information about the state of the application when it crashed.
|
||||
CheckSubmit=Submit crash report to %s
|
||||
CheckEmail=Email me when the problem is fixed
|
||||
Close=Close
|
||||
CrashReporterTitle=Mozilla Crash Reporter
|
||||
CrashReporterDescription=Crash reporting blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah
|
||||
RadioEnable=Enable Crash Reporting
|
||||
RadioDisable=Disable Crash Reporting
|
||||
SendTitle=Sending Crash Report...
|
||||
SubmitSuccess=Crash report submitted successfully
|
||||
Restart=Restart %s
|
||||
SubmitFailed=Failed to submit crash report
|
||||
CrashID=Crash ID: %s
|
||||
CrashDetailsURL=You can view details of this crash at %s
|
||||
|
|
|
@ -1,124 +1,114 @@
|
|||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winresrc.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winresrc.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
IDI_DIALOG ICON "crashreporter.ico"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_ENABLEDIALOG DIALOGEX 0, 0, 322, 140
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
|
||||
WS_VISIBLE | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Crash Reporter"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "",IDC_DESCRIPTIONTEXT,"RichEdit20W",
|
||||
ES_AUTOHSCROLL | ES_READONLY | WS_BORDER | WS_TABSTOP | ES_MULTILINE,
|
||||
62,7,179,47
|
||||
CONTROL "Enable Crash Reporting",IDC_RADIOENABLE,"Button",
|
||||
BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,73,72,158,13
|
||||
CONTROL "Disable Crash Reporting",IDC_RADIODISABLE,"Button",
|
||||
BS_AUTORADIOBUTTON | WS_TABSTOP,73,86,158,13
|
||||
DEFPUSHBUTTON "OK",IDOK,125,119,50,14,WS_GROUP
|
||||
END
|
||||
|
||||
IDD_SENDDIALOG DIALOGEX 0, 0, 186, 46
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
|
||||
WS_VISIBLE | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Sending Crash Report..."
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
PUSHBUTTON "Cancel",IDCANCEL,67,25,50,14
|
||||
CONTROL "",IDC_PROGRESS,"msctls_progress32",WS_BORDER,7,7,172,14
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
IDD_ENABLEDIALOG, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 315
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 133
|
||||
END
|
||||
|
||||
IDD_SENDDIALOG, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 179
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 39
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winresrc.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winresrc.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_DIALOG ICON "crashreporter.ico"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_SENDDIALOG DIALOGEX 0, 0, 239, 105
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Sending Crash Report..."
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "",IDC_DESCRIPTIONTEXT,"RichEdit20A",ES_MULTILINE | ES_READONLY,7,7,226,12,WS_EX_TRANSPARENT
|
||||
CONTROL "view report",IDC_VIEWREPORTCHECK,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,12,24,54,12
|
||||
CONTROL "",IDC_VIEWREPORTTEXT,"RichEdit20A",ES_MULTILINE | ES_READONLY | NOT WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP,12,42,222,56
|
||||
CONTROL "submit a crash report to mozilla",IDC_SUBMITREPORTCHECK,
|
||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,42,222,10
|
||||
CONTROL "email me when the problem is fixed",IDC_EMAILMECHECK,
|
||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,54,222,10
|
||||
EDITTEXT IDC_EMAILTEXT,24,66,208,14,ES_AUTOHSCROLL
|
||||
PUSHBUTTON "close",IDC_CLOSEBUTTON,111,84,50,14
|
||||
DEFPUSHBUTTON "restart firefox",IDC_RESTARTBUTTON,165,84,68,14
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
IDD_SENDDIALOG, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 232
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 98
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
|
|
|
@ -47,39 +47,48 @@
|
|||
{
|
||||
IBOutlet NSWindow* window;
|
||||
|
||||
/* Enabled view */
|
||||
IBOutlet NSView* enableView;
|
||||
|
||||
/* Crash reporter view */
|
||||
IBOutlet NSTextField* headerLabel;
|
||||
IBOutlet NSTextField* descriptionLabel;
|
||||
IBOutlet NSButton* disableReportingButton;
|
||||
IBOutlet NSButton* dontSendButton;
|
||||
IBOutlet NSButton* sendButton;
|
||||
|
||||
/* Upload progress view */
|
||||
IBOutlet NSView* uploadingView;
|
||||
|
||||
IBOutlet NSTextField* progressLabel;
|
||||
IBOutlet NSProgressIndicator* progressBar;
|
||||
IBOutlet NSButton* viewReportButton;
|
||||
IBOutlet NSTextField* viewReportLabel;
|
||||
IBOutlet NSScrollView* viewReportScrollView;
|
||||
IBOutlet NSTextView* viewReportTextView;
|
||||
IBOutlet NSButton* submitReportButton;
|
||||
IBOutlet NSButton* emailMeButton;
|
||||
IBOutlet NSTextField* emailText;
|
||||
IBOutlet NSButton* closeButton;
|
||||
IBOutlet NSButton* restartButton;
|
||||
|
||||
/* Error view */
|
||||
IBOutlet NSView* errorView;
|
||||
IBOutlet NSTextField* errorHeaderLabel;
|
||||
IBOutlet NSTextField* errorLabel;
|
||||
IBOutlet NSButton* errorCloseButton;
|
||||
|
||||
HTTPMultipartUpload *mPost;
|
||||
}
|
||||
|
||||
- (void)showDefaultUI;
|
||||
- (void)showCrashUI:(const std::string&)dumpfile
|
||||
queryParameters:(const StringTable&)queryParameters
|
||||
sendURL:(const std::string&)sendURL;
|
||||
- (void)showErrorUI:(const std::string&)dumpfile;
|
||||
- (void)showReportInfo;
|
||||
|
||||
- (IBAction)viewReportClicked:(id)sender;
|
||||
- (IBAction)closeClicked:(id)sender;
|
||||
- (IBAction)sendClicked:(id)sender;
|
||||
- (IBAction)closeAndSendClicked:(id)sender;
|
||||
- (IBAction)restartClicked:(id)sender;
|
||||
- (IBAction)emailMeClicked:(id)sender;
|
||||
|
||||
- (void)setView:(NSWindow *)w newView: (NSView *)v animate: (BOOL) animate;
|
||||
- (void)controlTextDidChange:(NSNotification *)note;
|
||||
|
||||
- (float)setStringFitVertically:(NSControl*)control
|
||||
string:(NSString*)str
|
||||
resizeWindow:(BOOL)resizeWindow;
|
||||
- (void)setView:(NSView*)v animate: (BOOL) animate;
|
||||
- (void)updateEmail;
|
||||
- (void)sendReport;
|
||||
- (bool)setupPost;
|
||||
- (void)uploadThread:(id)post;
|
||||
- (void)uploadComplete:(id)data;
|
||||
|
|
|
@ -45,24 +45,50 @@
|
|||
#include <fcntl.h>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
static NSAutoreleasePool* gMainPool;
|
||||
static CrashReporterUI* gUI = 0;
|
||||
static string gDumpFile;
|
||||
static StringTable gQueryParameters;
|
||||
static string gSendURL;
|
||||
|
||||
static vector<string> gRestartArgs;
|
||||
|
||||
#define NSSTR(s) [NSString stringWithUTF8String:(s).c_str()]
|
||||
|
||||
static NSString *
|
||||
Str(const char* aName)
|
||||
static NSString* Str(const char* aName)
|
||||
{
|
||||
string str = gStrings[aName];
|
||||
if (str.empty()) str = "?";
|
||||
return NSSTR(str);
|
||||
}
|
||||
|
||||
static bool RestartApplication()
|
||||
{
|
||||
char** argv = reinterpret_cast<char**>(
|
||||
malloc(sizeof(char*) * (gRestartArgs.size() + 1)));
|
||||
|
||||
if (!argv) return false;
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < gRestartArgs.size(); i++) {
|
||||
argv[i] = (char*)gRestartArgs[i].c_str();
|
||||
}
|
||||
argv[i] = 0;
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == -1)
|
||||
return false;
|
||||
else if (pid == 0) {
|
||||
(void)execv(argv[0], argv);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
free(argv);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@implementation CrashReporterUI
|
||||
|
||||
-(void)awakeFromNib
|
||||
|
@ -71,22 +97,7 @@ Str(const char* aName)
|
|||
[window center];
|
||||
|
||||
[window setTitle:[[NSBundle mainBundle]
|
||||
objectForInfoDictionaryKey:@"CFBundleName"]];
|
||||
[descriptionLabel setStringValue:Str(ST_CRASHREPORTERDESCRIPTION)];
|
||||
[disableReportingButton setTitle:Str(ST_RADIODISABLE)];
|
||||
|
||||
[closeButton setTitle:Str(ST_CLOSE)];
|
||||
[errorCloseButton setTitle:Str(ST_CLOSE)];
|
||||
}
|
||||
|
||||
-(void)showDefaultUI
|
||||
{
|
||||
[dontSendButton setFrame:[sendButton frame]];
|
||||
[dontSendButton setTitle:Str(ST_CLOSE)];
|
||||
[dontSendButton setKeyEquivalent:@"\r"];
|
||||
[sendButton removeFromSuperview];
|
||||
|
||||
[window makeKeyAndOrderFront:nil];
|
||||
objectForInfoDictionaryKey:@"CFBundleName"]];
|
||||
}
|
||||
|
||||
-(void)showCrashUI:(const string&)dumpfile
|
||||
|
@ -97,45 +108,197 @@ Str(const char* aName)
|
|||
gQueryParameters = queryParameters;
|
||||
gSendURL = sendURL;
|
||||
|
||||
[sendButton setTitle:Str(ST_SEND)];
|
||||
[sendButton setKeyEquivalent:@"\r"];
|
||||
[dontSendButton setTitle:Str(ST_DONTSEND)];
|
||||
[headerLabel setStringValue:Str(ST_CRASHREPORTERHEADER)];
|
||||
|
||||
[self setStringFitVertically:descriptionLabel
|
||||
string:Str(ST_CRASHREPORTERDESCRIPTION)
|
||||
resizeWindow:YES];
|
||||
[viewReportLabel setStringValue:Str(ST_VIEWREPORT)];
|
||||
[submitReportButton setTitle:Str(ST_CHECKSUBMIT)];
|
||||
[emailMeButton setTitle:Str(ST_CHECKEMAIL)];
|
||||
[closeButton setTitle:Str(ST_CLOSE)];
|
||||
|
||||
[viewReportScrollView retain];
|
||||
[viewReportScrollView removeFromSuperview];
|
||||
|
||||
if (gRestartArgs.size() == 0) {
|
||||
NSRect restartFrame = [restartButton frame];
|
||||
[restartButton removeFromSuperview];
|
||||
NSRect closeFrame = [closeButton frame];
|
||||
closeFrame.origin.x = restartFrame.origin.x +
|
||||
(restartFrame.size.width - closeFrame.size.width);
|
||||
[closeButton setFrame: closeFrame];
|
||||
[closeButton setKeyEquivalent:@"\r"];
|
||||
} else {
|
||||
[restartButton setTitle:Str(ST_RESTART)];
|
||||
[restartButton setKeyEquivalent:@"\r"];
|
||||
}
|
||||
|
||||
[self updateEmail];
|
||||
[self showReportInfo];
|
||||
|
||||
[window makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
-(void)showErrorUI:(const string&)message
|
||||
{
|
||||
[errorLabel setStringValue: NSSTR(message)];
|
||||
[self setView: errorView animate: NO];
|
||||
|
||||
[errorHeaderLabel setStringValue:Str(ST_CRASHREPORTERHEADER)];
|
||||
[self setStringFitVertically:errorLabel
|
||||
string:NSSTR(message)
|
||||
resizeWindow:YES];
|
||||
[errorCloseButton setTitle:Str(ST_CLOSE)];
|
||||
|
||||
[self setView: window newView: errorView animate: NO];
|
||||
[window makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
-(void)showReportInfo
|
||||
{
|
||||
NSDictionary* boldAttr = [NSDictionary
|
||||
dictionaryWithObject:[NSFont boldSystemFontOfSize:0]
|
||||
forKey:NSFontAttributeName];
|
||||
NSDictionary* normalAttr = [NSDictionary
|
||||
dictionaryWithObject:[NSFont systemFontOfSize:0]
|
||||
forKey:NSFontAttributeName];
|
||||
|
||||
[viewReportTextView setString:@""];
|
||||
for (StringTable::iterator iter = gQueryParameters.begin();
|
||||
iter != gQueryParameters.end();
|
||||
iter++) {
|
||||
[[viewReportTextView textStorage]
|
||||
appendAttributedString: [[NSAttributedString alloc]
|
||||
initWithString:NSSTR(iter->first + ": ")
|
||||
attributes:boldAttr]];
|
||||
[[viewReportTextView textStorage]
|
||||
appendAttributedString: [[NSAttributedString alloc]
|
||||
initWithString:NSSTR(iter->second + "\n")
|
||||
attributes:normalAttr]];
|
||||
}
|
||||
|
||||
[[viewReportTextView textStorage]
|
||||
appendAttributedString: [[NSAttributedString alloc]
|
||||
initWithString:NSSTR("\n" + gStrings[ST_EXTRAREPORTINFO])
|
||||
attributes:normalAttr]];
|
||||
}
|
||||
|
||||
-(IBAction)viewReportClicked:(id)sender
|
||||
{
|
||||
NSRect frame = [window frame];
|
||||
NSRect scrolledFrame = [viewReportScrollView frame];
|
||||
|
||||
float delta = scrolledFrame.size.height + 5; // FIXME
|
||||
|
||||
if ([viewReportButton state] == NSOnState) {
|
||||
[[window contentView] addSubview:viewReportScrollView];
|
||||
} else {
|
||||
delta = 0 - delta;
|
||||
}
|
||||
|
||||
frame.origin.y -= delta;
|
||||
frame.size.height += delta;
|
||||
|
||||
int buttonMask = [viewReportButton autoresizingMask];
|
||||
int textMask = [viewReportLabel autoresizingMask];
|
||||
int reportMask = [viewReportScrollView autoresizingMask];
|
||||
|
||||
[viewReportButton setAutoresizingMask:NSViewMinYMargin];
|
||||
[viewReportLabel setAutoresizingMask:NSViewMinYMargin];
|
||||
[viewReportScrollView setAutoresizingMask:NSViewMinYMargin];
|
||||
|
||||
[window setFrame: frame display: true animate: NO];
|
||||
|
||||
if ([viewReportButton state] == NSOffState) {
|
||||
[viewReportScrollView removeFromSuperview];
|
||||
}
|
||||
|
||||
[viewReportButton setAutoresizingMask:buttonMask];
|
||||
[viewReportLabel setAutoresizingMask:textMask];
|
||||
[viewReportScrollView setAutoresizingMask:reportMask];
|
||||
}
|
||||
|
||||
-(IBAction)closeClicked:(id)sender
|
||||
{
|
||||
[NSApp terminate: self];
|
||||
}
|
||||
|
||||
-(IBAction)sendClicked:(id)sender
|
||||
-(IBAction)closeAndSendClicked:(id)sender
|
||||
{
|
||||
[self setView: window newView: uploadingView animate: YES];
|
||||
[progressBar startAnimation: self];
|
||||
[progressLabel setStringValue:Str(ST_SENDTITLE)];
|
||||
|
||||
if (![self setupPost])
|
||||
[NSApp terminate];
|
||||
|
||||
[NSThread detachNewThreadSelector:@selector(uploadThread:)
|
||||
toTarget:self
|
||||
withObject:mPost];
|
||||
if ([submitReportButton state] == NSOnState) {
|
||||
// Hide the dialog after "closing", but leave it around to coordinate
|
||||
// with the upload thread
|
||||
[window orderOut:nil];
|
||||
[self sendReport];
|
||||
} else {
|
||||
[NSApp terminate:self];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)setView:(NSWindow*)w newView: (NSView*)v animate: (BOOL)animate
|
||||
-(IBAction)restartClicked:(id)sender
|
||||
{
|
||||
NSRect frame = [w frame];
|
||||
RestartApplication();
|
||||
if ([submitReportButton state] == NSOnState) {
|
||||
// Hide the dialog after "closing", but leave it around to coordinate
|
||||
// with the upload thread
|
||||
[window orderOut:nil];
|
||||
[self sendReport];
|
||||
} else {
|
||||
[NSApp terminate:self];
|
||||
}
|
||||
}
|
||||
|
||||
NSRect oldViewFrame = [[w contentView] frame];
|
||||
-(IBAction)emailMeClicked:(id)sender
|
||||
{
|
||||
[self updateEmail];
|
||||
[self showReportInfo];
|
||||
}
|
||||
|
||||
-(void)controlTextDidChange:(NSNotification *)note
|
||||
{
|
||||
// Email text changed, assume they want the "Email me" checkbox
|
||||
// updated appropriately
|
||||
if ([[emailText stringValue] length] > 0)
|
||||
[emailMeButton setState:NSOnState];
|
||||
else
|
||||
[emailMeButton setState:NSOffState];
|
||||
|
||||
[self updateEmail];
|
||||
[self showReportInfo];
|
||||
}
|
||||
|
||||
-(float)setStringFitVertically:(NSControl*)control
|
||||
string:(NSString*)str
|
||||
resizeWindow:(BOOL)resizeWindow
|
||||
{
|
||||
// hack to make the text field grow vertically
|
||||
NSRect frame = [control frame];
|
||||
float oldHeight = frame.size.height;
|
||||
|
||||
frame.size.height = 10000;
|
||||
NSSize oldCellSize = [[control cell] cellSizeForBounds: frame];
|
||||
[control setStringValue: str];
|
||||
NSSize newCellSize = [[control cell] cellSizeForBounds: frame];
|
||||
|
||||
float delta = newCellSize.height - oldCellSize.height;
|
||||
frame.origin.y -= delta;
|
||||
frame.size.height = oldHeight + delta;
|
||||
[control setFrame: frame];
|
||||
|
||||
if (resizeWindow) {
|
||||
NSRect frame = [window frame];
|
||||
frame.origin.y -= delta;
|
||||
frame.size.height += delta;
|
||||
[window setFrame:frame display: true animate: NO];
|
||||
}
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
-(void)setView: (NSView*)v animate: (BOOL)animate
|
||||
{
|
||||
NSRect frame = [window frame];
|
||||
|
||||
NSRect oldViewFrame = [[window contentView] frame];
|
||||
NSRect newViewFrame = [v frame];
|
||||
|
||||
frame.origin.y += oldViewFrame.size.height - newViewFrame.size.height;
|
||||
|
@ -144,8 +307,28 @@ Str(const char* aName)
|
|||
frame.origin.x += oldViewFrame.size.width - newViewFrame.size.width;
|
||||
frame.size.width -= oldViewFrame.size.width - newViewFrame.size.width;
|
||||
|
||||
[w setContentView: v];
|
||||
[w setFrame: frame display: true animate: animate];
|
||||
[window setContentView:v];
|
||||
[window setFrame:frame display:true animate:animate];
|
||||
}
|
||||
|
||||
-(void)updateEmail
|
||||
{
|
||||
if ([emailMeButton state] == NSOnState) {
|
||||
NSString* email = [emailText stringValue];
|
||||
gQueryParameters["Email"] = [email UTF8String];
|
||||
} else {
|
||||
gQueryParameters.erase("Email");
|
||||
}
|
||||
}
|
||||
|
||||
-(void)sendReport
|
||||
{
|
||||
if (![self setupPost])
|
||||
[NSApp terminate:self];
|
||||
|
||||
[NSThread detachNewThreadSelector:@selector(uploadThread:)
|
||||
toTarget:self
|
||||
withObject:mPost];
|
||||
}
|
||||
|
||||
-(bool)setupPost
|
||||
|
@ -177,19 +360,14 @@ Str(const char* aName)
|
|||
|
||||
-(void)uploadComplete:(id)data
|
||||
{
|
||||
[progressBar stopAnimation: self];
|
||||
|
||||
NSHTTPURLResponse* response = [mPost response];
|
||||
|
||||
NSString* status;
|
||||
bool success;
|
||||
string reply;
|
||||
if (!data || !response || [response statusCode] != 200) {
|
||||
status = Str(ST_SUBMITFAILED);
|
||||
success = false;
|
||||
reply = "";
|
||||
} else {
|
||||
status = Str(ST_SUBMITSUCCESS);
|
||||
success = true;
|
||||
|
||||
NSString* encodingName = [response textEncodingName];
|
||||
|
@ -204,11 +382,13 @@ Str(const char* aName)
|
|||
reply = [r UTF8String];
|
||||
}
|
||||
|
||||
[progressLabel setStringValue: status];
|
||||
[closeButton setEnabled: true];
|
||||
[closeButton setKeyEquivalent:@"\r"];
|
||||
|
||||
CrashReporterSendCompleted(success, reply);
|
||||
|
||||
if (success) {
|
||||
[NSApp terminate:self];
|
||||
} else {
|
||||
[self showErrorUI:gStrings[ST_SUBMITFAILED]];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)uploadThread:(id)post
|
||||
|
@ -246,14 +426,16 @@ void UIShutdown()
|
|||
|
||||
void UIShowDefaultUI()
|
||||
{
|
||||
[gUI showDefaultUI];
|
||||
[NSApp run];
|
||||
UIError(gStrings[ST_CRASHREPORTERDEFAULT]);
|
||||
}
|
||||
|
||||
void UIShowCrashUI(const string& dumpfile,
|
||||
const StringTable& queryParameters,
|
||||
const string& sendURL)
|
||||
const string& sendURL,
|
||||
const vector<string>& restartArgs)
|
||||
{
|
||||
gRestartArgs = restartArgs;
|
||||
|
||||
[gUI showCrashUI: dumpfile
|
||||
queryParameters: queryParameters
|
||||
sendURL: sendURL];
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ted Mielczarek <ted.mielczarek@gmail.com>
|
||||
* Dave Camp <dcamp@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -47,226 +49,553 @@
|
|||
#include <shellapi.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
#include <set>
|
||||
#include "resource.h"
|
||||
#include "client/windows/sender/crash_report_sender.h"
|
||||
#include "common/windows/string_utils-inl.h"
|
||||
|
||||
#define CRASH_REPORTER_KEY L"Software\\Mozilla\\Crash Reporter"
|
||||
#define CRASH_REPORTER_VALUE L"Enabled"
|
||||
#define SUBMIT_REPORT_VALUE L"SubmitReport"
|
||||
#define EMAIL_ME_VALUE L"EmailMe"
|
||||
#define EMAIL_VALUE L"Email"
|
||||
#define MAX_EMAIL_LENGTH 1024
|
||||
|
||||
#define WM_UPLOADCOMPLETE WM_APP
|
||||
|
||||
using std::string;
|
||||
using std::wstring;
|
||||
using std::map;
|
||||
|
||||
static wstring UTF8ToWide(const string& utf8, bool *success = 0);
|
||||
static string WideToUTF8(const wstring& wide, bool *success = 0);
|
||||
static DWORD WINAPI SendThreadProc(LPVOID param);
|
||||
using std::vector;
|
||||
using std::set;
|
||||
|
||||
typedef struct {
|
||||
HWND hDlg;
|
||||
wstring dumpFile;
|
||||
const StringTable* query_parameters;
|
||||
wstring send_url;
|
||||
wstring* server_response;
|
||||
} SENDTHREADDATA;
|
||||
map<wstring,wstring> queryParameters;
|
||||
wstring sendURL;
|
||||
|
||||
wstring serverResponse;
|
||||
} SendThreadData;
|
||||
|
||||
static HANDLE gThreadHandle;
|
||||
static SendThreadData gSendData = { 0, };
|
||||
static vector<string> gRestartArgs;
|
||||
static map<wstring,wstring> gQueryParameters;
|
||||
static wstring gCrashReporterKey(L"Software\\Mozilla\\Crash Reporter");
|
||||
|
||||
// When vertically resizing the dialog, these items should move down
|
||||
static set<UINT> gAttachedBottom;
|
||||
|
||||
// Default set of items for gAttachedBottom
|
||||
static const UINT kDefaultAttachedBottom[] = {
|
||||
IDC_VIEWREPORTCHECK,
|
||||
IDC_VIEWREPORTTEXT,
|
||||
IDC_SUBMITCRASHCHECK,
|
||||
IDC_EMAILMECHECK,
|
||||
IDC_EMAILTEXT,
|
||||
IDC_CLOSEBUTTON,
|
||||
IDC_RESTARTBUTTON,
|
||||
};
|
||||
|
||||
static wstring UTF8ToWide(const string& utf8, bool *success = 0);
|
||||
static string WideToUTF8(const wstring& wide, bool *success = 0);
|
||||
static DWORD WINAPI SendThreadProc(LPVOID param);
|
||||
|
||||
static wstring Str(const char* key)
|
||||
{
|
||||
return UTF8ToWide(gStrings[key]);
|
||||
}
|
||||
|
||||
/* === win32 helper functions === */
|
||||
|
||||
static void DoInitCommonControls()
|
||||
{
|
||||
INITCOMMONCONTROLSEX ic;
|
||||
ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
|
||||
ic.dwICC = ICC_PROGRESS_CLASS;
|
||||
InitCommonControlsEx(&ic);
|
||||
INITCOMMONCONTROLSEX ic;
|
||||
ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
|
||||
ic.dwICC = ICC_PROGRESS_CLASS;
|
||||
InitCommonControlsEx(&ic);
|
||||
// also get the rich edit control
|
||||
LoadLibrary(L"riched20.dll");
|
||||
}
|
||||
|
||||
static BOOL CALLBACK EnableDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (message) {
|
||||
case WM_INITDIALOG:
|
||||
SetWindowText(hwndDlg, Str(ST_CRASHREPORTERTITLE).c_str());
|
||||
SetDlgItemText(hwndDlg, IDOK, Str(ST_OK).c_str());
|
||||
SetDlgItemText(hwndDlg, IDC_RADIOENABLE, Str(ST_RADIOENABLE).c_str());
|
||||
SetDlgItemText(hwndDlg, IDC_RADIODISABLE, Str(ST_RADIODISABLE).c_str());
|
||||
SetDlgItemText(hwndDlg, IDC_DESCRIPTIONTEXT, Str(ST_CRASHREPORTERDESCRIPTION).c_str());
|
||||
SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETTARGETDEVICE, (WPARAM)NULL, 0);
|
||||
SetFocus(GetDlgItem(hwndDlg, IDC_RADIOENABLE));
|
||||
CheckRadioButton(hwndDlg, IDC_RADIOENABLE, IDC_RADIODISABLE, lParam ? IDC_RADIOENABLE : IDC_RADIODISABLE);
|
||||
return FALSE;
|
||||
|
||||
case WM_COMMAND:
|
||||
if (LOWORD(wParam) == IDOK && HIWORD(wParam) == BN_CLICKED)
|
||||
{
|
||||
UINT enableChecked = IsDlgButtonChecked(hwndDlg, IDC_RADIOENABLE);
|
||||
EndDialog(hwndDlg, (enableChecked > 0) ? 1 : 0);
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static bool GetRegValue(HKEY hRegKey, LPCTSTR valueName, DWORD* value)
|
||||
static bool GetBoolValue(HKEY hRegKey, LPCTSTR valueName, DWORD* value)
|
||||
{
|
||||
DWORD type, dataSize;
|
||||
dataSize = sizeof(DWORD);
|
||||
if (RegQueryValueEx(hRegKey, valueName, NULL, &type, (LPBYTE)value, &dataSize) == ERROR_SUCCESS
|
||||
&& type == REG_DWORD)
|
||||
return true;
|
||||
DWORD type, dataSize;
|
||||
dataSize = sizeof(DWORD);
|
||||
if (RegQueryValueEx(hRegKey, valueName, NULL, &type, (LPBYTE)value, &dataSize) == ERROR_SUCCESS
|
||||
&& type == REG_DWORD)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool CheckCrashReporterEnabled(bool* enabled)
|
||||
static bool CheckBoolKey(const wchar_t* key,
|
||||
const wchar_t* valueName,
|
||||
bool* enabled)
|
||||
{
|
||||
*enabled = false;
|
||||
bool found = false;
|
||||
HKEY hRegKey;
|
||||
DWORD val;
|
||||
// see if our reg key is set globally
|
||||
if (RegOpenKey(HKEY_LOCAL_MACHINE, CRASH_REPORTER_KEY, &hRegKey) == ERROR_SUCCESS)
|
||||
{
|
||||
if (GetRegValue(hRegKey, CRASH_REPORTER_VALUE, &val))
|
||||
{
|
||||
*enabled = (val == 1);
|
||||
found = true;
|
||||
}
|
||||
if (RegOpenKey(HKEY_LOCAL_MACHINE, key, &hRegKey) == ERROR_SUCCESS) {
|
||||
if (GetBoolValue(hRegKey, valueName, &val)) {
|
||||
*enabled = (val == 1);
|
||||
found = true;
|
||||
}
|
||||
RegCloseKey(hRegKey);
|
||||
} else {
|
||||
// look for it in user settings
|
||||
if (RegOpenKey(HKEY_CURRENT_USER, key, &hRegKey) == ERROR_SUCCESS) {
|
||||
if (GetBoolValue(hRegKey, valueName, &val)) {
|
||||
*enabled = (val == 1);
|
||||
found = true;
|
||||
}
|
||||
RegCloseKey(hRegKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
// look for it in user settings
|
||||
if (RegOpenKey(HKEY_CURRENT_USER, CRASH_REPORTER_KEY, &hRegKey) == ERROR_SUCCESS)
|
||||
{
|
||||
if (GetRegValue(hRegKey, CRASH_REPORTER_VALUE, &val))
|
||||
{
|
||||
*enabled = (val == 1);
|
||||
found = true;
|
||||
}
|
||||
RegCloseKey(hRegKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// didn't find our reg key, ask user
|
||||
return found;
|
||||
}
|
||||
|
||||
static void SetCrashReporterEnabled(bool enabled)
|
||||
static void SetBoolKey(const wchar_t* key, const wchar_t* value, bool enabled)
|
||||
{
|
||||
HKEY hRegKey;
|
||||
if (RegCreateKey(HKEY_CURRENT_USER, CRASH_REPORTER_KEY, &hRegKey) == ERROR_SUCCESS) {
|
||||
if (RegCreateKey(HKEY_CURRENT_USER, key, &hRegKey) == ERROR_SUCCESS) {
|
||||
DWORD data = (enabled ? 1 : 0);
|
||||
RegSetValueEx(hRegKey, CRASH_REPORTER_VALUE, 0, REG_DWORD, (LPBYTE)&data, sizeof(data));
|
||||
RegSetValueEx(hRegKey, value, 0, REG_DWORD, (LPBYTE)&data, sizeof(data));
|
||||
RegCloseKey(hRegKey);
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL CALLBACK SendDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
static bool GetStringValue(HKEY hRegKey, LPCTSTR valueName, wstring& value)
|
||||
{
|
||||
static bool finishedOk = false;
|
||||
static HANDLE hThread = NULL;
|
||||
DWORD type, dataSize;
|
||||
wchar_t buf[2048];
|
||||
dataSize = sizeof(buf);
|
||||
if (RegQueryValueEx(hRegKey, valueName, NULL, &type, (LPBYTE)buf, &dataSize) == ERROR_SUCCESS
|
||||
&& type == REG_SZ) {
|
||||
value = buf;
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (message) {
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
//init strings
|
||||
SetWindowText(hwndDlg, Str(ST_SENDTITLE).c_str());
|
||||
SetDlgItemText(hwndDlg, IDCANCEL, Str(ST_CANCEL).c_str());
|
||||
// init progressmeter
|
||||
SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
|
||||
SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETPOS, 0, 0);
|
||||
// now create a thread to actually do the sending
|
||||
SENDTHREADDATA* td = (SENDTHREADDATA*)lParam;
|
||||
td->hDlg = hwndDlg;
|
||||
CreateThread(NULL, 0, SendThreadProc, td, 0, NULL);
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case WM_UPLOADCOMPLETE:
|
||||
WaitForSingleObject(hThread, INFINITE);
|
||||
finishedOk = (wParam == 1);
|
||||
if (finishedOk) {
|
||||
SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETPOS, 100, 0);
|
||||
MessageBox(hwndDlg,
|
||||
Str(ST_SUBMITSUCCESS).c_str(),
|
||||
Str(ST_CRASHREPORTERTITLE).c_str(),
|
||||
MB_OK | MB_ICONINFORMATION);
|
||||
}
|
||||
else {
|
||||
MessageBox(hwndDlg,
|
||||
Str(ST_SUBMITFAILED).c_str(),
|
||||
Str(ST_CRASHREPORTERTITLE).c_str(),
|
||||
MB_OK | MB_ICONERROR);
|
||||
}
|
||||
EndDialog(hwndDlg, finishedOk ? 1 : 0);
|
||||
return TRUE;
|
||||
|
||||
case WM_COMMAND:
|
||||
if (LOWORD(wParam) == IDCANCEL && HIWORD(wParam) == BN_CLICKED) {
|
||||
EndDialog(hwndDlg, finishedOk ? 1 : 0);
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool SendCrashReport(wstring dumpFile,
|
||||
const StringTable* query_parameters,
|
||||
wstring send_url,
|
||||
wstring* server_response)
|
||||
static bool GetStringKey(const wchar_t* key,
|
||||
const wchar_t* valueName,
|
||||
wstring& value)
|
||||
{
|
||||
SENDTHREADDATA td;
|
||||
td.hDlg = NULL;
|
||||
td.dumpFile = dumpFile;
|
||||
td.query_parameters = query_parameters;
|
||||
td.send_url = send_url;
|
||||
td.server_response = server_response;
|
||||
value = L"";
|
||||
bool found = false;
|
||||
HKEY hRegKey;
|
||||
// see if our reg key is set globally
|
||||
if (RegOpenKey(HKEY_LOCAL_MACHINE, key, &hRegKey) == ERROR_SUCCESS) {
|
||||
if (GetStringValue(hRegKey, valueName, value)) {
|
||||
found = true;
|
||||
}
|
||||
RegCloseKey(hRegKey);
|
||||
} else {
|
||||
// look for it in user settings
|
||||
if (RegOpenKey(HKEY_CURRENT_USER, key, &hRegKey) == ERROR_SUCCESS) {
|
||||
if (GetStringValue(hRegKey, valueName, value)) {
|
||||
found = true;
|
||||
}
|
||||
RegCloseKey(hRegKey);
|
||||
}
|
||||
}
|
||||
|
||||
int res = (int)DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_SENDDIALOG), NULL,
|
||||
(DLGPROC)SendDialogProc, (LPARAM)&td);
|
||||
return found;
|
||||
}
|
||||
|
||||
return (res >= 0);
|
||||
static void SetStringKey(const wchar_t* key,
|
||||
const wchar_t* valueName,
|
||||
const wstring& value)
|
||||
{
|
||||
HKEY hRegKey;
|
||||
if (RegCreateKey(HKEY_CURRENT_USER, key, &hRegKey) == ERROR_SUCCESS) {
|
||||
RegSetValueEx(hRegKey, valueName, 0, REG_SZ,
|
||||
(LPBYTE)value.c_str(),
|
||||
(value.length() + 1) * sizeof(wchar_t));
|
||||
RegCloseKey(hRegKey);
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the position of a window relative to another window's client area
|
||||
static void GetRelativeRect(HWND hwnd, HWND hwndParent, RECT* r)
|
||||
{
|
||||
GetWindowRect(hwnd, r);
|
||||
ScreenToClient(hwndParent, (POINT*)&(r->left));
|
||||
ScreenToClient(hwndParent, (POINT*)&(r->right));
|
||||
}
|
||||
|
||||
static void SetDlgItemVisible(HWND hwndDlg, UINT item, bool visible)
|
||||
{
|
||||
HWND hwnd = GetDlgItem(hwndDlg, item);
|
||||
LONG style = GetWindowLong(hwnd, GWL_STYLE);
|
||||
if (visible)
|
||||
style |= WS_VISIBLE;
|
||||
else
|
||||
style &= ~WS_VISIBLE;
|
||||
|
||||
SetWindowLong(hwnd, GWL_STYLE, style);
|
||||
}
|
||||
|
||||
static void SetDlgItemDisabled(HWND hwndDlg, UINT item, bool disabled)
|
||||
{
|
||||
HWND hwnd = GetDlgItem(hwndDlg, item);
|
||||
LONG style = GetWindowLong(hwnd, GWL_STYLE);
|
||||
if (!disabled)
|
||||
style |= WS_DISABLED;
|
||||
else
|
||||
style &= ~WS_DISABLED;
|
||||
|
||||
SetWindowLong(hwnd, GWL_STYLE, style);
|
||||
}
|
||||
|
||||
/* === Crash Reporting Dialog === */
|
||||
|
||||
static void StretchDialog(HWND hwndDlg, int ydiff)
|
||||
{
|
||||
RECT r;
|
||||
GetWindowRect(hwndDlg, &r);
|
||||
r.bottom += ydiff;
|
||||
MoveWindow(hwndDlg, r.left, r.top,
|
||||
r.right - r.left, r.bottom - r.top, TRUE);
|
||||
}
|
||||
|
||||
static void ReflowDialog(HWND hwndDlg, int ydiff)
|
||||
{
|
||||
// Move items attached to the bottom down/up by as much as
|
||||
// the window resize
|
||||
for (set<UINT>::const_iterator item = gAttachedBottom.begin();
|
||||
item != gAttachedBottom.end();
|
||||
item++) {
|
||||
RECT r;
|
||||
HWND hwnd = GetDlgItem(hwndDlg, *item);
|
||||
GetRelativeRect(hwnd, hwndDlg, &r);
|
||||
r.top += ydiff;
|
||||
r.bottom += ydiff;
|
||||
MoveWindow(hwnd, r.left, r.top,
|
||||
r.right - r.left, r.bottom - r.top, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD WINAPI SendThreadProc(LPVOID param)
|
||||
{
|
||||
bool finishedOk;
|
||||
SENDTHREADDATA* td = (SENDTHREADDATA*)param;
|
||||
SendThreadData* td = (SendThreadData*)param;
|
||||
|
||||
if (td->send_url.empty()) {
|
||||
if (td->sendURL.empty()) {
|
||||
finishedOk = false;
|
||||
}
|
||||
else {
|
||||
map<wstring,wstring>query_parameters;
|
||||
StringTable::const_iterator end = td->query_parameters->end();
|
||||
for (StringTable::const_iterator i = td->query_parameters->begin();
|
||||
i != end;
|
||||
i++) {
|
||||
query_parameters[UTF8ToWide(i->first)] = UTF8ToWide(i->second);
|
||||
}
|
||||
|
||||
} else {
|
||||
google_breakpad::CrashReportSender sender(L"");
|
||||
finishedOk = (sender.SendCrashReport(td->send_url,
|
||||
query_parameters,
|
||||
finishedOk = (sender.SendCrashReport(td->sendURL,
|
||||
td->queryParameters,
|
||||
td->dumpFile,
|
||||
td->server_response)
|
||||
&td->serverResponse)
|
||||
== google_breakpad::RESULT_SUCCEEDED);
|
||||
}
|
||||
|
||||
PostMessage(td->hDlg, WM_UPLOADCOMPLETE, finishedOk ? 1 : 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void EndCrashReporterDialog(HWND hwndDlg, int code)
|
||||
{
|
||||
// Save the current values to the registry
|
||||
wchar_t email[MAX_EMAIL_LENGTH];
|
||||
GetDlgItemText(hwndDlg, IDC_EMAILTEXT, email, sizeof(email));
|
||||
SetStringKey(gCrashReporterKey.c_str(), EMAIL_VALUE, email);
|
||||
|
||||
SetBoolKey(gCrashReporterKey.c_str(), EMAIL_ME_VALUE,
|
||||
IsDlgButtonChecked(hwndDlg, IDC_EMAILMECHECK) != 0);
|
||||
SetBoolKey(gCrashReporterKey.c_str(), SUBMIT_REPORT_VALUE,
|
||||
IsDlgButtonChecked(hwndDlg, IDC_SUBMITREPORTCHECK) != 0);
|
||||
|
||||
EndDialog(hwndDlg, code);
|
||||
}
|
||||
|
||||
static void MaybeSendReport(HWND hwndDlg)
|
||||
{
|
||||
if (!IsDlgButtonChecked(hwndDlg, IDC_SUBMITREPORTCHECK)) {
|
||||
EndCrashReporterDialog(hwndDlg, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
gThreadHandle = NULL;
|
||||
gSendData.hDlg = hwndDlg;
|
||||
gSendData.queryParameters = gQueryParameters;
|
||||
|
||||
gThreadHandle = CreateThread(NULL, 0, SendThreadProc, &gSendData, 0, NULL);
|
||||
}
|
||||
|
||||
static void RestartApplication()
|
||||
{
|
||||
wstring cmdLine;
|
||||
|
||||
for (unsigned int i = 0; i < gRestartArgs.size(); i++) {
|
||||
cmdLine += L"\"" + UTF8ToWide(gRestartArgs[i]) + L"\" ";
|
||||
}
|
||||
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
si.dwFlags = STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_SHOWNORMAL;
|
||||
ZeroMemory(&pi, sizeof(pi));
|
||||
|
||||
if (CreateProcess(NULL, (LPWSTR)cmdLine.c_str(), NULL, NULL, FALSE, 0,
|
||||
NULL, NULL, &si, &pi)) {
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
}
|
||||
|
||||
static void ShowReportInfo(HWND hwndDlg)
|
||||
{
|
||||
wstring description;
|
||||
|
||||
for (map<wstring,wstring>::const_iterator i = gQueryParameters.begin();
|
||||
i != gQueryParameters.end();
|
||||
i++) {
|
||||
description += i->first;
|
||||
description += L": ";
|
||||
description += i->second;
|
||||
description += L"\n";
|
||||
}
|
||||
|
||||
description += L"\n";
|
||||
description += Str(ST_EXTRAREPORTINFO);
|
||||
|
||||
SetDlgItemText(hwndDlg, IDC_VIEWREPORTTEXT, description.c_str());
|
||||
}
|
||||
|
||||
static void ShowHideReport(HWND hwndDlg)
|
||||
{
|
||||
// When resizing the dialog to show the report, these items should
|
||||
// stay put
|
||||
gAttachedBottom.erase(IDC_VIEWREPORTCHECK);
|
||||
gAttachedBottom.erase(IDC_VIEWREPORTTEXT);
|
||||
|
||||
RECT r;
|
||||
HWND hwnd = GetDlgItem(hwndDlg, IDC_VIEWREPORTTEXT);
|
||||
|
||||
GetWindowRect(hwnd, &r);
|
||||
int diff = (r.bottom - r.top) + 10;
|
||||
if (IsDlgButtonChecked(hwndDlg, IDC_VIEWREPORTCHECK)) {
|
||||
SetDlgItemVisible(hwndDlg, IDC_VIEWREPORTTEXT, true);
|
||||
} else {
|
||||
SetDlgItemVisible(hwndDlg, IDC_VIEWREPORTTEXT, false);
|
||||
diff = -diff;
|
||||
}
|
||||
|
||||
StretchDialog(hwndDlg, diff);
|
||||
|
||||
// set these back to normal
|
||||
gAttachedBottom.insert(IDC_VIEWREPORTCHECK);
|
||||
gAttachedBottom.insert(IDC_VIEWREPORTTEXT);
|
||||
}
|
||||
|
||||
static void UpdateEmail(HWND hwndDlg)
|
||||
{
|
||||
if (IsDlgButtonChecked(hwndDlg, IDC_EMAILMECHECK)) {
|
||||
wchar_t email[MAX_EMAIL_LENGTH];
|
||||
GetDlgItemText(hwndDlg, IDC_EMAILTEXT, email, sizeof(email));
|
||||
gQueryParameters[L"Email"] = email;
|
||||
} else {
|
||||
gQueryParameters.erase(L"Email");
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL CALLBACK CrashReporterDialogProc(HWND hwndDlg, UINT message,
|
||||
WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static int sHeight = 0;
|
||||
|
||||
bool success;
|
||||
bool enabled;
|
||||
|
||||
switch (message) {
|
||||
case WM_INITDIALOG: {
|
||||
RECT r;
|
||||
GetClientRect(hwndDlg, &r);
|
||||
sHeight = r.bottom - r.top;
|
||||
|
||||
SetWindowText(hwndDlg, Str(ST_CRASHREPORTERTITLE).c_str());
|
||||
|
||||
SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT,
|
||||
EM_SETEVENTMASK, (WPARAM)NULL,
|
||||
ENM_REQUESTRESIZE);
|
||||
wstring description = Str(ST_CRASHREPORTERHEADER);
|
||||
description += L"\n\n";
|
||||
description += Str(ST_CRASHREPORTERDESCRIPTION);
|
||||
SetDlgItemText(hwndDlg, IDC_DESCRIPTIONTEXT, description.c_str());
|
||||
|
||||
// Make the title bold.
|
||||
CHARFORMAT fmt = { 0, };
|
||||
fmt.cbSize = sizeof(fmt);
|
||||
fmt.dwMask = CFM_BOLD;
|
||||
fmt.dwEffects = CFE_BOLD;
|
||||
SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETSEL,
|
||||
0, Str(ST_CRASHREPORTERHEADER).length());
|
||||
SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETCHARFORMAT,
|
||||
SCF_SELECTION, (LPARAM)&fmt);
|
||||
SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETSEL, 0, 0);
|
||||
SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT,
|
||||
EM_SETTARGETDEVICE, (WPARAM)NULL, 0);
|
||||
|
||||
SetDlgItemText(hwndDlg, IDC_VIEWREPORTCHECK, Str(ST_VIEWREPORT).c_str());
|
||||
SendDlgItemMessage(hwndDlg, IDC_VIEWREPORTTEXT,
|
||||
EM_SETTARGETDEVICE, (WPARAM)NULL, 0);
|
||||
|
||||
|
||||
SetDlgItemText(hwndDlg, IDC_SUBMITREPORTCHECK,
|
||||
Str(ST_CHECKSUBMIT).c_str());
|
||||
if (CheckBoolKey(gCrashReporterKey.c_str(),
|
||||
SUBMIT_REPORT_VALUE, &enabled) &&
|
||||
!enabled) {
|
||||
CheckDlgButton(hwndDlg, IDC_SUBMITREPORTCHECK, BST_UNCHECKED);
|
||||
EnableWindow(GetDlgItem(hwndDlg, IDC_EMAILMECHECK), enabled);
|
||||
EnableWindow(GetDlgItem(hwndDlg, IDC_EMAILTEXT), enabled);
|
||||
} else {
|
||||
CheckDlgButton(hwndDlg, IDC_SUBMITREPORTCHECK, BST_CHECKED);
|
||||
}
|
||||
|
||||
SetDlgItemText(hwndDlg, IDC_EMAILMECHECK, Str(ST_CHECKEMAIL).c_str());
|
||||
if (CheckBoolKey(gCrashReporterKey.c_str(), EMAIL_ME_VALUE, &enabled) &&
|
||||
enabled) {
|
||||
CheckDlgButton(hwndDlg, IDC_EMAILMECHECK, BST_CHECKED);
|
||||
} else {
|
||||
CheckDlgButton(hwndDlg, IDC_EMAILMECHECK, BST_UNCHECKED);
|
||||
}
|
||||
|
||||
wstring email;
|
||||
if (GetStringKey(gCrashReporterKey.c_str(), EMAIL_VALUE, email)) {
|
||||
SetDlgItemText(hwndDlg, IDC_EMAILTEXT, email.c_str());
|
||||
}
|
||||
|
||||
SetDlgItemText(hwndDlg, IDC_CLOSEBUTTON, Str(ST_CLOSE).c_str());
|
||||
|
||||
if (gRestartArgs.size() > 0) {
|
||||
SetDlgItemText(hwndDlg, IDC_RESTARTBUTTON, Str(ST_RESTART).c_str());
|
||||
} else {
|
||||
// No restart arguments, move the close button over to the side
|
||||
// and hide the restart button
|
||||
SetDlgItemVisible(hwndDlg, IDC_RESTARTBUTTON, false);
|
||||
|
||||
RECT closeRect;
|
||||
HWND hwndClose = GetDlgItem(hwndDlg, IDC_CLOSEBUTTON);
|
||||
GetRelativeRect(hwndClose, hwndDlg, &closeRect);
|
||||
|
||||
RECT restartRect;
|
||||
HWND hwndRestart = GetDlgItem(hwndDlg, IDC_RESTARTBUTTON);
|
||||
GetRelativeRect(hwndRestart, hwndDlg, &restartRect);
|
||||
|
||||
int size = closeRect.right - closeRect.left;
|
||||
closeRect.right = restartRect.right;
|
||||
closeRect.left = closeRect.right - size;
|
||||
|
||||
MoveWindow(hwndClose, closeRect.left, closeRect.top,
|
||||
closeRect.right - closeRect.left,
|
||||
closeRect.bottom - closeRect.top,
|
||||
TRUE);
|
||||
}
|
||||
UpdateEmail(hwndDlg);
|
||||
ShowReportInfo(hwndDlg);
|
||||
|
||||
SetFocus(GetDlgItem(hwndDlg, IDC_EMAILTEXT));
|
||||
return FALSE;
|
||||
}
|
||||
case WM_SIZE: {
|
||||
ReflowDialog(hwndDlg, HIWORD(lParam) - sHeight);
|
||||
sHeight = HIWORD(lParam);
|
||||
InvalidateRect(hwndDlg, NULL, TRUE);
|
||||
return FALSE;
|
||||
}
|
||||
case WM_NOTIFY: {
|
||||
NMHDR* notification = reinterpret_cast<NMHDR*>(lParam);
|
||||
if (notification->code == EN_REQUESTRESIZE) {
|
||||
// Resizing the rich edit control to fit the description text.
|
||||
REQRESIZE* reqresize = reinterpret_cast<REQRESIZE*>(lParam);
|
||||
RECT newSize = reqresize->rc;
|
||||
RECT oldSize;
|
||||
GetRelativeRect(notification->hwndFrom, hwndDlg, &oldSize);
|
||||
|
||||
// resize the text box as requested
|
||||
MoveWindow(notification->hwndFrom, newSize.left, newSize.top,
|
||||
newSize.right - newSize.left, newSize.bottom - newSize.top,
|
||||
TRUE);
|
||||
|
||||
// Resize the dialog to fit (the WM_SIZE handler will move the controls)
|
||||
StretchDialog(hwndDlg, newSize.bottom - oldSize.bottom);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
case WM_COMMAND: {
|
||||
if (HIWORD(wParam) == BN_CLICKED) {
|
||||
switch(LOWORD(wParam)) {
|
||||
case IDC_VIEWREPORTCHECK:
|
||||
ShowHideReport(hwndDlg);
|
||||
break;
|
||||
case IDC_SUBMITREPORTCHECK:
|
||||
enabled = (IsDlgButtonChecked(hwndDlg, IDC_SUBMITREPORTCHECK) != 0);
|
||||
EnableWindow(GetDlgItem(hwndDlg, IDC_EMAILMECHECK), enabled);
|
||||
EnableWindow(GetDlgItem(hwndDlg, IDC_EMAILTEXT), enabled);
|
||||
break;
|
||||
case IDC_EMAILMECHECK:
|
||||
UpdateEmail(hwndDlg);
|
||||
ShowReportInfo(hwndDlg);
|
||||
break;
|
||||
case IDC_CLOSEBUTTON:
|
||||
// Hide the dialog after "closing", but leave it around to coordinate
|
||||
// with the upload thread
|
||||
ShowWindow(hwndDlg, SW_HIDE);
|
||||
MaybeSendReport(hwndDlg);
|
||||
break;
|
||||
case IDC_RESTARTBUTTON:
|
||||
// Hide the dialog after "closing", but leave it around to coordinate
|
||||
// with the upload thread
|
||||
ShowWindow(hwndDlg, SW_HIDE);
|
||||
RestartApplication();
|
||||
MaybeSendReport(hwndDlg);
|
||||
break;
|
||||
}
|
||||
} else if (HIWORD(wParam) == EN_CHANGE) {
|
||||
switch(LOWORD(wParam)) {
|
||||
case IDC_EMAILTEXT:
|
||||
wchar_t email[MAX_EMAIL_LENGTH];
|
||||
if (GetDlgItemText(hwndDlg, IDC_EMAILTEXT, email, sizeof(email)) > 0)
|
||||
CheckDlgButton(hwndDlg, IDC_EMAILMECHECK, BST_CHECKED);
|
||||
else
|
||||
CheckDlgButton(hwndDlg, IDC_EMAILMECHECK, BST_UNCHECKED);
|
||||
UpdateEmail(hwndDlg);
|
||||
ShowReportInfo(hwndDlg);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
case WM_UPLOADCOMPLETE: {
|
||||
WaitForSingleObject(gThreadHandle, INFINITE);
|
||||
success = (wParam == 1);
|
||||
CrashReporterSendCompleted(success, WideToUTF8(gSendData.serverResponse));
|
||||
if (!success) {
|
||||
MessageBox(hwndDlg,
|
||||
Str(ST_SUBMITFAILED).c_str(),
|
||||
Str(ST_CRASHREPORTERTITLE).c_str(),
|
||||
MB_OK | MB_ICONERROR);
|
||||
}
|
||||
EndCrashReporterDialog(hwndDlg, success ? 1 : 0);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static wstring UTF8ToWide(const string& utf8, bool *success)
|
||||
{
|
||||
wchar_t* buffer = NULL;
|
||||
|
@ -329,6 +658,10 @@ static string WideToUTF8(const wstring& wide, bool *success)
|
|||
|
||||
bool UIInit()
|
||||
{
|
||||
for (int i = 0; i < sizeof(kDefaultAttachedBottom) / sizeof(UINT); i++) {
|
||||
gAttachedBottom.insert(kDefaultAttachedBottom[i]);
|
||||
}
|
||||
|
||||
DoInitCommonControls();
|
||||
return true;
|
||||
}
|
||||
|
@ -339,34 +672,36 @@ void UIShutdown()
|
|||
|
||||
void UIShowDefaultUI()
|
||||
{
|
||||
bool enabled;
|
||||
// no dump file specified, just ask about enabling
|
||||
if (!CheckCrashReporterEnabled(&enabled))
|
||||
enabled = true;
|
||||
|
||||
enabled = (1 == DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_ENABLEDIALOG), NULL, (DLGPROC)EnableDialogProc, (LPARAM)enabled));
|
||||
SetCrashReporterEnabled(enabled);
|
||||
MessageBox(NULL, Str(ST_CRASHREPORTERDEFAULT).c_str(),
|
||||
L"Crash Reporter",
|
||||
MB_OK | MB_ICONSTOP);
|
||||
}
|
||||
|
||||
void UIShowCrashUI(const string& dumpfile,
|
||||
const StringTable& query_parameters,
|
||||
const string& send_url)
|
||||
void UIShowCrashUI(const string& dumpFile,
|
||||
const StringTable& queryParameters,
|
||||
const string& sendURL,
|
||||
const vector<string>& restartArgs)
|
||||
{
|
||||
bool enabled;
|
||||
if (!CheckCrashReporterEnabled(&enabled)) {
|
||||
//ask user if crash reporter should be enabled
|
||||
enabled = (1 == DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_ENABLEDIALOG), NULL, (DLGPROC)EnableDialogProc, (LPARAM)true));
|
||||
SetCrashReporterEnabled(enabled);
|
||||
gSendData.hDlg = NULL;
|
||||
gSendData.dumpFile = UTF8ToWide(dumpFile);
|
||||
gSendData.sendURL = UTF8ToWide(sendURL);
|
||||
|
||||
for (StringTable::const_iterator i = queryParameters.begin();
|
||||
i != queryParameters.end();
|
||||
i++) {
|
||||
gQueryParameters[UTF8ToWide(i->first)] = UTF8ToWide(i->second);
|
||||
}
|
||||
// if enabled, send crash report
|
||||
if (enabled) {
|
||||
wstring server_response;
|
||||
bool success = SendCrashReport(UTF8ToWide(dumpfile),
|
||||
&query_parameters,
|
||||
UTF8ToWide(send_url),
|
||||
&server_response);
|
||||
CrashReporterSendCompleted(success, WideToUTF8(server_response));
|
||||
|
||||
if (gQueryParameters.find(L"Vendor") != gQueryParameters.end()) {
|
||||
gCrashReporterKey = L"Software\\" +
|
||||
gQueryParameters[L"Vendor"] +
|
||||
L"\\Crash Reporter";
|
||||
}
|
||||
|
||||
gRestartArgs = restartArgs;
|
||||
|
||||
DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_SENDDIALOG), NULL,
|
||||
(DLGPROC)CrashReporterDialogProc, 0);
|
||||
}
|
||||
|
||||
void UIError(const string& message)
|
||||
|
@ -430,6 +765,9 @@ bool UIEnsurePathExists(const string& path)
|
|||
|
||||
bool UIMoveFile(const string& oldfile, const string& newfile)
|
||||
{
|
||||
if (oldfile == newfile)
|
||||
return true;
|
||||
|
||||
return MoveFile(UTF8ToWide(oldfile).c_str(), UTF8ToWide(newfile).c_str())
|
||||
== TRUE;
|
||||
}
|
||||
|
|
|
@ -1,22 +1,31 @@
|
|||
{
|
||||
IBClasses = (
|
||||
{
|
||||
ACTIONS = {closeClicked = id; sendClicked = id; };
|
||||
ACTIONS = {
|
||||
closeAndSendClicked = id;
|
||||
closeClicked = id;
|
||||
emailMeClicked = id;
|
||||
restartClicked = id;
|
||||
viewReportClicked = id;
|
||||
};
|
||||
CLASS = CrashReporterUI;
|
||||
LANGUAGE = ObjC;
|
||||
OUTLETS = {
|
||||
closeButton = NSButton;
|
||||
descriptionLabel = NSTextField;
|
||||
disableReportingButton = NSButton;
|
||||
dontSendButton = NSButton;
|
||||
enableView = NSView;
|
||||
emailMeButton = NSButton;
|
||||
emailText = NSTextField;
|
||||
errorCloseButton = NSButton;
|
||||
errorHeaderLabel = NSTextField;
|
||||
errorLabel = NSTextField;
|
||||
errorView = NSView;
|
||||
progressBar = NSProgressIndicator;
|
||||
progressLabel = NSTextField;
|
||||
sendButton = NSButton;
|
||||
uploadingView = NSView;
|
||||
headerLabel = NSTextField;
|
||||
restartButton = NSButton;
|
||||
submitReportButton = NSButton;
|
||||
viewReportButton = NSButton;
|
||||
viewReportLabel = NSTextField;
|
||||
viewReportScrollView = NSScrollView;
|
||||
viewReportTextView = NSTextView;
|
||||
window = NSWindow;
|
||||
};
|
||||
SUPERCLASS = NSObject;
|
||||
|
|
|
@ -3,17 +3,17 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBDocumentLocation</key>
|
||||
<string>299 87 356 240 0 0 1440 878 </string>
|
||||
<string>128 190 504 836 0 0 1920 1178 </string>
|
||||
<key>IBEditorPositions</key>
|
||||
<dict>
|
||||
<key>282</key>
|
||||
<string>24 681 550 163 0 0 1440 878 </string>
|
||||
<string>685 720 550 163 0 0 1920 1178 </string>
|
||||
<key>29</key>
|
||||
<string>447 315 137 44 0 0 1440 878 </string>
|
||||
<key>356</key>
|
||||
<string>643 213 551 213 0 0 1440 878 </string>
|
||||
<string>684 695 551 213 0 0 1920 1178 </string>
|
||||
<key>386</key>
|
||||
<string>23 537 456 145 0 0 1440 878 </string>
|
||||
<string>492 520 456 164 0 0 1440 878 </string>
|
||||
</dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>446.1</string>
|
||||
|
@ -26,9 +26,8 @@
|
|||
<integer>2</integer>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>386</integer>
|
||||
<integer>282</integer>
|
||||
<integer>29</integer>
|
||||
<integer>386</integer>
|
||||
<integer>21</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
|
|
Двоичные данные
toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib
сгенерированный
Двоичные данные
toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib
сгенерированный
Двоичный файл не отображается.
|
@ -1,13 +1,22 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by CrashReporter.rc
|
||||
// Used by crashreporter.rc
|
||||
//
|
||||
#define IDD_ENABLEDIALOG 101
|
||||
#define IDD_SENDDIALOG 102
|
||||
#define IDC_RADIOENABLE 1001
|
||||
#define IDC_RADIODISABLE 1002
|
||||
#define IDC_PROGRESS 1003
|
||||
#define IDC_DESCRIPTIONTEXT 1004
|
||||
#define IDC_CLOSEBUTTON 1005
|
||||
#define IDC_VIEWREPORTBUTTON 1006
|
||||
#define IDC_SUBMITCRASHCHECK 1007
|
||||
#define IDC_SUBMITREPORTCHECK 1007
|
||||
#define IDC_EMAILMECHECK 1008
|
||||
#define IDC_EMAILTEXT 1009
|
||||
#define IDC_HEADERLABEL 1010
|
||||
#define IDC_RESTARTBUTTON 1012
|
||||
#define IDC_DESCRIPTIONLABEL 1013
|
||||
#define IDC_VIEWREPORTTEXT 1015
|
||||
#define IDC_VIEWREPORTCHECK 1016
|
||||
#define IDC_PROGRESSLABEL -1
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
|
@ -15,7 +24,7 @@
|
|||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 103
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1005
|
||||
#define _APS_NEXT_CONTROL_VALUE 1017
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -414,4 +414,26 @@ nsresult AnnotateCrashReport(const nsACString &key, const nsACString &data)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SetRestartArgs(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
nsCAutoString envVar;
|
||||
for (i = 0; i < argc; i++) {
|
||||
envVar = "MOZ_CRASHREPORTER_RESTART_ARG_";
|
||||
envVar.AppendInt(i);
|
||||
envVar += "=";
|
||||
envVar += argv[i];
|
||||
PR_SetEnv(envVar.get());
|
||||
}
|
||||
|
||||
// make sure the arg list is terminated
|
||||
envVar = "MOZ_CRASHREPORTER_RESTART_ARG_";
|
||||
envVar.AppendInt(i);
|
||||
envVar += "=";
|
||||
|
||||
PR_SetEnv(envVar.get());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
} // namespace CrashReporter
|
||||
|
|
|
@ -48,6 +48,7 @@ nsresult SetExceptionHandler(nsILocalFile* aXREDirectory,
|
|||
nsresult SetMinidumpPath(const nsAString& aPath);
|
||||
nsresult UnsetExceptionHandler();
|
||||
nsresult AnnotateCrashReport(const nsACString &key, const nsACString &data);
|
||||
nsresult SetRestartArgs(int argc, char **argv);
|
||||
}
|
||||
|
||||
#endif /* nsAirbagExceptionHandler_h__ */
|
||||
|
|
Загрузка…
Ссылка в новой задаче