Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1870 lines
60 KiB

  1. /******************************************************************************
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. fruser.cpp
  5. Abstract:
  6. Implements user fault reporting for unhandled exceptions
  7. Revision History:
  8. created derekm 07/07/00
  9. ******************************************************************************/
  10. #include "stdafx.h"
  11. #include "dbghelp.h"
  12. #include "wtsapi32.h"
  13. #include "pchrexec.h"
  14. #include "frmc.h"
  15. #include "Tlhelp32.h"
  16. // the size of the following buffer must be evenly divisible by 2 or an
  17. // alignment fault could occur on ia64.
  18. struct SQueuedFaultBlob
  19. {
  20. DWORD cbTotal;
  21. DWORD cbFB;
  22. DWORD_PTR dwpAppPath;
  23. DWORD_PTR dwpModPath;
  24. UINT64 pvOffset;
  25. WORD rgAppVer[4];
  26. WORD rgModVer[4];
  27. BOOL fIs64bit;
  28. SYSTEMTIME stFault;
  29. };
  30. struct SQueuePruneData
  31. {
  32. LPWSTR wszVal;
  33. FILETIME ftFault;
  34. };
  35. ///////////////////////////////////////////////////////////////////////////////
  36. // utility functions
  37. // **************************************************************************
  38. BOOL GetFaultingModuleFilename(LPVOID pvFaultAddr, LPWSTR wszMod,
  39. DWORD cchMod)
  40. {
  41. USE_TRACING("GetFaultingModuleFilename");
  42. MODULEENTRY32W mod;
  43. HRESULT hr = NOERROR;
  44. HANDLE hSnap = INVALID_HANDLE_VALUE;
  45. LPVOID pvEnd;
  46. DWORD dwFlags = 0, iMod,cch;
  47. BOOL fRet = FALSE;
  48. VALIDATEPARM(hr, (pvFaultAddr == 0 || wszMod == NULL || cchMod == 0));
  49. if (FAILED(hr))
  50. goto done;
  51. *wszMod = L'\0';
  52. hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
  53. TESTBOOL(hr, (hSnap != NULL));
  54. if (FAILED(hr))
  55. goto done;
  56. ZeroMemory(&mod, sizeof(mod));
  57. mod.dwSize = sizeof(mod);
  58. TESTBOOL(hr, Module32FirstW(hSnap, &mod));
  59. if (FAILED(hr))
  60. goto done;
  61. do
  62. {
  63. pvEnd = mod.modBaseAddr + mod.modBaseSize;
  64. if (pvFaultAddr >= mod.modBaseAddr && pvFaultAddr < pvEnd)
  65. {
  66. if (cchMod > wcslen(mod.szExePath))
  67. {
  68. wcscpy(wszMod, mod.szExePath);
  69. fRet = TRUE;
  70. }
  71. else
  72. {
  73. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  74. fRet = FALSE;
  75. }
  76. break;
  77. }
  78. }
  79. while(Module32NextW(hSnap, &mod));
  80. done:
  81. if (hSnap != NULL)
  82. CloseHandle(hSnap);
  83. return fRet;
  84. }
  85. // **************************************************************************
  86. EFaultRepRetVal StartDWException(LPEXCEPTION_POINTERS pep, DWORD dwOpt,
  87. DWORD dwFlags, LPCSTR szServer,
  88. DWORD dwTimeToWait)
  89. {
  90. USE_TRACING("StartDWException");
  91. SECURITY_ATTRIBUTES sa;
  92. PROCESS_INFORMATION pi;
  93. EFaultRepRetVal frrvRet = frrvErrNoDW;
  94. DWSharedMem15 *pdwsm = NULL;
  95. STARTUPINFOW si;
  96. HRESULT hr = NOERROR;
  97. HANDLE hevDone = NULL, hevAlive = NULL, hmut = NULL;
  98. HANDLE hfmShared = NULL, hProc = NULL;
  99. HANDLE rghWait[2];
  100. LPWSTR wszAppCompat = NULL;
  101. WCHAR *pwszCmdLine, wszDir[MAX_PATH];
  102. WCHAR wszAppName[MAX_PATH];
  103. DWORD dw, dwStart, cch, cchNeed;
  104. BOOL fDWRunning = TRUE;
  105. ZeroMemory(&pi, sizeof(pi));
  106. VALIDATEPARM(hr, (pep == NULL));
  107. if (FAILED(hr))
  108. goto done;
  109. dwFlags |= (fDwWhistler | fDwUseHKLM | fDwAllowSuspend | fDwMiniDumpWithUnloadedModules);
  110. // we need the following things to be inheritable, so create a SD that
  111. // says it can be.
  112. ZeroMemory(&sa, sizeof(sa));
  113. sa.nLength = sizeof(sa);
  114. sa.bInheritHandle = TRUE;
  115. // create the necessary events & mutexes
  116. hevDone = CreateEvent(&sa, FALSE, FALSE, NULL);
  117. TESTBOOL(hr, (hevDone != NULL));
  118. if (FAILED(hr))
  119. goto done;
  120. hevAlive = CreateEvent(&sa, FALSE, FALSE, NULL);
  121. TESTBOOL(hr, (hevAlive != NULL));
  122. if (FAILED(hr))
  123. goto done;
  124. hmut = CreateMutex(&sa, FALSE, NULL);
  125. TESTBOOL(hr, (hmut != NULL));
  126. if (FAILED(hr))
  127. goto done;
  128. TESTBOOL(hr, DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
  129. GetCurrentProcess(), &hProc,
  130. PROCESS_ALL_ACCESS, TRUE, 0));
  131. if (FAILED(hr))
  132. goto done;
  133. // create the shared memory region & map it
  134. hfmShared = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0,
  135. sizeof(DWSharedMem), NULL);
  136. TESTBOOL(hr, (hfmShared != NULL));
  137. if (FAILED(hr))
  138. goto done;
  139. pdwsm = (DWSharedMem *)MapViewOfFile(hfmShared,
  140. FILE_MAP_READ | FILE_MAP_WRITE, 0, 0,
  141. 0);
  142. TESTBOOL(hr, (pdwsm != NULL));
  143. if (FAILED(hr))
  144. goto done;
  145. // populate all the stuff that DW needs
  146. ZeroMemory(pdwsm, sizeof(DWSharedMem15));
  147. pdwsm->dwSize = sizeof(DWSharedMem15);
  148. pdwsm->pid = GetCurrentProcessId();
  149. pdwsm->tid = GetCurrentThreadId();
  150. pdwsm->eip = (DWORD_PTR)pep->ExceptionRecord->ExceptionAddress;
  151. pdwsm->pep = pep;
  152. pdwsm->hEventDone = hevDone;
  153. pdwsm->hEventNotifyDone = NULL;
  154. pdwsm->hEventAlive = hevAlive;
  155. pdwsm->hMutex = hmut;
  156. pdwsm->hProc = hProc;
  157. pdwsm->bfDWBehaviorFlags = dwFlags;
  158. pdwsm->msoctdsResult = msoctdsNull;
  159. pdwsm->fReportProblem = FALSE;
  160. pdwsm->bfmsoctdsOffer = msoctdsQuit;
  161. pdwsm->bfmsoctdsNotify = 0;
  162. if (dwOpt == 1)
  163. pdwsm->bfmsoctdsOffer |= msoctdsDebug;
  164. pdwsm->bfmsoctdsLetRun = pdwsm->bfmsoctdsOffer;
  165. pdwsm->iPingCurrent = 0;
  166. pdwsm->iPingEnd = 0;
  167. pdwsm->lcidUI = GetUserDefaultUILanguage();
  168. strcpy(pdwsm->szServer, szServer);
  169. strcpy(pdwsm->szRegSubPath, c_szDWRegSubPath);
  170. strcpy(pdwsm->szBrand, c_szDWBrand);
  171. strcpy(pdwsm->szPIDRegKey, c_szRKVDigPid);
  172. GetModuleFileNameW(NULL, pdwsm->wzModuleFileName, DW_MAX_PATH);
  173. TESTHR(hr, GetVerName(pdwsm->wzModuleFileName, wszAppName,
  174. sizeofSTRW(wszAppName)));
  175. if (FAILED(hr))
  176. goto done;
  177. cch = CreateTempDirAndFile(NULL, c_wszACFileName, &wszAppCompat);
  178. TESTBOOL(hr, (cch != 0));
  179. if (SUCCEEDED(hr))
  180. {
  181. WCHAR wszMod[MAX_PATH], *pwszMod = NULL;
  182. TESTBOOL(hr, GetFaultingModuleFilename(pep->ExceptionRecord->ExceptionAddress,
  183. wszMod, sizeofSTRW(wszMod)));
  184. if (SUCCEEDED(hr))
  185. pwszMod = wszMod;
  186. TESTBOOL(hr, GetAppCompatData(pdwsm->wzModuleFileName, pwszMod,
  187. wszAppCompat));
  188. if (SUCCEEDED(hr) && wszAppCompat != NULL &&
  189. wcslen(wszAppCompat) < sizeofSTRW(pdwsm->wzAdditionalFile))
  190. wcscpy(pdwsm->wzAdditionalFile, wszAppCompat);
  191. }
  192. wszAppName[sizeofSTRW(wszAppName) - 1] = L'\0';
  193. wcsncpy(pdwsm->wzFormalAppName, wszAppName, DW_APPNAME_LENGTH);
  194. // pdwsm->wzDotDataDlls[0]=0;
  195. cch = GetSystemDirectoryW(wszDir, sizeofSTRW(wszDir));
  196. if (cch == 0 || cch > sizeofSTRW(wszDir))
  197. {
  198. DBG_MSG("Bad GetSystemDirectoryW call");
  199. goto done;
  200. }
  201. // the +12 is for the max size of an integer in decimal
  202. cchNeed = cch + wcslen(wszDir) + sizeofSTRW(c_wszDWCmdLineU) + 12;
  203. __try { pwszCmdLine = (WCHAR *)_alloca(cchNeed * sizeof(WCHAR)); }
  204. __except(EXCEPTION_STACK_OVERFLOW) { pwszCmdLine = NULL; }
  205. if (pwszCmdLine == NULL)
  206. {
  207. DBG_MSG("Out of memory");
  208. SetLastError(ERROR_OUTOFMEMORY);
  209. goto done;
  210. }
  211. swprintf(pwszCmdLine, c_wszDWCmdLineU, wszDir, hfmShared);
  212. // create the process
  213. ZeroMemory(&si, sizeof(si));
  214. ZeroMemory(&pi, sizeof(pi));
  215. // always want to launch this in the interactive workstation
  216. si.cb = sizeof(si);
  217. si.lpDesktop = L"Winsta0\\Default";
  218. ErrorTrace(0, "launching [%S]", pwszCmdLine);
  219. TESTBOOL(hr, CreateProcessW(NULL, pwszCmdLine, NULL, NULL, TRUE,
  220. CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS,
  221. NULL, wszDir, &si, &pi));
  222. if (FAILED(hr))
  223. goto done;
  224. // don't need the thread handle & we gotta close it, so close it now
  225. CloseHandle(pi.hThread);
  226. // assume we succeed from here on...
  227. if ((dwFlags & fDwHeadless) == fDwHeadless)
  228. frrvRet = frrvOkHeadless;
  229. else
  230. frrvRet = frrvOk;
  231. rghWait[0] = hevAlive;
  232. rghWait[1] = pi.hProcess;
  233. dwStart = GetTickCount();
  234. while(fDWRunning)
  235. {
  236. // gotta periodically get the Alive signal from DW.
  237. switch(WaitForMultipleObjects(2, rghWait, FALSE, 300000))
  238. {
  239. case WAIT_OBJECT_0:
  240. DBG_MSG("hevAlive signalled");
  241. if (WaitForSingleObject(hevDone, 0) == WAIT_OBJECT_0)
  242. {
  243. DBG_MSG("hevDone signalled");
  244. fDWRunning = FALSE;
  245. }
  246. if (dwTimeToWait != (DWORD)-1 &&
  247. RolloverSubtract(GetTickCount(), dwStart) > dwTimeToWait)
  248. {
  249. frrvRet = frrvErrTimeout;
  250. fDWRunning = FALSE;
  251. }
  252. continue;
  253. case WAIT_OBJECT_0 + 1:
  254. DBG_MSG("DW died");
  255. fDWRunning = FALSE;
  256. continue;
  257. }
  258. switch(WaitForSingleObject(hmut, DW_TIMEOUT_VALUE))
  259. {
  260. // yay! we got the mutex. Try to detemine if DW finally responded
  261. // while we were grabbing the mutex.
  262. case WAIT_OBJECT_0:
  263. DBG_MSG("got hmut");
  264. switch(WaitForMultipleObjects(2, rghWait, FALSE, 0))
  265. {
  266. // If it hasn't responded, tell it to go away & fall thru
  267. // into the 'it died' case.
  268. case WAIT_TIMEOUT:
  269. DBG_MSG("wait timed out");
  270. SetEvent(hevDone);
  271. // It died. Clean up.
  272. case WAIT_OBJECT_0 + 1:
  273. DBG_MSG("wait died");
  274. fDWRunning = FALSE;
  275. frrvRet = frrvErrNoDW;
  276. continue;
  277. }
  278. // ok, it responded. Is it done?
  279. if (WaitForSingleObject(hevDone, 0) == WAIT_OBJECT_0)
  280. fDWRunning = FALSE;
  281. ReleaseMutex(hmut);
  282. break;
  283. // if the wait was abandoned, it means DW has gone to the great bit
  284. // bucket in the sky without cleaning up. So release the mutex and
  285. // fall into the default case
  286. case WAIT_ABANDONED:
  287. DBG_MSG("hmut timed out");
  288. ReleaseMutex(hmut);
  289. // if we timed out or otherwise failed, just die.
  290. default:
  291. DBG_MSG("hmut died");
  292. frrvRet = frrvErrNoDW;
  293. fDWRunning = FALSE;
  294. break;
  295. }
  296. }
  297. if (frrvRet != frrvOk)
  298. {
  299. DBG_MSG("not OK");
  300. goto done;
  301. }
  302. // if user told us to debug, return that back to the
  303. if (pdwsm->msoctdsResult == msoctdsDebug)
  304. frrvRet = frrvLaunchDebugger;
  305. // if we're going to launch Dr. Watson, wait for the DW process to die.
  306. // Give it 5 minutes. If the user doesn't hit close by then, just return
  307. // anyway...
  308. if (dwOpt == (DWORD)-1)
  309. {
  310. if (WaitForSingleObject(pi.hProcess, 300000) == WAIT_TIMEOUT)
  311. frrvRet = frrvErrTimeout;
  312. }
  313. done:
  314. // preserve the error code so that the following calls don't overwrite it
  315. dw = GetLastError();
  316. if (wszAppCompat != NULL)
  317. {
  318. if (pi.hProcess)
  319. WaitForSingleObject(pi.hProcess, 300000);
  320. DeleteTempDirAndFile(wszAppCompat, TRUE);
  321. MyFree(wszAppCompat);
  322. }
  323. if (pi.hProcess)
  324. CloseHandle(pi.hProcess);
  325. if (pdwsm != NULL)
  326. UnmapViewOfFile(pdwsm);
  327. if (hfmShared != NULL)
  328. CloseHandle(hfmShared);
  329. if (hevDone != NULL)
  330. CloseHandle(hevDone);
  331. if (hevAlive != NULL)
  332. CloseHandle(hevAlive);
  333. if (hmut != NULL)
  334. CloseHandle(hmut);
  335. if (hProc != NULL)
  336. CloseHandle(hProc);
  337. SetLastError(dw);
  338. return frrvRet;
  339. }
  340. // **************************************************************************
  341. EFaultRepRetVal StartManifestReport(LPEXCEPTION_POINTERS pep, LPWSTR wszExe,
  342. DWORD dwOpt, DWORD dwTimeToWait)
  343. {
  344. USE_TRACING("StartManifestReport");
  345. SPCHExecServFaultRequest *pesdwreq = NULL;
  346. SPCHExecServFaultReply *pesrep = NULL;
  347. EFaultRepRetVal frrvRet = frrvErrNoDW;
  348. HRESULT hr = NOERROR;
  349. DWORD cbReq, cbRead;
  350. WCHAR wszName[MAX_PATH];
  351. BYTE Buf[ERRORREP_PIPE_BUF_SIZE], *pBuf;
  352. BYTE BufRep[ERRORREP_PIPE_BUF_SIZE];
  353. VALIDATEPARM(hr, (wszExe == NULL));
  354. if (FAILED(hr))
  355. goto done;
  356. ZeroMemory(Buf, sizeof(Buf));
  357. pesdwreq = (SPCHExecServFaultRequest *)Buf;
  358. // the following calculation ensures that pBuf is always aligned on a
  359. // sizeof(WCHAR) boundry...
  360. cbReq = sizeof(SPCHExecServFaultRequest) +
  361. sizeof(SPCHExecServFaultRequest) % sizeof(WCHAR);
  362. pBuf = Buf + cbReq;
  363. pesdwreq->cbESR = sizeof(SPCHExecServFaultRequest);
  364. pesdwreq->pidReqProcess = GetCurrentProcessId();
  365. pesdwreq->thidFault = GetCurrentThreadId();
  366. pesdwreq->pvFaultAddr = (UINT64)pep->ExceptionRecord->ExceptionAddress;
  367. pesdwreq->pEP = (UINT64)pep;
  368. #ifdef _WIN64
  369. pesdwreq->fIs64bit = TRUE;
  370. #else
  371. pesdwreq->fIs64bit = FALSE;
  372. #endif
  373. // marshal in the strings
  374. pesdwreq->wszExe = (UINT64)MarshallString(wszExe, Buf, sizeof(Buf), &pBuf,
  375. &cbReq);
  376. if (pesdwreq->wszExe == 0)
  377. goto done;
  378. pesdwreq->cbTotal = cbReq;
  379. // check and see if the system is shutting down. If so, CreateProcess is
  380. // gonna pop up some annoying UI that we can't get rid of, so we don't
  381. // want to call it if we know it's gonna happen.
  382. if (GetSystemMetrics(SM_SHUTTINGDOWN))
  383. goto done;
  384. // Send the buffer out to the server- wait at most 2m for this to
  385. // succeed. If it times out, bail. BTW, need to zero out BufRep here
  386. // cuz the call to the named pipe CAN fail & we don't want to start
  387. // processing garbage results...
  388. ZeroMemory(BufRep, sizeof(BufRep));
  389. wcscpy(wszName, ERRORREP_FAULT_PIPENAME);
  390. TESTHR(hr, MyCallNamedPipe(wszName, Buf, cbReq, BufRep, sizeof(BufRep),
  391. &cbRead, 120000, 120000));
  392. if (FAILED(hr))
  393. {
  394. // determine the error code that indicates whether we've timed out so
  395. // we can set the return code appropriately.
  396. goto done;
  397. }
  398. pesrep = (SPCHExecServFaultReply *)BufRep;
  399. // did the call succeed?
  400. VALIDATEEXPR(hr, (pesrep->ess == essErr), Err2HR(pesrep->dwErr));
  401. if (FAILED(hr))
  402. {
  403. SetLastError(pesrep->dwErr);
  404. goto done;
  405. }
  406. // this is only necessary if we actually launched DW. If we just queued
  407. // the fault for later, then we obviously can't wait on DW.
  408. if (pesrep->ess == essOk)
  409. {
  410. DWORD dwExitCode = msoctdsNull;
  411. // gotta wait for DW to be done before we nuke the manifest file, but
  412. // if it hasn't parsed it in 5 minutes, something's wrong with it.
  413. if (pesrep->hProcess != NULL)
  414. {
  415. DWORD dwTimeout;
  416. // so, if we're going to pop up the JIT debugger dialog if we timeout,
  417. // then maybe we should just not bother timeing out...
  418. dwTimeout = (dwOpt == froDebug) ? INFINITE : 300000;
  419. if (WaitForSingleObject(pesrep->hProcess, dwTimeout) == WAIT_TIMEOUT)
  420. frrvRet = frrvErrTimeout;
  421. // see if we need to debug the process
  422. else if (GetExitCodeProcess(pesrep->hProcess, &dwExitCode) == FALSE)
  423. dwExitCode = msoctdsNull;
  424. CloseHandle(pesrep->hProcess);
  425. pesrep->hProcess = NULL;
  426. }
  427. // we're only going to delete the files if DW has finished with them.
  428. // Yes this means we can leave stray files in the temp dir, but this
  429. // is better than having DW randomly fail while sending...
  430. if (frrvRet != frrvErrTimeout)
  431. {
  432. LPWSTR pwsz, pwszEnd;
  433. if (pesrep->wszDir != 0)
  434. {
  435. if (pesrep->wszDir < cbRead &&
  436. pesrep->wszDir >= sizeof(SPCHExecServFaultReply))
  437. pesrep->wszDir += (UINT64)pesrep;
  438. else
  439. pesrep->wszDir = 0;
  440. }
  441. if (pesrep->wszDumpName != 0)
  442. {
  443. if (pesrep->wszDumpName < cbRead &&
  444. pesrep->wszDumpName >= sizeof(SPCHExecServFaultReply))
  445. pesrep->wszDumpName += (UINT64)pesrep;
  446. else
  447. pesrep->wszDumpName = 0;
  448. }
  449. // make sure that there is a NULL terminator for each string
  450. // before the end of the buffer...
  451. pwszEnd = (LPWSTR)((BYTE *)pesrep + cbRead);
  452. if (pesrep->wszDumpName != 0)
  453. {
  454. for (pwsz = (LPWSTR)pesrep->wszDumpName;
  455. pwsz < pwszEnd && *pwsz != L'\0';
  456. pwsz++);
  457. if (*pwsz != L'\0')
  458. pesrep->wszDumpName = 0;
  459. }
  460. if (pesrep->wszDir != 0)
  461. {
  462. for (pwsz = (LPWSTR)pesrep->wszDir;
  463. pwsz < pwszEnd && *pwsz != L'\0';
  464. pwsz++);
  465. if (*pwsz != L'\0')
  466. pesrep->wszDir = 0;
  467. }
  468. }
  469. frrvRet = (dwExitCode == msoctdsDebug) ? frrvLaunchDebugger :
  470. frrvOkManifest;
  471. }
  472. // if we queued it, set the appropriate return code (duh)
  473. else if (pesrep->ess == essOkQueued)
  474. {
  475. frrvRet = frrvOkQueued;
  476. }
  477. SetLastError(0);
  478. done:
  479. if ((frrvRet == frrvOkManifest || frrvRet == frrvLaunchDebugger) &&
  480. pesrep != NULL && pesrep->wszDir != 0)
  481. {
  482. LPWSTR wszToDel = NULL;
  483. DWORD cchDir = 0, cchFile = 0;
  484. cchDir = wcslen((LPWSTR)pesrep->wszDir);
  485. if (pesrep->wszDumpName != 0)
  486. cchFile = wcslen((LPWSTR)pesrep->wszDumpName);
  487. if (cchFile < sizeofSTRW(c_wszACFileName))
  488. cchFile = sizeofSTRW(c_wszACFileName);
  489. if (cchFile < sizeofSTRW(c_wszManFileName))
  490. cchFile = sizeofSTRW(c_wszManFileName);
  491. __try { wszToDel = (LPWSTR)_alloca((cchFile + cchDir + 4) * sizeof(WCHAR)); }
  492. __except(EXCEPTION_STACK_OVERFLOW) { wszToDel = NULL; }
  493. if (wszToDel != NULL)
  494. {
  495. LPWSTR pwszToDel;
  496. wcscpy(wszToDel, (LPWSTR)pesrep->wszDir);
  497. pwszToDel = wszToDel + cchDir;
  498. *pwszToDel++ = L'\\';
  499. if (pesrep->wszDumpName != 0)
  500. {
  501. wcscpy(pwszToDel, (LPWSTR)pesrep->wszDumpName);
  502. #ifdef MANIFEST_HEAP
  503. DeleteFullAndTriageMiniDumps(wszToDel);
  504. #else
  505. DeleteFileW(wszToDel);
  506. #endif
  507. }
  508. wcscpy(pwszToDel, c_wszACFileName);
  509. DeleteFileW(wszToDel);
  510. wcscpy(pwszToDel, c_wszManFileName);
  511. DeleteFileW(wszToDel);
  512. }
  513. DeleteTempDirAndFile((LPWSTR)pesrep->wszDir, FALSE);
  514. }
  515. return frrvRet;
  516. }
  517. // **************************************************************************
  518. HRESULT PruneQ(HKEY hkeyQ, DWORD cQSize, DWORD cMaxQSize, DWORD cchMaxVal,
  519. DWORD cbMaxData)
  520. {
  521. USE_TRACING("PruneQ");
  522. SQueuedFaultBlob *psqfb = NULL;
  523. SQueuePruneData *pqpd = NULL;
  524. FILETIME ft;
  525. HRESULT hr = NOERROR;
  526. LPWSTR pwsz, pwszCurrent = NULL;
  527. DWORD cchVal, cbData, dwType, cToDel = 0, cInDelList = 0;
  528. DWORD i, iEntry, dw, cValid = 0;
  529. VALIDATEPARM(hr, (hkeyQ == NULL));
  530. if (FAILED(hr))
  531. goto done;
  532. if (cMaxQSize > cQSize)
  533. goto done;
  534. cToDel = cQSize - cMaxQSize + 1;
  535. // alloc the various buffers that we'll need:
  536. // the delete list
  537. // the current file we're working with
  538. // the data blob associated with the current file
  539. cbData = (sizeof(SQueuePruneData) + (cchMaxVal * sizeof(WCHAR))) * cToDel;
  540. pwszCurrent = (LPWSTR)MyAlloc(cchMaxVal * sizeof(WCHAR));
  541. psqfb = (SQueuedFaultBlob *)MyAlloc(cbMaxData);
  542. pqpd = (SQueuePruneData *)MyAlloc(cbData);
  543. if (psqfb == NULL || pwszCurrent == NULL || pqpd == NULL)
  544. {
  545. SetLastError(ERROR_OUTOFMEMORY);
  546. hr = E_OUTOFMEMORY;
  547. goto done;
  548. }
  549. // intiailize all the string pointers in the delete list
  550. pwsz = (LPWSTR)((BYTE *)pqpd + (sizeof(SQueuePruneData) * cToDel));
  551. for (i = 0; i < cToDel; i++)
  552. {
  553. pqpd[i].ftFault.dwHighDateTime = 0;
  554. pqpd[i].ftFault.dwLowDateTime = 0;
  555. pqpd[i].wszVal = pwsz;
  556. pqpd[i].wszVal[0] = L'\0';
  557. pwsz += cchMaxVal;
  558. }
  559. // ok, get a list of all the valid items and build an array in sorted order
  560. // so that we can easily pick off the top n items
  561. for(iEntry = 0; iEntry < cQSize; iEntry++)
  562. {
  563. cchVal = cchMaxVal;
  564. cbData = cbMaxData;
  565. dw = RegEnumValueW(hkeyQ, iEntry, pwszCurrent, &cchVal, 0, &dwType,
  566. (PBYTE)psqfb, &cbData);
  567. if (dw == ERROR_NO_MORE_ITEMS)
  568. break;
  569. else if (dw != ERROR_SUCCESS)
  570. continue;
  571. else if (cbData < sizeof(SQueuedFaultBlob) ||
  572. psqfb->cbFB != sizeof(SQueuedFaultBlob) ||
  573. psqfb->cbTotal != cbData)
  574. {
  575. RegDeleteValueW(hkeyQ, pwszCurrent);
  576. DeleteFileW(pwszCurrent);
  577. continue;
  578. }
  579. SystemTimeToFileTime(&psqfb->stFault, &ft);
  580. for (i = 0; i < cInDelList; i++)
  581. {
  582. if ((ft.dwHighDateTime < pqpd[i].ftFault.dwHighDateTime) ||
  583. (ft.dwHighDateTime == pqpd[i].ftFault.dwHighDateTime &&
  584. ft.dwLowDateTime < pqpd[i].ftFault.dwLowDateTime))
  585. break;
  586. }
  587. // if it's in the middle of the current list, then we gotta move
  588. // stuff around
  589. if (cInDelList > 0 && i < cInDelList - 1)
  590. {
  591. LPWSTR pwszTemp = pqpd[cInDelList - 1].wszVal;
  592. MoveMemory(&pqpd[i], &pqpd[i + 1],
  593. (cInDelList - i) * sizeof(SQueuePruneData));
  594. pqpd[i].wszVal = pwszTemp;
  595. }
  596. if (i < cToDel)
  597. {
  598. // note that this copy is safe cuz each string slot is the same
  599. // size as the buffer pointed to by pwszCurrent and that buffer is
  600. // protected from overflow by the size we pass into
  601. // RegEnumValueW()
  602. wcscpy(pqpd[i].wszVal, pwszCurrent);
  603. pqpd[i].ftFault = ft;
  604. if (cInDelList < cToDel)
  605. cInDelList++;
  606. }
  607. cValid++;
  608. }
  609. // if there aren't enuf valid entries to warrant a purge, then don't purge
  610. if (cValid < cMaxQSize)
  611. goto done;
  612. cToDel = MyMin(cToDel, cValid - cMaxQSize + 1);
  613. // purge enuf entries that we go down to 1 below our max (since we have to
  614. // be adding 1 to get here- don't want that 1 to drive us over the limit
  615. for(i = 0; i < cToDel; i++)
  616. {
  617. if (pqpd[i].wszVal != NULL)
  618. {
  619. DeleteFileW(pqpd[i].wszVal);
  620. RegDeleteValueW(hkeyQ, pqpd[i].wszVal);
  621. }
  622. }
  623. done:
  624. if (pqpd != NULL)
  625. MyFree(pqpd);
  626. if (psqfb != NULL)
  627. MyFree(psqfb);
  628. if (pwszCurrent != NULL)
  629. MyFree(pwszCurrent);
  630. return hr;
  631. }
  632. // **************************************************************************
  633. HRESULT CheckQSizeAndPrune(HKEY hkeyQ)
  634. {
  635. USE_TRACING("CheckQueueSizeAndPrune");
  636. HRESULT hr = NOERROR;
  637. HANDLE hmut = NULL;
  638. DWORD cMaxQSize = 0, cDefMaxQSize = 10;
  639. DWORD cQSize, cchMaxVal, cbMaxData;
  640. DWORD cb, dw;
  641. HKEY hkey = NULL;
  642. VALIDATEPARM(hr, (hkeyQ == NULL));
  643. if (FAILED(hr))
  644. goto done;
  645. // find out the max Q size
  646. TESTHR(hr, OpenRegKey(HKEY_LOCAL_MACHINE, c_wszRPCfg, 0, &hkey));
  647. if (FAILED(hr))
  648. goto done;
  649. cb = sizeof(cMaxQSize);
  650. TESTHR(hr, ReadRegEntry(hkey, c_wszRVMaxQueueSize, NULL, (PBYTE)&cMaxQSize,
  651. &cb, (PBYTE)&cDefMaxQSize, sizeof(cDefMaxQSize)));
  652. RegCloseKey(hkey);
  653. hkey = NULL;
  654. if (FAILED(hr))
  655. goto done;
  656. // if the Q size is 0, then we are effectively disabled for Qing faults.
  657. // Return S_FALSE to indicate this
  658. if (cMaxQSize == 0)
  659. {
  660. hr = S_FALSE;
  661. goto done;
  662. }
  663. // -1 means there is no limit
  664. else if (cMaxQSize == (DWORD)-1)
  665. {
  666. hr = NOERROR;
  667. goto done;
  668. }
  669. else if (cMaxQSize > c_cMaxQueue)
  670. cMaxQSize = c_cMaxQueue;
  671. hmut = OpenMutexW(SYNCHRONIZE, FALSE, c_wszMutUserName);
  672. TESTBOOL(hr, (hmut != NULL));
  673. if (FAILED(hr))
  674. goto done;
  675. // wait for 5s for the mutex to become available- this should be enuf time
  676. // for anyone else to add something to the queue dir. It could take longer
  677. // if someone is processing the dir, but then items are being removed
  678. // anyway...
  679. dw = WaitForSingleObject(hmut, 5000);
  680. if (dw != WAIT_OBJECT_0)
  681. {
  682. // if the wait timed out, then someone is already going thru the faults
  683. // so it's likely to be reduced sometime soon
  684. if (dw == WAIT_TIMEOUT)
  685. hr = NOERROR;
  686. else
  687. hr = Err2HR(GetLastError());
  688. goto done;
  689. }
  690. __try
  691. {
  692. // determine what the Q size is.
  693. TESTERR(hr, RegQueryInfoKey(hkeyQ, NULL, NULL, NULL, NULL, NULL, NULL,
  694. &cQSize, &cchMaxVal, &cbMaxData, NULL, NULL));
  695. if (SUCCEEDED(hr) && (cQSize >= cMaxQSize))
  696. {
  697. cchMaxVal++;
  698. TESTHR(hr, PruneQ(hkeyQ, cQSize, cMaxQSize, cchMaxVal, cbMaxData));
  699. }
  700. else
  701. {
  702. hr = NOERROR;
  703. }
  704. }
  705. __except(EXCEPTION_EXECUTE_HANDLER)
  706. {
  707. }
  708. done:
  709. if (hmut != NULL)
  710. {
  711. ReleaseMutex(hmut);
  712. CloseHandle(hmut);
  713. }
  714. return hr;
  715. }
  716. ///////////////////////////////////////////////////////////////////////////////
  717. // exported functions
  718. // **************************************************************************
  719. EFaultRepRetVal APIENTRY ReportFaultFromQueue(LPWSTR wszDump, BYTE *pbData,
  720. DWORD cbData)
  721. {
  722. USE_TRACING("ReportFaultFromQueue");
  723. CPFFaultClientCfg oCfg;
  724. SQueuedFaultBlob *pqfb = (SQueuedFaultBlob *)pbData;
  725. EFaultRepRetVal frrvRet = frrvErrNoDW;
  726. SDWManifestBlob dwmb;
  727. SYSTEMTIME stLocal;
  728. FILETIME ft, ftLocal;
  729. HRESULT hr = NOERROR;
  730. LPWSTR wszAppPath, wszModPath;
  731. LPWSTR wszModName, wszAppName, pwszApp, pwszEnd;
  732. LPWSTR wszStage1, wszStage2, wszCorpPath, wszHdr, wszErrMsg;
  733. LPWSTR wszNewDump = NULL, wszDir = NULL;
  734. LPWSTR wszManifest = NULL, pwszAppCompat = NULL;
  735. WCHAR wszDate[128], wszTime[128], *pwsz;
  736. WCHAR *pwch;
  737. WCHAR wszAppFriendlyName[MAX_PATH];
  738. WCHAR wszBuffer[160];
  739. WCHAR wszUnknown[] = L"unknown";
  740. DWORD dw, cchTotal, cchSep = 0, cch, cchDir;
  741. BYTE *pbBuf = NULL;
  742. BOOL fMSApp = FALSE, fAllowSend = TRUE, fOkCopy = FALSE;
  743. VALIDATEPARM(hr, (wszDump == NULL || pbData == NULL) ||
  744. cbData < sizeof(SQueuedFaultBlob) ||
  745. pqfb->cbFB != sizeof(SQueuedFaultBlob) ||
  746. pqfb->cbTotal != cbData ||
  747. pqfb->dwpAppPath >= cbData ||
  748. pqfb->dwpModPath >= cbData);
  749. if (FAILED(hr))
  750. goto done;
  751. wszAppPath = (LPWSTR)(pqfb->dwpAppPath + pbData);
  752. wszModPath = (LPWSTR)(pqfb->dwpModPath + pbData);
  753. pwszEnd = (LPWSTR)(pbData + cbData);
  754. // make sure there's a NULL terminator on the ModPath string before the end
  755. // of the buffer...
  756. for (pwch = wszModPath; pwch < pwszEnd && *pwch != L'\0'; pwch++);
  757. if (pwch >= pwszEnd)
  758. {
  759. SetLastError(ERROR_INVALID_PARAMETER);
  760. goto done;
  761. }
  762. // convieniently, pwch is now at the end of ModPath string, so we can
  763. // parse back to find the first backslash & get the module name
  764. for(pwch -= 1; pwch >= wszModPath && *pwch != L'\\'; pwch--);
  765. if (*pwch == L'\\')
  766. wszModName = pwch + 1;
  767. else
  768. wszModName = wszModPath;
  769. if (*wszModName == L'\0')
  770. wszModName = wszUnknown;
  771. // make sure there's a NULL terminator on the AppPath string before the end
  772. // of the buffer...
  773. for (pwch = wszAppPath; pwch < wszModPath && *pwch != L'\0'; pwch++);
  774. if (pwch >= wszModPath)
  775. {
  776. SetLastError(ERROR_INVALID_PARAMETER);
  777. goto done;
  778. }
  779. // convieniently, pwch is now at the end of AppPath string, so we can
  780. // parse back to find the first backslash & get the module name
  781. for(pwch -= 1; pwch >= wszAppPath && *pwch != L'\\'; pwch--);
  782. if (*pwch == L'\\')
  783. wszAppName = pwch + 1;
  784. else
  785. wszAppName = wszAppPath;
  786. // get the config info
  787. TESTHR(hr, oCfg.Read(eroPolicyRO));
  788. if (FAILED(hr))
  789. goto done;
  790. if (oCfg.get_ShowUI() == eedDisabled && oCfg.get_DoReport() == eedDisabled)
  791. goto done;
  792. // figure out how we're reporting / notifying the user
  793. if (oCfg.get_DoReport() == eedDisabled ||
  794. oCfg.ShouldCollect(wszAppPath, &fMSApp) == FALSE)
  795. fAllowSend = FALSE;
  796. if (oCfg.get_ShowUI() == eedDisabled)
  797. {
  798. LPCWSTR wszULPath = oCfg.get_DumpPath(NULL, 0);
  799. // check and make sure that we have a corporate path specified. If we
  800. // don't, bail
  801. if (wszULPath == NULL || *wszULPath == L'\0')
  802. goto done;
  803. }
  804. // log an event- don't care if it fails or not.
  805. TESTHR(hr, LogUser(wszAppName, pqfb->rgAppVer, wszModName, pqfb->rgModVer,
  806. pqfb->pvOffset, pqfb->fIs64bit, ER_QUEUEREPORT_LOG));
  807. if (CreateTempDirAndFile(NULL, NULL, &wszDir) == 0)
  808. goto done;
  809. cchDir = wcslen(wszDir);
  810. cch = cchDir + sizeofSTRW(c_wszManFileName) + 4;
  811. __try { wszManifest = (LPWSTR)_alloca(cch * sizeof(WCHAR)); }
  812. __except(EXCEPTION_STACK_OVERFLOW) { wszManifest = NULL; }
  813. if (wszManifest == NULL)
  814. {
  815. SetLastError(ERROR_OUTOFMEMORY);
  816. goto done;
  817. }
  818. wcscpy(wszManifest, wszDir);
  819. wszManifest[cchDir] = L'\\';
  820. wszManifest[cchDir + 1] = L'\0';
  821. wcscat(wszManifest, c_wszManFileName);
  822. cchDir = wcslen(wszDir);
  823. cch = 2 * cchDir + wcslen(wszDump) + sizeofSTRW(c_wszACFileName) + 4;
  824. __try { wszNewDump = (LPWSTR)_alloca(cch * sizeof(WCHAR)); }
  825. __except(EXCEPTION_STACK_OVERFLOW) { wszNewDump = NULL; }
  826. if (wszNewDump == NULL)
  827. {
  828. SetLastError(ERROR_OUTOFMEMORY);
  829. goto done;
  830. }
  831. wcscpy(wszNewDump, wszDir);
  832. wszNewDump[cchDir] = L'\\';
  833. wszNewDump[cchDir + 1] = L'\0';
  834. fOkCopy = FALSE;
  835. for (pwsz = wszDump + wcslen(wszDump);
  836. *pwsz != L'\\' && pwsz > wszDump;
  837. pwsz--);
  838. if (*pwsz == L'\\')
  839. {
  840. pwsz++;
  841. wcscat(wszNewDump, pwsz);
  842. for (pwsz = wszNewDump + wcslen(wszNewDump);
  843. *pwsz != L'.' && pwsz > wszNewDump;
  844. pwsz--);
  845. if (*pwsz == L'.' && pwsz > wszNewDump &&
  846. _wcsicmp(pwsz, c_wszDumpSuffix) == 0)
  847. {
  848. pwsz--;
  849. for(;
  850. *pwsz != L'.' && pwsz > wszNewDump;
  851. pwsz--);
  852. if (*pwsz == L'.' && pwsz > wszNewDump)
  853. {
  854. wcscpy(pwsz, c_wszDumpSuffix);
  855. #ifdef MANIFEST_HEAP
  856. fOkCopy = CopyFullAndTriageMiniDumps(wszDump, wszNewDump);
  857. #else
  858. fOkCopy = CopyFileW(wszDump, wszNewDump, FALSE);
  859. #endif
  860. }
  861. }
  862. }
  863. if (fOkCopy == FALSE)
  864. wcscpy(wszNewDump, wszDump);
  865. // generate all the URLs / filepaths that we need...
  866. TESTHR(hr, BuildManifestURLs(wszAppName, wszModName, pqfb->rgAppVer,
  867. pqfb->rgModVer, pqfb->pvOffset,
  868. pqfb->fIs64bit, &wszStage1, &wszStage2,
  869. &wszCorpPath, &pbBuf));
  870. if (FAILED(hr))
  871. goto done;
  872. // get the friendly name for the app
  873. TESTHR(hr, GetVerName(wszAppPath, wszAppFriendlyName,
  874. sizeofSTRW(wszAppFriendlyName)));
  875. if (FAILED(hr))
  876. goto done;
  877. wszAppFriendlyName[sizeofSTRW(wszAppFriendlyName) - 1] = L'\0';
  878. // build the header string
  879. dw = LoadStringW(g_hInstance, IDS_FQHDRTXT, wszBuffer,
  880. sizeofSTRW(wszBuffer));
  881. if (dw == 0)
  882. goto done;
  883. cchTotal = dw + wcslen(wszAppFriendlyName) + 1;
  884. __try { wszHdr = (LPWSTR)_alloca(cchTotal * sizeof(WCHAR)); }
  885. __except(EXCEPTION_STACK_OVERFLOW) { wszHdr = NULL; }
  886. if (wszHdr == NULL)
  887. {
  888. SetLastError(ERROR_OUTOFMEMORY);
  889. goto done;
  890. }
  891. swprintf(wszHdr, wszBuffer, wszAppFriendlyName);
  892. // need to convert the time of the fault to a local time (cuz
  893. // GetSystemTime() returns a UTC time), but unfortunately, only filetimes
  894. // can be converted back and forth between UTC & local, so we have to do
  895. // all of this stuff...
  896. SystemTimeToFileTime(&pqfb->stFault, &ft);
  897. FileTimeToLocalFileTime(&ft, &ftLocal);
  898. FileTimeToSystemTime(&ftLocal, &stLocal);
  899. // build the error message string
  900. dw = LoadStringW(g_hInstance, IDS_FQERRMSG, wszBuffer,
  901. sizeofSTRW(wszBuffer));
  902. if (dw == 0)
  903. goto done;
  904. cchTotal = dw;
  905. dw = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &stLocal,
  906. NULL, wszDate, sizeofSTRW(wszDate));
  907. if (dw == 0)
  908. goto done;
  909. cchTotal += dw;
  910. dw = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &stLocal, NULL, wszTime,
  911. sizeofSTRW(wszTime));
  912. if (dw == 0)
  913. goto done;
  914. cchTotal += dw;
  915. cchTotal++;
  916. __try { wszErrMsg = (LPWSTR)_alloca(cchTotal * sizeof(WCHAR)); }
  917. __except(EXCEPTION_STACK_OVERFLOW) { wszErrMsg = NULL; }
  918. if (wszErrMsg == NULL)
  919. {
  920. SetLastError(ERROR_OUTOFMEMORY);
  921. goto done;
  922. }
  923. swprintf(wszErrMsg, wszBuffer, wszDate, wszTime);
  924. // we created the wszDump buffer above big enuf to hold both the
  925. // dumpfile path as well as the app compat filename. So make
  926. // use of that right now.
  927. cchSep = wcslen(wszNewDump);
  928. pwszAppCompat = wszNewDump + cchSep + 1;
  929. wcscpy(pwszAppCompat, wszDir);
  930. pwszAppCompat[cchDir] = L'\\';
  931. pwszAppCompat[cchDir + 1] = L'\0';
  932. wcscat(pwszAppCompat, c_wszACFileName);
  933. // if we succeed, turn the NULL following the dump file path into
  934. // the DW separator character
  935. TESTBOOL(hr, GetAppCompatData(wszAppPath, wszModPath, pwszAppCompat));
  936. if (SUCCEEDED(hr))
  937. wszNewDump[cchSep] = DW_FILESEP;
  938. ZeroMemory(&dwmb, sizeof(dwmb));
  939. dwmb.wszTitle = wszAppFriendlyName;
  940. dwmb.wszErrMsg = wszErrMsg;
  941. dwmb.wszHdr = wszHdr;
  942. dwmb.wszStage1 = wszStage1;
  943. dwmb.wszStage2 = wszStage2;
  944. dwmb.wszBrand = c_wszDWBrand;
  945. dwmb.wszFileList = wszNewDump;
  946. dwmb.fIsMSApp = fMSApp;
  947. dwmb.wszCorpPath = wszCorpPath;
  948. // check and see if the system is shutting down. If so, CreateProcess is
  949. // gonna pop up some annoying UI that we can't get rid of, so we don't
  950. // want to call it if we know it's gonna happen.
  951. if (GetSystemMetrics(SM_SHUTTINGDOWN))
  952. goto done;
  953. // we get back the name of the manifest file here.
  954. frrvRet = StartDWManifest(oCfg, dwmb, wszManifest, fAllowSend);
  955. done:
  956. dw = GetLastError();
  957. if (pbBuf != NULL)
  958. MyFree(pbBuf);
  959. if (frrvRet != frrvErrTimeout)
  960. {
  961. if (wszNewDump != NULL)
  962. {
  963. if (pwszAppCompat != NULL)
  964. {
  965. wszNewDump[cchSep] = L'\0';
  966. DeleteFileW(pwszAppCompat);
  967. }
  968. #ifdef MANIFEST_HEAP
  969. DeleteFullAndTriageMiniDumps(wszNewDump);
  970. #else
  971. DeleteFileW(wszNewDump);
  972. #endif
  973. }
  974. if (wszManifest != NULL)
  975. DeleteFileW(wszManifest);
  976. if (wszDir != NULL)
  977. {
  978. DeleteTempDirAndFile(wszDir, FALSE);
  979. MyFree(wszDir);
  980. }
  981. }
  982. SetLastError(dw);
  983. return frrvRet;
  984. }
  985. // **************************************************************************
  986. #define ER_ALL_RIGHTS GENERIC_ALL | STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL
  987. EFaultRepRetVal APIENTRY ReportFaultToQueue(SFaultRepManifest *pfrm)
  988. {
  989. USE_TRACING("ReportFaultToQueue");
  990. SECURITY_ATTRIBUTES sa;
  991. SECURITY_DESCRIPTOR sd;
  992. SQueuedFaultBlob *pqfb;
  993. EFaultRepRetVal frrvRet = frrvErrNoDW;
  994. SMDumpOptions smdo;
  995. SYSTEMTIME st;
  996. HRESULT hr = NOERROR;
  997. LPWSTR pwsz, pwszAppName = NULL, pwszDump = NULL;
  998. HANDLE hFile = INVALID_HANDLE_VALUE;
  999. HANDLE hProc = NULL;
  1000. USHORT usCompress;
  1001. DWORD cch, cchNeed, cb, dw;
  1002. WCHAR wszDump[MAX_PATH];
  1003. HKEY hkeyQ = NULL, hkeyRun = NULL;
  1004. WORD iFile = 0;
  1005. ZeroMemory(&sa, sizeof(sa));
  1006. wszDump[0] = L'\0';
  1007. VALIDATEPARM(hr, (pfrm == NULL || pfrm->wszExe == NULL ||
  1008. pfrm->pidReqProcess == 0));
  1009. if (FAILED(hr))
  1010. goto done;
  1011. // get the SD for the file we need to create
  1012. TESTBOOL(hr, AllocSD(&sd, ER_ALL_RIGHTS, ER_ALL_RIGHTS, 0));
  1013. if (FAILED(hr))
  1014. goto done;
  1015. sa.nLength = sizeof(sa);
  1016. sa.lpSecurityDescriptor = &sd;
  1017. sa.bInheritHandle = FALSE;
  1018. // get the name of the faulting application
  1019. for (pwszAppName = pfrm->wszExe + wcslen(pfrm->wszExe) - 1;
  1020. *pwszAppName != L'\\' && pwszAppName >= pfrm->wszExe;
  1021. pwszAppName--);
  1022. if (*pwszAppName == L'\\')
  1023. pwszAppName++;
  1024. // generate the filename
  1025. cch = GetSystemWindowsDirectoryW(wszDump, sizeofSTRW(wszDump));
  1026. if (cch == 0)
  1027. goto done;
  1028. // compute minimum required buffer size needed (the '5 * 6' at the end is
  1029. // to allow for the 6 WORD values that will be inserted)
  1030. cchNeed = cch + wcslen(pwszAppName) + 5 * 6 + sizeofSTRW(c_wszQFileName);
  1031. if (cchNeed > sizeofSTRW(wszDump))
  1032. {
  1033. __try { pwszDump = (LPWSTR)_alloca(cchNeed * sizeof(WCHAR)); }
  1034. __except(EXCEPTION_STACK_OVERFLOW) { pwszDump = NULL; }
  1035. if (pwszDump == NULL)
  1036. {
  1037. SetLastError(ERROR_OUTOFMEMORY);
  1038. goto done;
  1039. }
  1040. if (cch > sizeofSTRW(wszDump))
  1041. cch = GetSystemWindowsDirectoryW(wszDump, cchNeed);
  1042. else
  1043. wcscpy(pwszDump, wszDump);
  1044. }
  1045. else
  1046. {
  1047. pwszDump = wszDump;
  1048. }
  1049. pwsz = pwszDump + cch - 1;
  1050. if (*pwsz != L'\\')
  1051. {
  1052. *(++pwsz) = L'\\';
  1053. *(++pwsz) = L'\0';
  1054. }
  1055. wcscpy(pwsz, c_wszQSubdir);
  1056. pwsz += (sizeofSTRW(c_wszQSubdir) - 1);
  1057. GetSystemTime(&st);
  1058. swprintf(pwsz, c_wszQFileName, pwszAppName, st.wYear, st.wMonth, st.wDay,
  1059. st.wHour, st.wMinute, st.wSecond);
  1060. // set pwsz to point to the 00 at the end of the above string...
  1061. pwsz += (wcslen(pwsz) - 7);
  1062. // do this in this section to make sure we can open these keys
  1063. TESTHR(hr, OpenRegKey(HKEY_LOCAL_MACHINE, c_wszRKUser, orkWantWrite,
  1064. &hkeyQ));
  1065. if (FAILED(hr))
  1066. goto done;
  1067. TESTHR(hr, OpenRegKey(HKEY_LOCAL_MACHINE, c_wszRKRun, orkWantWrite,
  1068. &hkeyRun));
  1069. if (FAILED(hr))
  1070. goto done;
  1071. // check the size of the file Q and purge it if necessary
  1072. TESTHR(hr, CheckQSizeAndPrune(hkeyQ));
  1073. if (FAILED(hr) || hr == S_FALSE)
  1074. goto done;
  1075. for(iFile = 1; iFile <= 100; iFile++)
  1076. {
  1077. hFile = CreateFileW(pwszDump, GENERIC_WRITE | GENERIC_READ, 0, &sa,
  1078. CREATE_NEW, 0, NULL);
  1079. if (hFile != INVALID_HANDLE_VALUE)
  1080. break;
  1081. if (hFile == INVALID_HANDLE_VALUE &&
  1082. GetLastError() != ERROR_FILE_EXISTS)
  1083. break;
  1084. *pwsz = L'0' + (WCHAR)(iFile / 10);
  1085. *(pwsz + 1) = L'0' + (WCHAR)(iFile % 10);
  1086. }
  1087. if (hFile == INVALID_HANDLE_VALUE)
  1088. goto done;
  1089. // get a handle to the target process
  1090. hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
  1091. pfrm->pidReqProcess);
  1092. if (hProc == NULL)
  1093. goto done;
  1094. // generate the minidump
  1095. ZeroMemory(&smdo, sizeof(smdo));
  1096. #ifdef MANIFEST_HEAP
  1097. smdo.ulThread = c_ulThreadWriteDefault;
  1098. smdo.ulMod = c_ulModuleWriteDefault;
  1099. #else
  1100. smdo.ulThread = ThreadWriteThread | ThreadWriteContext | ThreadWriteStack;
  1101. smdo.ulMod = ModuleWriteModule | ModuleWriteMiscRecord | ModuleWriteDataSeg;
  1102. #endif
  1103. smdo.dwThreadID = pfrm->thidFault;
  1104. smdo.dfOptions = dfCollectSig;
  1105. smdo.pvFaultAddr = pfrm->pvFaultAddr;
  1106. smdo.pEP = pfrm->pEP;
  1107. smdo.fEPClient = TRUE;
  1108. smdo.wszModFullPath[0] = L'\0';
  1109. wcscpy(smdo.wszAppFullPath, pfrm->wszExe);
  1110. wcscpy(smdo.wszMod, L"unknown");
  1111. #ifdef MANIFEST_HEAP
  1112. TESTBOOL(hr, InternalGenFullAndTriageMinidumps(hProc, pfrm->pidReqProcess,
  1113. pwszDump, hFile, &smdo, pfrm->fIs64bit));
  1114. #else
  1115. TESTBOOL(hr, InternalGenerateMinidump(hProc, pfrm->pidReqProcess, hFile,
  1116. &smdo, pwszDump));
  1117. #endif
  1118. if (FAILED(hr))
  1119. goto done;
  1120. // set the file to use NTFS compression- it is ok if this fails.
  1121. usCompress = COMPRESSION_FORMAT_DEFAULT;
  1122. TESTBOOL(hr, DeviceIoControl(hFile, FSCTL_SET_COMPRESSION, &usCompress,
  1123. sizeof(usCompress), NULL, 0, &cb, NULL));
  1124. // log an event- don't care if it fails or not.
  1125. TESTHR(hr, LogUser(smdo.wszApp, smdo.rgAppVer, smdo.wszMod, smdo.rgModVer,
  1126. smdo.pvOffset, pfrm->fIs64bit, ER_USERCRASH_LOG));
  1127. // build the blob we'll store with the filename in the registry
  1128. cch = wcslen(smdo.wszAppFullPath) + 1;
  1129. cb = sizeof(SQueuedFaultBlob) +
  1130. (cch + wcslen(smdo.wszModFullPath) + 2) * sizeof(WCHAR);
  1131. __try { pqfb = (SQueuedFaultBlob *)_alloca(cb); }
  1132. __except(EXCEPTION_STACK_OVERFLOW) { pqfb = NULL; }
  1133. if (pqfb == NULL)
  1134. {
  1135. SetLastError(ERROR_OUTOFMEMORY);
  1136. goto done;
  1137. }
  1138. CopyMemory(&pqfb->rgAppVer, &smdo.rgAppVer, 4 * sizeof(DWORD));
  1139. CopyMemory(&pqfb->rgModVer, &smdo.rgModVer, 4 * sizeof(DWORD));
  1140. CopyMemory(&pqfb->stFault, &st, sizeof(st));
  1141. pqfb->cbFB = sizeof(SQueuedFaultBlob);
  1142. pqfb->cbTotal = cb;
  1143. pqfb->fIs64bit = pfrm->fIs64bit;
  1144. pqfb->pvOffset = smdo.pvOffset;
  1145. pwsz = (WCHAR *)((BYTE *)pqfb + sizeof(SQueuedFaultBlob));
  1146. pqfb->dwpAppPath = sizeof(SQueuedFaultBlob);
  1147. pqfb->dwpModPath = sizeof(SQueuedFaultBlob) + cch * sizeof(WCHAR);
  1148. CopyMemory(pwsz, smdo.wszAppFullPath, cch * sizeof(WCHAR));
  1149. pwsz += cch;
  1150. wcscpy(pwsz, smdo.wszModFullPath);
  1151. // write out the value to our 'queue' in the registry.
  1152. TESTERR(hr, RegSetValueExW(hkeyQ, pwszDump, 0, REG_BINARY, (LPBYTE)pqfb,
  1153. cb));
  1154. if (FAILED(hr))
  1155. goto done;
  1156. // write out our app to the 'run' key so that the next admin to log
  1157. // in will see that a fault has occurred.
  1158. TESTERR(hr, RegSetValueExW(hkeyRun, c_wszRVUFC, 0, REG_EXPAND_SZ,
  1159. (LPBYTE)c_wszRVVUFC, sizeof(c_wszRVVUFC)));
  1160. if (FAILED(hr))
  1161. {
  1162. RegDeleteValueW(hkeyQ, pwszDump);
  1163. goto done;
  1164. }
  1165. frrvRet = frrvOk;
  1166. done:
  1167. dw = GetLastError();
  1168. // if we failed, then clean everything up.
  1169. if (hFile != INVALID_HANDLE_VALUE)
  1170. CloseHandle(hFile);
  1171. if (frrvRet != frrvOk && iFile <= 100 && pwszDump != NULL)
  1172. DeleteFileW(pwszDump);
  1173. if (sa.lpSecurityDescriptor != NULL)
  1174. FreeSD((SECURITY_DESCRIPTOR *)sa.lpSecurityDescriptor);
  1175. if (hkeyQ != NULL)
  1176. RegCloseKey(hkeyQ);
  1177. if (hkeyRun != NULL)
  1178. RegCloseKey(hkeyRun);
  1179. if (hProc != NULL)
  1180. CloseHandle(hProc);
  1181. SetLastError(dw);
  1182. return frrvRet;
  1183. }
  1184. // **************************************************************************
  1185. EFaultRepRetVal APIENTRY ReportFaultDWM(SFaultRepManifest *pfrm,
  1186. LPCWSTR wszDir, HANDLE hToken,
  1187. LPVOID pvEnv, PROCESS_INFORMATION *ppi,
  1188. LPWSTR wszDumpFile)
  1189. {
  1190. USE_TRACING("ReportFaultDWM");
  1191. CPFFaultClientCfg oCfg;
  1192. EFaultRepRetVal frrvRet = frrvErrNoDW;
  1193. SDWManifestBlob dwmb;
  1194. SMDumpOptions smdo;
  1195. HRESULT hr = NOERROR;
  1196. HANDLE hProc = NULL;
  1197. #ifndef MANIFEST_HEAP
  1198. HANDLE hFile = INVALID_HANDLE_VALUE;
  1199. #endif
  1200. LPWSTR wszStage1, wszStage2, wszCorpPath;
  1201. LPWSTR wszManifest = NULL, wszDump = NULL, pwszAppCompat = NULL;
  1202. DWORD dw, cch, cchDir, cchSep = 0;
  1203. WCHAR wszAppName[MAX_PATH];
  1204. HKEY hkeyDebug = NULL;
  1205. BOOL fAllowSend = TRUE, fMSApp = FALSE, fShowDebug = FALSE;
  1206. BYTE *pbBuf = NULL;
  1207. VALIDATEPARM(hr, (pfrm == NULL || pfrm->wszExe == NULL || ppi == NULL ||
  1208. wszDir == NULL || hToken == NULL || wszDumpFile == NULL ||
  1209. wszDir[0] == L'\0'));
  1210. if (FAILED(hr))
  1211. {
  1212. SetLastError(ERROR_INVALID_PARAMETER);
  1213. goto done;
  1214. }
  1215. // get the config info
  1216. TESTHR(hr, oCfg.Read(eroPolicyRO));
  1217. if (FAILED(hr))
  1218. goto done;
  1219. if (oCfg.get_ShowUI() == eedDisabled && oCfg.get_DoReport() == eedDisabled)
  1220. goto done;
  1221. // figure out how we're reporting / notifying the user
  1222. if (oCfg.get_DoReport() == eedDisabled ||
  1223. oCfg.ShouldCollect(pfrm->wszExe, &fMSApp) == FALSE)
  1224. fAllowSend = FALSE;
  1225. if (oCfg.get_ShowUI() == eedDisabled)
  1226. {
  1227. LPCWSTR wszULPath = oCfg.get_DumpPath(NULL, 0);
  1228. // check and make sure that we have a corporate path specified. If we
  1229. // don't, bail
  1230. if (wszULPath == NULL || *wszULPath == L'\0')
  1231. goto done;
  1232. }
  1233. cchDir = wcslen(wszDir);
  1234. cch = cchDir + sizeofSTRW(c_wszManFileName) + 4;
  1235. __try { wszManifest = (LPWSTR)_alloca(cch * sizeof(WCHAR)); }
  1236. __except(EXCEPTION_STACK_OVERFLOW) { wszManifest = NULL; }
  1237. if (wszManifest == NULL)
  1238. {
  1239. SetLastError(ERROR_OUTOFMEMORY);
  1240. goto done;
  1241. }
  1242. wcscpy(wszManifest, wszDir);
  1243. wszManifest[cchDir] = L'\\';
  1244. wszManifest[cchDir + 1] = L'\0';
  1245. wcscat(wszManifest, c_wszManFileName);
  1246. cchDir = wcslen(wszDir);
  1247. cch = 2 * cchDir + wcslen(wszDumpFile) + sizeofSTRW(c_wszACFileName) + 4;
  1248. __try { wszDump = (LPWSTR)_alloca(cch * sizeof(WCHAR)); }
  1249. __except(EXCEPTION_STACK_OVERFLOW) { wszDump = NULL; }
  1250. if (wszDump == NULL)
  1251. {
  1252. SetLastError(ERROR_OUTOFMEMORY);
  1253. goto done;
  1254. }
  1255. wcscpy(wszDump, wszDir);
  1256. wszDump[cchDir] = L'\\';
  1257. wszDump[cchDir + 1] = L'\0';
  1258. wcscat(wszDump, wszDumpFile);
  1259. // checlk and see if we need to put a debug button on the DW dialog
  1260. dw = RegOpenKeyExW(HKEY_LOCAL_MACHINE, c_wszRKAeDebug, 0, KEY_READ,
  1261. &hkeyDebug);
  1262. if (dw == ERROR_SUCCESS)
  1263. {
  1264. LPWSTR wszDebugger;
  1265. WCHAR wszAuto[32];
  1266. DWORD dwType, cbNeed;
  1267. cbNeed = sizeof(wszAuto);
  1268. dw = RegQueryValueExW(hkeyDebug, c_wszRVAuto, NULL, &dwType,
  1269. (LPBYTE)wszAuto, &cbNeed);
  1270. if (dw != ERROR_SUCCESS || cbNeed == 0 || dwType != REG_SZ)
  1271. goto doneDebugCheck;
  1272. // only way to get here if Auto == 1 is if drwtsn32 is the JIT debugger
  1273. if (wszAuto[0] == L'1')
  1274. goto doneDebugCheck;
  1275. cbNeed = 0;
  1276. dw = RegQueryValueExW(hkeyDebug, c_wszRVDebugger, NULL, &dwType, NULL,
  1277. &cbNeed);
  1278. if (dw != ERROR_SUCCESS || cbNeed == 0 || dwType != REG_SZ)
  1279. goto doneDebugCheck;
  1280. cbNeed += sizeof(WCHAR);
  1281. __try { wszDebugger = (LPWSTR)_alloca(cbNeed); }
  1282. __except(EXCEPTION_STACK_OVERFLOW) { wszDebugger = NULL; }
  1283. if (wszDebugger == NULL)
  1284. goto doneDebugCheck;
  1285. dw = RegQueryValueExW(hkeyDebug, c_wszRVDebugger, NULL, NULL,
  1286. (LPBYTE)wszDebugger, &cbNeed);
  1287. if (dw != ERROR_SUCCESS)
  1288. goto doneDebugCheck;
  1289. if (wszDebugger[0] != L'\0')
  1290. fShowDebug = TRUE;
  1291. doneDebugCheck:
  1292. RegCloseKey(hkeyDebug);
  1293. hkeyDebug = NULL;
  1294. }
  1295. #ifndef MANIFEST_HEAP
  1296. hFile = CreateFileW(wszDump, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0,
  1297. NULL);
  1298. if (hFile == INVALID_HANDLE_VALUE)
  1299. {
  1300. SetLastError(dw);
  1301. goto done;
  1302. }
  1303. #endif // !MANIFEST_HEAP
  1304. // get a handle to the target process
  1305. hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
  1306. pfrm->pidReqProcess);
  1307. if (hProc == NULL)
  1308. goto done;
  1309. // generate the minidump
  1310. ZeroMemory(&smdo, sizeof(smdo));
  1311. #ifdef MANIFEST_HEAP
  1312. smdo.ulThread = c_ulThreadWriteDefault;
  1313. smdo.ulMod = c_ulModuleWriteDefault;
  1314. #else
  1315. smdo.ulThread = ThreadWriteThread | ThreadWriteContext | ThreadWriteStack;
  1316. smdo.ulMod = ModuleWriteModule | ModuleWriteMiscRecord | ModuleWriteDataSeg;
  1317. #endif
  1318. smdo.dwThreadID = pfrm->thidFault;
  1319. smdo.dfOptions = dfCollectSig;
  1320. smdo.pvFaultAddr = pfrm->pvFaultAddr;
  1321. smdo.pEP = pfrm->pEP;
  1322. smdo.fEPClient = TRUE;
  1323. smdo.wszModFullPath[0] = L'\0';
  1324. wcscpy(smdo.wszAppFullPath, pfrm->wszExe);
  1325. wcscpy(smdo.wszMod, L"unknown");
  1326. #ifdef MANIFEST_HEAP
  1327. TESTBOOL(hr, InternalGenFullAndTriageMinidumps(hProc, pfrm->pidReqProcess,
  1328. wszDump, NULL, &smdo, pfrm->fIs64bit));
  1329. #else
  1330. TESTBOOL(hr, InternalGenerateMinidump(hProc, pfrm->pidReqProcess, hFile,
  1331. &smdo, wszDump));
  1332. #endif
  1333. if (FAILED(hr))
  1334. goto done;
  1335. // log an event- don't care if it fails or not.
  1336. TESTHR(hr, LogUser(smdo.wszApp, smdo.rgAppVer, smdo.wszMod, smdo.rgModVer,
  1337. smdo.pvOffset, pfrm->fIs64bit, ER_USERCRASH_LOG));
  1338. // generate all the URLs & file paths we'll need for reporting
  1339. TESTHR(hr, BuildManifestURLs(smdo.wszApp, smdo.wszMod, smdo.rgAppVer,
  1340. smdo.rgModVer, smdo.pvOffset,
  1341. pfrm->fIs64bit, &wszStage1, &wszStage2,
  1342. &wszCorpPath, &pbBuf));
  1343. if (FAILED(hr))
  1344. goto done;
  1345. TESTHR(hr, GetVerName(smdo.wszAppFullPath, wszAppName,
  1346. sizeofSTRW(wszAppName)));
  1347. if (FAILED(hr))
  1348. goto done;
  1349. wszAppName[sizeofSTRW(wszAppName) - 1] = L'\0';
  1350. // we created the wszDump buffer above big enuf to hold both the
  1351. // dumpfile path as well as the app compat filename. So make
  1352. // use of that right now.
  1353. cchSep = wcslen(wszDump);
  1354. pwszAppCompat = wszDump + cchSep + 1;
  1355. wcscpy(pwszAppCompat, wszDir);
  1356. pwszAppCompat[cchDir] = L'\\';
  1357. pwszAppCompat[cchDir + 1] = L'\0';
  1358. wcscat(pwszAppCompat, c_wszACFileName);
  1359. // if we succeed, turn the NULL following the dump file path into
  1360. // the DW separator character
  1361. TESTBOOL(hr, GetAppCompatData(smdo.wszAppFullPath, smdo.wszAppFullPath,
  1362. pwszAppCompat));
  1363. if (SUCCEEDED(hr))
  1364. wszDump[cchSep] = DW_FILESEP;
  1365. ZeroMemory(&dwmb, sizeof(dwmb));
  1366. dwmb.wszTitle = wszAppName;
  1367. dwmb.nidErrMsg = IDS_FERRMSG;
  1368. dwmb.wszStage1 = wszStage1;
  1369. dwmb.wszStage2 = wszStage2;
  1370. dwmb.wszBrand = c_wszDWBrand;
  1371. dwmb.wszFileList = wszDump;
  1372. dwmb.hToken = hToken;
  1373. dwmb.pvEnv = pvEnv;
  1374. dwmb.fIsMSApp = fMSApp;
  1375. dwmb.wszCorpPath = wszCorpPath;
  1376. if (fShowDebug)
  1377. dwmb.dwOptions = emoShowDebugButton;
  1378. // check and see if the system is shutting down. If so, CreateProcess is
  1379. // gonna pop up some annoying UI that we can't get rid of, so we don't
  1380. // want to call it if we know it's gonna happen.
  1381. if (GetSystemMetrics(SM_SHUTTINGDOWN))
  1382. goto done;
  1383. // we get back the name of the manifest file here. it will be up to the client to
  1384. // delete it.
  1385. frrvRet = StartDWManifest(oCfg, dwmb, wszManifest, fAllowSend);
  1386. CopyMemory(ppi, &dwmb.pi, sizeof(PROCESS_INFORMATION));
  1387. done:
  1388. dw = GetLastError();
  1389. if (pbBuf != NULL)
  1390. MyFree(pbBuf);
  1391. if (hProc != NULL)
  1392. CloseHandle(hProc);
  1393. #ifndef MANIFEST_HEAP
  1394. if (hFile != NULL)
  1395. CloseHandle(hFile);
  1396. #endif
  1397. if (frrvRet != frrvOk)
  1398. {
  1399. if (wszDump != NULL)
  1400. {
  1401. if (pwszAppCompat != NULL)
  1402. {
  1403. wszDump[cchSep] = L'\0';
  1404. DeleteFileW(pwszAppCompat);
  1405. }
  1406. #ifdef MANIFEST_HEAP
  1407. DeleteFullAndTriageMiniDumps(wszDump);
  1408. #else
  1409. DeleteFileW(wszDump);
  1410. #endif
  1411. }
  1412. if (wszManifest != NULL)
  1413. DeleteFileW(wszManifest);
  1414. }
  1415. SetLastError(dw);
  1416. return frrvRet;
  1417. }
  1418. // **************************************************************************
  1419. EFaultRepRetVal APIENTRY ReportFault(LPEXCEPTION_POINTERS pep, DWORD dwOpt)
  1420. {
  1421. USE_TRACING("ReportFault");
  1422. CPFFaultClientCfg oCfg;
  1423. EFaultRepRetVal frrvRet = frrvErrNoDW;
  1424. HRESULT hr = NOERROR;
  1425. WCHAR wszFile[MAX_PATH], *pwsz;
  1426. DWORD dwFlags = 0;
  1427. HKEY hkey = NULL;
  1428. BOOL fUseExceptionMode = TRUE, fMSApp = FALSE;
  1429. __try
  1430. {
  1431. VALIDATEPARM(hr, (pep == NULL));
  1432. if (FAILED(hr))
  1433. goto done;
  1434. // get the config info
  1435. TESTHR(hr, oCfg.Read(eroPolicyRO));
  1436. if (FAILED(hr))
  1437. goto done;
  1438. // assume system is on a local drive with a base path of "X:\"
  1439. if (oCfg.get_TextLog() == eedEnabled)
  1440. {
  1441. HANDLE hFaultLog = INVALID_HANDLE_VALUE;
  1442. GetSystemDirectoryW(wszFile, sizeofSTRW(wszFile));
  1443. wszFile[3] = L'\0';
  1444. wcscat(wszFile, c_wszLogFileName);
  1445. hFaultLog = CreateFileW(wszFile, GENERIC_WRITE,
  1446. FILE_SHARE_WRITE | FILE_SHARE_READ,
  1447. NULL, OPEN_ALWAYS, 0, NULL);
  1448. if (hFaultLog != INVALID_HANDLE_VALUE)
  1449. {
  1450. SYSTEMTIME st;
  1451. DWORD cb, cbWritten;
  1452. char szMsg[512];
  1453. GetSystemTime(&st);
  1454. GetModuleFileNameW(NULL, wszFile, sizeofSTRW(wszFile));
  1455. cb = wsprintf(szMsg,
  1456. "%02d-%02d-%04d %02d:%02d:%02d User fault %08x in %ls\r\n",
  1457. st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute,
  1458. st.wSecond, pep->ExceptionRecord->ExceptionCode,
  1459. wszFile);
  1460. SetFilePointer(hFaultLog, 0, NULL, FILE_END);
  1461. WriteFile(hFaultLog, szMsg, cb, &cbWritten, NULL);
  1462. CloseHandle(hFaultLog);
  1463. }
  1464. wszFile[0] = L'\0';
  1465. }
  1466. // if reporting and notification are both disabled, then there's nothing of
  1467. // great value that we're gonna do here, so bail.
  1468. // Return frrvErrNoDW to indicate that we didn't do squat
  1469. if (oCfg.get_ShowUI() == eedDisabled && oCfg.get_DoReport() == eedDisabled)
  1470. goto done;
  1471. // if setup is in progress, we want to just bail cuz we don't want to hang
  1472. // setup. Also, the network isn't setup so we can't really report anyway.
  1473. // At some point, might want to cache this info & report on first launch.
  1474. TESTERR(hr, RegOpenKeyExW(HKEY_LOCAL_MACHINE, c_wszRKSetup, 0, KEY_READ,
  1475. &hkey));
  1476. if (SUCCEEDED(hr))
  1477. {
  1478. DWORD cbData;
  1479. DWORD dwData;
  1480. cbData = sizeof(dwData);
  1481. dwData = 0;
  1482. TESTERR(hr, RegQueryValueExW(hkey, c_wszRVSetupNow, NULL, NULL,
  1483. (LPBYTE)&dwData, &cbData));
  1484. RegCloseKey(hkey);
  1485. if (SUCCEEDED(hr) && dwData != 0)
  1486. goto done;
  1487. }
  1488. if (oCfg.get_ShowUI() == eedDisabled)
  1489. {
  1490. LPCWSTR wszULPath = oCfg.get_DumpPath(NULL, 0);
  1491. fUseExceptionMode = TRUE;
  1492. dwFlags |= fDwHeadless;
  1493. // check and make sure that we have a corporate path specified. If
  1494. // we don't, bail
  1495. if (wszULPath == NULL || *wszULPath == L'\0')
  1496. goto done;
  1497. }
  1498. // don't want to go into this if we're already in the middle of reporting
  1499. if (g_fAlreadyReportingFault)
  1500. goto done;
  1501. g_fAlreadyReportingFault = TRUE;
  1502. // make sure we're not trying to report for DW or dumprep-
  1503. GetModuleFileNameW(NULL, wszFile, sizeofSTRW(wszFile));
  1504. for(pwsz = wszFile + wcslen(wszFile);
  1505. pwsz >= wszFile && *pwsz != L'\\';
  1506. pwsz--);
  1507. if (*pwsz == L'\\')
  1508. pwsz++;
  1509. if (_wcsicmp(pwsz, L"dwwin.exe") == 0 ||
  1510. _wcsicmp(pwsz, L"dumprep.exe") == 0)
  1511. goto done;
  1512. // figure out how we're reporting / notifying the user
  1513. if (oCfg.get_DoReport() == eedDisabled ||
  1514. oCfg.ShouldCollect(wszFile, &fMSApp) == FALSE)
  1515. dwFlags |= fDwNoReporting;
  1516. // if it's a MS app, set the flag that says we can have 'please help
  1517. // Microsoft' text in DW.
  1518. if (fMSApp == FALSE)
  1519. dwFlags |= fDwUseLitePlea;
  1520. // if we're not headless, then we have to see if we have the correct
  1521. // security context to launch DW directly. The correct security context
  1522. // is defined as the current process having the same security context as
  1523. // the user currently logged on interactively to the current session
  1524. if (oCfg.get_ShowUI() != eedDisabled)
  1525. {
  1526. if (oCfg.get_ForceQueueMode())
  1527. {
  1528. fUseExceptionMode = FALSE;
  1529. }
  1530. else
  1531. {
  1532. fUseExceptionMode = DoUserContextsMatch();
  1533. if (fUseExceptionMode == FALSE)
  1534. fUseExceptionMode = DoWinstaDesktopMatch() &&
  1535. (AmIPrivileged(FALSE) == FALSE);
  1536. }
  1537. }
  1538. // if we can use exception mode, then just go ahead and use the normal
  1539. // reporting mechanism (shared memory block, etc)
  1540. if (fUseExceptionMode)
  1541. {
  1542. LPCWSTR pwszServer = oCfg.get_DefaultServer(NULL, 0);
  1543. LPCSTR szServer;
  1544. char szBuf[MAX_PATH];
  1545. // determine what server we're going to send the data to.
  1546. szBuf[0] = '\0';
  1547. if (pwszServer != NULL && *pwszServer != L'\0')
  1548. WideCharToMultiByte(CP_ACP, 0, pwszServer, -1, szBuf,
  1549. sizeof(szBuf), NULL, NULL);
  1550. if (szBuf[0] != '\0')
  1551. szServer = szBuf;
  1552. else
  1553. szServer = (oCfg.get_UseInternal() == 1) ? c_szDWDefServerI :
  1554. c_szDWDefServerE;
  1555. frrvRet = StartDWException(pep, dwOpt, dwFlags, szServer, -1);
  1556. }
  1557. // otherwise, have to use manifest, which of course means generating the
  1558. // minidump ourselves, parsing it for the signature, and everything else
  1559. // that DW does automatically for us... Sigh...
  1560. else
  1561. {
  1562. frrvRet = StartManifestReport(pep, wszFile, dwOpt, -1);
  1563. }
  1564. }
  1565. __except(SetLastError(GetExceptionCode()), EXCEPTION_EXECUTE_HANDLER)
  1566. {
  1567. }
  1568. done:
  1569. g_fAlreadyReportingFault = FALSE;
  1570. return frrvRet;
  1571. }