PageRenderTime 53ms CodeModel.GetById 12ms app.highlight 35ms RepoModel.GetById 2ms app.codeStats 0ms

/thirdparty/breakpad/client/windows/tests/crash_generation_app/crash_generation_app.cc

http://github.com/tomahawk-player/tomahawk
C++ | 522 lines | 426 code | 48 blank | 48 comment | 20 complexity | 644f02477ddd32020ce0c9f9918bbb3f MD5 | raw file
  1// Copyright (c) 2008, Google Inc.
  2// All rights reserved.
  3//
  4// Redistribution and use in source and binary forms, with or without
  5// modification, are permitted provided that the following conditions are
  6// met:
  7//
  8//     * Redistributions of source code must retain the above copyright
  9// notice, this list of conditions and the following disclaimer.
 10//     * Redistributions in binary form must reproduce the above
 11// copyright notice, this list of conditions and the following disclaimer
 12// in the documentation and/or other materials provided with the
 13// distribution.
 14//     * Neither the name of Google Inc. nor the names of its
 15// contributors may be used to endorse or promote products derived from
 16// this software without specific prior written permission.
 17//
 18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 29
 30// crash_generation_app.cpp : Defines the entry point for the application.
 31//
 32
 33#include "client/windows/tests/crash_generation_app/crash_generation_app.h"
 34
 35#include <windows.h>
 36#include <tchar.h>
 37
 38#include "client/windows/crash_generation/client_info.h"
 39#include "client/windows/crash_generation/crash_generation_server.h"
 40#include "client/windows/handler/exception_handler.h"
 41#include "client/windows/common/ipc_protocol.h"
 42
 43#include "client/windows/tests/crash_generation_app/abstract_class.h"
 44
 45namespace google_breakpad {
 46
 47const int kMaxLoadString = 100;
 48const wchar_t kPipeName[] = L"\\\\.\\pipe\\BreakpadCrashServices\\TestServer";
 49
 50const DWORD kEditBoxStyles = WS_CHILD |
 51                             WS_VISIBLE |
 52                             WS_VSCROLL |
 53                             ES_LEFT |
 54                             ES_MULTILINE |
 55                             ES_AUTOVSCROLL |
 56                             ES_READONLY;
 57
 58// Maximum length of a line in the edit box.
 59const size_t kMaximumLineLength = 256;
 60
 61// CS to access edit control in a thread safe way.
 62static CRITICAL_SECTION* cs_edit = NULL;
 63
 64// Edit control.
 65static HWND client_status_edit_box;
 66
 67HINSTANCE current_instance;             // Current instance.
 68TCHAR title[kMaxLoadString];            // Title bar text.
 69TCHAR window_class[kMaxLoadString];     // Main window class name.
 70
 71ATOM MyRegisterClass(HINSTANCE instance);
 72BOOL InitInstance(HINSTANCE, int);
 73LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
 74INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
 75
 76static int kCustomInfoCount = 2;
 77static CustomInfoEntry kCustomInfoEntries[] = {
 78    CustomInfoEntry(L"prod", L"CrashTestApp"),
 79    CustomInfoEntry(L"ver", L"1.0"),
 80};
 81
 82static ExceptionHandler* handler = NULL;
 83static CrashGenerationServer* crash_server = NULL;
 84
 85// Registers the window class.
 86//
 87// This function and its usage are only necessary if you want this code
 88// to be compatible with Win32 systems prior to the 'RegisterClassEx'
 89// function that was added to Windows 95. It is important to call this
 90// function so that the application will get 'well formed' small icons
 91// associated with it.
 92ATOM MyRegisterClass(HINSTANCE instance) {
 93  WNDCLASSEX wcex;
 94  wcex.cbSize = sizeof(WNDCLASSEX);
 95  wcex.style = CS_HREDRAW | CS_VREDRAW;
 96  wcex.lpfnWndProc = WndProc;
 97  wcex.cbClsExtra = 0;
 98  wcex.cbWndExtra = 0;
 99  wcex.hInstance = instance;
100  wcex.hIcon = LoadIcon(instance,
101                        MAKEINTRESOURCE(IDI_CRASHGENERATIONAPP));
102  wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
103  wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
104  wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CRASHGENERATIONAPP);
105  wcex.lpszClassName = window_class;
106  wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
107
108  return RegisterClassEx(&wcex);
109}
110
111// Saves instance handle and creates main window
112//
113// In this function, we save the instance handle in a global variable and
114//   create and display the main program window.
115BOOL InitInstance(HINSTANCE instance, int command_show) {
116  current_instance = instance;
117  HWND wnd = CreateWindow(window_class,
118                          title,
119                          WS_OVERLAPPEDWINDOW,
120                          CW_USEDEFAULT,
121                          0,
122                          CW_USEDEFAULT,
123                          0,
124                          NULL,
125                          NULL,
126                          instance,
127                          NULL);
128
129  if (!wnd) {
130    return FALSE;
131  }
132
133  ShowWindow(wnd, command_show);
134  UpdateWindow(wnd);
135
136  return TRUE;
137}
138
139static void AppendTextToEditBox(TCHAR* text) {
140  EnterCriticalSection(cs_edit);
141  SYSTEMTIME current_time;
142  GetLocalTime(&current_time);
143  TCHAR line[kMaximumLineLength];
144  int result = swprintf_s(line,
145                          kMaximumLineLength,
146                          L"[%.2d-%.2d-%.4d %.2d:%.2d:%.2d] %s",
147                          current_time.wMonth,
148                          current_time.wDay,
149                          current_time.wYear,
150                          current_time.wHour,
151                          current_time.wMinute,
152                          current_time.wSecond,
153                          text);
154
155  if (result == -1) {
156    return;
157  }
158
159  int length = GetWindowTextLength(client_status_edit_box);
160  SendMessage(client_status_edit_box,
161              EM_SETSEL,
162              (WPARAM)length,
163              (LPARAM)length);
164  SendMessage(client_status_edit_box,
165              EM_REPLACESEL,
166              (WPARAM)FALSE,
167              (LPARAM)line);
168  LeaveCriticalSection(cs_edit);
169}
170
171static DWORD WINAPI AppendTextWorker(void* context) {
172  TCHAR* text = reinterpret_cast<TCHAR*>(context);
173
174  AppendTextToEditBox(text);
175  delete[] text;
176
177  return 0;
178}
179
180bool ShowDumpResults(const wchar_t* dump_path,
181                     const wchar_t* minidump_id,
182                     void* context,
183                     EXCEPTION_POINTERS* exinfo,
184                     MDRawAssertionInfo* assertion,
185                     bool succeeded) {
186  TCHAR* text = new TCHAR[kMaximumLineLength];
187  text[0] = _T('\0');
188  int result = swprintf_s(text,
189                          kMaximumLineLength,
190                          TEXT("Dump generation request %s\r\n"),
191                          succeeded ? TEXT("succeeded") : TEXT("failed"));
192  if (result == -1) {
193    delete [] text;
194  }
195
196  QueueUserWorkItem(AppendTextWorker, text, WT_EXECUTEDEFAULT);
197  return succeeded;
198}
199
200static void _cdecl ShowClientConnected(void* context,
201                                       const ClientInfo* client_info) {
202  TCHAR* line = new TCHAR[kMaximumLineLength];
203  line[0] = _T('\0');
204  int result = swprintf_s(line,
205                          kMaximumLineLength,
206                          L"Client connected:\t\t%d\r\n",
207                          client_info->pid());
208
209  if (result == -1) {
210    delete[] line;
211    return;
212  }
213
214  QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
215}
216
217static void _cdecl ShowClientCrashed(void* context,
218                                     const ClientInfo* client_info,
219                                     const wstring* dump_path) {
220  TCHAR* line = new TCHAR[kMaximumLineLength];
221  line[0] = _T('\0');
222  int result = swprintf_s(line,
223                          kMaximumLineLength,
224                          TEXT("Client requested dump:\t%d\r\n"),
225                          client_info->pid());
226
227  if (result == -1) {
228    delete[] line;
229    return;
230  }
231
232  QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
233
234  CustomClientInfo custom_info = client_info->GetCustomInfo();
235  if (custom_info.count <= 0) {
236    return;
237  }
238
239  wstring str_line;
240  for (size_t i = 0; i < custom_info.count; ++i) {
241    if (i > 0) {
242      str_line += L", ";
243    }
244    str_line += custom_info.entries[i].name;
245    str_line += L": ";
246    str_line += custom_info.entries[i].value;
247  }
248
249  line = new TCHAR[kMaximumLineLength];
250  line[0] = _T('\0');
251  result = swprintf_s(line,
252                      kMaximumLineLength,
253                      L"%s\n",
254                      str_line.c_str());
255  if (result == -1) {
256    delete[] line;
257    return;
258  }
259  QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
260}
261
262static void _cdecl ShowClientExited(void* context,
263                                    const ClientInfo* client_info) {
264  TCHAR* line = new TCHAR[kMaximumLineLength];
265  line[0] = _T('\0');
266  int result = swprintf_s(line,
267                          kMaximumLineLength,
268                          TEXT("Client exited:\t\t%d\r\n"),
269                          client_info->pid());
270
271  if (result == -1) {
272    delete[] line;
273    return;
274  }
275
276  QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
277}
278
279void CrashServerStart() {
280  // Do not create another instance of the server.
281  if (crash_server) {
282    return;
283  }
284
285  std::wstring dump_path = L"C:\\Dumps\\";
286  crash_server = new CrashGenerationServer(kPipeName,
287                                           NULL,
288                                           ShowClientConnected,
289                                           NULL,
290                                           ShowClientCrashed,
291                                           NULL,
292                                           ShowClientExited,
293                                           NULL,
294                                           NULL,
295                                           NULL,
296                                           true,
297                                           &dump_path);
298
299  if (!crash_server->Start()) {
300    MessageBoxW(NULL, L"Unable to start server", L"Dumper", MB_OK);
301    delete crash_server;
302    crash_server = NULL;
303  }
304}
305
306void CrashServerStop() {
307  delete crash_server;
308  crash_server = NULL;
309}
310
311void DerefZeroCrash() {
312  int* x = 0;
313  *x = 1;
314}
315
316void InvalidParamCrash() {
317  printf(NULL);
318}
319
320void PureCallCrash() {
321  Derived derived;
322}
323
324void RequestDump() {
325  if (!handler->WriteMinidump()) {
326    MessageBoxW(NULL, L"Dump request failed", L"Dumper", MB_OK);
327  }
328  kCustomInfoEntries[1].set_value(L"1.1");
329}
330
331void CleanUp() {
332  if (cs_edit) {
333    DeleteCriticalSection(cs_edit);
334    delete cs_edit;
335  }
336
337  if (handler) {
338    delete handler;
339  }
340
341  if (crash_server) {
342    delete crash_server;
343  }
344}
345
346// Processes messages for the main window.
347//
348// WM_COMMAND	- process the application menu.
349// WM_PAINT	- Paint the main window.
350// WM_DESTROY	- post a quit message and return.
351LRESULT CALLBACK WndProc(HWND wnd,
352                         UINT message,
353                         WPARAM w_param,
354                         LPARAM l_param) {
355  int message_id;
356  int message_event;
357  PAINTSTRUCT ps;
358  HDC hdc;
359
360#pragma warning(push)
361#pragma warning(disable:4312)
362  // Disable warning	C4312: 'type cast' : conversion from 'LONG' to
363  // 'HINSTANCE' of greater size.
364  // The value returned by GetwindowLong in the case below returns unsigned.
365  HINSTANCE instance = (HINSTANCE)GetWindowLong(wnd, GWL_HINSTANCE);
366#pragma warning(pop)
367
368  switch (message) {
369    case WM_COMMAND:
370      // Parse the menu selections.
371      message_id = LOWORD(w_param);
372      message_event = HIWORD(w_param);
373      switch (message_id) {
374        case IDM_ABOUT:
375          DialogBox(current_instance,
376                    MAKEINTRESOURCE(IDD_ABOUTBOX),
377                    wnd,
378                    About);
379          break;
380        case IDM_EXIT:
381          DestroyWindow(wnd);
382          break;
383        case ID_SERVER_START:
384          CrashServerStart();
385          break;
386        case ID_SERVER_STOP:
387          CrashServerStop();
388          break;
389        case ID_CLIENT_DEREFZERO:
390          DerefZeroCrash();
391          break;
392        case ID_CLIENT_INVALIDPARAM:
393          InvalidParamCrash();
394          break;
395        case ID_CLIENT_PURECALL:
396          PureCallCrash();
397          break;
398        case ID_CLIENT_REQUESTEXPLICITDUMP:
399          RequestDump();
400          break;
401        default:
402          return DefWindowProc(wnd, message, w_param, l_param);
403      }
404      break;
405    case WM_CREATE:
406      client_status_edit_box = CreateWindow(TEXT("EDIT"),
407                                            NULL,
408                                            kEditBoxStyles,
409                                            0,
410                                            0,
411                                            0,
412                                            0,
413                                            wnd,
414                                            NULL,
415                                            instance,
416                                            NULL);
417      break;
418    case WM_SIZE: 
419      // Make the edit control the size of the window's client area. 
420      MoveWindow(client_status_edit_box, 
421                 0,
422                 0,
423                 LOWORD(l_param),        // width of client area.
424                 HIWORD(l_param),        // height of client area.
425                 TRUE);                  // repaint window.
426      break;
427    case WM_SETFOCUS: 
428      SetFocus(client_status_edit_box);
429      break;
430    case WM_PAINT:
431      hdc = BeginPaint(wnd, &ps);
432      EndPaint(wnd, &ps);
433      break;
434    case WM_DESTROY:
435      CleanUp();
436      PostQuitMessage(0);
437      break;
438    default:
439      return DefWindowProc(wnd, message, w_param, l_param);
440  }
441
442  return 0;
443}
444
445// Message handler for about box.
446INT_PTR CALLBACK About(HWND dlg,
447                       UINT message,
448                       WPARAM w_param,
449                       LPARAM l_param) {
450  UNREFERENCED_PARAMETER(l_param);
451  switch (message) {
452    case WM_INITDIALOG:
453      return (INT_PTR)TRUE;
454
455    case WM_COMMAND:
456      if (LOWORD(w_param) == IDOK || LOWORD(w_param) == IDCANCEL) {
457        EndDialog(dlg, LOWORD(w_param));
458        return (INT_PTR)TRUE;
459      }
460      break;
461  }
462
463  return (INT_PTR)FALSE;
464}
465
466}  // namespace google_breakpad
467
468int APIENTRY _tWinMain(HINSTANCE instance,
469                       HINSTANCE previous_instance,
470                       LPTSTR command_line,
471                       int command_show) {
472  using namespace google_breakpad;
473
474  UNREFERENCED_PARAMETER(previous_instance);
475  UNREFERENCED_PARAMETER(command_line);
476
477  cs_edit = new CRITICAL_SECTION();
478  InitializeCriticalSection(cs_edit);
479
480  CustomClientInfo custom_info = {kCustomInfoEntries, kCustomInfoCount};
481
482  CrashServerStart();
483  // This is needed for CRT to not show dialog for invalid param
484  // failures and instead let the code handle it.
485  _CrtSetReportMode(_CRT_ASSERT, 0);
486  handler = new ExceptionHandler(L"C:\\dumps\\",
487                                 NULL,
488                                 google_breakpad::ShowDumpResults,
489                                 NULL,
490                                 ExceptionHandler::HANDLER_ALL,
491                                 MiniDumpNormal,
492                                 kPipeName,
493                                 &custom_info);
494
495  // Initialize global strings.
496  LoadString(instance, IDS_APP_TITLE, title, kMaxLoadString);
497  LoadString(instance,
498             IDC_CRASHGENERATIONAPP,
499             window_class,
500             kMaxLoadString);
501  MyRegisterClass(instance);
502
503  // Perform application initialization.
504  if (!InitInstance (instance, command_show)) {
505    return FALSE;
506  }
507
508  HACCEL accel_table = LoadAccelerators(
509      instance,
510      MAKEINTRESOURCE(IDC_CRASHGENERATIONAPP));
511
512  // Main message loop.
513  MSG msg;
514  while (GetMessage(&msg, NULL, 0, 0)) {
515    if (!TranslateAccelerator(msg.hwnd, accel_table, &msg)) {
516      TranslateMessage(&msg);
517      DispatchMessage(&msg);
518    }
519  }
520
521  return (int)msg.wParam;
522}