/reporting/crashsender/ProgressDlg.cpp

http://crashrpt.googlecode.com/ · C++ · 499 lines · 332 code · 84 blank · 83 comment · 51 complexity · 5b5178d878f24ca03b8f5f40683f2335 MD5 · raw file

  1. /*************************************************************************************
  2. This file is a part of CrashRpt library.
  3. Copyright (c) 2003-2013 The CrashRpt project authors. All Rights Reserved.
  4. Use of this source code is governed by a BSD-style license
  5. that can be found in the License.txt file in the root of the source
  6. tree. All contributing project authors may
  7. be found in the Authors.txt file in the root of the source tree.
  8. ***************************************************************************************/
  9. #include "stdafx.h"
  10. #include "ProgressDlg.h"
  11. #include "Utility.h"
  12. #include "CrashInfoReader.h"
  13. LRESULT CProgressDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  14. {
  15. // Check if current UI language is an RTL language
  16. CErrorReportSender* pSender = CErrorReportSender::GetInstance();
  17. CString sRTL = pSender->GetLangStr(_T("Settings"), _T("RTLReading"));
  18. if(sRTL.CompareNoCase(_T("1"))==0)
  19. {
  20. // Mirror this window
  21. Utility::SetLayoutRTL(m_hWnd);
  22. }
  23. HICON hIcon = NULL;
  24. // Try to load custom icon
  25. hIcon = pSender->GetCrashInfo()->GetCustomIcon();
  26. // If there is no custom icon, load the default one
  27. if(hIcon==NULL)
  28. hIcon = ::LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME));
  29. // Set dialog icon
  30. SetIcon(hIcon, FALSE);
  31. SetIcon(hIcon, TRUE);
  32. // Set status text
  33. m_statText = GetDlgItem(IDC_TEXT);
  34. m_statText.SetWindowText(pSender->GetLangStr(_T("ProgressDlg"), _T("CollectingCrashInfo")));
  35. // Set progress bar style
  36. m_prgProgress = GetDlgItem(IDC_PROGRESS);
  37. m_prgProgress.SetRange(0, 100);
  38. m_prgProgress.ModifyStyle(0, PBS_MARQUEE);
  39. // Set up list view
  40. m_listView = GetDlgItem(IDC_LIST);
  41. m_listView.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
  42. m_listView.InsertColumn(0, _T("Status"), LVCFMT_LEFT, 2048);
  43. // Set up Cancel button
  44. m_btnCancel = GetDlgItem(IDCANCEL);
  45. m_btnCancel.SetWindowText(pSender->GetLangStr(_T("ProgressDlg"), _T("Cancel")));
  46. // Init flags
  47. m_ActionOnCancel = DONT_CLOSE;
  48. m_ActionOnClose = CLOSE_MYSELF;
  49. // Init dialog resize functionality
  50. DlgResize_Init();
  51. return TRUE;
  52. }
  53. LRESULT CProgressDlg::OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  54. {
  55. // This method is called when user clicks the close (x) button
  56. // on the dialog.
  57. if(m_ActionOnClose==CLOSE_MYSELF_AND_PARENT)
  58. {
  59. // Hide this window smoothly
  60. AnimateWindow(m_hWnd, 200, AW_HIDE|AW_BLEND);
  61. // Request parent window to close
  62. HWND hWndParent = ::GetParent(m_hWnd);
  63. ::PostMessage(hWndParent, WM_CLOSE, 0, 0);
  64. return 0;
  65. }
  66. else if(m_ActionOnClose==CLOSE_MYSELF)
  67. {
  68. // Hide this window smoothly
  69. AnimateWindow(m_hWnd, 200, AW_HIDE|AW_BLEND);
  70. return 0;
  71. }
  72. return 0;
  73. }
  74. LRESULT CProgressDlg::OnCancel(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  75. {
  76. // This method is called when user clicks the "Cancel" button
  77. // on the dialog.
  78. if(m_ActionOnCancel==CLOSE_MYSELF_AND_PARENT)
  79. {
  80. // Hide this window smoothly
  81. AnimateWindow(m_hWnd, 200, AW_HIDE|AW_BLEND);
  82. // Request parent window to close
  83. HWND hWndParent = ::GetParent(m_hWnd);
  84. ::PostMessage(hWndParent, WM_CLOSE, 0, 0);
  85. return 0;
  86. }
  87. else if(m_ActionOnCancel==CLOSE_MYSELF)
  88. {
  89. // Hide this window smoothly
  90. AnimateWindow(m_hWnd, 200, AW_HIDE|AW_BLEND);
  91. return 0;
  92. }
  93. // Start cancelling the worker thread
  94. CErrorReportSender* pSender = CErrorReportSender::GetInstance();
  95. pSender->Cancel();
  96. // Disable Cancel button
  97. m_btnCancel.EnableWindow(0);
  98. return 0;
  99. }
  100. void CProgressDlg::Start(BOOL bCollectInfo, BOOL bMakeVisible)
  101. {
  102. // This method displays the progress dialog and starts the timer
  103. // that will update the dialog periodically and react on
  104. // incoming events.
  105. CErrorReportSender* pSender = CErrorReportSender::GetInstance();
  106. // Set up correct dialog caption
  107. if(bCollectInfo)
  108. {
  109. CString sCaption;
  110. sCaption.Format(pSender->GetLangStr(_T("ProgressDlg"), _T("DlgCaption2")), pSender->GetCrashInfo()->m_sAppName);
  111. SetWindowText(sCaption);
  112. }
  113. else
  114. {
  115. CString sCaption;
  116. sCaption.Format(pSender->GetLangStr(_T("ProgressDlg"), _T("DlgCaption")), pSender->GetCrashInfo()->m_sAppName);
  117. SetWindowText(sCaption);
  118. }
  119. // Show the window on top of other windows
  120. SetWindowPos(HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
  121. // Center the dialog on the screen
  122. CenterWindow();
  123. // Check if we need to make the dialog visible
  124. if(bMakeVisible)
  125. {
  126. // Show the dialog and set focus on it
  127. ShowWindow(SW_SHOW);
  128. SetFocus();
  129. }
  130. if(!bCollectInfo)
  131. {
  132. // If we are not collecting crash information now, than hide this dialog in 3 sec.
  133. SetTimer(1, 3000);
  134. }
  135. // Update this dialog each 200 ms.
  136. SetTimer(0, 200);
  137. // If user clicks the Close button (x), do not close the window.
  138. m_ActionOnCancel = DONT_CLOSE;
  139. }
  140. void CProgressDlg::Stop()
  141. {
  142. // Stop timers
  143. KillTimer(0);
  144. KillTimer(1);
  145. }
  146. LRESULT CProgressDlg::OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  147. {
  148. // This method is called when a timer ticks.
  149. WORD wTimerId = (WORD)wParam;
  150. CErrorReportSender* pSender = CErrorReportSender::GetInstance();
  151. if(wTimerId==0) // Dialog update timer
  152. {
  153. // Get current progress
  154. int nProgressPct = 0;
  155. std::vector<CString> messages;
  156. pSender->GetCurOpStatus(nProgressPct, messages);
  157. // Update progress bar
  158. m_prgProgress.SetPos(nProgressPct);
  159. int attempt = 0; // Sending attempt
  160. // Walk through incoming messages and look for special ones (enclosed in [ ])
  161. unsigned i;
  162. for(i=0; i<messages.size(); i++)
  163. {
  164. if(messages[i].CompareNoCase(_T("[creating_dump]"))==0)
  165. {
  166. // Creating minidump
  167. m_ActionOnCancel = DONT_CLOSE;
  168. m_ActionOnClose = CLOSE_MYSELF_AND_PARENT;
  169. m_statText.SetWindowText(pSender->GetLangStr(_T("ProgressDlg"), _T("CollectingCrashInfo")));
  170. }
  171. else if(messages[i].CompareNoCase(_T("[copying_files]"))==0)
  172. {
  173. // Copying files
  174. m_ActionOnCancel = DONT_CLOSE;
  175. m_ActionOnClose = CLOSE_MYSELF_AND_PARENT;
  176. // Remove marquee style from progress bar
  177. m_prgProgress.ModifyStyle(PBS_MARQUEE, 0);
  178. }
  179. else if(messages[i].CompareNoCase(_T("[confirm_send_report]"))==0)
  180. {
  181. // User should consent to send error report, so we hide this dialog
  182. // and send a message to our parent dialog that will receive user input.
  183. m_ActionOnCancel = CLOSE_MYSELF_AND_PARENT;
  184. ShowWindow(SW_HIDE);
  185. HWND hWndParent = ::GetParent(m_hWnd);
  186. ::PostMessage(hWndParent, WM_COMPLETECOLLECT, 0, 0);
  187. }
  188. else if(messages[i].CompareNoCase(_T("[exporting_report]"))==0)
  189. {
  190. // Exporting error report as a ZIP archive
  191. m_ActionOnCancel = DONT_CLOSE;
  192. m_ActionOnClose = DONT_CLOSE;
  193. CString sCaption;
  194. sCaption.Format(pSender->GetLangStr(_T("ProgressDlg"), _T("DlgCaptionExport")),
  195. pSender->GetCrashInfo()->m_sAppName);
  196. SetWindowText(sCaption);
  197. m_statText.SetWindowText(pSender->GetLangStr(_T("ProgressDlg"), _T("CompressingFiles")));
  198. m_btnCancel.SetWindowText(pSender->GetLangStr(_T("ProgressDlg"), _T("Cancel")));
  199. ShowWindow(SW_SHOW);
  200. }
  201. else if(messages[i].CompareNoCase(_T("[end_exporting_report_ok]"))==0)
  202. {
  203. // End exporting error report
  204. m_ActionOnCancel = CLOSE_MYSELF;
  205. ShowWindow(SW_HIDE);
  206. }
  207. else if(messages[i].CompareNoCase(_T("[end_exporting_report_failed]"))==0)
  208. {
  209. // Failed to export error report
  210. m_ActionOnCancel = CLOSE_MYSELF;
  211. m_ActionOnClose = CLOSE_MYSELF;
  212. m_statText.SetWindowText(pSender->GetLangStr(_T("ProgressDlg"), _T("ExportedWithErrors")));
  213. m_btnCancel.EnableWindow(1);
  214. m_btnCancel.SetWindowText(pSender->GetLangStr(_T("ProgressDlg"), _T("Close")));
  215. }
  216. else if(messages[i].CompareNoCase(_T("[compressing_files]"))==0)
  217. {
  218. // Compressing error report files
  219. m_ActionOnCancel = DONT_CLOSE;
  220. m_ActionOnClose = CLOSE_MYSELF;
  221. m_statText.SetWindowText(pSender->GetLangStr(_T("ProgressDlg"), _T("CompressingFiles")));
  222. m_btnCancel.SetWindowText(pSender->GetLangStr(_T("ProgressDlg"), _T("Cancel")));
  223. }
  224. else if(messages[i].CompareNoCase(_T("[end_compressing_files]"))==0)
  225. {
  226. // File compression finished
  227. if(!pSender->GetCrashInfo()->m_bSendErrorReport && pSender->GetCrashInfo()->m_bStoreZIPArchives)
  228. {
  229. m_ActionOnCancel = CLOSE_MYSELF;
  230. m_ActionOnClose = CLOSE_MYSELF;
  231. HWND hWndParent = ::GetParent(m_hWnd);
  232. ::PostMessage(hWndParent, WM_CLOSE, 0, 0);
  233. }
  234. }
  235. else if(messages[i].CompareNoCase(_T("[status_success]"))==0)
  236. {
  237. // Error report has been delivered ok
  238. m_ActionOnCancel = CLOSE_MYSELF_AND_PARENT;
  239. m_ActionOnClose = CLOSE_MYSELF_AND_PARENT;
  240. // Close the parent dialog.
  241. HWND hWndParent = ::GetParent(m_hWnd);
  242. ::PostMessage(hWndParent, WM_CLOSE, 0, 0);
  243. }
  244. else if(messages[i].CompareNoCase(_T("[status_failed]"))==0)
  245. {
  246. // Error report delivery has failed
  247. m_ActionOnCancel = CLOSE_MYSELF_AND_PARENT;
  248. m_ActionOnClose = CLOSE_MYSELF_AND_PARENT;
  249. // Stop timer
  250. KillTimer(1);
  251. // Update status text.
  252. m_statText.SetWindowText(pSender->GetLangStr(_T("ProgressDlg"), _T("CompletedWithErrors")));
  253. // Enable "Close" button
  254. m_btnCancel.EnableWindow(1);
  255. m_btnCancel.SetWindowText(pSender->GetLangStr(_T("ProgressDlg"), _T("Close")));
  256. // Show the dialog
  257. ShowWindow(SW_SHOW);
  258. }
  259. else if(messages[i].CompareNoCase(_T("[exit_silently]"))==0)
  260. {
  261. // Silent exit
  262. m_ActionOnCancel = CLOSE_MYSELF_AND_PARENT;
  263. m_ActionOnClose = CLOSE_MYSELF_AND_PARENT;
  264. // Stop timer
  265. KillTimer(1);
  266. // Close the parent dialog.
  267. HWND hWndParent = ::GetParent(m_hWnd);
  268. ::PostMessage(hWndParent, WM_CLOSE, 0, 0);
  269. }
  270. else if(messages[i].CompareNoCase(_T("[cancelled_by_user]"))==0)
  271. {
  272. // The operation was cancelled by user
  273. m_statText.SetWindowText(pSender->GetLangStr(_T("ProgressDlg"), _T("Cancelling")));
  274. }
  275. else if(messages[i].CompareNoCase(_T("[sending_attempt]"))==0)
  276. {
  277. // Trying to send error report using another method
  278. attempt ++;
  279. CString str;
  280. str.Format(pSender->GetLangStr(_T("ProgressDlg"), _T("StatusText")), attempt);
  281. m_statText.SetWindowText(str);
  282. }
  283. else if(messages[i].CompareNoCase(_T("[confirm_launch_email_client]"))==0)
  284. {
  285. // User should confirm he allows to launch email client
  286. KillTimer(1);
  287. // Show the dialog
  288. ShowWindow(SW_SHOW);
  289. // Determine window mirroring settings.
  290. DWORD dwFlags = 0;
  291. CString sRTL = pSender->GetLangStr(_T("Settings"), _T("RTLReading"));
  292. if(sRTL.CompareNoCase(_T("1"))==0)
  293. dwFlags = MB_RTLREADING;
  294. // Display the message box, so user to be able to confirm.
  295. CString sMailClientName;
  296. CMailMsg::DetectMailClient(sMailClientName);
  297. CString msg;
  298. msg.Format(pSender->GetLangStr(_T("ProgressDlg"), _T("ConfirmLaunchEmailClient")), sMailClientName);
  299. CString sCaption = pSender->GetLangStr(_T("ProgressDlg"), _T("DlgCaption"));
  300. CString sTitle;
  301. sTitle.Format(sCaption, pSender->GetCrashInfo()->m_sAppName);
  302. INT_PTR result = MessageBox(msg,
  303. sTitle,
  304. MB_OKCANCEL|MB_ICONQUESTION|dwFlags);
  305. // Unblock worker thread.
  306. pSender->FeedbackReady(result==IDOK?0:1);
  307. // Hide the dialog
  308. ShowWindow(SW_HIDE);
  309. }
  310. // Ensure the last item of the log is visible
  311. int count = m_listView.GetItemCount();
  312. int indx = m_listView.InsertItem(count, messages[i]);
  313. m_listView.EnsureVisible(indx, TRUE);
  314. }
  315. }
  316. else if(wTimerId==1) // The timer that hides this window
  317. {
  318. // Hide the window smoothly
  319. AnimateWindow(m_hWnd, 200, AW_HIDE|AW_BLEND);
  320. // Stop the timer
  321. KillTimer(1);
  322. }
  323. return 0;
  324. }
  325. LRESULT CProgressDlg::OnListRClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
  326. {
  327. // User right-clicks the log area. We should display context menu.
  328. CErrorReportSender* pSender = CErrorReportSender::GetInstance();
  329. LPNMITEMACTIVATE lpnmitem = (LPNMITEMACTIVATE) pnmh;
  330. POINT pt;
  331. GetCursorPos(&pt);
  332. CMenu popup_menu;
  333. popup_menu.LoadMenu(IDR_POPUPMENU);
  334. CMenu submenu = popup_menu.GetSubMenu(0);
  335. if(lpnmitem->iItem<0)
  336. {
  337. submenu.EnableMenuItem(ID_MENU1_COPYSEL, MF_BYCOMMAND|MF_GRAYED);
  338. }
  339. CString sCopySelLines = pSender->GetLangStr(_T("ProgressDlg"), _T("CopySelectedLines"));
  340. CString sCopyWholeLog = pSender->GetLangStr(_T("ProgressDlg"), _T("CopyTheWholeLog"));
  341. MENUITEMINFO mii;
  342. memset(&mii, 0, sizeof(MENUITEMINFO));
  343. mii.cbSize = sizeof(MENUITEMINFO);
  344. mii.fMask = MIIM_STRING;
  345. mii.dwTypeData = sCopySelLines.GetBuffer(0);
  346. mii.cch = sCopySelLines.GetLength();
  347. submenu.SetMenuItemInfo(ID_MENU1_COPYSEL, FALSE, &mii);
  348. mii.dwTypeData = sCopyWholeLog.GetBuffer(0);
  349. mii.cch = sCopyWholeLog.GetLength();
  350. submenu.SetMenuItemInfo(ID_MENU1_COPYLOG, FALSE, &mii);
  351. submenu.TrackPopupMenu(TPM_LEFTALIGN, pt.x, pt.y, m_hWnd);
  352. return 0;
  353. }
  354. LRESULT CProgressDlg::OnCopySel(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  355. {
  356. // User wants to copy selected lines to clipboard.
  357. CString sData;
  358. int i;
  359. for(i=0; i<m_listView.GetItemCount(); i++)
  360. {
  361. DWORD dwState = m_listView.GetItemState(i, LVIS_SELECTED);
  362. if(dwState==0)
  363. continue;
  364. TCHAR buf[4096];
  365. buf[0]=0;
  366. int n = m_listView.GetItemText(i, 0, buf, 4095);
  367. sData += CString(buf,n);
  368. sData += "\r\n";
  369. }
  370. SetClipboard(sData);
  371. return 0;
  372. }
  373. LRESULT CProgressDlg::OnCopyLog(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  374. {
  375. // User wants to copy the entire log to clipboard.
  376. CString sData;
  377. int i;
  378. for(i=0; i<m_listView.GetItemCount(); i++)
  379. {
  380. TCHAR buf[4096];
  381. buf[0]=0;
  382. int n = m_listView.GetItemText(i, 0, buf, 4095);
  383. sData += CString(buf,n);
  384. sData += "\r\n";
  385. }
  386. SetClipboard(sData);
  387. return 0;
  388. }
  389. int CProgressDlg::SetClipboard(CString& sData)
  390. {
  391. // This method places the data to clipboard.
  392. if (OpenClipboard())
  393. {
  394. EmptyClipboard();
  395. HGLOBAL hClipboardData;
  396. DWORD dwSize = (sData.GetLength()+1)*sizeof(TCHAR);
  397. hClipboardData = GlobalAlloc(GMEM_DDESHARE, dwSize);
  398. TCHAR* pszData = (TCHAR*)GlobalLock(hClipboardData);
  399. if(pszData!=NULL)
  400. {
  401. _TCSNCPY_S(pszData, dwSize/sizeof(TCHAR), sData, sData.GetLength()*sizeof(TCHAR));
  402. GlobalUnlock(hClipboardData);
  403. #ifdef _UNICODE
  404. SetClipboardData(CF_UNICODETEXT, hClipboardData);
  405. #else
  406. SetClipboardData(CF_TEXT, hClipboardData);
  407. #endif
  408. CloseClipboard();
  409. return 0;
  410. }
  411. CloseClipboard();
  412. }
  413. return 1;
  414. }