1 // Copyright (c) 2008, Google Inc.
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
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
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.
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.
30 // crash_generation_app.cpp : Defines the entry point for the application.
33 #include "client/windows/tests/crash_generation_app/crash_generation_app.h"
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"
43 #include "client/windows/tests/crash_generation_app/abstract_class.h"
45 namespace google_breakpad {
47 const int kMaxLoadString = 100;
48 const wchar_t kPipeName[] = L"\\\\.\\pipe\\BreakpadCrashServices\\TestServer";
50 const DWORD kEditBoxStyles = WS_CHILD |
58 // Maximum length of a line in the edit box.
59 const size_t kMaximumLineLength = 256;
61 // CS to access edit control in a thread safe way.
62 static CRITICAL_SECTION* cs_edit = NULL;
65 static HWND client_status_edit_box;
67 HINSTANCE current_instance; // Current instance.
68 TCHAR title[kMaxLoadString]; // Title bar text.
69 TCHAR window_class[kMaxLoadString]; // Main window class name.
71 ATOM MyRegisterClass(HINSTANCE instance);
72 BOOL InitInstance(HINSTANCE, int);
73 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
74 INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
76 static int kCustomInfoCount = 2;
77 static CustomInfoEntry kCustomInfoEntries[] = {
78 CustomInfoEntry(L"prod", L"CrashTestApp"),
79 CustomInfoEntry(L"ver", L"1.0"),
82 static ExceptionHandler* handler = NULL;
83 static CrashGenerationServer* crash_server = NULL;
85 // Registers the window class.
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.
92 ATOM MyRegisterClass(HINSTANCE instance) {
94 wcex.cbSize = sizeof(WNDCLASSEX);
95 wcex.style = CS_HREDRAW | CS_VREDRAW;
96 wcex.lpfnWndProc = WndProc;
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));
108 return RegisterClassEx(&wcex);
111 // Saves instance handle and creates main window
113 // In this function, we save the instance handle in a global variable and
114 // create and display the main program window.
115 BOOL InitInstance(HINSTANCE instance, int command_show) {
116 current_instance = instance;
117 HWND wnd = CreateWindow(window_class,
133 ShowWindow(wnd, command_show);
139 static void AppendTextToEditBox(TCHAR* text) {
140 EnterCriticalSection(cs_edit);
141 SYSTEMTIME current_time;
142 GetLocalTime(¤t_time);
143 TCHAR line[kMaximumLineLength];
144 int result = swprintf_s(line,
146 L"[%.2d-%.2d-%.4d %.2d:%.2d:%.2d] %s",
151 current_time.wMinute,
152 current_time.wSecond,
159 int length = GetWindowTextLength(client_status_edit_box);
160 SendMessage(client_status_edit_box,
164 SendMessage(client_status_edit_box,
168 LeaveCriticalSection(cs_edit);
171 static DWORD WINAPI AppendTextWorker(void* context) {
172 TCHAR* text = reinterpret_cast<TCHAR*>(context);
174 AppendTextToEditBox(text);
180 bool ShowDumpResults(const wchar_t* dump_path,
181 const wchar_t* minidump_id,
183 EXCEPTION_POINTERS* exinfo,
184 MDRawAssertionInfo* assertion,
186 TCHAR* text = new TCHAR[kMaximumLineLength];
188 int result = swprintf_s(text,
190 TEXT("Dump generation request %s\r\n"),
191 succeeded ? TEXT("succeeded") : TEXT("failed"));
196 QueueUserWorkItem(AppendTextWorker, text, WT_EXECUTEDEFAULT);
200 static void _cdecl ShowClientConnected(void* context,
201 const ClientInfo* client_info) {
202 TCHAR* line = new TCHAR[kMaximumLineLength];
204 int result = swprintf_s(line,
206 L"Client connected:\t\t%d\r\n",
214 QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
217 static void _cdecl ShowClientCrashed(void* context,
218 const ClientInfo* client_info,
219 const wstring* dump_path) {
220 TCHAR* line = new TCHAR[kMaximumLineLength];
222 int result = swprintf_s(line,
224 TEXT("Client requested dump:\t%d\r\n"),
232 QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
234 CustomClientInfo custom_info = client_info->GetCustomInfo();
235 if (custom_info.count <= 0) {
240 for (size_t i = 0; i < custom_info.count; ++i) {
244 str_line += custom_info.entries[i].name;
246 str_line += custom_info.entries[i].value;
249 line = new TCHAR[kMaximumLineLength];
251 result = swprintf_s(line,
259 QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
262 static void _cdecl ShowClientExited(void* context,
263 const ClientInfo* client_info) {
264 TCHAR* line = new TCHAR[kMaximumLineLength];
266 int result = swprintf_s(line,
268 TEXT("Client exited:\t\t%d\r\n"),
276 QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
279 void CrashServerStart() {
280 // Do not create another instance of the server.
285 std::wstring dump_path = L"C:\\Dumps\\";
287 if (_wmkdir(dump_path.c_str()) && (errno != EEXIST)) {
288 MessageBoxW(NULL, L"Unable to create dump directory", L"Dumper", MB_OK);
292 crash_server = new CrashGenerationServer(kPipeName,
305 if (!crash_server->Start()) {
306 MessageBoxW(NULL, L"Unable to start server", L"Dumper", MB_OK);
312 void CrashServerStop() {
317 void DerefZeroCrash() {
322 void InvalidParamCrash() {
326 void PureCallCrash() {
331 if (!handler->WriteMinidump()) {
332 MessageBoxW(NULL, L"Dump request failed", L"Dumper", MB_OK);
334 kCustomInfoEntries[1].set_value(L"1.1");
339 DeleteCriticalSection(cs_edit);
352 // Processes messages for the main window.
354 // WM_COMMAND - process the application menu.
355 // WM_PAINT - Paint the main window.
356 // WM_DESTROY - post a quit message and return.
357 LRESULT CALLBACK WndProc(HWND wnd,
366 HINSTANCE instance = (HINSTANCE)GetWindowLongPtr(wnd, GWLP_HINSTANCE);
370 // Parse the menu selections.
371 message_id = LOWORD(w_param);
372 message_event = HIWORD(w_param);
373 switch (message_id) {
375 DialogBox(current_instance,
376 MAKEINTRESOURCE(IDD_ABOUTBOX),
383 case ID_SERVER_START:
389 case ID_CLIENT_DEREFZERO:
392 case ID_CLIENT_INVALIDPARAM:
395 case ID_CLIENT_PURECALL:
398 case ID_CLIENT_REQUESTEXPLICITDUMP:
402 return DefWindowProc(wnd, message, w_param, l_param);
406 client_status_edit_box = CreateWindow(TEXT("EDIT"),
419 // Make the edit control the size of the window's client area.
420 MoveWindow(client_status_edit_box,
423 LOWORD(l_param), // width of client area.
424 HIWORD(l_param), // height of client area.
425 TRUE); // repaint window.
428 SetFocus(client_status_edit_box);
431 hdc = BeginPaint(wnd, &ps);
439 return DefWindowProc(wnd, message, w_param, l_param);
445 // Message handler for about box.
446 INT_PTR CALLBACK About(HWND dlg,
450 UNREFERENCED_PARAMETER(l_param);
453 return (INT_PTR)TRUE;
456 if (LOWORD(w_param) == IDOK || LOWORD(w_param) == IDCANCEL) {
457 EndDialog(dlg, LOWORD(w_param));
458 return (INT_PTR)TRUE;
463 return (INT_PTR)FALSE;
466 } // namespace google_breakpad
468 int APIENTRY _tWinMain(HINSTANCE instance,
469 HINSTANCE previous_instance,
472 using namespace google_breakpad;
474 UNREFERENCED_PARAMETER(previous_instance);
475 UNREFERENCED_PARAMETER(command_line);
477 cs_edit = new CRITICAL_SECTION();
478 InitializeCriticalSection(cs_edit);
480 CustomClientInfo custom_info = {kCustomInfoEntries, kCustomInfoCount};
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\\",
488 google_breakpad::ShowDumpResults,
490 ExceptionHandler::HANDLER_ALL,
495 // Initialize global strings.
496 LoadString(instance, IDS_APP_TITLE, title, kMaxLoadString);
498 IDC_CRASHGENERATIONAPP,
501 MyRegisterClass(instance);
503 // Perform application initialization.
504 if (!InitInstance(instance, command_show)) {
508 HACCEL accel_table = LoadAccelerators(
510 MAKEINTRESOURCE(IDC_CRASHGENERATIONAPP));
512 // Main message loop.
514 while (GetMessage(&msg, NULL, 0, 0)) {
515 if (!TranslateAccelerator(msg.hwnd, accel_table, &msg)) {
516 TranslateMessage(&msg);
517 DispatchMessage(&msg);
521 return static_cast<int>(msg.wParam);