X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ce4fd7b577cdeb1ceb085cb1380c0df97b6ceef4..cd794127ff73748f8199587897f57aa02c5ef059:/samples/debugrpt/debugrpt.cpp?ds=inline diff --git a/samples/debugrpt/debugrpt.cpp b/samples/debugrpt/debugrpt.cpp index 1cec0dfa13..7a1f9c83a3 100644 --- a/samples/debugrpt/debugrpt.cpp +++ b/samples/debugrpt/debugrpt.cpp @@ -6,7 +6,7 @@ // Created: 2005-01-20 // RCS-ID: $Id$ // Copyright: (c) 2005 Vadim Zeitlin -// License: wxWindows licence +// Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// // ---------------------------------------------------------------------------- @@ -14,65 +14,108 @@ // ---------------------------------------------------------------------------- #include "wx/app.h" +#include "wx/log.h" +#include "wx/frame.h" +#include "wx/icon.h" +#include "wx/menu.h" +#include "wx/msgdlg.h" +#include "wx/button.h" +#include "wx/dcclient.h" + #include "wx/datetime.h" #include "wx/ffile.h" #include "wx/filename.h" -#include "wx/dynlib.h" #include "wx/debugrpt.h" -#include "wx/msgdlg.h" - #if !wxUSE_DEBUGREPORT #error "This sample can't be built without wxUSE_DEBUGREPORT" #endif // wxUSE_DEBUGREPORT +#if !wxUSE_ON_FATAL_EXCEPTION + #error "This sample can't be built without wxUSE_ON_FATAL_EXCEPTION" +#endif // wxUSE_ON_FATAL_EXCEPTION + +#ifndef wxHAS_IMAGES_IN_RESOURCES + #include "../sample.xpm" +#endif + // ---------------------------------------------------------------------------- // custom debug reporting class // ---------------------------------------------------------------------------- -// this is your custom debug reporter, you will probably want to parse the XML -// document in OnServerReply() instead of just dumping it as I do +// this is your custom debug reporter: it will use curl program (which should +// be available) to upload the crash report to the given URL (which should be +// set up by you) class MyDebugReport : public wxDebugReportUpload { public: MyDebugReport() : wxDebugReportUpload ( - _T("http://iml2.hitchcock.org/intranet/crashes/wxtest"), - _T("report:file"), - _T("action") + wxT("http://your.url.here/"), + wxT("report:file"), + wxT("action") ) { } protected: + // this is called with the contents of the server response: you will + // probably want to parse the XML document in OnServerReply() instead of + // just dumping it as I do virtual bool OnServerReply(const wxArrayString& reply) { if ( reply.IsEmpty() ) { - wxLogError(_T("Didn't receive the expected server reply.")); + wxLogError(wxT("Didn't receive the expected server reply.")); return false; } - wxString s(_T("Server replied:\n")); + wxString s(wxT("Server replied:\n")); const size_t count = reply.GetCount(); for ( size_t n = 0; n < count; n++ ) { - s << _T('\t') << reply[n] << _T('\n'); + s << wxT('\t') << reply[n] << wxT('\n'); } - wxLogMessage(_T("%s"), s.c_str()); + wxLogMessage(wxT("%s"), s.c_str()); return true; } }; +// another possibility would be to build email library from contrib and use +// this class, after uncommenting it: +#if 0 + +#include "wx/net/email.h" + +class MyDebugReport : public wxDebugReportCompress +{ +public: + virtual bool DoProcess() + { + if ( !wxDebugReportCompress::DoProcess() ) + return false; + wxMailMessage msg(GetReportName() + wxT(" crash report"), + wxT("vadim@wxwindows.org"), + wxEmptyString, // mail body + wxEmptyString, // from address + GetCompressedFileName(), + wxT("crashreport.zip")); + + return wxEmail::Send(msg); + } +}; + +#endif // 0 + // ---------------------------------------------------------------------------- // helper functions // ---------------------------------------------------------------------------- // just some functions to get a slightly deeper stack trace -static void bar(const wxChar *p) +static void bar(const char *p) { char *pc = 0; *pc = *p; @@ -82,17 +125,54 @@ static void bar(const wxChar *p) void baz(const wxString& s) { - printf("baz: %s\n", s.c_str()); + printf("baz: %s\n", (const char*)s.c_str()); } void foo(int n) { if ( n % 2 ) - baz(wxT("odd")); + baz("odd"); else - bar(wxT("even")); + bar("even"); } +// ---------------------------------------------------------------------------- +// main window +// ---------------------------------------------------------------------------- + +enum +{ + DebugRpt_Quit = wxID_EXIT, + DebugRpt_Crash = 100, + DebugRpt_Current, + DebugRpt_Paint, + DebugRpt_Upload, + DebugRpt_About = wxID_ABOUT +}; + +class MyFrame : public wxFrame +{ +public: + MyFrame(); + +private: + void OnQuit(wxCommandEvent& event); + void OnReportForCrash(wxCommandEvent& event); + void OnReportForCurrent(wxCommandEvent& event); + void OnReportPaint(wxCommandEvent& event); + void OnReportUpload(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + + void OnPaint(wxPaintEvent& event); + + + // number of lines drawn in OnPaint() + int m_numLines; + + wxDECLARE_NO_COPY_CLASS(MyFrame); + DECLARE_EVENT_TABLE() +}; + // ---------------------------------------------------------------------------- // application class // ---------------------------------------------------------------------------- @@ -104,84 +184,216 @@ void foo(int n) class MyApp : public wxApp { public: - virtual bool OnInit() - { - wxHandleFatalExceptions(); + // call wxHandleFatalExceptions here + MyApp(); - if ( !wxApp::OnInit() ) - return false; + // create our main window here + virtual bool OnInit(); - return true; - } + // called when a crash occurs in this application + virtual void OnFatalException(); - virtual int OnRun() - { - // a real program would be presumably be a bit harder to crash than - // just pressing "yes" in a dialog... but this is just an example - switch ( wxMessageBox - ( - _T("Generate report for crash (or just current context)?"), - _T("wxDebugReport Test"), - wxYES_NO | wxCANCEL - ) ) - { - case wxYES: - // this call is going to crash - foo(32); - foo(17); - break; - - case wxNO: - // example of manually generated report, this could be also - // used in wxApp::OnAssert() - GenerateReport(wxDebugReport::Context_Curent); - break; - - case wxCANCEL: - break; - } + // this is where we really generate the debug report + void GenerateReport(wxDebugReport::Context ctx); - return 0; - } + // if this function is called, we'll use MyDebugReport which would try to + // upload the (next) generated debug report to its URL, otherwise we just + // generate the debug report and leave it in a local file + void UploadReport(bool doIt) { m_uploadReport = doIt; } + +private: + bool m_uploadReport; + + wxDECLARE_NO_COPY_CLASS(MyApp); +}; + +IMPLEMENT_APP(MyApp) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// MyFrame +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(DebugRpt_Quit, MyFrame::OnQuit) + EVT_MENU(DebugRpt_Crash, MyFrame::OnReportForCrash) + EVT_MENU(DebugRpt_Current, MyFrame::OnReportForCurrent) + EVT_MENU(DebugRpt_Paint, MyFrame::OnReportPaint) + EVT_MENU(DebugRpt_Upload, MyFrame::OnReportUpload) + EVT_MENU(DebugRpt_About, MyFrame::OnAbout) + + EVT_PAINT(MyFrame::OnPaint) +END_EVENT_TABLE() + +MyFrame::MyFrame() + : wxFrame(NULL, wxID_ANY, wxT("wxWidgets Debug Report Sample"), + wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE|wxDEFAULT_FRAME_STYLE) +{ + m_numLines = 10; + + SetIcon(wxICON(sample)); + + wxMenu *menuFile = new wxMenu; + menuFile->Append(DebugRpt_Quit, wxT("E&xit\tAlt-X")); - virtual void OnFatalException() + wxMenu *menuReport = new wxMenu; + menuReport->Append(DebugRpt_Crash, wxT("Report for &crash\tCtrl-C"), + wxT("Provoke a crash inside the program and create report for it")); + menuReport->Append(DebugRpt_Current, wxT("Report for c&urrent context\tCtrl-U"), + wxT("Create report for the current program context")); + menuReport->Append(DebugRpt_Paint, wxT("Report for &paint handler\tCtrl-P"), + wxT("Provoke a repeatable crash in wxEVT_PAINT handler")); + menuReport->AppendSeparator(); + menuReport->AppendCheckItem(DebugRpt_Upload, wxT("Up&load debug report"), + wxT("You need to configure a web server accepting debug report uploads to use this function")); + + wxMenu *menuHelp = new wxMenu; + menuHelp->Append(DebugRpt_About, wxT("&About\tF1")); + + wxMenuBar *mbar = new wxMenuBar(); + mbar->Append(menuFile, wxT("&File")); + mbar->Append(menuReport, wxT("&Report")); + mbar->Append(menuHelp, wxT("&Help")); + SetMenuBar(mbar); + + CreateStatusBar(); + + Show(); +} + +void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) +{ + Close(true); +} + +void MyFrame::OnReportForCrash(wxCommandEvent& WXUNUSED(event)) +{ + // this call is going to crash + foo(32); + foo(17); +} + +void MyFrame::OnReportForCurrent(wxCommandEvent& WXUNUSED(event)) +{ + // example of manually generated report, this could be also + // used in wxApp::OnAssert() + wxGetApp().GenerateReport(wxDebugReport::Context_Current); +} + +void MyFrame::OnReportPaint(wxCommandEvent& WXUNUSED(event)) +{ + // this will result in a crash in OnPaint() + m_numLines = 0; + + // ensure it's called immediately + Refresh(); +} + +void MyFrame::OnReportUpload(wxCommandEvent& event) +{ + wxGetApp().UploadReport(event.IsChecked()); +} + +void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) +{ + wxMessageBox + ( + wxT("wxDebugReport sample\n(c) 2005 Vadim Zeitlin "), + wxT("wxWidgets Debug Report Sample"), + wxOK | wxICON_INFORMATION, + this + ); +} + +void MyFrame::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + wxPaintDC dc(this); + const wxSize size = GetClientSize(); + for ( wxCoord x = 0; x < size.x; x += size.x/m_numLines ) + dc.DrawLine(x, 0, x, size.y); +} + +// ---------------------------------------------------------------------------- +// MyApp +// ---------------------------------------------------------------------------- + +MyApp::MyApp() +{ + // user needs to explicitly enable this + m_uploadReport = false; + + // call this to tell the library to call our OnFatalException() + wxHandleFatalExceptions(); +} + +bool MyApp::OnInit() +{ + if ( !wxApp::OnInit() ) + return false; + + new MyFrame; + + return true; +} + +void MyApp::OnFatalException() +{ + GenerateReport(wxDebugReport::Context_Exception); +} + +void MyApp::GenerateReport(wxDebugReport::Context ctx) +{ + wxDebugReportCompress *report = m_uploadReport ? new MyDebugReport + : new wxDebugReportCompress; + + // add all standard files: currently this means just a minidump and an + // XML file with system info and stack trace + report->AddAll(ctx); + + // you can also call report->AddFile(...) with your own log files, files + // created using wxRegKey::Export() and so on, here we just add a test + // file containing the date of the crash + wxFileName fn(report->GetDirectory(), wxT("timestamp.my")); + wxFFile file(fn.GetFullPath(), wxT("w")); + if ( file.IsOpened() ) { - GenerateReport(wxDebugReport::Context_Exception); + wxDateTime dt = wxDateTime::Now(); + file.Write(dt.FormatISODate() + wxT(' ') + dt.FormatISOTime()); + file.Close(); } - void GenerateReport(wxDebugReport::Context ctx) - { - MyDebugReport report; - - // add all standard files: currently this means just a minidump and an - // XML file with system info and stack trace - report.AddAll(ctx); - - // you can also call report.AddFile(...) with your own log files, files - // created using wxRegKey::Export() and so on, here we just add a test - // file containing the date of the crash - wxFileName fn(report.GetDirectory(), _T("timestamp.my")); - wxFFile file(fn.GetFullPath(), _T("w")); - if ( file.IsOpened() ) - { - wxDateTime dt = wxDateTime::Now(); - file.Write(dt.FormatISODate() + _T(' ') + dt.FormatISOTime()); - file.Close(); - } + report->AddFile(fn.GetFullName(), wxT("timestamp of this report")); - report.AddFile(fn.GetFullName(), _T("timestamp of this report")); + // can also add an existing file directly, it will be copied + // automatically +#ifdef __WXMSW__ + report->AddFile(wxT("c:\\autoexec.bat"), wxT("DOS startup file")); +#else + report->AddFile(wxT("/etc/motd"), wxT("Message of the day")); +#endif - // calling Show() is not mandatory, but is more polite - if ( wxDebugReportPreviewStd().Show(report) ) + // calling Show() is not mandatory, but is more polite + if ( wxDebugReportPreviewStd().Show(*report) ) + { + if ( report->Process() ) { - if ( report.Process() ) + if ( m_uploadReport ) + { + wxLogMessage(wxT("Report successfully uploaded.")); + } + else { - // report successfully uploaded + wxLogMessage(wxT("Report generated in \"%s\"."), + report->GetCompressedFileName().c_str()); + report->Reset(); } } - //else: user cancelled the report } -}; + //else: user cancelled the report -IMPLEMENT_APP(MyApp) + delete report; +}