1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: minimal sample showing wxDebugReport and related classes
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2005 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // License: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ----------------------------------------------------------------------------
14 // ----------------------------------------------------------------------------
19 #include "wx/msgdlg.h"
20 #include "wx/button.h"
21 #include "wx/dcclient.h"
23 #include "wx/datetime.h"
25 #include "wx/filename.h"
26 #include "wx/debugrpt.h"
28 #if !wxUSE_DEBUGREPORT
29 #error "This sample can't be built without wxUSE_DEBUGREPORT"
30 #endif // wxUSE_DEBUGREPORT
32 #if !wxUSE_ON_FATAL_EXCEPTION
33 #error "This sample can't be built without wxUSE_ON_FATAL_EXCEPTION"
34 #endif // wxUSE_ON_FATAL_EXCEPTION
36 #if !defined(__WXMSW__) && !defined(__WXPM__)
37 #include "../sample.xpm"
40 // ----------------------------------------------------------------------------
41 // custom debug reporting class
42 // ----------------------------------------------------------------------------
44 // this is your custom debug reporter: it will use curl program (which should
45 // be available) to upload the crash report to the given URL (which should be
47 class MyDebugReport
: public wxDebugReportUpload
50 MyDebugReport() : wxDebugReportUpload
52 _T("http://your.url.here/"),
60 // this is called with the contents of the server response: you will
61 // probably want to parse the XML document in OnServerReply() instead of
62 // just dumping it as I do
63 virtual bool OnServerReply(const wxArrayString
& reply
)
65 if ( reply
.IsEmpty() )
67 wxLogError(_T("Didn't receive the expected server reply."));
71 wxString
s(_T("Server replied:\n"));
73 const size_t count
= reply
.GetCount();
74 for ( size_t n
= 0; n
< count
; n
++ )
76 s
<< _T('\t') << reply
[n
] << _T('\n');
79 wxLogMessage(_T("%s"), s
.c_str());
85 // another possibility would be to build email library from contrib and use
86 // this class, after uncommenting it:
89 #include "wx/net/email.h"
91 class MyDebugReport
: public wxDebugReportCompress
94 virtual bool DoProcess()
96 if ( !wxDebugReportCompress
::DoProcess() )
98 wxMailMessage
msg(GetReportName() + _T(" crash report"),
99 _T("vadim@wxwindows.org"),
100 wxEmptyString
, // mail body
101 wxEmptyString
, // from address
102 GetCompressedFileName(),
103 _T("crashreport.zip"));
105 return wxEmail
::Send(msg
);
111 // ----------------------------------------------------------------------------
113 // ----------------------------------------------------------------------------
115 // just some functions to get a slightly deeper stack trace
116 static void bar(const wxChar
*p
)
121 printf("bar: %s\n", p
);
124 void baz(const wxString
& s
)
126 printf("baz: %s\n", s
.c_str());
137 // ----------------------------------------------------------------------------
139 // ----------------------------------------------------------------------------
143 DebugRpt_Quit
= wxID_EXIT
,
144 DebugRpt_Crash
= 100,
148 DebugRpt_About
= wxID_ABOUT
151 class MyFrame
: public wxFrame
157 void OnQuit(wxCommandEvent
& event
);
158 void OnReportForCrash(wxCommandEvent
& event
);
159 void OnReportForCurrent(wxCommandEvent
& event
);
160 void OnReportPaint(wxCommandEvent
& event
);
161 void OnReportUpload(wxCommandEvent
& event
);
162 void OnAbout(wxCommandEvent
& event
);
164 void OnPaint(wxPaintEvent
& event
);
167 // number of lines drawn in OnPaint()
170 DECLARE_NO_COPY_CLASS(MyFrame
)
171 DECLARE_EVENT_TABLE()
174 // ----------------------------------------------------------------------------
176 // ----------------------------------------------------------------------------
178 // this is a usual application class modified to work with debug reporter
180 // basically just 2 things are necessary: call wxHandleFatalExceptions() as
181 // early as possible and override OnFatalException() to create the report there
182 class MyApp
: public wxApp
185 // call wxHandleFatalExceptions here
188 // create our main window here
189 virtual bool OnInit();
191 // called when a crash occurs in this application
192 virtual void OnFatalException();
194 // this is where we really generate the debug report
195 void GenerateReport(wxDebugReport
::Context ctx
);
197 // if this function is called, we'll use MyDebugReport which would try to
198 // upload the (next) generated debug report to its URL, otherwise we just
199 // generate the debug report and leave it in a local file
200 void UploadReport(bool doIt
) { m_uploadReport
= doIt
; }
205 DECLARE_NO_COPY_CLASS(MyApp
)
210 // ============================================================================
212 // ============================================================================
214 // ----------------------------------------------------------------------------
216 // ----------------------------------------------------------------------------
218 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
219 EVT_MENU(DebugRpt_Quit
, MyFrame
::OnQuit
)
220 EVT_MENU(DebugRpt_Crash
, MyFrame
::OnReportForCrash
)
221 EVT_MENU(DebugRpt_Current
, MyFrame
::OnReportForCurrent
)
222 EVT_MENU(DebugRpt_Paint
, MyFrame
::OnReportPaint
)
223 EVT_MENU(DebugRpt_Upload
, MyFrame
::OnReportUpload
)
224 EVT_MENU(DebugRpt_About
, MyFrame
::OnAbout
)
226 EVT_PAINT(MyFrame
::OnPaint
)
230 : wxFrame(NULL
, wxID_ANY
, _T("wxWidgets Debug Report Sample"))
234 SetIcon(wxICON(sample
));
236 wxMenu
*menuFile
= new wxMenu
;
237 menuFile
->Append(DebugRpt_Quit
, _T("E&xit\tAlt-X"));
239 wxMenu
*menuReport
= new wxMenu
;
240 menuReport
->Append(DebugRpt_Crash
, _T("Report for &crash\tCtrl-C"),
241 _T("Provoke a crash inside the program and create report for it"));
242 menuReport
->Append(DebugRpt_Current
, _T("Report for c&urrent context\tCtrl-U"),
243 _T("Create report for the current program context"));
244 menuReport
->Append(DebugRpt_Paint
, _T("Report for &paint handler\tCtrl-P"),
245 _T("Provoke a repeatable crash in wxEVT_PAINT handler"));
246 menuReport
->AppendSeparator();
247 menuReport
->AppendCheckItem(DebugRpt_Upload
, _T("Up&load debug report"),
248 _T("You need to configure a web server accepting debug report uploads to use this function"));
250 wxMenu
*menuHelp
= new wxMenu
;
251 menuHelp
->Append(DebugRpt_About
, _T("&About...\tF1"));
253 wxMenuBar
*mbar
= new wxMenuBar();
254 mbar
->Append(menuFile
, _T("&File"));
255 mbar
->Append(menuReport
, _T("&Report"));
256 mbar
->Append(menuHelp
, _T("&Help"));
264 void MyFrame
::OnQuit(wxCommandEvent
& WXUNUSED(event
))
269 void MyFrame
::OnReportForCrash(wxCommandEvent
& WXUNUSED(event
))
271 // this call is going to crash
276 void MyFrame
::OnReportForCurrent(wxCommandEvent
& WXUNUSED(event
))
278 // example of manually generated report, this could be also
279 // used in wxApp::OnAssert()
280 wxGetApp().GenerateReport(wxDebugReport
::Context_Current
);
283 void MyFrame
::OnReportPaint(wxCommandEvent
& WXUNUSED(event
))
285 // this will result in a crash in OnPaint()
288 // ensure it's called immediately
292 void MyFrame
::OnReportUpload(wxCommandEvent
& event
)
294 wxGetApp().UploadReport(event
.IsChecked());
297 void MyFrame
::OnAbout(wxCommandEvent
& WXUNUSED(event
))
301 _T("wxDebugReport sample\n(c) 2005 Vadim Zeitlin <vadim@wxwindows.org>"),
302 _T("wxWidgets Debug Report Sample"),
303 wxOK
| wxICON_INFORMATION
,
308 void MyFrame
::OnPaint(wxPaintEvent
& WXUNUSED(event
))
311 const wxSize size
= GetClientSize();
312 for ( wxCoord x
= 0; x
< size
.x
; x
+= size
.x
/m_numLines
)
313 dc
.DrawLine(x
, 0, x
, size
.y
);
316 // ----------------------------------------------------------------------------
318 // ----------------------------------------------------------------------------
322 // user needs to explicitely enable this
323 m_uploadReport
= false;
325 // call this to tell the library to call our OnFatalException()
326 wxHandleFatalExceptions();
331 if ( !wxApp
::OnInit() )
339 void MyApp
::OnFatalException()
341 GenerateReport(wxDebugReport
::Context_Exception
);
344 void MyApp
::GenerateReport(wxDebugReport
::Context ctx
)
346 wxDebugReportCompress
*report
= m_uploadReport ?
new MyDebugReport
347 : new wxDebugReportCompress
;
349 // add all standard files: currently this means just a minidump and an
350 // XML file with system info and stack trace
353 // you can also call report->AddFile(...) with your own log files, files
354 // created using wxRegKey::Export() and so on, here we just add a test
355 // file containing the date of the crash
356 wxFileName
fn(report
->GetDirectory(), _T("timestamp.my"));
357 wxFFile
file(fn
.GetFullPath(), _T("w"));
358 if ( file
.IsOpened() )
360 wxDateTime dt
= wxDateTime
::Now();
361 file
.Write(dt
.FormatISODate() + _T(' ') + dt
.FormatISOTime());
365 report
->AddFile(fn
.GetFullName(), _T("timestamp of this report"));
367 // can also add an existing file directly, it will be copied
370 report
->AddFile(_T("c:\\autoexec.bat"), _T("DOS startup file"));
372 report
->AddFile(_T("/etc/motd"), _T("Message of the day"));
375 // calling Show() is not mandatory, but is more polite
376 if ( wxDebugReportPreviewStd().Show(*report
) )
378 if ( report
->Process() )
380 if ( m_uploadReport
)
382 wxLogMessage(_T("Report successfully uploaded."));
386 wxLogMessage(_T("Report generated in \"%s\"."),
387 report
->GetCompressedFileName().c_str());
392 //else: user cancelled the report