Leaked source code of windows server 2003
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.

2084 lines
68 KiB

  1. /**************************** Module Header ********************************\
  2. * Module Name: harderr.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Hard error handler
  7. *
  8. * History:
  9. * 07-03-91 JimA Created scaffolding.
  10. \***************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include <ntlpcapi.h>
  14. #include <winsta.h>
  15. VOID UserHardErrorEx(
  16. PCSR_THREAD pt,
  17. PHARDERROR_MSG pmsg,
  18. PCTXHARDERRORINFO pCtxHEInfo);
  19. VOID ProcessHardErrorRequest(
  20. BOOL fNewThread);
  21. #ifdef PRERELEASE
  22. HARDERRORINFO hiLastProcessed;
  23. #endif
  24. CONST UINT wIcons[] = {
  25. 0,
  26. MB_ICONINFORMATION,
  27. MB_ICONEXCLAMATION,
  28. MB_ICONSTOP
  29. };
  30. CONST UINT wOptions[] = {
  31. MB_ABORTRETRYIGNORE,
  32. MB_OK,
  33. MB_OKCANCEL,
  34. MB_RETRYCANCEL,
  35. MB_YESNO,
  36. MB_YESNOCANCEL,
  37. MB_OK, // OptionShutdownSystem
  38. MB_OK, // OptionOkNoWait
  39. MB_CANCELTRYCONTINUE
  40. };
  41. CONST DWORD dwResponses[] = {
  42. ResponseNotHandled, // MessageBox error
  43. ResponseOk, // IDOK
  44. ResponseCancel, // IDCANCEL
  45. ResponseAbort, // IDABORT
  46. ResponseRetry, // IDRETRY
  47. ResponseIgnore, // IDIGNORE
  48. ResponseYes, // IDYES
  49. ResponseNo, // IDNO
  50. ResponseNotHandled, // Error as IDCLOSE can't show up
  51. ResponseNotHandled, // error as IDHELP can't show up
  52. ResponseTryAgain, // IDTRYAGAIN
  53. ResponseContinue // IDCONTINUE
  54. };
  55. CONST DWORD dwResponseDefault[] = {
  56. ResponseAbort, // OptionAbortRetryIgnore
  57. ResponseOk, // OptionOK
  58. ResponseOk, // OptionOKCancel
  59. ResponseCancel, // OptionRetryCancel
  60. ResponseYes, // OptionYesNo
  61. ResponseYes, // OptionYesNoCancel
  62. ResponseOk, // OptionShutdownSystem
  63. ResponseOk, // OptionOKNoWait
  64. ResponseCancel // OptionCancelTryContinue
  65. };
  66. /*
  67. * Citrix SendMessage entry point to harderror handler and cleanup routine
  68. */
  69. VOID HardErrorInsert(PCSR_THREAD, PHARDERROR_MSG, PCTXHARDERRORINFO);
  70. VOID HardErrorRemove(PCTXHARDERRORINFO);
  71. /***************************************************************************\
  72. * LogErrorPopup
  73. *
  74. * History:
  75. * 09-22-97 GerardoB Added Header
  76. \***************************************************************************/
  77. VOID LogErrorPopup(
  78. IN LPWSTR Caption,
  79. IN LPWSTR Message)
  80. {
  81. LPWSTR lps[2];
  82. lps[0] = Caption;
  83. lps[1] = Message;
  84. UserAssert(gEventSource != NULL);
  85. ReportEvent(gEventSource,
  86. EVENTLOG_INFORMATION_TYPE,
  87. 0,
  88. STATUS_LOG_HARD_ERROR,
  89. NULL,
  90. ARRAY_SIZE(lps),
  91. 0,
  92. lps,
  93. NULL);
  94. }
  95. /***************************************************************************\
  96. * SubstituteDeviceName
  97. *
  98. * History:
  99. * 09-22-97 GerardoB Added Header
  100. \***************************************************************************/
  101. static WCHAR wszDosDevices[] = L"\\??\\A:";
  102. VOID
  103. SubstituteDeviceName(
  104. PUNICODE_STRING InputDeviceName,
  105. LPSTR OutputDriveLetter
  106. )
  107. {
  108. UNICODE_STRING LinkName;
  109. UNICODE_STRING DeviceName;
  110. OBJECT_ATTRIBUTES Obja;
  111. HANDLE LinkHandle;
  112. NTSTATUS Status;
  113. ULONG i;
  114. PWCHAR p;
  115. WCHAR DeviceNameBuffer[MAXIMUM_FILENAME_LENGTH];
  116. RtlInitUnicodeString(&LinkName,wszDosDevices);
  117. p = wszDosDevices + ARRAY_SIZE(wszDosDevices) - ARRAY_SIZE(L"A:");
  118. for(i=0;i<26;i++){
  119. *p = (WCHAR)('A' + i);
  120. InitializeObjectAttributes(
  121. &Obja,
  122. &LinkName,
  123. OBJ_CASE_INSENSITIVE,
  124. NULL,
  125. NULL
  126. );
  127. Status = NtOpenSymbolicLinkObject(
  128. &LinkHandle,
  129. SYMBOLIC_LINK_QUERY,
  130. &Obja
  131. );
  132. if (NT_SUCCESS( Status )) {
  133. //
  134. // Open succeeded, Now get the link value
  135. //
  136. DeviceName.Length = 0;
  137. DeviceName.MaximumLength = sizeof(DeviceNameBuffer);
  138. DeviceName.Buffer = DeviceNameBuffer;
  139. Status = NtQuerySymbolicLinkObject(
  140. LinkHandle,
  141. &DeviceName,
  142. NULL
  143. );
  144. NtClose(LinkHandle);
  145. if ( NT_SUCCESS(Status) ) {
  146. if ( RtlEqualUnicodeString(InputDeviceName,&DeviceName,TRUE) ) {
  147. OutputDriveLetter[0]=(CHAR)('A'+i);
  148. OutputDriveLetter[1]=':';
  149. OutputDriveLetter[2]='\0';
  150. return;
  151. }
  152. }
  153. }
  154. }
  155. }
  156. /***************************************************************************\
  157. * GetErrorMode
  158. *
  159. * History:
  160. * 09-22-97 GerardoB Added Header
  161. \***************************************************************************/
  162. DWORD GetErrorMode(VOID)
  163. {
  164. HANDLE hKey;
  165. UNICODE_STRING UnicodeString;
  166. OBJECT_ATTRIBUTES OA;
  167. LONG Status;
  168. BYTE Buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
  169. DWORD cbSize;
  170. DWORD dwRet = 0;
  171. RtlInitUnicodeString(&UnicodeString,
  172. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Windows");
  173. InitializeObjectAttributes(&OA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
  174. Status = NtOpenKey(&hKey, KEY_READ, &OA);
  175. if (NT_SUCCESS(Status)) {
  176. RtlInitUnicodeString(&UnicodeString, L"ErrorMode");
  177. Status = NtQueryValueKey(hKey,
  178. &UnicodeString,
  179. KeyValuePartialInformation,
  180. (PKEY_VALUE_PARTIAL_INFORMATION)Buf,
  181. sizeof(Buf),
  182. &cbSize);
  183. if (NT_SUCCESS(Status)) {
  184. dwRet = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->Data);
  185. }
  186. NtClose(hKey);
  187. }
  188. return dwRet;
  189. }
  190. /***************************************************************************\
  191. * FreePhi
  192. *
  193. * History:
  194. * 09-18-97 GerardoB Created
  195. \***************************************************************************/
  196. void FreePhi (PHARDERRORINFO phi)
  197. {
  198. if (phi->dwHEIFFlags & HEIF_ALLOCATEDMSG) {
  199. LocalFree(phi->pmsg);
  200. }
  201. RtlFreeUnicodeString(&phi->usText);
  202. RtlFreeUnicodeString(&phi->usCaption);
  203. LocalFree(phi);
  204. }
  205. /***************************************************************************\
  206. * ReplyHardError
  207. *
  208. * This function is called when we are done with a hard error.
  209. *
  210. * History:
  211. * 03-11-97 GerardoB Created
  212. \***************************************************************************/
  213. VOID ReplyHardError(
  214. PHARDERRORINFO phi,
  215. DWORD dwResponse)
  216. {
  217. phi->pmsg->Response = dwResponse;
  218. /*
  219. * Signal the event if any. If not, reply if we haven't done so already.
  220. */
  221. if (phi->hEventHardError != NULL) {
  222. NtSetEvent(phi->hEventHardError, NULL);
  223. } else if (!(phi->dwHEIFFlags & HEIF_REPLIED)) {
  224. NtReplyPort(((PCSR_THREAD)phi->pthread)->Process->ClientPort,
  225. (PPORT_MESSAGE)phi->pmsg);
  226. }
  227. /*
  228. * If we had locked the thread or were holding the client port, then let
  229. * it go now.
  230. */
  231. if (phi->dwHEIFFlags & HEIF_DEREFTHREAD) {
  232. CsrDereferenceThread(phi->pthread);
  233. }
  234. /*
  235. * We're done with this dude.
  236. */
  237. FreePhi(phi);
  238. }
  239. /***************************************************************************\
  240. * CheckDefaultDesktop
  241. *
  242. * This function is called by the HardErrorHandler when it's notified that
  243. * we've switched desktops or upon waking up. If we're on the default desktop
  244. * now, then we clear the HEIF_WRONGDESKTOP flag. This flag is set when we
  245. * find a MB_DEFAULT_DESKTOP_ONLY request but we are not in the right
  246. * (default) desktop.
  247. *
  248. * History:
  249. * 06-02-97 GerardoB Created
  250. \***************************************************************************/
  251. VOID CheckDefaultDesktop(
  252. VOID)
  253. {
  254. PHARDERRORINFO phi;
  255. if (HEC_WRONGDESKTOP == NtUserHardErrorControl(HardErrorInDefDesktop, NULL, NULL)) {
  256. return;
  257. }
  258. EnterCrit();
  259. phi = gphiList;
  260. while (phi != NULL) {
  261. phi->dwHEIFFlags &= ~HEIF_WRONGDESKTOP;
  262. phi = phi->phiNext;
  263. }
  264. LeaveCrit();
  265. }
  266. /***************************************************************************\
  267. * GetHardErrorText
  268. *
  269. * This function figures out the message box title, text and flags. We want
  270. * to do this up front so we can log this error when the hard error is
  271. * raised. Previously we used to log it after the user had dismissed the
  272. * message box -- but that was not when the error occurred (DCR Bug 107590).
  273. *
  274. * History:
  275. * 09-18-97 GerardoB Extracted (and cleaned up) from HardErrorHandler
  276. \***************************************************************************/
  277. VOID GetHardErrorText(
  278. PHARDERRORINFO phi)
  279. {
  280. static WCHAR wszUnkownSoftwareException [] = L"unknown software exception";
  281. static WCHAR wszException [] = L"{EXCEPTION}";
  282. static WCHAR wszUnknownHardError [] = L"Unknown Hard Error";
  283. ANSI_STRING asLocal, asMessage;
  284. BOOL fFreeAppNameBuffer, fFreeCaption;
  285. BOOL fResAllocated, fResAllocated1, fErrorIsFromSystem;
  286. WCHAR wszErrorMessage[WSPRINTF_LIMIT + 1];
  287. DWORD dwCounter, dwStringsToFreeMask, dwMBFlags, dwTimeout;
  288. ULONG_PTR adwParameterVector[MAXIMUM_HARDERROR_PARAMETERS];
  289. HANDLE hClientProcess;
  290. HWND hwndOwner;
  291. NTSTATUS Status;
  292. PHARDERROR_MSG phemsg;
  293. PMESSAGE_RESOURCE_ENTRY MessageEntry;
  294. PWSTR pwszCaption, pwszFormatString;
  295. PWSTR pwszAppName, pwszResBuffer, pwszResBuffer1;
  296. PWSTR pwszMsg, pwszTitle, pwszFullCaption;
  297. UINT uMsgLen, uCaptionLen, uTitleLen;
  298. UNICODE_STRING usScratch, usLocal, usMessage, usCaption;
  299. /*
  300. * Initialize working variables
  301. */
  302. fFreeAppNameBuffer = fFreeCaption = FALSE;
  303. hClientProcess = NULL;
  304. RtlInitUnicodeString(&usCaption, NULL);
  305. RtlInitUnicodeString(&usMessage, NULL);
  306. dwTimeout = INFINITE;
  307. /*
  308. * Initialize response in case something goes wrong
  309. */
  310. phemsg = phi->pmsg;
  311. phemsg->Response = ResponseNotHandled;
  312. /*
  313. * Make a copy of the parameters. Initialize unused ones to point to
  314. * empty strings (in case we expect a string there).
  315. */
  316. UserAssert(phemsg->NumberOfParameters <= MAXIMUM_HARDERROR_PARAMETERS);
  317. RtlCopyMemory(adwParameterVector, phemsg->Parameters, phemsg->NumberOfParameters * sizeof(*phemsg->Parameters));
  318. dwCounter = phemsg->NumberOfParameters;
  319. while (dwCounter < MAXIMUM_HARDERROR_PARAMETERS) {
  320. adwParameterVector[dwCounter++] = (ULONG_PTR)L"";
  321. }
  322. /*
  323. * Open the client process so we can read the strings parameters, process
  324. * name, etc ... from its address space.
  325. */
  326. hClientProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
  327. FALSE, HandleToUlong(phemsg->h.ClientId.UniqueProcess));
  328. fErrorIsFromSystem = (hClientProcess == NULL);
  329. /*
  330. * If there are unicode strings, then we need to convert them to ansi
  331. * and store them in the parameter vector.
  332. */
  333. dwStringsToFreeMask = 0;
  334. if (phemsg->UnicodeStringParameterMask) {
  335. for (dwCounter = 0; dwCounter < phemsg->NumberOfParameters; dwCounter++) {
  336. /*
  337. * If there is no string in this position, continue.
  338. */
  339. if (!(phemsg->UnicodeStringParameterMask & (1 << dwCounter))) {
  340. continue;
  341. }
  342. /*
  343. * Point to an empty string in case we don't have a client to
  344. * read from or something fails later on.
  345. */
  346. adwParameterVector[dwCounter] = (ULONG_PTR)L"";
  347. if (hClientProcess == NULL) {
  348. continue;
  349. }
  350. Status = NtReadVirtualMemory(hClientProcess,
  351. (PVOID)phemsg->Parameters[dwCounter],
  352. (PVOID)&usScratch,
  353. sizeof(usScratch), NULL);
  354. if (!NT_SUCCESS(Status)) {
  355. RIPMSG0(RIP_WARNING, "Failed to read error string struct!");
  356. continue;
  357. }
  358. usLocal = usScratch;
  359. usLocal.Buffer = (PWSTR)LocalAlloc(LMEM_ZEROINIT, usLocal.Length + sizeof(UNICODE_NULL));
  360. if (usLocal.Buffer == NULL) {
  361. RIPMSG0(RIP_WARNING, "Failed to alloc string buffer!");
  362. continue;
  363. }
  364. Status = NtReadVirtualMemory(hClientProcess,
  365. (PVOID)usScratch.Buffer,
  366. (PVOID)usLocal.Buffer,
  367. usLocal.Length,
  368. NULL);
  369. if (!NT_SUCCESS(Status)) {
  370. LocalFree(usLocal.Buffer);
  371. RIPMSG0(RIP_WARNING, "Failed to read error string!");
  372. continue;
  373. }
  374. usLocal.MaximumLength = usLocal.Length;
  375. Status = RtlUnicodeStringToAnsiString(&asLocal, &usLocal, TRUE);
  376. if (!NT_SUCCESS(Status)) {
  377. LocalFree(usLocal.Buffer);
  378. RIPMSG0(RIP_WARNING, "Failed to translate error string!");
  379. continue;
  380. }
  381. /*
  382. * Check to see if string contains an NT device name. If so,
  383. * then attempt a drive letter substitution.
  384. */
  385. if (strstr(asLocal.Buffer,"\\Device") == asLocal.Buffer) {
  386. SubstituteDeviceName(&usLocal,asLocal.Buffer);
  387. } else if ((asLocal.Length > 4) && !_strnicmp(asLocal.Buffer, "\\??\\", 4)) {
  388. strcpy( asLocal.Buffer, asLocal.Buffer+4 );
  389. asLocal.Length -= 4;
  390. } else {
  391. /*
  392. * Processing some status code doesn't require ansi strings.
  393. * Since no substitution took place, let's ignore the
  394. * translation to avoid losing chars due to incorrect code
  395. * page translation.
  396. */
  397. switch (phemsg->Status) {
  398. case STATUS_SERVICE_NOTIFICATION:
  399. case STATUS_VDM_HARD_ERROR:
  400. adwParameterVector[dwCounter] = (ULONG_PTR)usLocal.Buffer;
  401. RtlFreeAnsiString(&asLocal);
  402. continue;
  403. }
  404. }
  405. LocalFree(usLocal.Buffer);
  406. dwStringsToFreeMask |= (1 << dwCounter);
  407. adwParameterVector[dwCounter] = (ULONG_PTR)asLocal.Buffer;
  408. }
  409. }
  410. /*
  411. * Read additional MB flags, if provided.
  412. */
  413. #if (HARDERROR_PARAMETERS_FLAGSPOS >= MAXIMUM_HARDERROR_PARAMETERS)
  414. #error Invalid HARDERROR_PARAMETERS_FLAGSPOS value.
  415. #endif
  416. #if (HARDERROR_FLAGS_DEFDESKTOPONLY != MB_DEFAULT_DESKTOP_ONLY)
  417. #error Invalid HARDERROR_FLAGS_DEFDESKTOPONLY
  418. #endif
  419. dwMBFlags = 0;
  420. if (phemsg->NumberOfParameters > HARDERROR_PARAMETERS_FLAGSPOS) {
  421. /*
  422. * Currently we only use MB_DEFAULT_DESKTOP_ONLY
  423. */
  424. UserAssert(!(adwParameterVector[HARDERROR_PARAMETERS_FLAGSPOS] & ~MB_DEFAULT_DESKTOP_ONLY));
  425. if (adwParameterVector[HARDERROR_PARAMETERS_FLAGSPOS] & MB_DEFAULT_DESKTOP_ONLY) {
  426. dwMBFlags |= MB_DEFAULT_DESKTOP_ONLY;
  427. }
  428. }
  429. /*
  430. * For some status codes, all MessageBox parameters are provided in the
  431. * HardError parameters.
  432. */
  433. switch (phemsg->Status) {
  434. case STATUS_SERVICE_NOTIFICATION:
  435. if (phemsg->UnicodeStringParameterMask & 0x1) {
  436. RtlInitUnicodeString(&usMessage,
  437. *(PWSTR)adwParameterVector[0] ?
  438. (PWSTR)adwParameterVector[0] : NULL);
  439. } else {
  440. RtlInitAnsiString(&asMessage, (PSTR)adwParameterVector[0]);
  441. RtlAnsiStringToUnicodeString(&usMessage, &asMessage, TRUE);
  442. }
  443. if (phemsg->UnicodeStringParameterMask & 0x2) {
  444. RtlInitUnicodeString(&usCaption,
  445. *(PWSTR)adwParameterVector[1] ?
  446. (PWSTR)adwParameterVector[1] : NULL);
  447. } else {
  448. RtlInitAnsiString(&asMessage, (PSTR)adwParameterVector[1]);
  449. RtlAnsiStringToUnicodeString(&usCaption, &asMessage, TRUE);
  450. }
  451. dwMBFlags = (DWORD)adwParameterVector[2] & ~MB_SERVICE_NOTIFICATION;
  452. if (phemsg->NumberOfParameters == 4) {
  453. dwTimeout = (DWORD)adwParameterVector[3];
  454. } else {
  455. dwTimeout = INFINITE;
  456. }
  457. goto CleanUpAndSaveParams;
  458. case STATUS_VDM_HARD_ERROR:
  459. /*
  460. * Parameters[0] = (fForWOW << 16) | wBtn1;
  461. * Parameters[1] = (wBtn2 << 16) | wBtn3;
  462. * Parameters[2] = (DWORD) szTitle;
  463. * Parameters[3] = (DWORD) szMessage;
  464. */
  465. phi->dwHEIFFlags |= HEIF_VDMERROR;
  466. /*
  467. * Save VDM's Button(s) info to be used later.
  468. */
  469. phi->dwVDMParam0 = (DWORD)adwParameterVector[0];
  470. phi->dwVDMParam1 = (DWORD)adwParameterVector[1];
  471. /*
  472. * Get caption and text.
  473. */
  474. try {
  475. if (phemsg->UnicodeStringParameterMask & 0x4) {
  476. RtlInitUnicodeString(&usCaption,
  477. *(PWSTR)adwParameterVector[2] ?
  478. (PWSTR)adwParameterVector[2] : NULL);
  479. } else {
  480. if (!MBToWCS((LPSTR)adwParameterVector[2], -1, &pwszTitle, -1, TRUE)) {
  481. goto CleanUpAndSaveParams;
  482. }
  483. RtlCreateUnicodeString(&usCaption, pwszTitle);
  484. RtlFreeHeap(RtlProcessHeap(), 0, pwszTitle);
  485. }
  486. if (phemsg->UnicodeStringParameterMask & 0x8) {
  487. RtlInitUnicodeString(&usMessage,
  488. *(PWSTR)adwParameterVector[3] ?
  489. (PWSTR)adwParameterVector[3] : NULL);
  490. } else {
  491. if (!MBToWCS((LPSTR)adwParameterVector[3], -1, &pwszMsg, -1, TRUE)) {
  492. goto CleanUpAndSaveParams;
  493. }
  494. RtlCreateUnicodeString(&usMessage, pwszMsg);
  495. RtlFreeHeap(RtlProcessHeap(), 0, pwszMsg);
  496. }
  497. } except (EXCEPTION_EXECUTE_HANDLER) {
  498. RIPMSG0(RIP_WARNING, "Exception reading STATUS_VDM_HARD_ERROR paramerters");
  499. RtlFreeUnicodeString(&usCaption);
  500. RtlCreateUnicodeString(&usCaption, L"VDM Internal Error");
  501. RtlFreeUnicodeString(&usMessage);
  502. RtlCreateUnicodeString(&usMessage, L"Exception retrieving error text.");
  503. }
  504. goto CleanUpAndSaveParams;
  505. }
  506. /*
  507. * For all other status codes, we generate the information from the
  508. * status code. First, Map status code and valid response to MessageBox
  509. * flags.
  510. */
  511. dwMBFlags |= wIcons[(ULONG)(phemsg->Status) >> 30] | wOptions[phemsg->ValidResponseOptions];
  512. /*
  513. * If we have a client process, try to get the actual application name.
  514. */
  515. pwszAppName = NULL;
  516. if (!fErrorIsFromSystem) {
  517. PPEB Peb;
  518. PROCESS_BASIC_INFORMATION BasicInfo;
  519. PLDR_DATA_TABLE_ENTRY LdrEntry;
  520. LDR_DATA_TABLE_ENTRY LdrEntryData;
  521. PLIST_ENTRY LdrHead, LdrNext;
  522. PPEB_LDR_DATA Ldr;
  523. PVOID ImageBaseAddress;
  524. PWSTR ClientApplicationName;
  525. /*
  526. * This is cumbersome, but basically, we locate the processes loader
  527. * data table and get its name directly out of the loader table.
  528. */
  529. Status = NtQueryInformationProcess(hClientProcess,
  530. ProcessBasicInformation,
  531. &BasicInfo,
  532. sizeof(BasicInfo),
  533. NULL);
  534. if (!NT_SUCCESS(Status)) {
  535. fErrorIsFromSystem = TRUE;
  536. goto noname;
  537. }
  538. Peb = BasicInfo.PebBaseAddress;
  539. if (Peb == NULL) {
  540. fErrorIsFromSystem = TRUE;
  541. goto noname;
  542. }
  543. /*
  544. * ldr = Peb->Ldr
  545. */
  546. Status = NtReadVirtualMemory(hClientProcess,
  547. &Peb->Ldr,
  548. &Ldr,
  549. sizeof(Ldr),
  550. NULL);
  551. if (!NT_SUCCESS(Status)) {
  552. goto noname;
  553. }
  554. LdrHead = &Ldr->InLoadOrderModuleList;
  555. /*
  556. * LdrNext = Head->Flink;
  557. */
  558. Status = NtReadVirtualMemory(hClientProcess,
  559. &LdrHead->Flink,
  560. &LdrNext,
  561. sizeof(LdrNext),
  562. NULL);
  563. if (!NT_SUCCESS(Status)) {
  564. goto noname;
  565. }
  566. if (LdrNext == LdrHead) {
  567. goto noname;
  568. }
  569. /*
  570. * This is the entry data for the image.
  571. */
  572. LdrEntry = CONTAINING_RECORD(LdrNext, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
  573. Status = NtReadVirtualMemory(hClientProcess,
  574. LdrEntry,
  575. &LdrEntryData,
  576. sizeof(LdrEntryData),
  577. NULL);
  578. if (!NT_SUCCESS(Status)) {
  579. goto noname;
  580. }
  581. Status = NtReadVirtualMemory(hClientProcess,
  582. &Peb->ImageBaseAddress,
  583. &ImageBaseAddress,
  584. sizeof(ImageBaseAddress),
  585. NULL);
  586. if (!NT_SUCCESS(Status)) {
  587. goto noname;
  588. }
  589. if (ImageBaseAddress != LdrEntryData.DllBase) {
  590. goto noname;
  591. }
  592. LdrNext = LdrEntryData.InLoadOrderLinks.Flink;
  593. ClientApplicationName = LocalAlloc(LMEM_ZEROINIT, LdrEntryData.BaseDllName.MaximumLength);
  594. if (ClientApplicationName == NULL) {
  595. goto noname;
  596. }
  597. Status = NtReadVirtualMemory(hClientProcess,
  598. LdrEntryData.BaseDllName.Buffer,
  599. ClientApplicationName,
  600. LdrEntryData.BaseDllName.MaximumLength,
  601. NULL);
  602. if (!NT_SUCCESS(Status)) {
  603. LocalFree(ClientApplicationName);
  604. goto noname;
  605. }
  606. pwszAppName = ClientApplicationName;
  607. fFreeAppNameBuffer = TRUE;
  608. noname:;
  609. }
  610. if (pwszAppName == NULL) {
  611. /*
  612. * Load default application name (to be used in the caption).
  613. */
  614. pwszAppName = ServerLoadString(ghModuleWin,
  615. STR_UNKNOWN_APPLICATION,
  616. L"System Process",
  617. &fFreeAppNameBuffer);
  618. }
  619. /*
  620. * Map status code to (optional) caption and format string. If a caption
  621. * is provided, it's enclosed in {} and it's the first thing in the
  622. * format string.
  623. */
  624. EnterCrit();
  625. if (gNtDllHandle == NULL) {
  626. gNtDllHandle = GetModuleHandle(TEXT("ntdll"));
  627. UserAssert(gNtDllHandle != NULL);
  628. }
  629. LeaveCrit();
  630. Status = RtlFindMessage((PVOID)gNtDllHandle,
  631. (ULONG_PTR)RT_MESSAGETABLE,
  632. LANG_NEUTRAL,
  633. phemsg->Status,
  634. &MessageEntry);
  635. /*
  636. * Parse the caption (if any) and the format string.
  637. */
  638. pwszCaption = NULL;
  639. if (!NT_SUCCESS(Status)) {
  640. pwszFormatString = wszUnknownHardError;
  641. } else {
  642. pwszFormatString = (PWSTR)MessageEntry->Text;
  643. /*
  644. * If the message starts with a '{', it has a caption.
  645. */
  646. if (*pwszFormatString == L'{') {
  647. uCaptionLen = 0;
  648. pwszFormatString++;
  649. /*
  650. * Find the closing bracket.
  651. */
  652. while (*pwszFormatString != (WCHAR)0 && *pwszFormatString++ != L'}') {
  653. uCaptionLen++;
  654. }
  655. /*
  656. * Eat any non-printable stuff (\r\n), up to the NULL.
  657. */
  658. while (*pwszFormatString != (WCHAR)0 && *pwszFormatString <= L' ') {
  659. pwszFormatString++;
  660. }
  661. /*
  662. * Allocate a buffer an copy the caption string.
  663. */
  664. if (uCaptionLen++ > 0 && (pwszCaption = (PWSTR)LocalAlloc(LPTR, uCaptionLen * sizeof(WCHAR))) != NULL) {
  665. RtlCopyMemory(pwszCaption, (PWSTR)MessageEntry->Text + 1, (uCaptionLen - 1) * sizeof(WCHAR));
  666. fFreeCaption = TRUE;
  667. }
  668. }
  669. if (*pwszFormatString == (WCHAR)0) {
  670. pwszFormatString = wszUnknownHardError;
  671. }
  672. }
  673. /*
  674. * If the message didn't include a caption (or we didn't find the message),
  675. * default to something.
  676. */
  677. if (pwszCaption == NULL) {
  678. switch (phemsg->Status & ERROR_SEVERITY_ERROR) {
  679. case ERROR_SEVERITY_SUCCESS:
  680. pwszCaption = gpwszaSUCCESS;
  681. break;
  682. case ERROR_SEVERITY_INFORMATIONAL:
  683. pwszCaption = gpwszaSYSTEM_INFORMATION;
  684. break;
  685. case ERROR_SEVERITY_WARNING:
  686. pwszCaption = gpwszaSYSTEM_WARNING;
  687. break;
  688. case ERROR_SEVERITY_ERROR:
  689. pwszCaption = gpwszaSYSTEM_ERROR;
  690. break;
  691. }
  692. }
  693. UserAssert(pwszCaption != NULL);
  694. /*
  695. * If the client has a window, get its title so it can be added to the
  696. * caption.
  697. */
  698. hwndOwner = NULL;
  699. EnumThreadWindows(HandleToUlong(phemsg->h.ClientId.UniqueThread),
  700. FindWindowFromThread,
  701. (LPARAM)&hwndOwner);
  702. if (hwndOwner == NULL) {
  703. uTitleLen = 0;
  704. } else {
  705. uTitleLen = GetWindowTextLength(hwndOwner);
  706. if (uTitleLen != 0) {
  707. pwszTitle = (PWSTR)LocalAlloc(LPTR, (uTitleLen + 3) * sizeof(WCHAR));
  708. if (pwszTitle != NULL) {
  709. GetWindowText(hwndOwner, pwszTitle, uTitleLen + 1);
  710. /*
  711. * Add format chars.
  712. */
  713. *(pwszTitle + uTitleLen++) = (WCHAR)':';
  714. *(pwszTitle + uTitleLen++) = (WCHAR)' ';
  715. } else {
  716. /*
  717. * We couldn't allocate a buffer to get the title.
  718. */
  719. uTitleLen = 0;
  720. }
  721. }
  722. }
  723. /*
  724. * If we don't have a window title, make it an empty string so we won't
  725. * have to special case it later.
  726. */
  727. if (uTitleLen == 0) {
  728. pwszTitle = L"";
  729. }
  730. /*
  731. * Finally we can build the caption string now. It looks like this:
  732. * [WindowTile: ]ApplicationName - ErrorCaption
  733. */
  734. uCaptionLen = uTitleLen + wcslen(pwszAppName) + 3 + wcslen(pwszCaption) + 1;
  735. pwszFullCaption = (PWSTR)LocalAlloc(LPTR, uCaptionLen * sizeof(WCHAR));
  736. if (pwszFullCaption != NULL) {
  737. #if DBG
  738. int iLen =
  739. #endif
  740. wsprintfW(pwszFullCaption, L"%s%s - %s", pwszTitle, pwszAppName, pwszCaption);
  741. UserAssert((UINT)iLen < uCaptionLen);
  742. RtlCreateUnicodeString(&usCaption, pwszFullCaption);
  743. LocalFree(pwszFullCaption);
  744. }
  745. /*
  746. * Free caption working buffers, as appropriate.
  747. */
  748. if (fFreeCaption) {
  749. LocalFree(pwszCaption);
  750. }
  751. if (fFreeAppNameBuffer) {
  752. LocalFree(pwszAppName);
  753. }
  754. if (uTitleLen != 0) {
  755. LocalFree(pwszTitle);
  756. }
  757. /*
  758. * Build the error message using pszFormatString and adwParameterVector.
  759. * Special case UAE.
  760. */
  761. if (phemsg->Status == STATUS_UNHANDLED_EXCEPTION ) {
  762. /*
  763. * The first parameter has the exception status code. Map it to a
  764. * format string and build the error message with it and the
  765. * parameters.
  766. */
  767. Status = RtlFindMessage((PVOID)gNtDllHandle,
  768. (ULONG_PTR)RT_MESSAGETABLE,
  769. LANG_NEUTRAL,
  770. (ULONG)adwParameterVector[0],
  771. &MessageEntry);
  772. if (!NT_SUCCESS(Status)) {
  773. /*
  774. * We couldn't read the exception name so let's use unknown.
  775. */
  776. pwszResBuffer = ServerLoadString(ghModuleWin, STR_UNKNOWN_EXCEPTION,
  777. wszUnkownSoftwareException, &fResAllocated);
  778. wsprintfW(wszErrorMessage, pwszFormatString, pwszResBuffer,
  779. adwParameterVector[0], adwParameterVector[1]);
  780. if (fResAllocated) {
  781. LocalFree(pwszResBuffer);
  782. }
  783. RtlCreateUnicodeString(&usMessage, wszErrorMessage);
  784. UserAssert(usMessage.MaximumLength <= sizeof(wszErrorMessage));
  785. } else {
  786. /*
  787. * Access Violations are handled a bit differently.
  788. */
  789. if (adwParameterVector[0] == STATUS_ACCESS_VIOLATION ) {
  790. wsprintfW(wszErrorMessage, (PWSTR)MessageEntry->Text, adwParameterVector[1],
  791. adwParameterVector[3], adwParameterVector[2] ? L"written" : L"read");
  792. } else if (adwParameterVector[0] == STATUS_IN_PAGE_ERROR) {
  793. wsprintfW(wszErrorMessage, (PWSTR)MessageEntry->Text, adwParameterVector[1],
  794. adwParameterVector[3], adwParameterVector[2]);
  795. } else {
  796. /*
  797. * If this is a marked exception, skip the mark; the
  798. * exception name follows it.
  799. */
  800. pwszCaption = (PWSTR)MessageEntry->Text;
  801. if (!wcsncmp(pwszCaption, wszException, ARRAY_SIZE(wszException) - 1)) {
  802. pwszCaption += ARRAY_SIZE(wszException) - 1;
  803. /*
  804. * Skip non-printable stuff (\r\n).
  805. */
  806. while (*pwszCaption != (WCHAR)0 && *pwszCaption <= L' ') {
  807. pwszCaption++;
  808. }
  809. } else {
  810. pwszCaption = wszUnkownSoftwareException;
  811. }
  812. wsprintfW(wszErrorMessage, pwszFormatString, pwszCaption,
  813. adwParameterVector[0], adwParameterVector[1]);
  814. }
  815. UserAssert(wcslen(wszErrorMessage) < ARRAY_SIZE(wszErrorMessage));
  816. /*
  817. * Add button(s) explanation text.
  818. */
  819. pwszResBuffer = ServerLoadString(ghModuleWin, STR_OK_TO_TERMINATE,
  820. L"Click on OK to terminate the application",
  821. &fResAllocated);
  822. if (phemsg->ValidResponseOptions == OptionOkCancel ) {
  823. pwszResBuffer1 = ServerLoadString(ghModuleWin,
  824. STR_CANCEL_TO_DEBUG, L"Click on CANCEL xx to debug the application",
  825. &fResAllocated1);
  826. } else {
  827. pwszResBuffer1 = NULL;
  828. fResAllocated1 = FALSE;
  829. }
  830. /*
  831. * Conncatenate all strings, one per line.
  832. */
  833. uMsgLen = wcslen(wszErrorMessage)
  834. + wcslen(pwszResBuffer) + 1
  835. + (pwszResBuffer1 == NULL ? 0 : wcslen(pwszResBuffer1) + 1)
  836. + 1;
  837. pwszMsg = (PWSTR) LocalAlloc(LPTR, uMsgLen * sizeof(WCHAR));
  838. if (pwszMsg != NULL) {
  839. #if DBG
  840. int iLen =
  841. #endif
  842. wsprintfW(pwszMsg, L"%s\n%s%s%s", wszErrorMessage, pwszResBuffer,
  843. (pwszResBuffer1 == NULL ? L"" : L"\n"),
  844. (pwszResBuffer1 == NULL ? L"" : pwszResBuffer1));
  845. UserAssert((UINT)iLen < uMsgLen);
  846. RtlCreateUnicodeString(&usMessage, pwszMsg);
  847. LocalFree(pwszMsg);
  848. }
  849. /*
  850. * Free ServerLoadString allocations.
  851. */
  852. if (fResAllocated) {
  853. LocalFree(pwszResBuffer);
  854. }
  855. if (fResAllocated1) {
  856. LocalFree(pwszResBuffer1);
  857. }
  858. }
  859. } else {
  860. /*
  861. * Default message text generation for all other status codes.
  862. */
  863. try {
  864. #if DBG
  865. int iLen =
  866. #endif
  867. wsprintfW(wszErrorMessage, pwszFormatString, adwParameterVector[0],
  868. adwParameterVector[1],
  869. adwParameterVector[2],
  870. adwParameterVector[3]);
  871. UserAssert((UINT)iLen < ARRAY_SIZE(wszErrorMessage));
  872. /*
  873. * Remove \r\n.
  874. */
  875. pwszFormatString = wszErrorMessage;
  876. while (*pwszFormatString != (WCHAR)0) {
  877. if (*pwszFormatString == (WCHAR)0xd) {
  878. *pwszFormatString = L' ';
  879. /*
  880. * Move everything up if a CR LF sequence is found.
  881. */
  882. if (*(pwszFormatString+1) == (WCHAR)0xa) {
  883. UINT uSize = (wcslen(pwszFormatString+1) + 1) * sizeof(WCHAR);
  884. RtlMoveMemory(pwszFormatString, pwszFormatString+1, uSize);
  885. }
  886. }
  887. if (*pwszFormatString == (WCHAR)0xa) {
  888. *pwszFormatString = L' ';
  889. }
  890. pwszFormatString++;
  891. }
  892. RtlCreateUnicodeString(&usMessage, wszErrorMessage);
  893. UserAssert(usMessage.MaximumLength <= sizeof(wszErrorMessage));
  894. } except(EXCEPTION_EXECUTE_HANDLER) {
  895. wsprintfW(wszErrorMessage, L"Exception Processing Message %lx Parameters %lx %lx %lx %lx",
  896. phemsg->Status, adwParameterVector[0], adwParameterVector[1],
  897. adwParameterVector[2], adwParameterVector[3]);
  898. RtlFreeUnicodeString(&usMessage);
  899. RtlCreateUnicodeString(&usMessage, wszErrorMessage);
  900. UserAssert(usMessage.MaximumLength <= sizeof(wszErrorMessage));
  901. }
  902. }
  903. CleanUpAndSaveParams:
  904. if (hClientProcess != NULL) {
  905. NtClose(hClientProcess);
  906. }
  907. /*
  908. * Free string parameters. Note that we're supposed to call
  909. * RtlFreeAnsiString since these were allocated by
  910. * RtlUnicodeStringToAnsiString, but we only saved the buffers.
  911. */
  912. if (dwStringsToFreeMask != 0) {
  913. for (dwCounter = 0; dwCounter < phemsg->NumberOfParameters; dwCounter++) {
  914. if (dwStringsToFreeMask & (1 << dwCounter)) {
  915. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)adwParameterVector[dwCounter]);
  916. }
  917. }
  918. }
  919. /*
  920. * Save MessageBox Parameters in phi to be used and freed later.
  921. */
  922. if (fErrorIsFromSystem) {
  923. phi->dwHEIFFlags |= HEIF_SYSTEMERROR;
  924. }
  925. phi->usText = usMessage;
  926. phi->usCaption = usCaption;
  927. phi->dwMBFlags = dwMBFlags;
  928. phi->dwTimeout = dwTimeout;
  929. }
  930. /***************************************************************************\
  931. * CheckShellHardError
  932. *
  933. * This function tries to send the hard error to the HardErrorHandler window
  934. * to see if we can avoid handling it here. If so, we avoid handling it.
  935. *
  936. * History:
  937. * 03-29-01 BobDay Added
  938. \***************************************************************************/
  939. BOOL CheckShellHardError(
  940. PHARDERRORINFO phi,
  941. int *pidResponse)
  942. {
  943. HANDLE hKey;
  944. UNICODE_STRING UnicodeString;
  945. OBJECT_ATTRIBUTES OA;
  946. LONG Status;
  947. BYTE Buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
  948. DWORD cbSize;
  949. DWORD dwShellErrorMode = 0;
  950. BOOL fHandledThisMessage = FALSE;
  951. HWND hwndTaskman;
  952. //
  953. // Shell can handle only the non-waiting case.
  954. //
  955. if (!(phi->dwHEIFFlags & HEIF_NOWAIT)) {
  956. return FALSE;
  957. }
  958. RtlInitUnicodeString(&UnicodeString,
  959. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Windows");
  960. InitializeObjectAttributes(&OA,
  961. &UnicodeString,
  962. OBJ_CASE_INSENSITIVE,
  963. NULL,
  964. NULL);
  965. Status = NtOpenKey(&hKey, KEY_READ, &OA);
  966. if (NT_SUCCESS(Status)) {
  967. RtlInitUnicodeString(&UnicodeString, L"ShellErrorMode");
  968. Status = NtQueryValueKey(hKey,
  969. &UnicodeString,
  970. KeyValuePartialInformation,
  971. (PKEY_VALUE_PARTIAL_INFORMATION)Buf,
  972. sizeof(Buf),
  973. &cbSize);
  974. if (NT_SUCCESS(Status)) {
  975. dwShellErrorMode = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->Data);
  976. }
  977. NtClose(hKey);
  978. }
  979. //
  980. // 1 = try shell ("HardErrorHandler" window).
  981. //
  982. if (dwShellErrorMode != 1) {
  983. return FALSE;
  984. }
  985. hwndTaskman = GetTaskmanWindow();
  986. if (hwndTaskman != NULL) {
  987. BYTE *lpData;
  988. UINT cbTitle = 0;
  989. UINT cbText = 0;
  990. UINT cbData;
  991. //
  992. // Build up a copy data buffer to send to the hard error handler
  993. // window.
  994. //
  995. cbTitle = phi->usCaption.Length + sizeof(WCHAR);
  996. cbText = phi->usText.Length + sizeof(WCHAR);
  997. cbData = sizeof(HARDERRORDATA) + cbTitle + cbText;
  998. lpData = (BYTE *)LocalAlloc(LPTR,cbData);
  999. if (lpData) {
  1000. COPYDATASTRUCT cd;
  1001. PHARDERRORDATA phed = (PHARDERRORDATA)lpData;
  1002. PWSTR pwszTitle = (PWSTR)(phed + 1);
  1003. PWSTR pwszText = (WCHAR *)((BYTE *)pwszTitle + cbTitle);
  1004. LRESULT lResult;
  1005. BOOL fSentMessage;
  1006. cd.dwData = RegisterWindowMessage(TEXT(COPYDATA_HARDERROR));
  1007. cd.cbData = cbData;
  1008. cd.lpData = lpData;
  1009. phed->dwSize = sizeof(HARDERRORDATA);
  1010. phed->dwError = phi->pmsg->Status;
  1011. phed->dwFlags = phi->dwMBFlags;
  1012. phed->uOffsetTitleW = 0;
  1013. phed->uOffsetTextW = 0;
  1014. if (cbTitle != 0) {
  1015. phed->uOffsetTitleW = (UINT)((BYTE *)pwszTitle - (BYTE *)phed);
  1016. RtlCopyMemory(pwszTitle, phi->usCaption.Buffer, cbTitle-sizeof(WCHAR));
  1017. pwszTitle[cbTitle/sizeof(WCHAR)-1] = (WCHAR)0;
  1018. }
  1019. if (cbText != 0) {
  1020. phed->uOffsetTextW = (UINT)((BYTE *)pwszText - (BYTE *)phed);
  1021. RtlCopyMemory(pwszText, phi->usText.Buffer, cbText-sizeof(WCHAR));
  1022. pwszText[cbText/sizeof(WCHAR)-1] = (WCHAR)0;
  1023. }
  1024. //
  1025. // Send the message. If the app doesn't respond in a short
  1026. // amount of time, blow it off and assume it's unhandled.
  1027. //
  1028. lResult = 0;
  1029. fSentMessage = (BOOL)SendMessageTimeout(hwndTaskman, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cd, SMTO_ABORTIFHUNG, 3000, &lResult);
  1030. //
  1031. // Has to both be handled and return non-zero.
  1032. //
  1033. if (fSentMessage && lResult != 0) {
  1034. fHandledThisMessage = TRUE;
  1035. *pidResponse = IDOK;
  1036. }
  1037. LocalFree(lpData);
  1038. }
  1039. }
  1040. return fHandledThisMessage;
  1041. }
  1042. #if DBG
  1043. VOID DBGCheckForHardError(
  1044. PHARDERRORINFO phi)
  1045. {
  1046. PHARDERRORINFO *pphi;
  1047. /*
  1048. * Let's make sure it was unlinked.
  1049. */
  1050. pphi = &gphiList;
  1051. while (*pphi != phi && *pphi != NULL) {
  1052. UserAssert(!((*pphi)->dwHEIFFlags & (HEIF_ACTIVE | HEIF_NUKED)));
  1053. pphi = &(*pphi)->phiNext;
  1054. }
  1055. UserAssert(*pphi == NULL);
  1056. }
  1057. #else
  1058. #define DBGCheckForHardError(phi)
  1059. #endif
  1060. /***************************************************************************\
  1061. * HardErrorHandler
  1062. *
  1063. * This routine processes hard error requests from the CSR exception port.
  1064. *
  1065. * History:
  1066. * 07-03-91 JimA Created.
  1067. \***************************************************************************/
  1068. VOID HardErrorHandler(
  1069. VOID)
  1070. {
  1071. UINT idResponse = 0;
  1072. PHARDERRORINFO phi, *pphi;
  1073. DWORD dwResponse;
  1074. DESKRESTOREDATA drdRestore;
  1075. BOOL fNuked;
  1076. UINT uHECRet;
  1077. DWORD dwCmd;
  1078. HANDLE hThread;
  1079. int aidButton[3], cButtons;
  1080. LPWSTR apstrButton[3];
  1081. MSGBOXDATA mbd;
  1082. BOOL bDoBlock;
  1083. PCTXHARDERRORINFO pCtxHEInfo = NULL;
  1084. MSG msg;
  1085. #if DBG
  1086. /*
  1087. * We should have only one error handler at the time.
  1088. */
  1089. static long glReentered = -1;
  1090. UserAssert(InterlockedIncrement(&glReentered) == 0);
  1091. #endif
  1092. if (ISTS()) {
  1093. bDoBlock = (gbExitInProgress || (HEC_ERROR == NtUserHardErrorControl(HardErrorSetup, NULL, NULL)));
  1094. } else {
  1095. bDoBlock = (HEC_ERROR == NtUserHardErrorControl(HardErrorSetup, NULL, NULL));
  1096. }
  1097. drdRestore.pdeskRestore = NULL;
  1098. if (bDoBlock) {
  1099. /*
  1100. * We failed to set up to process hard errors. Acknowledge all
  1101. * pending errors as NotHandled.
  1102. */
  1103. EnterCrit();
  1104. while (gphiList != NULL) {
  1105. phi = gphiList;
  1106. #ifdef PRERELEASE
  1107. hiLastProcessed = *phi;
  1108. #endif
  1109. gphiList = phi->phiNext;
  1110. LeaveCrit();
  1111. ReplyHardError(phi, ResponseNotHandled);
  1112. EnterCrit();
  1113. }
  1114. UserAssert(InterlockedDecrement(&glReentered) < 0);
  1115. UserAssert(gdwHardErrorThreadId == HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread));
  1116. gdwHardErrorThreadId = 0;
  1117. LeaveCrit();
  1118. return;
  1119. }
  1120. /*
  1121. * Process all hard error requests.
  1122. */
  1123. for (;;) {
  1124. /*
  1125. * Grab the next request (for the current desktop)
  1126. * If we're done, reset gdwHardErrorThreadId so any request
  1127. * after this point will be handled by someone else
  1128. */
  1129. EnterCrit();
  1130. phi = gphiList;
  1131. if (phi == NULL) {
  1132. UserAssert(InterlockedDecrement(&glReentered) < 0);
  1133. UserAssert(gdwHardErrorThreadId == HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread));
  1134. gdwHardErrorThreadId = 0;
  1135. } else {
  1136. while ((phi != NULL) && (phi->dwHEIFFlags & HEIF_WRONGDESKTOP)) {
  1137. phi = phi->phiNext;
  1138. }
  1139. if (phi != NULL) {
  1140. #ifdef PRERELEASE
  1141. hiLastProcessed = *phi;
  1142. #endif
  1143. /*
  1144. * We're going to show this one.
  1145. */
  1146. phi->dwHEIFFlags |= HEIF_ACTIVE;
  1147. } else {
  1148. /*
  1149. * We have some requests pending but they are not
  1150. * for the current desktop. Let's wait for another
  1151. * request (WM_NULL posted) or a desktop switch (PostQuitMessage)
  1152. */
  1153. LeaveCrit();
  1154. MsgWaitForMultipleObjects(0, NULL, FALSE, INFINITE, QS_POSTMESSAGE);
  1155. PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
  1156. CheckDefaultDesktop();
  1157. continue;
  1158. }
  1159. }
  1160. LeaveCrit();
  1161. /*
  1162. * If no messages are pending, we're done.
  1163. */
  1164. if (phi == NULL) {
  1165. NtUserHardErrorControl(HardErrorCleanup, NULL, NULL);
  1166. return;
  1167. }
  1168. /*
  1169. * The Boost routine can mess with the list, so must get citrix info now.
  1170. */
  1171. if (ISTS()) {
  1172. pCtxHEInfo = phi->pCtxHEInfo;
  1173. if (gbExitInProgress) {
  1174. dwResponse = ResponseOk;
  1175. goto Reply;
  1176. }
  1177. }
  1178. /*
  1179. * Get win32k attach parameters.
  1180. */
  1181. dwCmd = (phi->dwMBFlags & MB_DEFAULT_DESKTOP_ONLY) ? HardErrorAttachUser : HardErrorAttach;
  1182. hThread = (phi->pthread != NULL) ? phi->pthread->ThreadHandle : NULL;
  1183. /*
  1184. * We have already handled the MB_SERVICE_NOTIFICATION flags, so
  1185. * clear it to prevent recursion. Also, don't let hard error boxes
  1186. * steal the foreground.
  1187. */
  1188. phi->dwMBFlags &= ~(MB_SERVICE_NOTIFICATION | MB_SETFOREGROUND | MB_SYSTEMMODAL);
  1189. /*
  1190. * If this is a VDM error, figure out buttons, default id, style, etc.
  1191. */
  1192. if (phi->dwHEIFFlags & HEIF_VDMERROR) {
  1193. int i;
  1194. WORD rgwBtn[3], wBtn;
  1195. /*
  1196. * Initialize MSGBOXDATA with the information we have already
  1197. * figured out.
  1198. */
  1199. RtlZeroMemory(&mbd, sizeof(MSGBOXDATA));
  1200. mbd.cbSize = sizeof(MSGBOXPARAMS);
  1201. mbd.lpszText = phi->usText.Buffer;
  1202. mbd.lpszCaption = phi->usCaption.Buffer;
  1203. mbd.dwTimeout = INFINITE;
  1204. /*
  1205. * phi->dwVDMParam0 = (fForWOW << 16) | wBtn1;
  1206. * phi->dwVDMParam1 = (wBtn2 << 16) | wBtn3;
  1207. * Right now, only WOW does this. If NTVDM does it, fForWOW
  1208. * will be false.
  1209. */
  1210. rgwBtn[0] = LOWORD(phi->dwVDMParam0);
  1211. rgwBtn[1] = HIWORD(phi->dwVDMParam1);
  1212. rgwBtn[2] = LOWORD(phi->dwVDMParam1);
  1213. cButtons = 0;
  1214. for (i = 0; i < 3; i++) {
  1215. wBtn = rgwBtn[i] & ~SEB_DEFBUTTON;
  1216. if (wBtn && wBtn <= MAX_SEB_STYLES) {
  1217. apstrButton[cButtons] = MB_GetString(wBtn-1);
  1218. aidButton[cButtons] = i + 1;
  1219. if (rgwBtn[i] & SEB_DEFBUTTON) {
  1220. mbd.DefButton = cButtons;
  1221. }
  1222. if (wBtn == SEB_CANCEL) {
  1223. mbd.CancelId = cButtons;
  1224. }
  1225. cButtons++;
  1226. }
  1227. }
  1228. mbd.dwStyle = MB_TOPMOST;
  1229. if ((cButtons != 1) || (aidButton[0] != 1)) {
  1230. mbd.dwStyle |= MB_OKCANCEL;
  1231. }
  1232. mbd.ppszButtonText = apstrButton;
  1233. mbd.pidButton = aidButton;
  1234. mbd.cButtons = cButtons;
  1235. }
  1236. /*
  1237. * Attach to win32k and show the dialog. If we switch desktops,
  1238. * (loop and) show it on the new desktop (if applicable).
  1239. */
  1240. do {
  1241. phi->pmsg->Response = ResponseNotHandled;
  1242. uHECRet = NtUserHardErrorControl(dwCmd, hThread, &drdRestore);
  1243. if (uHECRet == HEC_SUCCESS) {
  1244. if (phi->dwHEIFFlags & HEIF_VDMERROR) {
  1245. idResponse = SoftModalMessageBox(&mbd);
  1246. } else {
  1247. /*
  1248. * Bring up the message box. Or in MB_TOPMOST so it
  1249. * comes up on top. We want to preserve the
  1250. * MB_DEFAULT_DESKTOP_ONLY flag but don't want to pass
  1251. * it to MessageBox or we'll recurse due to a
  1252. * compatibility hack.
  1253. */
  1254. if (CheckShellHardError(phi, &idResponse) == FALSE) {
  1255. DWORD dwTimeout;
  1256. if (pCtxHEInfo && pCtxHEInfo->Timeout != 0 && pCtxHEInfo->Timeout != -1) {
  1257. dwTimeout = pCtxHEInfo->Timeout * 1000;
  1258. } else {
  1259. dwTimeout = phi->dwTimeout;
  1260. }
  1261. idResponse = MessageBoxTimeout(NULL, phi->usText.Buffer, phi->usCaption.Buffer,
  1262. (phi->dwMBFlags | MB_TOPMOST) & ~MB_DEFAULT_DESKTOP_ONLY, 0, dwTimeout);
  1263. }
  1264. }
  1265. /*
  1266. * Restore hard error handler desktop; this will also tell
  1267. * us if the input desktop has changed. If so, we want to
  1268. * bring the error box again on the new desktop.
  1269. */
  1270. uHECRet = NtUserHardErrorControl(HardErrorDetach, NULL, &drdRestore);
  1271. if (ISTS()) {
  1272. /*
  1273. * Really a citrix message.
  1274. */
  1275. if (uHECRet != HEC_DESKTOPSWITCH && pCtxHEInfo != NULL) {
  1276. pCtxHEInfo->Response = idResponse;
  1277. /*
  1278. * Check for message box timeout.
  1279. */
  1280. if (idResponse == IDTIMEOUT) {
  1281. uHECRet = HEC_SUCCESS;
  1282. }
  1283. }
  1284. if (idResponse == IDTIMEOUT) {
  1285. idResponse = ResponseNotHandled;
  1286. }
  1287. if (idResponse >= ARRAY_SIZE(dwResponses)) {
  1288. RIPMSGF1(RIP_WARNING, "Index idResponse: %d is out of range.", idResponse);
  1289. idResponse = 0;
  1290. }
  1291. if (dwResponses[idResponse] == ResponseNotHandled &&
  1292. uHECRet == HEC_DESKTOPSWITCH && gSessionId == 0) {
  1293. RIPMSGF2(RIP_WARNING,
  1294. "Abort harderror, idResponse 0x%x, uHECRet 0x%x",
  1295. idResponse,
  1296. uHECRet);
  1297. break;
  1298. }
  1299. } else if (idResponse == IDTIMEOUT) {
  1300. idResponse = ResponseNotHandled;
  1301. }
  1302. } else {
  1303. idResponse = ResponseNotHandled;
  1304. }
  1305. if (idResponse >= ARRAY_SIZE(dwResponses)) {
  1306. RIPMSGF1(RIP_WARNING, "Index idResponse: %d is out of range.", idResponse);
  1307. idResponse = 0;
  1308. }
  1309. dwResponse = dwResponses[idResponse];
  1310. /*
  1311. * If we don't want to reshow this box, we're done.
  1312. */
  1313. if (uHECRet != HEC_DESKTOPSWITCH) {
  1314. break;
  1315. } else {
  1316. /*
  1317. * We've switched desktops; if we're in the default one now,
  1318. * then we can show all MB_DEFAULT_DESKTOP_ONLY requests.
  1319. */
  1320. CheckDefaultDesktop();
  1321. }
  1322. /*
  1323. * If BoostHardError nuked it, don't re-show it.
  1324. */
  1325. EnterCrit();
  1326. fNuked = (phi->dwHEIFFlags & HEIF_NUKED);
  1327. LeaveCrit();
  1328. } while (!fNuked);
  1329. /*
  1330. * If we didn't show this box because we're not in the default
  1331. * desktop, mark this phi and continue.
  1332. */
  1333. if (uHECRet == HEC_WRONGDESKTOP) {
  1334. UserAssert(phi->dwMBFlags & MB_DEFAULT_DESKTOP_ONLY);
  1335. if (ISTS() && phi->pCtxHEInfo) {
  1336. if (phi->pCtxHEInfo->DoNotWaitForCorrectDesktop) {
  1337. phi->pCtxHEInfo->Response = IDTIMEOUT;
  1338. dwResponse = ResponseNotHandled;
  1339. goto Reply;
  1340. }
  1341. }
  1342. EnterCrit();
  1343. COPY_FLAG(phi->dwHEIFFlags, HEIF_WRONGDESKTOP, HEIF_ACTIVE | HEIF_WRONGDESKTOP);
  1344. LeaveCrit();
  1345. continue;
  1346. }
  1347. Reply:
  1348. /*
  1349. * We're done with this phi. Unlink it if BoostHardError hasn't done
  1350. * so already. If unlinked, it is marked as nuked.
  1351. */
  1352. EnterCrit();
  1353. UserAssert(phi->dwHEIFFlags & HEIF_ACTIVE);
  1354. fNuked = (phi->dwHEIFFlags & HEIF_NUKED);
  1355. if (!fNuked) {
  1356. pphi = &gphiList;
  1357. while ((*pphi != phi) && (*pphi != NULL)) {
  1358. pphi = &(*pphi)->phiNext;
  1359. }
  1360. UserAssert(*pphi != NULL);
  1361. *pphi = phi->phiNext;
  1362. } else {
  1363. DBGCheckForHardError(phi);
  1364. }
  1365. if (phi->pCtxHEInfo) {
  1366. /*
  1367. * Clean up
  1368. */
  1369. HardErrorRemove(phi->pCtxHEInfo);
  1370. /*
  1371. * Done
  1372. */
  1373. phi->pCtxHEInfo = NULL;
  1374. }
  1375. LeaveCrit();
  1376. /*
  1377. * Save the response, reply and free phi
  1378. */
  1379. ReplyHardError(phi, (fNuked ? ResponseNotHandled : dwResponse));
  1380. }
  1381. /*
  1382. * Nobody should break out of the loop.
  1383. */
  1384. UserAssert(FALSE);
  1385. }
  1386. LPWSTR RtlLoadStringOrError(
  1387. HANDLE hModule,
  1388. UINT wID,
  1389. LPWSTR lpDefault,
  1390. PBOOL pAllocated,
  1391. BOOL bAnsi
  1392. )
  1393. {
  1394. LPTSTR lpsz;
  1395. int cch;
  1396. LPWSTR lpw;
  1397. PMESSAGE_RESOURCE_ENTRY MessageEntry;
  1398. NTSTATUS Status;
  1399. cch = 0;
  1400. lpw = NULL;
  1401. Status = RtlFindMessage((PVOID)hModule, (ULONG_PTR)RT_MESSAGETABLE,
  1402. 0, wID, &MessageEntry);
  1403. if (NT_SUCCESS(Status)) {
  1404. /*
  1405. * Return two fewer chars so the crlf in the message will be
  1406. * stripped out.
  1407. */
  1408. cch = wcslen((PWCHAR)MessageEntry->Text) - 2;
  1409. lpsz = (LPWSTR)MessageEntry->Text;
  1410. if (bAnsi) {
  1411. int ich;
  1412. /*
  1413. * Add one to zero terminate then force the termination.
  1414. */
  1415. ich = WCSToMB(lpsz, cch+1, (CHAR **)&lpw, -1, TRUE);
  1416. if (lpw) {
  1417. ((LPSTR)lpw)[ich - 1] = 0;
  1418. }
  1419. } else {
  1420. lpw = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (cch + 1) * sizeof(WCHAR));
  1421. if (lpw) {
  1422. /*
  1423. * Copy the string into the buffer.
  1424. */
  1425. RtlCopyMemory(lpw, lpsz, cch * sizeof(WCHAR));
  1426. }
  1427. }
  1428. }
  1429. if (!lpw) {
  1430. lpw = lpDefault;
  1431. *pAllocated = FALSE;
  1432. } else {
  1433. *pAllocated = TRUE;
  1434. }
  1435. return lpw;
  1436. }
  1437. /***************************************************************************\
  1438. * HardErrorWorkerThread
  1439. *
  1440. * Worker thread to handle hard error requests.
  1441. *
  1442. * History:
  1443. * 05-01-98 JerrySh Created.
  1444. \***************************************************************************/
  1445. NTSTATUS HardErrorWorkerThread(
  1446. PVOID ThreadParameter)
  1447. {
  1448. PCSR_THREAD pt;
  1449. UNREFERENCED_PARAMETER(ThreadParameter);
  1450. pt = CsrConnectToUser();
  1451. ProcessHardErrorRequest(FALSE);
  1452. if (pt) {
  1453. CsrDereferenceThread(pt);
  1454. }
  1455. #ifdef PRERELEASE
  1456. NtUserHardErrorControl(HardErrorCheckOnDesktop, NULL, NULL);
  1457. #endif
  1458. UserExitWorkerThread(STATUS_SUCCESS);
  1459. return STATUS_SUCCESS;
  1460. }
  1461. /***************************************************************************\
  1462. * ProcessHardErrorRequest
  1463. *
  1464. * Figures out who should process the hard error. There are 3 possible cases.
  1465. * - If there is already a hard error thread, hand it off to him.
  1466. * - If not and we don't want to wait, create a worker thread to deal with it.
  1467. * - If we want to wait or thread creation fails, deal with it ourselves.
  1468. *
  1469. * History:
  1470. * 05-01-98 JerrySh Created.
  1471. \***************************************************************************/
  1472. VOID ProcessHardErrorRequest(
  1473. BOOL fNewThread)
  1474. {
  1475. NTSTATUS Status;
  1476. CLIENT_ID ClientId;
  1477. HANDLE hThread;
  1478. EnterCrit();
  1479. /*
  1480. * If there's already a hard error handler, make sure he's awake.
  1481. */
  1482. if (gdwHardErrorThreadId) {
  1483. DWORD dwHardErrorHandler = gdwHardErrorThreadId;
  1484. LeaveCrit();
  1485. PostThreadMessage(dwHardErrorHandler, WM_NULL, 0, 0);
  1486. return;
  1487. }
  1488. /*
  1489. * Create a worker thread to handle the hard error.
  1490. */
  1491. if (fNewThread) {
  1492. LeaveCrit();
  1493. Status = RtlCreateUserThread(NtCurrentProcess(),
  1494. NULL,
  1495. TRUE,
  1496. 0,
  1497. 0,
  1498. 0,
  1499. HardErrorWorkerThread,
  1500. NULL,
  1501. &hThread,
  1502. &ClientId);
  1503. if (NT_SUCCESS(Status)) {
  1504. CsrAddStaticServerThread(hThread, &ClientId, 0);
  1505. NtResumeThread(hThread, NULL);
  1506. return;
  1507. }
  1508. EnterCrit();
  1509. }
  1510. /*
  1511. * Let this thread handle the hard error.
  1512. */
  1513. gdwHardErrorThreadId = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread);
  1514. LeaveCrit();
  1515. HardErrorHandler();
  1516. }
  1517. /***************************************************************************\
  1518. * UserHardError
  1519. *
  1520. * Called from CSR to pop up hard error messages.
  1521. *
  1522. * History:
  1523. * 03/12/97 GerardoB Rewritten to support OptionOkNoWait
  1524. * 07-03-91 JimA Created.
  1525. \***************************************************************************/
  1526. VOID UserHardError(
  1527. PCSR_THREAD pt,
  1528. PHARDERROR_MSG pmsg)
  1529. {
  1530. UserHardErrorEx(pt, pmsg, NULL);
  1531. }
  1532. /***************************************************************************\
  1533. * UserHardErrorEx
  1534. *
  1535. * Called from CSR to pop up hard error messages.
  1536. *
  1537. * History:
  1538. * 07-03-91 JimA Created.
  1539. \***************************************************************************/
  1540. VOID UserHardErrorEx(
  1541. PCSR_THREAD pt,
  1542. PHARDERROR_MSG pmsg,
  1543. PCTXHARDERRORINFO pCtxHEInfo)
  1544. {
  1545. BOOL fClientPort, fNoWait, fMsgBox, fLogEvent;
  1546. PHARDERRORINFO phi, *pphiLast;
  1547. HANDLE hEvent;
  1548. DWORD dwReportMode, dwResponse;
  1549. UserAssert((ULONG)pmsg->NumberOfParameters <= MAXIMUM_HARDERROR_PARAMETERS);
  1550. /*
  1551. * Allocate memory to queue request.
  1552. */
  1553. phi = (PHARDERRORINFO)LocalAlloc(LPTR, sizeof(HARDERRORINFO));
  1554. if (phi == NULL) {
  1555. goto ErrorExit;
  1556. }
  1557. phi->pthread = pt;
  1558. /*
  1559. * Set up citrix specific stuff.
  1560. */
  1561. if (ISTS()) {
  1562. phi->pCtxHEInfo = pCtxHEInfo;
  1563. }
  1564. /*
  1565. * Determine reply type.
  1566. */
  1567. fClientPort = ((pt != NULL) && (pt->Process->ClientPort != NULL));
  1568. fNoWait = (pmsg->ValidResponseOptions == OptionOkNoWait);
  1569. /*
  1570. * Capture HARDERROR_MSG data or create wait event as needed
  1571. */
  1572. if (fClientPort || fNoWait) {
  1573. phi->pmsg = (PHARDERROR_MSG)LocalAlloc(LPTR, pmsg->h.u1.s1.TotalLength);
  1574. if (phi->pmsg == NULL) {
  1575. goto ErrorExit;
  1576. }
  1577. phi->dwHEIFFlags |= HEIF_ALLOCATEDMSG;
  1578. RtlCopyMemory(phi->pmsg, pmsg, pmsg->h.u1.s1.TotalLength);
  1579. hEvent = NULL;
  1580. /*
  1581. * Set the magic response value (-1) to let CsrApiRequestThread know
  1582. * that we'll take care of dereferencing and replying.
  1583. */
  1584. if (pt != NULL) {
  1585. phi->dwHEIFFlags |= HEIF_DEREFTHREAD;
  1586. }
  1587. pmsg->Response = (ULONG)-1;
  1588. if (fNoWait) {
  1589. phi->dwHEIFFlags |= HEIF_NOWAIT;
  1590. phi->pmsg->ValidResponseOptions = OptionOk;
  1591. }
  1592. } else {
  1593. phi->pmsg = pmsg;
  1594. /*
  1595. * There is no reply port but we need to wait; create an event.
  1596. */
  1597. hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  1598. if (hEvent == NULL) {
  1599. goto ErrorExit;
  1600. }
  1601. phi->hEventHardError = hEvent;
  1602. }
  1603. /*
  1604. * Build hard error title, message and flags. Then log the event.
  1605. */
  1606. GetHardErrorText(phi);
  1607. /*
  1608. * Reply now if we're not going to wait.
  1609. */
  1610. if (fNoWait) {
  1611. phi->dwHEIFFlags |= HEIF_REPLIED;
  1612. phi->pmsg->Response = ResponseOk;
  1613. if (fClientPort) {
  1614. NtReplyPort(pt->Process->ClientPort, (PPORT_MESSAGE)phi->pmsg);
  1615. } else {
  1616. /*
  1617. * Must let CsrApiRequestThread reply since we don't have a port
  1618. */
  1619. pmsg->Response = ResponseOk;
  1620. /*
  1621. * If we have a thread, reference it because we're telling
  1622. * CsrApiRequestThread that we're done with it.
  1623. */
  1624. if (pt != NULL) {
  1625. /*
  1626. * Later5.0 GerardoB. Let's stop to see how this happens.
  1627. */
  1628. UserAssert(pt == NULL);
  1629. CsrReferenceThread(pt);
  1630. }
  1631. }
  1632. }
  1633. /*
  1634. * Register the event if we haven't done so already. Since
  1635. * RegisterEventSource is supported by a service, we must not hold any
  1636. * locks while making this call. Hence we might have several threads
  1637. * registering the event simultaneously.
  1638. */
  1639. fLogEvent = (gEventSource != NULL);
  1640. if (!fLogEvent) {
  1641. HANDLE hEventSource = RegisterEventSourceW(NULL, L"Application Popup");
  1642. /*
  1643. * Save the first handle, deregister all others.
  1644. */
  1645. if (InterlockedCompareExchangePointer(&gEventSource, hEventSource, NULL) == NULL) {
  1646. /*
  1647. * This is the first handle. If valid, we can log events.
  1648. */
  1649. fLogEvent = (hEventSource != NULL);
  1650. } else {
  1651. /*
  1652. * We had already saved another handle (so we can log events).
  1653. * Deregister this one.
  1654. */
  1655. if (hEventSource != NULL) {
  1656. UserVerify(DeregisterEventSource(hEventSource));
  1657. }
  1658. fLogEvent = TRUE;
  1659. }
  1660. }
  1661. dwReportMode = fLogEvent ? GetErrorMode() : 0;
  1662. if (fLogEvent) {
  1663. LogErrorPopup(phi->usCaption.Buffer, phi->usText.Buffer);
  1664. }
  1665. /*
  1666. * Determine if we need to display a message box.
  1667. */
  1668. if ((phi->pmsg->Status == STATUS_SERVICE_NOTIFICATION) || (dwReportMode == 0)) {
  1669. fMsgBox = TRUE;
  1670. } else if (phi->pmsg->Status == STATUS_VDM_HARD_ERROR) {
  1671. fMsgBox = (dwReportMode == 1);
  1672. if (!fMsgBox) {
  1673. dwResponse = ResponseOk;
  1674. }
  1675. } else {
  1676. fMsgBox = ((dwReportMode == 1) && !(phi->dwHEIFFlags & HEIF_SYSTEMERROR));
  1677. if (!fMsgBox) {
  1678. UserAssert((UINT)phi->pmsg->ValidResponseOptions < ARRAY_SIZE(dwResponseDefault));
  1679. dwResponse = dwResponseDefault[phi->pmsg->ValidResponseOptions];
  1680. }
  1681. }
  1682. /*
  1683. * If we don't have to display a message box, we're done.
  1684. */
  1685. if (!fMsgBox) {
  1686. goto DontNeedErrorHandler;
  1687. }
  1688. /*
  1689. * We want to display a message box. Queue the request and go for it.
  1690. *
  1691. * Never mind if the process has terminated. Got to check this holding the
  1692. * critical section to make sure that no other thread makes it to BoostHardError
  1693. * before we add this phi to the list.
  1694. */
  1695. EnterCrit();
  1696. if ((pt != NULL) && (pt->Process->Flags & CSR_PROCESS_TERMINATED)) {
  1697. LeaveCrit();
  1698. DontNeedErrorHandler:
  1699. ReplyHardError(phi, dwResponse);
  1700. if (hEvent != NULL) {
  1701. NtClose(hEvent);
  1702. }
  1703. return;
  1704. }
  1705. /*
  1706. * Add it to the end of the list.
  1707. */
  1708. pphiLast = &gphiList;
  1709. while (*pphiLast != NULL) {
  1710. pphiLast = &(*pphiLast)->phiNext;
  1711. }
  1712. *pphiLast = phi;
  1713. LeaveCrit();
  1714. /*
  1715. * Process the hard error request. If this is a NoWait request and there
  1716. * is no reply port, then we'll try to launch a new worker thread so this
  1717. * one can return.
  1718. */
  1719. ProcessHardErrorRequest(fNoWait && !fClientPort);
  1720. /*
  1721. * If there is an event handle, wait for it.
  1722. */
  1723. if (hEvent != NULL) {
  1724. NtWaitForSingleObject(hEvent, FALSE, NULL);
  1725. NtClose(hEvent);
  1726. }
  1727. return;
  1728. ErrorExit:
  1729. if (phi != NULL) {
  1730. FreePhi(phi);
  1731. }
  1732. pmsg->Response = ResponseNotHandled;
  1733. }
  1734. /***************************************************************************\
  1735. * BoostHardError
  1736. *
  1737. * If one or more hard errors exist for the specified process, remove them
  1738. * from the list if forced, otherwise bring the first one to the top of the
  1739. * hard error list and display it. Return TRUE if there is a hard error.
  1740. *
  1741. * History:
  1742. * 11-02-91 JimA Created.
  1743. \***************************************************************************/
  1744. BOOL BoostHardError(
  1745. ULONG_PTR dwProcessId,
  1746. DWORD dwCode)
  1747. {
  1748. DESKRESTOREDATA drdRestore;
  1749. PHARDERRORINFO phi, *pphi;
  1750. BOOL fHasError = FALSE;
  1751. EnterCrit();
  1752. /*
  1753. * If the list is empty, nothing do to here.
  1754. */
  1755. if (gphiList == NULL) {
  1756. LeaveCrit();
  1757. return FALSE;
  1758. }
  1759. drdRestore.pdeskRestore = NULL;
  1760. /*
  1761. * Walk the hard error list.
  1762. */
  1763. pphi = &gphiList;
  1764. while (*pphi != NULL) {
  1765. /*
  1766. * If not not nuking all and not owned by dwProcessId, continue
  1767. * walking.
  1768. */
  1769. if (dwProcessId != (ULONG_PTR)-1) {
  1770. if (((*pphi)->pthread == NULL)
  1771. || ((ULONG_PTR)((*pphi)->pthread->ClientId.UniqueProcess) != dwProcessId)) {
  1772. pphi = &(*pphi)->phiNext;
  1773. continue;
  1774. }
  1775. } else {
  1776. UserAssert(dwCode == BHE_FORCE);
  1777. }
  1778. /*
  1779. * Got one so we want to return TRUE.
  1780. */
  1781. fHasError = TRUE;
  1782. /*
  1783. * If nuking the request ...
  1784. */
  1785. if (dwCode == BHE_FORCE) {
  1786. /*
  1787. * Unlink it from the list.
  1788. */
  1789. phi = *pphi;
  1790. *pphi = phi->phiNext;
  1791. /*
  1792. * If this box is being shown right now, signal it to go away.
  1793. * Otherwise, nuke it.
  1794. */
  1795. if (phi->dwHEIFFlags & HEIF_ACTIVE) {
  1796. DWORD dwHardErrorHandler = gdwHardErrorThreadId;
  1797. phi->dwHEIFFlags |= HEIF_NUKED;
  1798. LeaveCrit();
  1799. PostThreadMessage(dwHardErrorHandler, WM_QUIT, 0, 0);
  1800. } else {
  1801. /*
  1802. * Acknowledge the error as not handled, reply and free.
  1803. */
  1804. LeaveCrit();
  1805. ReplyHardError(phi, ResponseNotHandled);
  1806. }
  1807. /*
  1808. * Restart the search because we left the crit sect.
  1809. */
  1810. EnterCrit();
  1811. pphi = &gphiList;
  1812. } else if (dwCode == BHE_ACTIVATE) {
  1813. /*
  1814. * If it's active, find it and show it.
  1815. */
  1816. phi = *pphi;
  1817. if (phi->dwHEIFFlags & HEIF_ACTIVE) {
  1818. HWND hwndError = NULL;
  1819. DWORD dwHardErrorHandler = gdwHardErrorThreadId;
  1820. LeaveCrit();
  1821. EnumThreadWindows(dwHardErrorHandler, FindWindowFromThread, (LPARAM)&hwndError);
  1822. if (hwndError != NULL &&
  1823. HEC_SUCCESS == NtUserHardErrorControl(HardErrorAttachNoQueue, NULL, &drdRestore)) {
  1824. SetForegroundWindow(hwndError);
  1825. NtUserHardErrorControl(HardErrorDetachNoQueue, NULL, &drdRestore);
  1826. }
  1827. return TRUE;
  1828. }
  1829. /*
  1830. * It's not active so move it to the head of the list to make it
  1831. * show up next.
  1832. */
  1833. *pphi = phi->phiNext;
  1834. phi->phiNext = gphiList;
  1835. gphiList = phi;
  1836. break;
  1837. } else {
  1838. /*
  1839. * The caller just want to know if this process owns a hard error.
  1840. */
  1841. break;
  1842. }
  1843. }
  1844. LeaveCrit();
  1845. /*
  1846. * Bug 284468. Wake up the hard error handler.
  1847. */
  1848. if (dwCode == BHE_FORCE && gdwHardErrorThreadId != 0) {
  1849. PostThreadMessage(gdwHardErrorThreadId, WM_NULL, 0, 0);
  1850. }
  1851. return fHasError;
  1852. }