Sync DrDump crash handler with TortoiseSVN codebase
[TortoiseGit.git] / ext / CrashServer / CrashHandler / SendRpt / CrashProcessor.cpp
blob5495ba3f853496c240640bc4a1d80e7d3d6cc5f7
1 // Copyright 2014 Idol Software, Inc.
2 //
3 // This file is part of Doctor Dump SDK.
4 //
5 // Doctor Dump SDK is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "stdafx.h"
19 #include "Serializer.h"
20 #include "DumpWriter.h"
21 #include "../../CommonLibs/Zlib/ZipUnzip.h"
22 #include "../../CommonLibs/Log/log.h"
23 #include "../../CommonLibs/Log/log_media.h"
24 #include "../../CommonLibs/Stat/stat.h"
25 #include "SendReportDlg.h"
26 #include "DoctorDump.h"
27 #include "../CrashHandler/CrashHandler.h"
28 #include "CrashInfo.h"
30 using namespace std;
32 BOOL IsWow64()
34 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
35 LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
37 BOOL bIsWow64 = FALSE;
39 HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32"));
40 if (NULL != hKernel32)
41 fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(hKernel32,"IsWow64Process");
43 if (NULL != fnIsWow64Process)
44 fnIsWow64Process(GetCurrentProcess(), &bIsWow64);
46 return bIsWow64;
49 CAtlStringW ToString(int n)
51 CAtlStringW result;
52 result.Format(L"%i", n);
53 return result;
56 bool g_cancel = false;
58 class UI: public doctor_dump::IUploadProgress
60 CHandle m_progressWindowThread;
61 CWindow* volatile m_progressWindow;
62 Translator m_translator;
63 bool m_additionalInfoAlreadyApproved;
64 bool m_serviceMode;
65 CStringW m_privacyPolicyUrl;
67 public:
68 UI(Config& config)
69 : m_progressWindow(NULL)
70 , m_translator(config.AppName, config.Company, GetModuleHandle(NULL), IDR_TRANSLATE_INI, config.LangFilePath)
71 , m_additionalInfoAlreadyApproved(config.SendAdditionalDataWithoutApproval != FALSE)
72 , m_serviceMode(!!config.ServiceMode)
73 , m_privacyPolicyUrl(config.PrivacyPolicyUrl)
77 ~UI()
79 CloseProgressWindow(true);
82 void OnProgress(SIZE_T total, SIZE_T sent) override
84 if (m_progressWindow)
85 m_progressWindow->PostMessage(WM_USER, total, sent);
88 void ShowInitialProgressWindow(bool wasAssert)
90 if (m_serviceMode)
91 return;
93 CloseProgressWindow();
94 m_progressWindowThread.Attach(CreateThread(NULL, 0, wasAssert ? SendAssertReportDlgThread : SendReportDlgThread, this, 0, NULL));
95 if (!m_progressWindowThread)
96 throw runtime_error("Failed to create thread");
99 void ShowFullDumpUploadProgressWindow()
101 if (m_serviceMode)
102 return;
104 CloseProgressWindow();
105 m_progressWindowThread.Attach(CreateThread(NULL, 0, SendFullDumpDlgThread, this, 0, NULL));
106 if (!m_progressWindowThread)
107 throw runtime_error("Failed to create thread");
108 Sleep(100); // Give time to draw a dialog before writing a dump (it will freeze a dialog for unknown reasons)
111 bool AskSendFullDump()
113 if (m_serviceMode)
114 return true;
116 CloseProgressWindow();
118 if (!m_additionalInfoAlreadyApproved && IDCANCEL == CAskSendFullDumpDlg(m_translator, m_privacyPolicyUrl).DoModal())
119 return false;
121 m_additionalInfoAlreadyApproved = true;
123 return true;
126 bool AskGetSolution(CSolutionDlg::Type type)
128 if (m_serviceMode)
129 return true;
131 CloseProgressWindow();
132 return IDOK == CSolutionDlg(m_translator, type).DoModal();
135 void Test()
137 ShowInitialProgressWindow(false);
138 while (!g_cancel)
139 Sleep(10);
140 g_cancel = false;
142 ShowInitialProgressWindow(true);
143 while (!g_cancel)
144 Sleep(10);
145 g_cancel = false;
147 AskSendFullDump();
149 ShowFullDumpUploadProgressWindow();
150 Sleep(3000);
151 for (int i = 0; m_progressWindow && i < 100; ++i)
153 m_progressWindow->PostMessage(WM_USER, 100, i);
154 Sleep(30);
157 AskGetSolution(CSolutionDlg::Read);
159 AskGetSolution(CSolutionDlg::Install);
162 private:
163 void SendReportDlg()
165 CSendReportDlg dlg(m_translator);
166 assert(!m_progressWindow);
167 m_progressWindow = &dlg;
168 if (dlg.DoModal() == IDCANCEL)
169 g_cancel = true;
170 m_progressWindow = NULL;
173 static DWORD WINAPI SendReportDlgThread(LPVOID param)
175 static_cast<UI*>(param)->SendReportDlg();
176 return 0;
179 void SendAssertReportDlg()
181 CSendAssertReportDlg dlg(m_translator);
182 assert(!m_progressWindow);
183 m_progressWindow = &dlg;
184 if (dlg.DoModal() == IDCANCEL)
185 g_cancel = true;
186 m_progressWindow = NULL;
189 static DWORD WINAPI SendAssertReportDlgThread(LPVOID param)
191 static_cast<UI*>(param)->SendAssertReportDlg();
192 return 0;
195 void SendFullDumpDlg()
197 CSendFullDumpDlg dlg(m_translator);
198 assert(!m_progressWindow);
199 m_progressWindow = &dlg;
200 if (dlg.DoModal() == IDCANCEL)
201 g_cancel = true;
202 m_progressWindow = NULL;
205 static DWORD WINAPI SendFullDumpDlgThread(LPVOID param)
207 static_cast<UI*>(param)->SendFullDumpDlg();
208 return 0;
211 void CloseProgressWindow(bool cancel = false)
213 if (!m_progressWindowThread)
214 return;
215 Sleep(100); // It could be that m_pProgressDlg->DoModal not yet created a window
216 if (m_progressWindow)
217 m_progressWindow->PostMessage(WM_CLOSE);
218 WaitForSingleObject(m_progressWindowThread, INFINITE);
219 m_progressWindowThread.Close();
220 if (!cancel)
221 g_cancel = false;
225 class CrashProcessor
227 Log& m_log;
228 Config& m_config;
230 unique_ptr<CrashInfo> m_crashInfo;
231 CStringW m_workingFolder;
232 CStringW m_miniDumpFile;
233 CStringW m_miniDumpZipFile;
234 CStringW m_fullDumpFile;
235 CStringW m_fullDumpZipFile;
236 CStringW m_infoDll;
237 CStringW m_infoFile;
238 CStringW m_patch;
239 DumpWriter m_dumpWriter;
240 doctor_dump::DumpUploaderWebServiceEx m_dumpUploader;
242 public:
243 CrashProcessor(Log& log, Config& config)
244 : m_log(log)
245 , m_config(config)
246 , m_dumpWriter(log)
247 , m_dumpUploader(log)
251 ~CrashProcessor()
253 if (!m_fullDumpFile.IsEmpty())
254 DeleteFile(m_fullDumpFile);
255 if (!m_miniDumpFile.IsEmpty())
256 DeleteFile(m_miniDumpFile);
257 if (!m_config.LeaveDumpFilesInTempFolder)
259 if (!m_fullDumpZipFile.IsEmpty())
260 DeleteFile(m_fullDumpZipFile);
261 if (!m_miniDumpZipFile.IsEmpty())
262 DeleteFile(m_miniDumpZipFile);
263 if (!m_workingFolder.IsEmpty())
264 RemoveDirectory(m_workingFolder);
268 void InitPathes()
270 GetTempPath(MAX_PATH, m_workingFolder.GetBuffer(MAX_PATH));
271 m_workingFolder.ReleaseBuffer();
273 SYSTEMTIME st;
274 GetLocalTime(&st);
276 CStringW t;
277 t.Format(L"%ls_%d.%d.%d.%d_%04d%02d%02d_%02d%02d%02d",
278 (LPCWSTR)m_config.Prefix,
279 m_config.V[0], m_config.V[1], m_config.V[2], m_config.V[3],
280 (int)st.wYear, (int)st.wMonth, (int)st.wDay, (int)st.wHour, (int)st.wMinute, (int)st.wSecond);
282 m_workingFolder += t;
283 m_miniDumpFile = m_workingFolder + _T("\\") + t + _T(".mini.dmp");
284 m_miniDumpZipFile = m_workingFolder + _T("\\doctor_dump_mini.zip");
285 m_fullDumpFile = m_workingFolder + _T("\\") + t + _T(".full.dmp");
286 m_fullDumpZipFile = m_workingFolder + _T("\\doctor_dump_full.zip");
287 m_infoDll = m_workingFolder + _T("\\info.dll");
288 m_infoFile = m_workingFolder + _T("\\info.zip");
289 m_patch = m_workingFolder + _T("\\solution.exe");
291 if (!CreateDirectory(m_workingFolder, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
292 throw std::runtime_error("failed to create temp directory");
295 int GetUserPCID() const
297 int PCID = 12345;
298 HKEY hCryptography;
299 #if defined (_WIN64)
300 DWORD param = 0;
301 #else
302 DWORD param = IsWow64() ? KEY_WOW64_64KEY : 0;
303 #endif
304 if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Cryptography"), 0, KEY_READ|param, &hCryptography))
306 TCHAR guid[1024];
307 DWORD size = sizeof(guid);
308 if (ERROR_SUCCESS == RegQueryValueEx(hCryptography, _T("MachineGuid"), NULL, NULL, (LPBYTE)guid, &size))
310 DWORD D1 = 0, D2 = 0, D3 = 0, D4 = 0, D5 = 0, D6 = 0;
311 _stscanf_s(guid, _T("%08x-%04x-%04x-%04x-%04x%08x"), &D1, &D2, &D3, &D4, &D5, &D6);
312 DWORD DD1 = MAKELONG(D2, D3);
313 DWORD DD2 = MAKELONG(D4, D5);
314 PCID = D1 ^ MAKELONG(D3, D2) ^ MAKELONG(D5, D4) ^ D6;
316 RegCloseKey(hCryptography);
318 m_log.Info(_T("Machine ID 0x%08X"), PCID);
319 return PCID;
322 void AppendUserInfo(const CStringW& dumpFile, Zip& zip)
324 CStringW crashInfoFile = m_workingFolder + L"\\crashinfo.xml";
325 if (m_crashInfo->GetCrashInfoFile(crashInfoFile))
326 m_config.FilesToAttach.push_back(std::make_pair<CStringW, CStringW>(CStringW(crashInfoFile), L"crashinfo.xml"));
328 CStringW crashUserInfoFile = m_workingFolder + L"\\crashuserinfo.xml";
329 if (m_config.UserInfo.size())
331 FILE* f = NULL;
332 if (0 == _wfopen_s(&f, crashUserInfoFile, L"wt,ccs=UTF-8"))
334 fwprintf_s(f, L"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<UserInfo>\n");
335 for (auto it = m_config.UserInfo.cbegin(), end = m_config.UserInfo.cend(); it != end; ++it)
337 m_log.Info(_T("Adding UserInfo \"%ls\" as \"%ls\"..."), static_cast<LPCWSTR>(it->first), static_cast<LPCWSTR>(it->second));
338 fwprintf_s(f,
339 L"<%ls>%ls</%ls>\n",
340 static_cast<LPCWSTR>(it->first),
341 static_cast<LPCWSTR>(it->second),
342 static_cast<LPCWSTR>(it->first));
344 fwprintf_s(f, L"</UserInfo>");
345 fclose(f);
346 m_config.FilesToAttach.push_back(std::make_pair<CStringW, CStringW>(CStringW(crashUserInfoFile), L"crashuserinfo.xml"));
350 WIN32_FIND_DATAW ff;
351 FindClose(FindFirstFileW(dumpFile, &ff));
352 __int64 attachedSizeLimit = max(1024*1024I64, (static_cast<__int64>(ff.nFileSizeHigh) << 32) | ff.nFileSizeLow);
354 m_log.Info(_T("Adding %d attaches..."), m_config.FilesToAttach.size());
355 for (auto it = m_config.FilesToAttach.begin(), end = m_config.FilesToAttach.end(); it != end; ++it)
357 m_log.Info(_T("Adding \"%ls\" as \"%ls\"..."), static_cast<LPCWSTR>(it->first), static_cast<LPCWSTR>(it->second));
358 WIN32_FIND_DATAW ff;
359 HANDLE hFind = FindFirstFileW(it->first, &ff);
360 if (hFind == INVALID_HANDLE_VALUE)
362 m_log.Warning(_T("File \"%ls\" not found..."), static_cast<LPCWSTR>(it->first));
363 continue;
365 FindClose(hFind);
366 __int64 size = (static_cast<__int64>(ff.nFileSizeHigh) << 32) | ff.nFileSizeLow;
367 if (size > attachedSizeLimit)
369 m_log.Warning(_T("File \"%ls\" not skipped by size..."), static_cast<LPCWSTR>(it->first));
370 continue;
372 attachedSizeLimit -= size;
374 zip.AddFile(it->first, it->second, &g_cancel);
375 m_log.Info(_T("Done."));
377 DeleteFile(crashInfoFile);
380 void PrepareDump(
381 const CString& dumpFile,
382 const CString& zipFile,
383 HANDLE hProcess,
384 DWORD processId,
385 MINIDUMP_EXCEPTION_INFORMATION* pExceptInfo,
386 MINIDUMP_TYPE type,
387 MINIDUMP_CALLBACK_INFORMATION* pCallback,
388 bool attachFiles)
390 if (g_cancel)
391 throw std::runtime_error("canceled");
393 m_log.Info(_T("Writing dump (%s)..."), static_cast<LPCTSTR>(dumpFile));
394 if (!m_dumpWriter.WriteMiniDump(hProcess, processId, pExceptInfo, dumpFile, type, pCallback))
396 // Frequent errors:
397 // 0x80070070 - There is not enough space on the disk
398 DWORD err = GetLastError();
399 m_log.Error(_T("WriteMiniDump has failed with error %d"), err);
400 CStringA text;
401 text.Format("WriteMiniDump has failed with error %d", err);
402 throw std::runtime_error(text);
404 m_log.Info(_T("Dump ready."));
406 if (g_cancel)
407 throw std::runtime_error("canceled");
409 m_log.Info(_T("Zipping dump (%s)..."), static_cast<LPCTSTR>(zipFile));
411 Zip zip(zipFile);
412 zip.AddFile(dumpFile, dumpFile.Mid(dumpFile.ReverseFind(_T('\\')) + 1));
413 if (attachFiles)
414 AppendUserInfo(dumpFile, zip);
416 m_log.Info(_T("Zipping done."));
418 if (g_cancel)
419 throw std::runtime_error("canceled");
422 void PrepareMiniDump(
423 HANDLE hProcess,
424 DWORD processId,
425 MINIDUMP_EXCEPTION_INFORMATION* pExceptInfo)
427 m_log.Info(_T("Prepare mini dump..."));
429 DumpFilter dumpFilter(g_cancel, pExceptInfo ? pExceptInfo->ThreadId : 0);
430 PrepareDump(m_miniDumpFile, m_miniDumpZipFile, hProcess, processId, pExceptInfo, MiniDumpFilterMemory, dumpFilter, false);
433 void PrepareFullDump(
434 HANDLE hProcess,
435 DWORD dwProcessId,
436 MINIDUMP_EXCEPTION_INFORMATION* pExceptInfo,
437 bool attachFiles)
439 m_log.Info(_T("Prepare full dump..."));
441 DumpFilter dumpFilter(g_cancel);
442 PrepareDump(m_fullDumpFile, m_fullDumpZipFile, hProcess, dwProcessId, pExceptInfo, (MINIDUMP_TYPE)m_config.FullDumpType, dumpFilter, attachFiles);
445 typedef bool (WINAPI *pfnCollectInfo)(LPCWSTR file, LPCWSTR cfg, HANDLE process, DWORD processId);
446 void PrepareAdditionalInfo(const doctor_dump::NeedMoreInfoResponse& response, HANDLE process, DWORD processId)
448 m_log.Info(_T("Prepare additional info..."));
449 HMODULE hInfoDll = NULL;
452 CAtlFile hFile(CreateFile(m_infoDll, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL));
453 if (hFile == INVALID_HANDLE_VALUE)
454 throw runtime_error("failed to create info.dll file");
455 if (FAILED(hFile.Write(&response.infoModule[0], static_cast<DWORD>(response.infoModule.size()))))
456 throw runtime_error("failed to write info.dll file");
457 hFile.Close();
459 hInfoDll = LoadLibraryW(m_infoDll);
460 if (!hInfoDll)
461 throw runtime_error("failed to load info.dll");
463 pfnCollectInfo CollectInfo = (pfnCollectInfo) GetProcAddress(hInfoDll, "CollectInfo");
464 if (!CollectInfo)
465 throw runtime_error("failed to get CollectInfo from info.dll");
467 if (!CollectInfo(m_infoFile, response.infoModuleCfg.c_str(), process, processId))
468 throw runtime_error("CollectInfo failed");
470 FreeLibrary(hInfoDll);
471 DeleteFile(m_infoDll);
473 catch (...)
475 if (hInfoDll)
476 FreeLibrary(hInfoDll);
477 DeleteFile(m_infoDll);
478 throw;
482 void ProcessSolution(UI& ui, const doctor_dump::HaveSolutionResponse& solution)
484 m_log.Info(_T("Process solution..."));
485 switch (solution.type)
487 case ns4__HaveSolutionResponse_SolutionType__Url:
488 if (!solution.askConfirmation || ui.AskGetSolution(CSolutionDlg::Read))
490 CAtlStringW url = solution.url.c_str();
491 url.Replace(L"{ClientID}", solution.clientID.c_str());
492 url.Replace(L"{ProblemID}", ToString(solution.problemID));
493 url.Replace(L"{DumpGroupID}", ToString(solution.dumpGroupID));
494 url.Replace(L"{DumpID}", ToString(solution.dumpID));
495 ShellExecute(NULL, _T("open"), CW2CT(url), NULL, NULL, SW_SHOWNORMAL);
497 break;
498 case ns4__HaveSolutionResponse_SolutionType__Exe:
499 if (!solution.askConfirmation || ui.AskGetSolution(CSolutionDlg::Install))
501 CAtlFile hFile(CreateFile(m_patch, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL));
502 if (hFile == INVALID_HANDLE_VALUE)
503 throw runtime_error("failed to create solution.exe file");
504 if (FAILED(hFile.Write(&solution.exe[0], static_cast<DWORD>(solution.exe.size()))))
505 throw runtime_error("failed to write solution.exe file");
506 hFile.Close();
508 STARTUPINFO si = {};
509 si.cb = sizeof(si);
510 PROCESS_INFORMATION pi = {};
511 if (!CreateProcess(NULL, m_patch.GetBuffer(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
512 throw runtime_error("failed to start solution.exe");
513 CloseHandle(pi.hThread);
514 CloseHandle(pi.hProcess);
516 break;
517 default:
518 throw runtime_error("Unknown SolutionType");
522 bool Process(Params& params)
524 HANDLE hProcess = params.Process;
525 DWORD dwProcessId = params.ProcessId;
526 MINIDUMP_EXCEPTION_INFORMATION* pExceptInfo = &params.ExceptInfo;
527 bool wasAssert = !!params.WasAssert;
529 m_dumpWriter.Init(m_config.DbgHelpPath);
531 // we need to get CrashInfo before writing the dumps, since dumps writing will change WorkingSet
532 m_crashInfo.reset(new CrashInfo(hProcess));
534 InitPathes();
536 UI ui(m_config);
538 ui.ShowInitialProgressWindow(wasAssert);
540 PrepareMiniDump(hProcess, dwProcessId, pExceptInfo);
541 if (m_config.ServiceMode)
543 PrepareFullDump(hProcess, dwProcessId, pExceptInfo, true);
544 TerminateProcess(hProcess, E_FAIL); // It is necessary for DUMPPARSER to terminate app, because it should process our dump, and it could not do it since it crashes.
545 CloseHandle(hProcess);
546 hProcess = NULL;
549 doctor_dump::Application app;
550 app.applicationGUID = m_config.ApplicationGUID;
551 app.v[0] = m_config.V[0];
552 app.v[1] = m_config.V[1];
553 app.v[2] = m_config.V[2];
554 app.v[3] = m_config.V[3];
555 app.hotfix = m_config.Hotfix;
556 app.processName = m_config.ProcessName;
557 m_log.Info(_T("App %d.%d.%d.%d %ls"), app.v[0], app.v[1], app.v[2], app.v[3], app.applicationGUID);
559 doctor_dump::DumpAdditionalInfo addInfo;
560 addInfo.crashDate = time(NULL);
561 addInfo.PCID = GetUserPCID();
562 addInfo.submitterID = m_config.SubmitterID;
563 addInfo.group = CA2W(params.Group);
564 addInfo.description = m_config.CustomInfo;
566 std::unique_ptr<doctor_dump::Response> response = m_dumpUploader.Hello(app, (LPCWSTR)m_config.AppName, (LPCWSTR)m_config.Company, addInfo);
567 while (1)
569 switch (response->GetResponseType())
571 case doctor_dump::Response::HaveSolutionResponseType:
572 ProcessSolution(ui, static_cast<doctor_dump::HaveSolutionResponse&>(*response));
573 goto finish;
575 case doctor_dump::Response::NeedMiniDumpResponseType:
576 response = m_dumpUploader.UploadMiniDump(response->context, app, addInfo, (LPCWSTR)m_miniDumpZipFile);
577 break;
579 case doctor_dump::Response::NeedFullDumpResponseType:
580 if (!ui.AskSendFullDump())
582 response = m_dumpUploader.RejectedToSendAdditionalInfo(response->context, app, response->dumpID);
583 break;
586 ui.ShowFullDumpUploadProgressWindow();
588 if (!m_config.ServiceMode)
590 auto& resp = static_cast<doctor_dump::NeedFullDumpResponse&>(*response);
591 m_config.FullDumpType = m_config.FullDumpType & (~resp.restrictedDumpType);
592 PrepareFullDump(hProcess, dwProcessId, pExceptInfo, resp.attachUserInfo);
593 CloseHandle(hProcess);
594 hProcess = NULL;
596 SetEvent(params.ReportReady);
597 response = m_dumpUploader.UploadFullDump(response->context, app, response->dumpID, (LPCWSTR)m_fullDumpZipFile, &ui);
598 break;
600 case doctor_dump::Response::NeedMoreInfoResponseType:
601 if (!ui.AskSendFullDump())
603 response = m_dumpUploader.RejectedToSendAdditionalInfo(response->context, app, response->dumpID);
604 break;
607 ui.ShowFullDumpUploadProgressWindow();
609 PrepareAdditionalInfo(static_cast<doctor_dump::NeedMoreInfoResponse&>(*response), hProcess, dwProcessId);
610 response = m_dumpUploader.UploadAdditionalInfo(response->context, app, response->dumpID, (LPCWSTR)m_infoFile, &ui);
611 break;
613 case doctor_dump::Response::ErrorResponseType:
614 throw runtime_error((const char*)CW2A(static_cast<doctor_dump::ErrorResponse&>(*response).error.c_str()));
616 case doctor_dump::Response::StopResponseType:
617 default:
618 goto finish;
621 finish:
622 if (!m_config.ServiceMode && !response->urlToProblem.empty() && m_config.OpenProblemInBrowser)
623 ShellExecuteW(NULL, L"open", response->urlToProblem.c_str(), NULL, NULL, SW_SHOWNORMAL);
625 return true;
629 bool IsNetworkProblemException()
633 throw;
635 catch (doctor_dump::SoapException& ex)
637 if (ex.IsNetworkProblem())
638 return true;
639 return false;
641 catch (...)
643 return false;
647 DWORD SendReportImpl(Log& log, Params& params, Config& config, bool isDebug)
651 log.Info(_T("SENDRPT was invoked to send report, PID 0x%x"), params.ProcessId);
652 CrashProcessor(log, config).Process(params);
654 return TRUE;
656 catch (std::exception& ex)
658 log.Error(_T("Problem occurred: %hs"), ex.what());
659 OutputDebugStringA(ex.what());
661 if (isDebug)
663 ::MessageBoxA(0, ex.what(), "SendRpt: Error", MB_ICONERROR);
665 else
667 bool statSend = statistics::SendExceptionToGoogleAnalytics("UA-25460132-5", "sendrpt", ex.what(), true);
668 if (!statSend && !IsNetworkProblemException())
669 ::MessageBoxA(0, ex.what(), "SendRpt: Error", MB_ICONERROR);
672 return FALSE;
676 int __cdecl SendReport(int argc, wchar_t* argv[])
678 Log log(NULL, _T("sendrpt"));
680 bool isDebug = false;
681 CRegKey reg;
682 if (ERROR_SUCCESS == reg.Open(HKEY_LOCAL_MACHINE, _T("Software\\Idol Software\\DumpUploader"), KEY_READ))
684 DWORD attachDebugger = FALSE;
685 reg.QueryDWORDValue(_T("AttachDebugger"), attachDebugger);
686 if (attachDebugger != FALSE)
688 if (IDYES == ::MessageBoxA(0, "Do you want to debug?\n\nYour should attach debugger to sendrpt.exe before choosing Yes.", "SendRpt: SendReport", MB_ICONWARNING | MB_YESNO))
689 DebugBreak();
692 DWORD traceEnable = FALSE;
693 if (ERROR_SUCCESS == reg.QueryDWORDValue(_T("TraceEnable"), traceEnable) && traceEnable != FALSE)
695 isDebug = true;
696 CString str;
697 ULONG size = 1000;
698 if (ERROR_SUCCESS == reg.QueryStringValue(_T("TraceFolder"), str.GetBuffer(size), &size))
700 str.ReleaseBuffer(size-1);
701 InitializeLog();
702 log.SetParams(LogMediaPtr(new FileMedia(str + _T("\\sendrpt.log"), true, false)));
707 Params params;
708 Config config;
710 if (argc >= 2 && wcscmp(argv[1], L"-uitest") == 0)
712 config.AppName = "Test App";
713 config.Company = "Long Company Name";
714 if (argc >= 3)
715 config.LangFilePath = argv[2];
716 UI ui(config);
717 ui.Test();
718 return FALSE;
721 Serializer ser(argv[1]);
722 ser << params << config;
723 params.ExceptInfo.ClientPointers = TRUE;
725 return SendReportImpl(log, params, config, isDebug);