Plan B - use a #error when !wxUSE_ON_FATAL_EXCEPTION
[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/log.h"
18 #include "wx/datetime.h"
19 #include "wx/ffile.h"
20 #include "wx/filename.h"
21 #include "wx/dynlib.h"
22 #include "wx/debugrpt.h"
23
24 #include "wx/msgdlg.h"
25
26 #if !wxUSE_DEBUGREPORT
27 #error "This sample can't be built without wxUSE_DEBUGREPORT"
28 #endif // wxUSE_DEBUGREPORT
29
30 #if !wxUSE_ON_FATAL_EXCEPTION
31 #error "This sample can't be built without wxUSE_ON_FATAL_EXCEPTION"
32 #endif // wxUSE_ON_FATAL_EXCEPTION
33
34 // ----------------------------------------------------------------------------
35 // custom debug reporting class
36 // ----------------------------------------------------------------------------
37
38 // this is your custom debug reporter: it will use curl program (which should
39 // be available) to upload the crash report to the given URL (which should be
40 // set up by you)
41 class MyDebugReport : public wxDebugReportUpload
42 {
43 public:
44 MyDebugReport() : wxDebugReportUpload
45 (
46 _T("http://your.url.here/"),
47 _T("report:file"),
48 _T("action")
49 )
50 {
51 }
52
53 protected:
54 // this is called with the contents of the server response: you will
55 // probably want to parse the XML document in OnServerReply() instead of
56 // just dumping it as I do
57 virtual bool OnServerReply(const wxArrayString& reply)
58 {
59 if ( reply.IsEmpty() )
60 {
61 wxLogError(_T("Didn't receive the expected server reply."));
62 return false;
63 }
64
65 wxString s(_T("Server replied:\n"));
66
67 const size_t count = reply.GetCount();
68 for ( size_t n = 0; n < count; n++ )
69 {
70 s << _T('\t') << reply[n] << _T('\n');
71 }
72
73 wxLogMessage(_T("%s"), s.c_str());
74
75 return true;
76 }
77 };
78
79 // another possibility would be to build email library from contrib and use
80 // this class, after uncommenting it:
81 #if 0
82
83 #include "wx/net/email.h"
84
85 class MyDebugReport : public wxDebugReportCompress
86 {
87 public:
88 virtual bool DoProcess()
89 {
90 if ( !wxDebugReportCompress::DoProcess() )
91 return false;
92 wxMailMessage msg(GetReportName() + _T(" crash report"),
93 _T("vadim@wxwindows.org"),
94 wxEmptyString, // mail body
95 wxEmptyString, // from address
96 GetCompressedFileName(),
97 _T("crashreport.zip"));
98
99 return wxEmail::Send(msg);
100 }
101 };
102
103 #endif // 0
104
105 // ----------------------------------------------------------------------------
106 // helper functions
107 // ----------------------------------------------------------------------------
108
109 // just some functions to get a slightly deeper stack trace
110 static void bar(const wxChar *p)
111 {
112 char *pc = 0;
113 *pc = *p;
114
115 printf("bar: %s\n", p);
116 }
117
118 void baz(const wxString& s)
119 {
120 printf("baz: %s\n", s.c_str());
121 }
122
123 void foo(int n)
124 {
125 if ( n % 2 )
126 baz(wxT("odd"));
127 else
128 bar(wxT("even"));
129 }
130
131 // ----------------------------------------------------------------------------
132 // application class
133 // ----------------------------------------------------------------------------
134
135 // this is a usual application class modified to work with debug reporter
136 //
137 // basically just 2 things are necessary: call wxHandleFatalExceptions() as
138 // early as possible and override OnFatalException() to create the report there
139 class MyApp : public wxApp
140 {
141 public:
142 virtual bool OnInit()
143 {
144 wxHandleFatalExceptions();
145
146 if ( !wxApp::OnInit() )
147 return false;
148
149 return true;
150 }
151
152 virtual int OnRun()
153 {
154 // a real program would be presumably be a bit harder to crash than
155 // just pressing "yes" in a dialog... but this is just an example
156 switch ( wxMessageBox
157 (
158 _T("Generate report for crash (or just current context)?"),
159 _T("wxDebugReport Test"),
160 wxYES_NO | wxCANCEL
161 ) )
162 {
163 case wxYES:
164 // this call is going to crash
165 foo(32);
166 foo(17);
167 break;
168
169 case wxNO:
170 // example of manually generated report, this could be also
171 // used in wxApp::OnAssert()
172 GenerateReport(wxDebugReport::Context_Current);
173 break;
174
175 case wxCANCEL:
176 break;
177 }
178
179 return 0;
180 }
181
182 virtual void OnFatalException()
183 {
184 GenerateReport(wxDebugReport::Context_Exception);
185 }
186
187 void GenerateReport(wxDebugReport::Context ctx)
188 {
189 MyDebugReport report;
190
191 // add all standard files: currently this means just a minidump and an
192 // XML file with system info and stack trace
193 report.AddAll(ctx);
194
195 // you can also call report.AddFile(...) with your own log files, files
196 // created using wxRegKey::Export() and so on, here we just add a test
197 // file containing the date of the crash
198 wxFileName fn(report.GetDirectory(), _T("timestamp.my"));
199 wxFFile file(fn.GetFullPath(), _T("w"));
200 if ( file.IsOpened() )
201 {
202 wxDateTime dt = wxDateTime::Now();
203 file.Write(dt.FormatISODate() + _T(' ') + dt.FormatISOTime());
204 file.Close();
205 }
206
207 report.AddFile(fn.GetFullName(), _T("timestamp of this report"));
208
209 // can also add an existing file directly, it will be copied
210 // automatically
211 #ifdef __WXMSW__
212 report.AddFile(_T("c:\\autoexec.bat"), _T("DOS startup file"));
213 #else
214 report.AddFile(_T("/etc/motd"), _T("Message of the day"));
215 #endif
216
217 // calling Show() is not mandatory, but is more polite
218 if ( wxDebugReportPreviewStd().Show(report) )
219 {
220 if ( report.Process() )
221 {
222 // report successfully uploaded
223 }
224 }
225 //else: user cancelled the report
226 }
227 };
228
229 IMPLEMENT_APP(MyApp)
230