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

http://github.com/tomahawk-player/tomahawk · C++ · 522 lines · 391 code · 70 blank · 61 comment · 32 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. // crash_generation_app.cpp : Defines the entry point for the application.
  30. //
  31. #include "client/windows/tests/crash_generation_app/crash_generation_app.h"
  32. #include <windows.h>
  33. #include <tchar.h>
  34. #include "client/windows/crash_generation/client_info.h"
  35. #include "client/windows/crash_generation/crash_generation_server.h"
  36. #include "client/windows/handler/exception_handler.h"
  37. #include "client/windows/common/ipc_protocol.h"
  38. #include "client/windows/tests/crash_generation_app/abstract_class.h"
  39. namespace google_breakpad {
  40. const int kMaxLoadString = 100;
  41. const wchar_t kPipeName[] = L"\\\\.\\pipe\\BreakpadCrashServices\\TestServer";
  42. const DWORD kEditBoxStyles = WS_CHILD |
  43. WS_VISIBLE |
  44. WS_VSCROLL |
  45. ES_LEFT |
  46. ES_MULTILINE |
  47. ES_AUTOVSCROLL |
  48. ES_READONLY;
  49. // Maximum length of a line in the edit box.
  50. const size_t kMaximumLineLength = 256;
  51. // CS to access edit control in a thread safe way.
  52. static CRITICAL_SECTION* cs_edit = NULL;
  53. // Edit control.
  54. static HWND client_status_edit_box;
  55. HINSTANCE current_instance; // Current instance.
  56. TCHAR title[kMaxLoadString]; // Title bar text.
  57. TCHAR window_class[kMaxLoadString]; // Main window class name.
  58. ATOM MyRegisterClass(HINSTANCE instance);
  59. BOOL InitInstance(HINSTANCE, int);
  60. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  61. INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
  62. static int kCustomInfoCount = 2;
  63. static CustomInfoEntry kCustomInfoEntries[] = {
  64. CustomInfoEntry(L"prod", L"CrashTestApp"),
  65. CustomInfoEntry(L"ver", L"1.0"),
  66. };
  67. static ExceptionHandler* handler = NULL;
  68. static CrashGenerationServer* crash_server = NULL;
  69. // Registers the window class.
  70. //
  71. // This function and its usage are only necessary if you want this code
  72. // to be compatible with Win32 systems prior to the 'RegisterClassEx'
  73. // function that was added to Windows 95. It is important to call this
  74. // function so that the application will get 'well formed' small icons
  75. // associated with it.
  76. ATOM MyRegisterClass(HINSTANCE instance) {
  77. WNDCLASSEX wcex;
  78. wcex.cbSize = sizeof(WNDCLASSEX);
  79. wcex.style = CS_HREDRAW | CS_VREDRAW;
  80. wcex.lpfnWndProc = WndProc;
  81. wcex.cbClsExtra = 0;
  82. wcex.cbWndExtra = 0;
  83. wcex.hInstance = instance;
  84. wcex.hIcon = LoadIcon(instance,
  85. MAKEINTRESOURCE(IDI_CRASHGENERATIONAPP));
  86. wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
  87. wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  88. wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CRASHGENERATIONAPP);
  89. wcex.lpszClassName = window_class;
  90. wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
  91. return RegisterClassEx(&wcex);
  92. }
  93. // Saves instance handle and creates main window
  94. //
  95. // In this function, we save the instance handle in a global variable and
  96. // create and display the main program window.
  97. BOOL InitInstance(HINSTANCE instance, int command_show) {
  98. current_instance = instance;
  99. HWND wnd = CreateWindow(window_class,
  100. title,
  101. WS_OVERLAPPEDWINDOW,
  102. CW_USEDEFAULT,
  103. 0,
  104. CW_USEDEFAULT,
  105. 0,
  106. NULL,
  107. NULL,
  108. instance,
  109. NULL);
  110. if (!wnd) {
  111. return FALSE;
  112. }
  113. ShowWindow(wnd, command_show);
  114. UpdateWindow(wnd);
  115. return TRUE;
  116. }
  117. static void AppendTextToEditBox(TCHAR* text) {
  118. EnterCriticalSection(cs_edit);
  119. SYSTEMTIME current_time;
  120. GetLocalTime(&current_time);
  121. TCHAR line[kMaximumLineLength];
  122. int result = swprintf_s(line,
  123. kMaximumLineLength,
  124. L"[%.2d-%.2d-%.4d %.2d:%.2d:%.2d] %s",
  125. current_time.wMonth,
  126. current_time.wDay,
  127. current_time.wYear,
  128. current_time.wHour,
  129. current_time.wMinute,
  130. current_time.wSecond,
  131. text);
  132. if (result == -1) {
  133. return;
  134. }
  135. int length = GetWindowTextLength(client_status_edit_box);
  136. SendMessage(client_status_edit_box,
  137. EM_SETSEL,
  138. (WPARAM)length,
  139. (LPARAM)length);
  140. SendMessage(client_status_edit_box,
  141. EM_REPLACESEL,
  142. (WPARAM)FALSE,
  143. (LPARAM)line);
  144. LeaveCriticalSection(cs_edit);
  145. }
  146. static DWORD WINAPI AppendTextWorker(void* context) {
  147. TCHAR* text = reinterpret_cast<TCHAR*>(context);
  148. AppendTextToEditBox(text);
  149. delete[] text;
  150. return 0;
  151. }
  152. bool ShowDumpResults(const wchar_t* dump_path,
  153. const wchar_t* minidump_id,
  154. void* context,
  155. EXCEPTION_POINTERS* exinfo,
  156. MDRawAssertionInfo* assertion,
  157. bool succeeded) {
  158. TCHAR* text = new TCHAR[kMaximumLineLength];
  159. text[0] = _T('\0');
  160. int result = swprintf_s(text,
  161. kMaximumLineLength,
  162. TEXT("Dump generation request %s\r\n"),
  163. succeeded ? TEXT("succeeded") : TEXT("failed"));
  164. if (result == -1) {
  165. delete [] text;
  166. }
  167. QueueUserWorkItem(AppendTextWorker, text, WT_EXECUTEDEFAULT);
  168. return succeeded;
  169. }
  170. static void _cdecl ShowClientConnected(void* context,
  171. const ClientInfo* client_info) {
  172. TCHAR* line = new TCHAR[kMaximumLineLength];
  173. line[0] = _T('\0');
  174. int result = swprintf_s(line,
  175. kMaximumLineLength,
  176. L"Client connected:\t\t%d\r\n",
  177. client_info->pid());
  178. if (result == -1) {
  179. delete[] line;
  180. return;
  181. }
  182. QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
  183. }
  184. static void _cdecl ShowClientCrashed(void* context,
  185. const ClientInfo* client_info,
  186. const wstring* dump_path) {
  187. TCHAR* line = new TCHAR[kMaximumLineLength];
  188. line[0] = _T('\0');
  189. int result = swprintf_s(line,
  190. kMaximumLineLength,
  191. TEXT("Client requested dump:\t%d\r\n"),
  192. client_info->pid());
  193. if (result == -1) {
  194. delete[] line;
  195. return;
  196. }
  197. QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
  198. CustomClientInfo custom_info = client_info->GetCustomInfo();
  199. if (custom_info.count <= 0) {
  200. return;
  201. }
  202. wstring str_line;
  203. for (size_t i = 0; i < custom_info.count; ++i) {
  204. if (i > 0) {
  205. str_line += L", ";
  206. }
  207. str_line += custom_info.entries[i].name;
  208. str_line += L": ";
  209. str_line += custom_info.entries[i].value;
  210. }
  211. line = new TCHAR[kMaximumLineLength];
  212. line[0] = _T('\0');
  213. result = swprintf_s(line,
  214. kMaximumLineLength,
  215. L"%s\n",
  216. str_line.c_str());
  217. if (result == -1) {
  218. delete[] line;
  219. return;
  220. }
  221. QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
  222. }
  223. static void _cdecl ShowClientExited(void* context,
  224. const ClientInfo* client_info) {
  225. TCHAR* line = new TCHAR[kMaximumLineLength];
  226. line[0] = _T('\0');
  227. int result = swprintf_s(line,
  228. kMaximumLineLength,
  229. TEXT("Client exited:\t\t%d\r\n"),
  230. client_info->pid());
  231. if (result == -1) {
  232. delete[] line;
  233. return;
  234. }
  235. QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
  236. }
  237. void CrashServerStart() {
  238. // Do not create another instance of the server.
  239. if (crash_server) {
  240. return;
  241. }
  242. std::wstring dump_path = L"C:\\Dumps\\";
  243. crash_server = new CrashGenerationServer(kPipeName,
  244. NULL,
  245. ShowClientConnected,
  246. NULL,
  247. ShowClientCrashed,
  248. NULL,
  249. ShowClientExited,
  250. NULL,
  251. NULL,
  252. NULL,
  253. true,
  254. &dump_path);
  255. if (!crash_server->Start()) {
  256. MessageBoxW(NULL, L"Unable to start server", L"Dumper", MB_OK);
  257. delete crash_server;
  258. crash_server = NULL;
  259. }
  260. }
  261. void CrashServerStop() {
  262. delete crash_server;
  263. crash_server = NULL;
  264. }
  265. void DerefZeroCrash() {
  266. int* x = 0;
  267. *x = 1;
  268. }
  269. void InvalidParamCrash() {
  270. printf(NULL);
  271. }
  272. void PureCallCrash() {
  273. Derived derived;
  274. }
  275. void RequestDump() {
  276. if (!handler->WriteMinidump()) {
  277. MessageBoxW(NULL, L"Dump request failed", L"Dumper", MB_OK);
  278. }
  279. kCustomInfoEntries[1].set_value(L"1.1");
  280. }
  281. void CleanUp() {
  282. if (cs_edit) {
  283. DeleteCriticalSection(cs_edit);
  284. delete cs_edit;
  285. }
  286. if (handler) {
  287. delete handler;
  288. }
  289. if (crash_server) {
  290. delete crash_server;
  291. }
  292. }
  293. // Processes messages for the main window.
  294. //
  295. // WM_COMMAND - process the application menu.
  296. // WM_PAINT - Paint the main window.
  297. // WM_DESTROY - post a quit message and return.
  298. LRESULT CALLBACK WndProc(HWND wnd,
  299. UINT message,
  300. WPARAM w_param,
  301. LPARAM l_param) {
  302. int message_id;
  303. int message_event;
  304. PAINTSTRUCT ps;
  305. HDC hdc;
  306. #pragma warning(push)
  307. #pragma warning(disable:4312)
  308. // Disable warning C4312: 'type cast' : conversion from 'LONG' to
  309. // 'HINSTANCE' of greater size.
  310. // The value returned by GetwindowLong in the case below returns unsigned.
  311. HINSTANCE instance = (HINSTANCE)GetWindowLong(wnd, GWL_HINSTANCE);
  312. #pragma warning(pop)
  313. switch (message) {
  314. case WM_COMMAND:
  315. // Parse the menu selections.
  316. message_id = LOWORD(w_param);
  317. message_event = HIWORD(w_param);
  318. switch (message_id) {
  319. case IDM_ABOUT:
  320. DialogBox(current_instance,
  321. MAKEINTRESOURCE(IDD_ABOUTBOX),
  322. wnd,
  323. About);
  324. break;
  325. case IDM_EXIT:
  326. DestroyWindow(wnd);
  327. break;
  328. case ID_SERVER_START:
  329. CrashServerStart();
  330. break;
  331. case ID_SERVER_STOP:
  332. CrashServerStop();
  333. break;
  334. case ID_CLIENT_DEREFZERO:
  335. DerefZeroCrash();
  336. break;
  337. case ID_CLIENT_INVALIDPARAM:
  338. InvalidParamCrash();
  339. break;
  340. case ID_CLIENT_PURECALL:
  341. PureCallCrash();
  342. break;
  343. case ID_CLIENT_REQUESTEXPLICITDUMP:
  344. RequestDump();
  345. break;
  346. default:
  347. return DefWindowProc(wnd, message, w_param, l_param);
  348. }
  349. break;
  350. case WM_CREATE:
  351. client_status_edit_box = CreateWindow(TEXT("EDIT"),
  352. NULL,
  353. kEditBoxStyles,
  354. 0,
  355. 0,
  356. 0,
  357. 0,
  358. wnd,
  359. NULL,
  360. instance,
  361. NULL);
  362. break;
  363. case WM_SIZE:
  364. // Make the edit control the size of the window's client area.
  365. MoveWindow(client_status_edit_box,
  366. 0,
  367. 0,
  368. LOWORD(l_param), // width of client area.
  369. HIWORD(l_param), // height of client area.
  370. TRUE); // repaint window.
  371. break;
  372. case WM_SETFOCUS:
  373. SetFocus(client_status_edit_box);
  374. break;
  375. case WM_PAINT:
  376. hdc = BeginPaint(wnd, &ps);
  377. EndPaint(wnd, &ps);
  378. break;
  379. case WM_DESTROY:
  380. CleanUp();
  381. PostQuitMessage(0);
  382. break;
  383. default:
  384. return DefWindowProc(wnd, message, w_param, l_param);
  385. }
  386. return 0;
  387. }
  388. // Message handler for about box.
  389. INT_PTR CALLBACK About(HWND dlg,
  390. UINT message,
  391. WPARAM w_param,
  392. LPARAM l_param) {
  393. UNREFERENCED_PARAMETER(l_param);
  394. switch (message) {
  395. case WM_INITDIALOG:
  396. return (INT_PTR)TRUE;
  397. case WM_COMMAND:
  398. if (LOWORD(w_param) == IDOK || LOWORD(w_param) == IDCANCEL) {
  399. EndDialog(dlg, LOWORD(w_param));
  400. return (INT_PTR)TRUE;
  401. }
  402. break;
  403. }
  404. return (INT_PTR)FALSE;
  405. }
  406. } // namespace google_breakpad
  407. int APIENTRY _tWinMain(HINSTANCE instance,
  408. HINSTANCE previous_instance,
  409. LPTSTR command_line,
  410. int command_show) {
  411. using namespace google_breakpad;
  412. UNREFERENCED_PARAMETER(previous_instance);
  413. UNREFERENCED_PARAMETER(command_line);
  414. cs_edit = new CRITICAL_SECTION();
  415. InitializeCriticalSection(cs_edit);
  416. CustomClientInfo custom_info = {kCustomInfoEntries, kCustomInfoCount};
  417. CrashServerStart();
  418. // This is needed for CRT to not show dialog for invalid param
  419. // failures and instead let the code handle it.
  420. _CrtSetReportMode(_CRT_ASSERT, 0);
  421. handler = new ExceptionHandler(L"C:\\dumps\\",
  422. NULL,
  423. google_breakpad::ShowDumpResults,
  424. NULL,
  425. ExceptionHandler::HANDLER_ALL,
  426. MiniDumpNormal,
  427. kPipeName,
  428. &custom_info);
  429. // Initialize global strings.
  430. LoadString(instance, IDS_APP_TITLE, title, kMaxLoadString);
  431. LoadString(instance,
  432. IDC_CRASHGENERATIONAPP,
  433. window_class,
  434. kMaxLoadString);
  435. MyRegisterClass(instance);
  436. // Perform application initialization.
  437. if (!InitInstance (instance, command_show)) {
  438. return FALSE;
  439. }
  440. HACCEL accel_table = LoadAccelerators(
  441. instance,
  442. MAKEINTRESOURCE(IDC_CRASHGENERATIONAPP));
  443. // Main message loop.
  444. MSG msg;
  445. while (GetMessage(&msg, NULL, 0, 0)) {
  446. if (!TranslateAccelerator(msg.hwnd, accel_table, &msg)) {
  447. TranslateMessage(&msg);
  448. DispatchMessage(&msg);
  449. }
  450. }
  451. return (int)msg.wParam;
  452. }