]> git.saurik.com Git - wxWidgets.git/blob - samples/debugrpt/debugrpt.cpp
rewrote sample to have a more conventional structure (in preparation for further...
[wxWidgets.git] / samples / debugrpt / debugrpt.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: debugrpt.cpp
3 // Purpose: minimal sample showing wxDebugReport and related classes
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 2005-01-20
7 // RCS-ID: $Id$
8 // Copyright: (c) 2005 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // License: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ----------------------------------------------------------------------------
13 // headers
14 // ----------------------------------------------------------------------------
15
16 #include "wx/app.h"
17 #include "wx/frame.h"
18 #include "wx/menu.h"
19 #include "wx/msgdlg.h"
20 #include "wx/button.h"
21
22 #include "wx/datetime.h"
23 #include "wx/ffile.h"
24 #include "wx/filename.h"
25 #include "wx/debugrpt.h"
26
27 #if !wxUSE_DEBUGREPORT
28 #error "This sample can't be built without wxUSE_DEBUGREPORT"
29 #endif // wxUSE_DEBUGREPORT
30
31 #if !wxUSE_ON_FATAL_EXCEPTION
32 #error "This sample can't be built without wxUSE_ON_FATAL_EXCEPTION"
33 #endif // wxUSE_ON_FATAL_EXCEPTION
34
35 #if !defined(__WXMSW__) && !defined(__WXPM__)
36 #include "../sample.xpm"
37 #endif
38
39 // ----------------------------------------------------------------------------
40 // custom debug reporting class
41 // ----------------------------------------------------------------------------
42
43 // this is your custom debug reporter: it will use curl program (which should
44 // be available) to upload the crash report to the given URL (which should be
45 // set up by you)
46 class MyDebugReport : public wxDebugReportUpload
47 {
48 public:
49 MyDebugReport() : wxDebugReportUpload
50 (
51 _T("http://your.url.here/"),
52 _T("report:file"),
53 _T("action")
54 )
55 {
56 }
57
58 protected:
59 // this is called with the contents of the server response: you will
60 // probably want to parse the XML document in OnServerReply() instead of
61 // just dumping it as I do
62 virtual bool OnServerReply(const wxArrayString& reply)
63 {
64 if ( reply.IsEmpty() )
65 {
66 wxLogError(_T("Didn't receive the expected server reply."));
67 return false;
68 }
69
70 wxString s(_T("Server replied:\n"));
71
72 const size_t count = reply.GetCount();
73 for ( size_t n = 0; n < count; n++ )
74 {
75 s << _T('\t') << reply[n] << _T('\n');
76 }
77
78 wxLogMessage(_T("%s"), s.c_str());
79
80 return true;
81 }
82 };
83
84 // another possibility would be to build email library from contrib and use
85 // this class, after uncommenting it:
86 #if 0
87
88 #include "wx/net/email.h"
89
90 class MyDebugReport : public wxDebugReportCompress
91 {
92 public:
93 virtual bool DoProcess()
94 {
95 if ( !wxDebugReportCompress::DoProcess() )
96 return false;
97 wxMailMessage msg(GetReportName() + _T(" crash report"),
98 _T("vadim@wxwindows.org"),
99 wxEmptyString, // mail body
100 wxEmptyString, // from address
101 GetCompressedFileName(),
102 _T("crashreport.zip"));
103
104 return wxEmail::Send(msg);
105 }
106 };
107
108 #endif // 0
109
110 // ----------------------------------------------------------------------------
111 // helper functions
112 // ----------------------------------------------------------------------------
113
114 // just some functions to get a slightly deeper stack trace
115 static void bar(const wxChar *p)
116 {
117 char *pc = 0;
118 *pc = *p;
119
120 printf("bar: %s\n", p);
121 }
122
123 void baz(const wxString& s)
124 {
125 printf("baz: %s\n", s.c_str());
126 }
127
128 void foo(int n)
129 {
130 if ( n % 2 )
131 baz(wxT("odd"));
132 else
133 bar(wxT("even"));
134 }
135
136 // ----------------------------------------------------------------------------
137 // main window
138 // ----------------------------------------------------------------------------
139
140 enum
141 {
142 DebugRpt_Quit = wxID_EXIT,
143 DebugRpt_Crash = 100,
144 DebugRpt_Current,
145 DebugRpt_Upload,
146 DebugRpt_About = wxID_ABOUT
147 };
148
149 class MyFrame : public wxFrame
150 {
151 public:
152 MyFrame();
153
154 private:
155 void OnQuit(wxCommandEvent& event);
156 void OnReportForCrash(wxCommandEvent& event);
157 void OnReportForCurrent(wxCommandEvent& event);
158 void OnReportUpload(wxCommandEvent& event);
159 void OnAbout(wxCommandEvent& event);
160
161 DECLARE_NO_COPY_CLASS(MyFrame)
162 DECLARE_EVENT_TABLE()
163 };
164
165 // ----------------------------------------------------------------------------
166 // application class
167 // ----------------------------------------------------------------------------
168
169 // this is a usual application class modified to work with debug reporter
170 //
171 // basically just 2 things are necessary: call wxHandleFatalExceptions() as
172 // early as possible and override OnFatalException() to create the report there
173 class MyApp : public wxApp
174 {
175 public:
176 // call wxHandleFatalExceptions here
177 MyApp();
178
179 // create our main window here
180 virtual bool OnInit();
181
182 // called when a crash occurs in this application
183 virtual void OnFatalException();
184
185 // this is where we really generate the debug report
186 void GenerateReport(wxDebugReport::Context ctx);
187
188 // if this function is called, we'll use MyDebugReport which would try to
189 // upload the (next) generated debug report to its URL, otherwise we just
190 // generate the debug report and leave it in a local file
191 void UploadReport(bool doIt) { m_uploadReport = doIt; }
192
193 private:
194 bool m_uploadReport;
195
196 DECLARE_NO_COPY_CLASS(MyApp)
197 };
198
199 IMPLEMENT_APP(MyApp)
200
201 // ============================================================================
202 // implementation
203 // ============================================================================
204
205 // ----------------------------------------------------------------------------
206 // MyFrame
207 // ----------------------------------------------------------------------------
208
209 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
210 EVT_MENU(DebugRpt_Quit, MyFrame::OnQuit)
211 EVT_MENU(DebugRpt_Crash, MyFrame::OnReportForCrash)
212 EVT_MENU(DebugRpt_Current, MyFrame::OnReportForCurrent)
213 EVT_MENU(DebugRpt_Upload, MyFrame::OnReportUpload)
214 EVT_MENU(DebugRpt_About, MyFrame::OnAbout)
215 END_EVENT_TABLE()
216
217 MyFrame::MyFrame()
218 : wxFrame(NULL, wxID_ANY, _T("wxWidgets Debug Report Sample"))
219 {
220 SetIcon(wxICON(sample));
221
222 wxMenu *menuFile = new wxMenu;
223 menuFile->Append(DebugRpt_Quit, _T("E&xit\tAlt-X"));
224
225 wxMenu *menuReport = new wxMenu;
226 menuReport->Append(DebugRpt_Crash, _T("Report for &crash\tCtrl-C"),
227 _T("Provoke a crash inside the program and create report for it"));
228 menuReport->Append(DebugRpt_Current, _T("Report for c&urrent context\tCtrl-U"),
229 _T("Create report for the current program context"));
230 menuReport->AppendSeparator();
231 menuReport->AppendCheckItem(DebugRpt_Upload, _T("Up&load debug report"),
232 _T("You need to configure a web server accepting debug report uploads to use this function"));
233
234 wxMenu *menuHelp = new wxMenu;
235 menuHelp->Append(DebugRpt_About, _T("&About...\tF1"));
236
237 wxMenuBar *mbar = new wxMenuBar();
238 mbar->Append(menuFile, _T("&File"));
239 mbar->Append(menuReport, _T("&Report"));
240 mbar->Append(menuHelp, _T("&Help"));
241 SetMenuBar(mbar);
242
243 CreateStatusBar();
244
245 Show();
246 }
247
248 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
249 {
250 Close(true);
251 }
252
253 void MyFrame::OnReportForCrash(wxCommandEvent& WXUNUSED(event))
254 {
255 // this call is going to crash
256 foo(32);
257 foo(17);
258 }
259
260 void MyFrame::OnReportForCurrent(wxCommandEvent& WXUNUSED(event))
261 {
262 // example of manually generated report, this could be also
263 // used in wxApp::OnAssert()
264 wxGetApp().GenerateReport(wxDebugReport::Context_Current);
265 }
266
267 void MyFrame::OnReportUpload(wxCommandEvent& event)
268 {
269 wxGetApp().UploadReport(event.IsChecked());
270 }
271
272 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
273 {
274 wxMessageBox
275 (
276 _T("wxDebugReport sample\n(c) 2005 Vadim Zeitlin <vadim@wxwindows.org>"),
277 _T("wxWidgets Debug Report Sample"),
278 wxOK | wxICON_INFORMATION,
279 this
280 );
281 }
282
283 // ----------------------------------------------------------------------------
284 // MyApp
285 // ----------------------------------------------------------------------------
286
287 MyApp::MyApp()
288 {
289 // user needs to explicitely enable this
290 m_uploadReport = false;
291
292 // call this to tell the library to call our OnFatalException()
293 wxHandleFatalExceptions();
294 }
295
296 bool MyApp::OnInit()
297 {
298 if ( !wxApp::OnInit() )
299 return false;
300
301 new MyFrame;
302
303 return true;
304 }
305
306 void MyApp::OnFatalException()
307 {
308 GenerateReport(wxDebugReport::Context_Exception);
309 }
310
311 void MyApp::GenerateReport(wxDebugReport::Context ctx)
312 {
313 wxDebugReportCompress *report = m_uploadReport ? new MyDebugReport
314 : new wxDebugReportCompress;
315
316 // add all standard files: currently this means just a minidump and an
317 // XML file with system info and stack trace
318 report->AddAll(ctx);
319
320 // you can also call report->AddFile(...) with your own log files, files
321 // created using wxRegKey::Export() and so on, here we just add a test
322 // file containing the date of the crash
323 wxFileName fn(report->GetDirectory(), _T("timestamp.my"));
324 wxFFile file(fn.GetFullPath(), _T("w"));
325 if ( file.IsOpened() )
326 {
327 wxDateTime dt = wxDateTime::Now();
328 file.Write(dt.FormatISODate() + _T(' ') + dt.FormatISOTime());
329 file.Close();
330 }
331
332 report->AddFile(fn.GetFullName(), _T("timestamp of this report"));
333
334 // can also add an existing file directly, it will be copied
335 // automatically
336 #ifdef __WXMSW__
337 report->AddFile(_T("c:\\autoexec.bat"), _T("DOS startup file"));
338 #else
339 report->AddFile(_T("/etc/motd"), _T("Message of the day"));
340 #endif
341
342 // calling Show() is not mandatory, but is more polite
343 if ( wxDebugReportPreviewStd().Show(*report) )
344 {
345 if ( report->Process() )
346 {
347 if ( m_uploadReport )
348 {
349 wxLogMessage(_T("Report successfully uploaded."));
350 }
351 else
352 {
353 wxLogMessage(_T("Report generated in \"%s\"."),
354 report->GetCompressedFileName().c_str());
355 report->Reset();
356 }
357 }
358 }
359 //else: user cancelled the report
360
361 delete report;
362 }
363