llcrashloggerwindows.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:11k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2. * @file llcrashloggerwindows.cpp
  3. * @brief Windows crash logger implementation
  4. *
  5. * $LicenseInfo:firstyear=2003&license=viewergpl$
  6. * Copyright (c) 2003-2010, Linden Research, Inc.
  7. * Second Life Viewer Source Code
  8. * The source code in this file ("Source Code") is provided by Linden Lab
  9. * to you under the terms of the GNU General Public License, version 2.0
  10. * ("GPL"), unless you have obtained a separate licensing agreement
  11. * ("Other License"), formally executed by you and Linden Lab.  Terms of
  12. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  13. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  14. * There are special exceptions to the terms and conditions of the GPL as
  15. * it is applied to this Source Code. View the full text of the exception
  16. * in the file doc/FLOSS-exception.txt in this software distribution, or
  17. * online at
  18. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  19. * By copying, modifying or distributing this software, you acknowledge
  20. * that you have read and understood your obligations described above,
  21. * and agree to abide by those obligations.
  22. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  23. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  24. * COMPLETENESS OR PERFORMANCE.
  25. * $/LicenseInfo$
  26. */
  27. #include "linden_common.h"
  28. #include "stdafx.h"
  29. #include "resource.h"
  30. #include "llcrashloggerwindows.h"
  31. #include <sstream>
  32. #include "boost/tokenizer.hpp"
  33. #include "dbghelp.h"
  34. #include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME
  35. #include "llerror.h"
  36. #include "llfile.h"
  37. #include "lltimer.h"
  38. #include "llstring.h"
  39. #include "lldxhardware.h"
  40. #include "lldir.h"
  41. #include "llsdserialize.h"
  42. #define MAX_LOADSTRING 100
  43. #define MAX_STRING 2048
  44. const char* const SETTINGS_FILE_HEADER = "version";
  45. const S32 SETTINGS_FILE_VERSION = 101;
  46. // Windows Message Handlers
  47. // Global Variables:
  48. HINSTANCE hInst= NULL; // current instance
  49. TCHAR szTitle[MAX_LOADSTRING]; /* Flawfinder: ignore */ // The title bar text
  50. TCHAR szWindowClass[MAX_LOADSTRING]; /* Flawfinder: ignore */ // The title bar text
  51. std::string gProductName;
  52. HWND gHwndReport = NULL; // Send/Don't Send dialog
  53. HWND gHwndProgress = NULL; // Progress window
  54. HCURSOR gCursorArrow = NULL;
  55. HCURSOR gCursorWait = NULL;
  56. BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialog?
  57. std::stringstream gDXInfo;
  58. bool gSendLogs = false;
  59. //Conversion from char* to wchar*
  60. //Replacement for ATL macros, doesn't allocate memory
  61. //For more info see: http://www.codeguru.com/forum/showthread.php?t=337247
  62. void ConvertLPCSTRToLPWSTR (const char* pCstring, WCHAR* outStr)
  63. {
  64.     if (pCstring != NULL)
  65.     {
  66.         int nInputStrLen = strlen (pCstring);
  67.         // Double NULL Termination
  68.         int nOutputStrLen = MultiByteToWideChar(CP_ACP, 0, pCstring, nInputStrLen, NULL, 0) + 2;
  69.         if (outStr)
  70.         {
  71.             memset (outStr, 0x00, sizeof (WCHAR)*nOutputStrLen);
  72.             MultiByteToWideChar (CP_ACP, 0, pCstring, nInputStrLen, outStr, nInputStrLen);
  73.         }
  74.     }
  75. }
  76. void write_debug(const char *str)
  77. {
  78. gDXInfo << str; /* Flawfinder: ignore */
  79. }
  80. void write_debug(std::string& str)
  81. {
  82. write_debug(str.c_str());
  83. }
  84. void show_progress(const std::string& message)
  85. {
  86. std::wstring msg = wstring_to_utf16str(utf8str_to_wstring(message));
  87. if (gHwndProgress)
  88. {
  89. SendDlgItemMessage(gHwndProgress,       // handle to destination window 
  90. IDC_LOG,
  91. WM_SETTEXT, // message to send
  92. FALSE, // undo option
  93. (LPARAM)msg.c_str());
  94. }
  95. }
  96. void update_messages()
  97. {
  98. MSG msg;
  99. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  100. {
  101. if (msg.message == WM_QUIT)
  102. {
  103. exit(0);
  104. }
  105. TranslateMessage(&msg);
  106. DispatchMessage(&msg);
  107. }
  108. }
  109. void sleep_and_pump_messages( U32 seconds )
  110. {
  111. const U32 CYCLES_PER_SECOND = 10;
  112. U32 cycles = seconds * CYCLES_PER_SECOND;
  113. while( cycles-- )
  114. {
  115. update_messages();
  116. ms_sleep(1000 / CYCLES_PER_SECOND);
  117. }
  118. }
  119. // Include product name in the window caption.
  120. void LLCrashLoggerWindows::ProcessCaption(HWND hWnd)
  121. {
  122. TCHAR templateText[MAX_STRING]; /* Flawfinder: ignore */
  123. TCHAR header[MAX_STRING];
  124. std::string final;
  125. GetWindowText(hWnd, templateText, sizeof(templateText));
  126. final = llformat(ll_convert_wide_to_string(templateText).c_str(), gProductName.c_str());
  127. ConvertLPCSTRToLPWSTR(final.c_str(), header);
  128. SetWindowText(hWnd, header);
  129. }
  130. // Include product name in the diaog item text.
  131. void LLCrashLoggerWindows::ProcessDlgItemText(HWND hWnd, int nIDDlgItem)
  132. {
  133. TCHAR templateText[MAX_STRING]; /* Flawfinder: ignore */
  134. TCHAR header[MAX_STRING];
  135. std::string final;
  136. GetDlgItemText(hWnd, nIDDlgItem, templateText, sizeof(templateText));
  137. final = llformat(ll_convert_wide_to_string(templateText).c_str(), gProductName.c_str());
  138. ConvertLPCSTRToLPWSTR(final.c_str(), header);
  139. SetDlgItemText(hWnd, nIDDlgItem, header);
  140. }
  141. bool handle_button_click(WORD button_id)
  142. {
  143. // Is this something other than Send or Don't Send?
  144. if (button_id != IDOK
  145. && button_id != IDCANCEL)
  146. {
  147. return false;
  148. }
  149. // See if "do this next time" is checked and save state
  150. S32 crash_behavior = CRASH_BEHAVIOR_ASK;
  151. LRESULT result = SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_GETCHECK, 0, 0);
  152. if (result == BST_CHECKED)
  153. {
  154. if (button_id == IDOK)
  155. {
  156. crash_behavior = CRASH_BEHAVIOR_ALWAYS_SEND;
  157. }
  158. else if (button_id == IDCANCEL)
  159. {
  160. crash_behavior = CRASH_BEHAVIOR_NEVER_SEND;
  161. }
  162. ((LLCrashLoggerWindows*)LLCrashLogger::instance())->saveCrashBehaviorSetting(crash_behavior);
  163. }
  164. // We're done with this dialog.
  165. gFirstDialog = FALSE;
  166. // Send the crash report if requested
  167. if (button_id == IDOK)
  168. {
  169. gSendLogs = TRUE;
  170. WCHAR wbuffer[20000];
  171. GetDlgItemText(gHwndReport, // handle to dialog box
  172. IDC_EDIT1,  // control identifier
  173. wbuffer, // pointer to buffer for text
  174. 20000 // maximum size of string
  175. );
  176. std::string user_text(ll_convert_wide_to_string(wbuffer));
  177. // Activate and show the window.
  178. ShowWindow(gHwndProgress, SW_SHOW); 
  179. // Try doing this second to make the progress window go frontmost.
  180. ShowWindow(gHwndReport, SW_HIDE);
  181. ((LLCrashLoggerWindows*)LLCrashLogger::instance())->setUserText(user_text);
  182. ((LLCrashLoggerWindows*)LLCrashLogger::instance())->sendCrashLogs();
  183. }
  184. // Quit the app
  185. LLApp::setQuitting();
  186. return true;
  187. }
  188. LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
  189. {
  190. switch( message )
  191. {
  192. case WM_CREATE:
  193. return 0;
  194. case WM_COMMAND:
  195. if( gFirstDialog )
  196. {
  197. WORD button_id = LOWORD(wParam);
  198. bool handled = handle_button_click(button_id);
  199. if (handled)
  200. {
  201. return 0;
  202. }
  203. }
  204. break;
  205. case WM_DESTROY:
  206. // Closing the window cancels
  207. LLApp::setQuitting();
  208. PostQuitMessage(0);
  209. return 0;
  210. }
  211. return DefWindowProc(hwnd, message, wParam, lParam);
  212. }
  213. LLCrashLoggerWindows::LLCrashLoggerWindows(void)
  214. {
  215. }
  216. LLCrashLoggerWindows::~LLCrashLoggerWindows(void)
  217. {
  218. }
  219. bool LLCrashLoggerWindows::init(void)
  220. {
  221. bool ok = LLCrashLogger::init();
  222. if(!ok) return false;
  223. /*
  224. mbstowcs( gProductName, mProductName.c_str(), LL_ARRAY_SIZE(gProductName) );
  225. gProductName[ LL_ARRY_SIZE(gProductName) - 1 ] = 0;
  226. swprintf(gProductName, L"Second Life");
  227. */
  228. llinfos << "Loading dialogs" << llendl;
  229. // Initialize global strings
  230. LoadString(mhInst, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
  231. LoadString(mhInst, IDC_WIN_CRASH_LOGGER, szWindowClass, MAX_LOADSTRING);
  232. gCursorArrow = LoadCursor(NULL, IDC_ARROW);
  233. gCursorWait = LoadCursor(NULL, IDC_WAIT);
  234. // Register a window class that will be used by our dialogs
  235. WNDCLASS wndclass;
  236. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  237. wndclass.lpfnWndProc = WndProc;
  238. wndclass.cbClsExtra = 0;
  239. wndclass.cbWndExtra = DLGWINDOWEXTRA;  // Required, since this is used for dialogs!
  240. wndclass.hInstance = mhInst;
  241. wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE( IDI_WIN_CRASH_LOGGER ) );
  242. wndclass.hCursor = gCursorArrow;
  243. wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
  244. wndclass.lpszMenuName = NULL;
  245. wndclass.lpszClassName = szWindowClass;
  246. RegisterClass( &wndclass );
  247. return true;
  248. }
  249. void LLCrashLoggerWindows::gatherPlatformSpecificFiles()
  250. {
  251. updateApplication("Gathering hardware information. App may appear frozen.");
  252. // DX hardware probe blocks, so we can't cancel during it
  253. //Generate our dx_info.log file 
  254. SetCursor(gCursorWait);
  255. // At this point we're responsive enough the user could click the close button
  256. SetCursor(gCursorArrow);
  257. mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo();
  258. mFileMap["CrashLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLifeException.log");
  259. }
  260. bool LLCrashLoggerWindows::mainLoop()
  261. {
  262. // Note: parent hwnd is 0 (the desktop).  No dlg proc.  See Petzold (5th ed) HexCalc example, Chapter 11, p529
  263. // win_crash_logger.rc has been edited by hand.
  264. // Dialogs defined with CLASS "WIN_CRASH_LOGGER" (must be same as szWindowClass)
  265. gProductName = mProductName;
  266. gHwndProgress = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROGRESS), 0, NULL);
  267. ProcessCaption(gHwndProgress);
  268. ShowWindow(gHwndProgress, SW_HIDE );
  269. if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND)
  270. {
  271. ShowWindow(gHwndProgress, SW_SHOW );
  272. sendCrashLogs();
  273. }
  274. else if (mCrashBehavior == CRASH_BEHAVIOR_ASK)
  275. {
  276. gHwndReport = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PREVREPORTBOX), 0, NULL);
  277. // Ignore result
  278. (void) SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_SETCHECK, 0, 0);
  279. // Include the product name in the caption and various dialog items.
  280. ProcessCaption(gHwndReport);
  281. ProcessDlgItemText(gHwndReport, IDC_STATIC_MSG);
  282. // Update the header to include whether or not we crashed on the last run.
  283. std::string headerStr;
  284. TCHAR header[MAX_STRING];
  285. if (mCrashInPreviousExec)
  286. {
  287. headerStr = llformat("%s appears to have crashed or frozen the last time it ran.", mProductName.c_str());
  288. }
  289. else
  290. {
  291. headerStr = llformat("%s appears to have crashed.", mProductName.c_str());
  292. }
  293. ConvertLPCSTRToLPWSTR(headerStr.c_str(), header);
  294. SetDlgItemText(gHwndReport, IDC_STATIC_HEADER, header);
  295. ShowWindow(gHwndReport, SW_SHOW );
  296. MSG msg;
  297. memset(&msg, 0, sizeof(msg));
  298. while (!LLApp::isQuitting() && GetMessage(&msg, NULL, 0, 0))
  299. {
  300. TranslateMessage(&msg);
  301. DispatchMessage(&msg);
  302. }
  303. return msg.wParam;
  304. }
  305. else
  306. {
  307. llwarns << "Unknown crash behavior " << mCrashBehavior << llendl;
  308. return 1;
  309. }
  310. return 0;
  311. }
  312. void LLCrashLoggerWindows::updateApplication(const std::string& message)
  313. {
  314. LLCrashLogger::updateApplication();
  315. if(!message.empty()) show_progress(message);
  316. update_messages();
  317. }
  318. bool LLCrashLoggerWindows::cleanup()
  319. {
  320. if(gSendLogs)
  321. {
  322. if(mSentCrashLogs) show_progress("Done");
  323. else show_progress("Could not connect to servers, logs not sent");
  324. sleep_and_pump_messages(3);
  325. }
  326. PostQuitMessage(0);
  327. return true;
  328. }