test: harderr.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# harderr.c

Go to the documentation of this file.

    00001 /**************************** Module Header ********************************\
    00002 * Module Name: harderr.c
    00003 *
    00004 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00005 *
    00006 * Hard error handler
    00007 *
    00008 * History:
    00009 * 07-03-91 JimA                Created scaffolding.
    00010 \***************************************************************************/
    00011
    00012 #include "precomp.h"
    00013 #pragma hdrstop
    00014 #include "ntlpcapi.h"
    00015
    00016 #include <winsta.h>
    00017 extern BOOLEAN gbExitInProgress;
    00018 BOOL gfTimedOut = FALSE;
    00019
    00020 VOID UserHardErrorEx(
    00021     PCSR_THREAD pt,
    00022     PHARDERROR_MSG pmsg,
    00023     PCTXHARDERRORINFO pCtxHEInfo);
    00024
    00025 VOID UserExitWorkerThread(VOID);
    00026
    00027 VOID ProcessHardErrorRequest(
    00028     BOOL fNewThread);
    00029
    00030
    00031 CONST UINT wIcons[] = {
    00032     0,
    00033     MB_ICONINFORMATION,
    00034     MB_ICONEXCLAMATION,
    00035     MB_ICONSTOP
    00036 };
    00037 CONST UINT wOptions[] = {
    00038     MB_ABORTRETRYIGNORE,
    00039     MB_OK,
    00040     MB_OKCANCEL,
    00041     MB_RETRYCANCEL,
    00042     MB_YESNO,
    00043     MB_YESNOCANCEL,
    00044     MB_OK,              // OptionShutdownSystem
    00045     MB_OK,              // OptionOkNoWait
    00046     MB_CANCELTRYCONTINUE
    00047 };
    00048 CONST DWORD dwResponses[] = {
    00049     ResponseNotHandled, // MessageBox error
    00050     ResponseOk,         // IDOK
    00051     ResponseCancel,     // IDCANCEL
    00052     ResponseAbort,      // IDABORT
    00053     ResponseRetry,      // IDRETRY
    00054     ResponseIgnore,     // IDIGNORE
    00055     ResponseYes,        // IDYES
    00056     ResponseNo,         // IDNO
    00057     ResponseNotHandled, // Error as IDCLOSE can't show up
    00058     ResponseNotHandled, // error as IDHELP can't show up
    00059     ResponseTryAgain,   // IDTRYAGAIN
    00060     ResponseContinue    // IDCONTINUE
    00061 };
    00062 CONST DWORD dwResponseDefault[] = {
    00063     ResponseAbort,      // OptionAbortRetryIgnore
    00064     ResponseOk,         // OptionOK
    00065     ResponseOk,         // OptionOKCancel
    00066     ResponseCancel,     // OptionRetryCancel
    00067     ResponseYes,        // OptionYesNo
    00068     ResponseYes,        // OptionYesNoCancel
    00069     ResponseOk,         // OptionShutdownSystem
    00070     ResponseOk,         // OptionOKNoWait
    00071     ResponseCancel      // OptionCancelTryContinue
    00072 };
    00073
    00074 /*
    00075  *  Global timer id
    00076  */
    00077 static UINT_PTR gTimerId = 0;
    00078
    00079 /*
    00080  *  Citrix SendMessage entry point to harderror handler and cleanup routine
    00081  */
    00082 VOID HardErrorInsert(PCSR_THREAD, PHARDERROR_MSG, PCTXHARDERRORINFO);
    00083 VOID HardErrorRemove(PCTXHARDERRORINFO);
    00084
    00085 FARPROC gfnRegisterEventSource;
    00086 FARPROC gfnDeregisterEventSource;
    00087 FARPROC gfnReportEvent;
    00088
    00089 /***************************************************************************\
    00090 * UserRegisterEventSource
    00091 *
    00092 * Dynamically link to the event functions in advapi32.dll and register the
    00093 * event source.
    00094 *
    00095 * History:
    00096 * 04-13-98 JerrySh      Created.
    00097 \***************************************************************************/
    00098 HANDLE
    00099 UserRegisterEventSource(
    00100     PCWSTR pwszSourceName)
    00101 {
    00102     /*
    00103      * If we haven't already dynamically linked to advadpi32.dll, do it now.
    00104      */
    00105     if (gfnRegisterEventSource == NULL) {
    00106         HINSTANCE hAdvApiDll;
    00107         FARPROC fnRegisterEventSource;
    00108         FARPROC fnDeregisterEventSource;
    00109         FARPROC fnReportEvent;
    00110
    00111         /*
    00112          * Try to load the DLL and function pointers.
    00113          */
    00114         if ((hAdvApiDll = LoadLibrary(L"advapi32.dll")) == NULL) {
    00115             return NULL;
    00116         }
    00117         fnRegisterEventSource = GetProcAddress(hAdvApiDll, "RegisterEventSourceW");
    00118         fnDeregisterEventSource = GetProcAddress(hAdvApiDll, "DeregisterEventSource");
    00119         fnReportEvent = GetProcAddress(hAdvApiDll, "ReportEventW");
    00120         if (!fnRegisterEventSource || !fnDeregisterEventSource || !fnReportEvent) {
    00121             FreeLibrary(hAdvApiDll);
    00122             return NULL;
    00123         }
    00124
    00125         /*
    00126          * Update the global function pointers if they're not set already.
    00127          */
    00128         EnterCrit();
    00129         if (gfnRegisterEventSource == NULL) {
    00130             gfnReportEvent = fnReportEvent;
    00131             gfnDeregisterEventSource = fnDeregisterEventSource;
    00132             // This must be last since we test it above
    00133             gfnRegisterEventSource = fnRegisterEventSource;
    00134             hAdvApiDll = NULL;
    00135         }
    00136         LeaveCrit();
    00137
    00138         /*
    00139          * If another thread beat us to it, free the library.
    00140          */
    00141         if (hAdvApiDll) {
    00142             FreeLibrary(hAdvApiDll);
    00143         }
    00144     }
    00145
    00146     /*
    00147      * Let's be paranoid and verify we loaded everything correctly.
    00148      */
    00149     UserAssert(gfnRegisterEventSource != NULL);
    00150     UserAssert(gfnDeregisterEventSource != NULL);
    00151     UserAssert(gfnReportEvent != NULL);
    00152
    00153     /*
    00154      * Call the real function.
    00155      */
    00156     return (HANDLE)gfnRegisterEventSource(NULL, pwszSourceName);
    00157 }
    00158
    00159 /***************************************************************************\
    00160 * LogErrorPopup
    00161 *
    00162 * History:
    00163 * 09-22-97 GerardoB     Added Header
    00164 \***************************************************************************/
    00165 VOID
    00166 LogErrorPopup(
    00167     IN LPWSTR Caption,
    00168     IN LPWSTR Message
    00169     )
    00170 {
    00171
    00172     LPWSTR lps[2];
    00173
    00174     lps[0] = Caption;
    00175     lps[1] = Message;
    00176
    00177     UserAssert(gEventSource != NULL);
    00178     gfnReportEvent(gEventSource, EVENTLOG_INFORMATION_TYPE, 0,
    00179         STATUS_LOG_HARD_ERROR, NULL, sizeof(lps) / sizeof(*lps),
    00180         0, lps, NULL);
    00181 }
    00182
    00183 /***************************************************************************\
    00184 * SubstituteDeviceName
    00185 *
    00186 * History:
    00187 * 09-22-97 GerardoB     Added Header
    00188 \***************************************************************************/
    00189 static WCHAR wszDosDevices[] = L"\\??\\A:";
    00190 VOID
    00191 SubstituteDeviceName(
    00192     PUNICODE_STRING InputDeviceName,
    00193     LPSTR OutputDriveLetter
    00194     )
    00195 {
    00196     UNICODE_STRING LinkName;
    00197     UNICODE_STRING DeviceName;
    00198     OBJECT_ATTRIBUTES Obja;
    00199     HANDLE LinkHandle;
    00200     NTSTATUS Status;
    00201     ULONG i;
    00202     PWCHAR p;
    00203     WCHAR DeviceNameBuffer[MAXIMUM_FILENAME_LENGTH];
    00204
    00205     RtlInitUnicodeString(&LinkName,wszDosDevices);
    00206     p = wszDosDevices + ARRAY_SIZE(wszDosDevices) - ARRAY_SIZE(L"A:");
    00207     for(i=0;i<26;i++){
    00208         *p = (WCHAR)('A' + i);
    00209
    00210         InitializeObjectAttributes(
    00211             &Obja,
    00212             &LinkName,
    00213             OBJ_CASE_INSENSITIVE,
    00214             NULL,
    00215             NULL
    00216             );
    00217         Status = NtOpenSymbolicLinkObject(
    00218                     &LinkHandle,
    00219                     SYMBOLIC_LINK_QUERY,
    00220                     &Obja
    00221                     );
    00222         if (NT_SUCCESS( Status )) {
    00223
    00224             //
    00225             // Open succeeded, Now get the link value
    00226             //
    00227
    00228             DeviceName.Length = 0;
    00229             DeviceName.MaximumLength = sizeof(DeviceNameBuffer);
    00230             DeviceName.Buffer = DeviceNameBuffer;
    00231
    00232             Status = NtQuerySymbolicLinkObject(
    00233                         LinkHandle,
    00234                         &DeviceName,
    00235                         NULL
    00236                         );
    00237             NtClose(LinkHandle);
    00238             if ( NT_SUCCESS(Status) ) {
    00239                 if ( RtlEqualUnicodeString(InputDeviceName,&DeviceName,TRUE) ) {
    00240                     OutputDriveLetter[0]=(CHAR)('A'+i);
    00241                     OutputDriveLetter[1]=':';
    00242                     OutputDriveLetter[2]='\0';
    00243                     return;
    00244                     }
    00245                 }
    00246             }
    00247         }
    00248 }
    00249 /***************************************************************************\
    00250 * GetErrorMode
    00251 *
    00252 * History:
    00253 * 09-22-97 GerardoB     Added Header
    00254 \***************************************************************************/
    00255 DWORD GetErrorMode(VOID)
    00256 {
    00257     HANDLE hKey;
    00258     UNICODE_STRING UnicodeString;
    00259     OBJECT_ATTRIBUTES OA;
    00260     LONG Status;
    00261     BYTE Buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
    00262     DWORD cbSize;
    00263     DWORD dwRet = 0;
    00264
    00265     RtlInitUnicodeString(&UnicodeString,
    00266             L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Windows");
    00267     InitializeObjectAttributes(&OA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
    00268
    00269     Status = NtOpenKey(&hKey, KEY_READ, &OA);
    00270     if (NT_SUCCESS(Status)) {
    00271         RtlInitUnicodeString(&UnicodeString, L"ErrorMode");
    00272         Status = NtQueryValueKey(hKey,
    00273                 &UnicodeString,
    00274                 KeyValuePartialInformation,
    00275                 (PKEY_VALUE_PARTIAL_INFORMATION)Buf,
    00276                 sizeof(Buf),
    00277                 &cbSize);
    00278         if (NT_SUCCESS(Status)) {
    00279             dwRet = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->Data);
    00280         }
    00281         NtClose(hKey);
    00282     }
    00283     return dwRet;
    00284 }
    00285 /***************************************************************************\
    00286 * FreePhi
    00287 *
    00288 * History:
    00289 * 09-18-97 GerardoB     Created
    00290 \***************************************************************************/
    00291 void FreePhi (PHARDERRORINFO phi)
    00292 {
    00293     if (phi->dwHEIFFlags & HEIF_ALLOCATEDMSG) {
    00294         LocalFree(phi->pmsg);
    00295     }
    00296
    00297     RtlFreeUnicodeString(&phi->usText);
    00298     RtlFreeUnicodeString(&phi->usCaption);
    00299
    00300     LocalFree(phi);
    00301 }
    00302 /***************************************************************************\
    00303 * ReplyHardError
    00304 *
    00305 * This function is called when we are done with a hard error.
    00306 *
    00307 * History:
    00308 * 03-11-97 GerardoB     Created
    00309 \***************************************************************************/
    00310 void ReplyHardError (PHARDERRORINFO phi, DWORD dwResponse)
    00311 {
    00312     phi->pmsg->Response = dwResponse;
    00313     /*
    00314      * Signal the event if any. If not, reply if we haven't done so
    00315      *  already.
    00316      */
    00317     if (phi->hEventHardError != NULL) {
    00318         NtSetEvent(phi->hEventHardError, NULL);
    00319     } else if (!(phi->dwHEIFFlags & HEIF_REPLIED)) {
    00320         NtReplyPort(((PCSR_THREAD)phi->pthread)->Process->ClientPort,
    00321                     (PPORT_MESSAGE)phi->pmsg);
    00322     }
    00323     /*
    00324      * If we had locked the thread or were holding the client port,
    00325      *   then let it go now.
    00326      */
    00327     if (phi->dwHEIFFlags & HEIF_DEREFTHREAD) {
    00328         CsrDereferenceThread(phi->pthread);
    00329     }
    00330     /*
    00331      * We're done with this dude
    00332      */
    00333     FreePhi(phi);
    00334 }
    00335 /***************************************************************************\
    00336 * CheckDefaultDesktop
    00337 *
    00338 * This function is called by the HardErrorHandler when it's notified
    00339 *  that we've switched desktops or upon waking up.
    00340 *  If we're on the default desktop now, then we clear the HEIF_WRONGDESKTOP
    00341 *  flag; this flag is set when we find a MB_DEFAULT_DESKTOP_ONLY request but
    00342 *  we are not in the right (default) desktop.
    00343 *
    00344 * History:
    00345 * 06-02-97 GerardoB     Created
    00346 \***************************************************************************/
    00347 void CheckDefaultDesktop(void)
    00348 {
    00349     PHARDERRORINFO phi;
    00350
    00351     if (HEC_WRONGDESKTOP == NtUserHardErrorControl(HardErrorInDefDesktop, NULL, NULL)) {
    00352         return;
    00353     }
    00354
    00355     EnterCrit();
    00356     phi = gphiList;
    00357     while (phi != NULL) {
    00358         phi->dwHEIFFlags &= ~HEIF_WRONGDESKTOP;
    00359         phi = phi->phiNext;
    00360     }
    00361     LeaveCrit();
    00362 }
    00363
    00364 /*****************************************************************************
    00365  *
    00366  *  MsgBoxTimerFunc
    00367  *
    00368  *  This function gets called when a timer fires on a GUI message box
    00369  *  is up that has a timeout set for it.
    00370  *
    00371  *  This function cancels the message box by posting a WM_QUIT into the
    00372  *  message queue of the Citrix Message box thread.
    00373  *
    00374  * ENTRY:
    00375  *
    00376  *
    00377  * EXIT:
    00378  *
    00379  *
    00380  ****************************************************************************/
    00381
    00382 VOID
    00383 MsgBoxTimerFunc(
    00384     HWND  hWnd,
    00385     UINT  MessageType,
    00386     UINT_PTR idEvent,
    00387     DWORD TimeWhenCalled
    00388     )
    00389 {
    00390     BOOL RetVal;
    00391
    00392     RIPMSG0(RIP_WARNING, "MsgBoxTimerFunc: timer poped");
    00393
    00394     //
    00395     // Post a WM_QUIT message into the messagebox threads queue
    00396     //
    00397     if ( gdwHardErrorThreadId != 0 ) {
    00398         gfTimedOut = TRUE;
    00399         RetVal = PostThreadMessage(gdwHardErrorThreadId, WM_QUIT, 0, 0);
    00400     }
    00401
    00402     if(- !RetVal ) {
    00403         RIPMSG0(RIP_WARNING, "MsgBoxTimerFunc: PostMessageFailed");
    00404     }
    00405
    00406     UNREFERENCED_PARAMETER(hWnd);
    00407     UNREFERENCED_PARAMETER(MessageType);
    00408     UNREFERENCED_PARAMETER(idEvent);
    00409     UNREFERENCED_PARAMETER(TimeWhenCalled);
    00410 }
    00411
    00412 /***************************************************************************\
    00413 * GetHardErrorText
    00414 *
    00415 * This function figures out the message box title, text and flags.
    00416 * We want to do this up front so we can log this error when the hard error is
    00417 *  raised. Previously we used to log it after the user had dismissed the message
    00418 *  box -- but that was not when the error occurred (DCR Bug 107590)
    00419 *
    00420 * History:
    00421 * 09-18-97 GerardoB     Extracted (and cleaned up) from HardErrorHandler
    00422 \***************************************************************************/
    00423 void GetHardErrorText (PHARDERRORINFO phi)
    00424 {
    00425     static WCHAR wszUnkownSoftwareException [] = L"unknown software exception";
    00426     static WCHAR wszException [] = L"{EXCEPTION}";
    00427     static WCHAR wszUnknownHardError [] = L"Unknown Hard Error";
    00428     ANSI_STRING asLocal, asMessage;
    00429     BOOL fFreeAppNameBuffer, fFreeCaption;
    00430     BOOL fResAllocated, fResAllocated1, fErrorIsFromSystem;
    00431     WCHAR wszErrorMessage[WSPRINTF_LIMIT + 1];
    00432     DWORD dwCounter, dwStringsToFreeMask, dwMBFlags;
    00433     ULONG_PTR adwParameterVector[MAXIMUM_HARDERROR_PARAMETERS];
    00434     HANDLE hClientProcess;
    00435     HWND hwndOwner;
    00436     NTSTATUS Status;
    00437     PHARDERROR_MSG phemsg;
    00438     PMESSAGE_RESOURCE_ENTRY MessageEntry;
    00439     PWSTR pwszCaption, pwszFormatString;
    00440     PWSTR pwszAppName, pwszResBuffer, pwszResBuffer1;
    00441     PWSTR pwszMsg, pwszTitle, pwszFullCaption;
    00442     UINT uMsgLen, uCaptionLen, uTitleLen;
    00443     UNICODE_STRING usScratch, usLocal, usMessage, usCaption;
    00444
    00445     /*
    00446      * Initialize working variables
    00447      */
    00448     fFreeAppNameBuffer = fFreeCaption = FALSE;
    00449     hClientProcess = NULL;
    00450     RtlInitUnicodeString(&usCaption, NULL);
    00451     RtlInitUnicodeString(&usMessage, NULL);
    00452     /*
    00453      * Initialize response in case something goes wrong
    00454      */
    00455     phemsg = phi->pmsg;
    00456     phemsg->Response = ResponseNotHandled;
    00457     /*
    00458      * Make a copy of the parameters. Initialize unused ones to point to empty
    00459      *  strings (in case we expect a string there).
    00460      */
    00461     UserAssert(phemsg->NumberOfParameters <= MAXIMUM_HARDERROR_PARAMETERS);
    00462     RtlCopyMemory(adwParameterVector, phemsg->Parameters, phemsg->NumberOfParameters * sizeof(*phemsg->Parameters));
    00463     dwCounter = phemsg->NumberOfParameters;
    00464     while (dwCounter < MAXIMUM_HARDERROR_PARAMETERS) {
    00465         adwParameterVector[dwCounter++] = (ULONG_PTR)L"";
    00466     }
    00467     /*
    00468      * Open the client process so we can read the strings parameters, process
    00469      *  name, etc., from its address space
    00470      */
    00471     hClientProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
    00472                                 FALSE, HandleToUlong(phemsg->h.ClientId.UniqueProcess));
    00473     fErrorIsFromSystem = (hClientProcess == NULL);
    00474     /*
    00475      * If there are unicode strings, then we need to
    00476      * convert them to ansi and store them in the
    00477      * parameter vector
    00478      */
    00479     dwStringsToFreeMask = 0;
    00480     if (phemsg->UnicodeStringParameterMask) {
    00481
    00482         for (dwCounter = 0; dwCounter < phemsg->NumberOfParameters; dwCounter++) {
    00483             /*
    00484              * if there is no string in this position, continue
    00485              */
    00486             if (!(phemsg->UnicodeStringParameterMask & (1 << dwCounter))) {
    00487                 continue;
    00488             }
    00489             /*
    00490              * Point to an empty string in case we don't have
    00491              * a client to read from or something fails later on.
    00492              */
    00493             adwParameterVector[dwCounter] = (ULONG_PTR)L"";
    00494             if (hClientProcess == NULL) {
    00495                 continue;
    00496             }
    00497
    00498             Status = NtReadVirtualMemory(hClientProcess,
    00499                             (PVOID)phemsg->Parameters[dwCounter],
    00500                             (PVOID)&usScratch,
    00501                              sizeof(usScratch), NULL);
    00502
    00503             if (!NT_SUCCESS(Status)) {
    00504                 RIPMSG0(RIP_WARNING, "Failed to read error string struct!");
    00505                 continue;
    00506             }
    00507
    00508             usLocal = usScratch;
    00509             usLocal.Buffer = (PWSTR)LocalAlloc(LMEM_ZEROINIT, usLocal.Length + sizeof(UNICODE_NULL));
    00510             if (usLocal.Buffer == NULL) {
    00511                 RIPMSG0(RIP_WARNING, "Failed to alloc string buffer!");
    00512                 continue;
    00513             }
    00514
    00515             Status = NtReadVirtualMemory(hClientProcess,
    00516                             (PVOID)usScratch.Buffer,
    00517                             (PVOID)usLocal.Buffer,
    00518                             usLocal.Length,
    00519                             NULL);
    00520
    00521             if (!NT_SUCCESS(Status)) {
    00522                 LocalFree(usLocal.Buffer);
    00523                 RIPMSG0(RIP_WARNING, "Failed to read error string!");
    00524                 continue;
    00525             }
    00526
    00527             usLocal.MaximumLength = usLocal.Length;
    00528             Status = RtlUnicodeStringToAnsiString(&asLocal, &usLocal, TRUE);
    00529             if (!NT_SUCCESS(Status)) {
    00530                 LocalFree(usLocal.Buffer);
    00531                 RIPMSG0(RIP_WARNING, "Failed to translate error string!");
    00532                 continue;
    00533             }
    00534
    00535             /*
    00536              * check to see if string contains an NT
    00537              * device name. If so, then attempt a
    00538              * drive letter substitution
    00539              */
    00540
    00541             if (strstr(asLocal.Buffer,"\\Device") == asLocal.Buffer) {
    00542                 SubstituteDeviceName(&usLocal,asLocal.Buffer);
    00543             } else if ((asLocal.Length > 4) && !_strnicmp(asLocal.Buffer, "\\??\\", 4)) {
    00544                 strcpy( asLocal.Buffer, asLocal.Buffer+4 );
    00545                 asLocal.Length -= 4;
    00546             } else {
    00547                 /*
    00548                  * Processing some status code doesn't require ansi strings.
    00549                  * Since no substitution took place, let's ignore the translation
    00550                  * to avoid losing chars -- incorrect code page translation
    00551                  */
    00552                 switch (phemsg->Status) {
    00553                     case STATUS_SERVICE_NOTIFICATION:
    00554                     case STATUS_VDM_HARD_ERROR:
    00555                         adwParameterVector[dwCounter] = (ULONG_PTR)usLocal.Buffer;
    00556                         RtlFreeAnsiString(&asLocal);
    00557                         continue;
    00558                 }
    00559
    00560             }
    00561
    00562             LocalFree(usLocal.Buffer);
    00563
    00564             dwStringsToFreeMask |= (1 << dwCounter);
    00565             adwParameterVector[dwCounter] = (ULONG_PTR)asLocal.Buffer;
    00566
    00567         } /* for (dwCounter... */
    00568
    00569     } /* if (phemsg->UnicodeStringParameterMask) */
    00570
    00571     /*
    00572      * Read additional MB flags, if provided.
    00573      */
    00574 #if (HARDERROR_PARAMETERS_FLAGSPOS >= MAXIMUM_HARDERROR_PARAMETERS)
    00575 #error Invalid HARDERROR_PARAMETERS_FLAGSPOS value.
    00576 #endif
    00577 #if (HARDERROR_FLAGS_DEFDESKTOPONLY != MB_DEFAULT_DESKTOP_ONLY)
    00578 #error Invalid HARDERROR_FLAGS_DEFDESKTOPONLY
    00579 #endif
    00580     dwMBFlags = 0;
    00581     if (phemsg->NumberOfParameters > HARDERROR_PARAMETERS_FLAGSPOS) {
    00582         /*
    00583          * Currently we only use MB_DEFAULT_DESKTOP_ONLY
    00584          */
    00585         UserAssert(!(adwParameterVector[HARDERROR_PARAMETERS_FLAGSPOS] & ~MB_DEFAULT_DESKTOP_ONLY));
    00586         if (adwParameterVector[HARDERROR_PARAMETERS_FLAGSPOS] & MB_DEFAULT_DESKTOP_ONLY) {
    00587             dwMBFlags |= MB_DEFAULT_DESKTOP_ONLY;
    00588         }
    00589     }
    00590     /*
    00591      * For some status codes, all MessageBox parameters are provided in the HardError parameters
    00592      */
    00593     switch (phemsg->Status) {
    00594         case STATUS_SERVICE_NOTIFICATION:
    00595             if (phemsg->UnicodeStringParameterMask & 0x1) {
    00596                 RtlInitUnicodeString(&usMessage, (PWSTR)adwParameterVector[0]);
    00597             } else {
    00598                 RtlInitAnsiString(&asMessage, (PSTR)adwParameterVector[0]);
    00599                 RtlAnsiStringToUnicodeString(&usMessage, &asMessage, TRUE);
    00600             }
    00601
    00602             if (phemsg->UnicodeStringParameterMask & 0x2) {
    00603                 RtlInitUnicodeString(&usCaption, (PWSTR)adwParameterVector[1]);
    00604             } else {
    00605                 RtlInitAnsiString(&asMessage, (PSTR)adwParameterVector[1]);
    00606                 RtlAnsiStringToUnicodeString(&usCaption, &asMessage, TRUE);
    00607             }
    00608
    00609             dwMBFlags = (DWORD)adwParameterVector[2] & ~MB_SERVICE_NOTIFICATION;
    00610             goto CleanUpAndSaveParams;
    00611
    00612         case STATUS_VDM_HARD_ERROR:
    00613             /*
    00614              * Parameters[0] = (fForWOW << 16) | wBtn1;
    00615              * Parameters[1] = (wBtn2   << 16) | wBtn3;
    00616              * Parameters[2] = (DWORD) szTitle;
    00617              * Parameters[3] = (DWORD) szMessage;
    00618              */
    00619             phi->dwHEIFFlags |= HEIF_VDMERROR;
    00620             /*
    00621              * Save VDM's Button(s) info to be used later.
    00622              */
    00623             phi->dwVDMParam0 = (DWORD)adwParameterVector[0];
    00624             phi->dwVDMParam1 = (DWORD)adwParameterVector[1];
    00625             /*
    00626              * Get caption and text.
    00627              */
    00628             try {
    00629                 if (phemsg->UnicodeStringParameterMask & 0x4) {
    00630                     RtlInitUnicodeString(&usCaption, (PWSTR)adwParameterVector[2]);
    00631                 } else {
    00632                     MBToWCS((LPSTR)adwParameterVector[2], -1, &pwszTitle, -1, TRUE);
    00633                     RtlCreateUnicodeString(&usCaption, pwszTitle);
    00634                     RtlFreeHeap(RtlProcessHeap(), 0, pwszTitle);
    00635                 }
    00636
    00637                 if (phemsg->UnicodeStringParameterMask & 0x8) {
    00638                     RtlInitUnicodeString(&usMessage, (PWSTR)adwParameterVector[3]);
    00639                 } else {
    00640                     MBToWCS((LPSTR)adwParameterVector[3], -1, &pwszMsg, -1, TRUE);
    00641                     RtlCreateUnicodeString(&usMessage, pwszMsg);
    00642                     RtlFreeHeap(RtlProcessHeap(), 0, pwszMsg);
    00643                 }
    00644
    00645
    00646             } except (EXCEPTION_EXECUTE_HANDLER) {
    00647
    00648                 RIPMSG0(RIP_WARNING, "Exception reading STATUS_VDM_HARD_ERROR paramerters");
    00649
    00650                 RtlFreeUnicodeString(&usCaption);
    00651                 RtlCreateUnicodeString(&usCaption, L"VDM Internal Error");
    00652                 RtlFreeUnicodeString(&usMessage);
    00653                 RtlCreateUnicodeString(&usMessage, L"Exception retrieving error text.");
    00654             }
    00655             goto CleanUpAndSaveParams;
    00656     }
    00657
    00658     /*
    00659      * For all other status codes, we generate the information from the status code.
    00660      * First, Map status code and valid response to MessageBox flags.
    00661      */
    00662     dwMBFlags |= wIcons[(ULONG)(phemsg->Status) >> 30] | wOptions[phemsg->ValidResponseOptions];
    00663
    00664
    00665     /*
    00666      * If we have a client process, try to get the actual application name
    00667      */
    00668     pwszAppName = NULL;
    00669     if (!fErrorIsFromSystem) {
    00670         PPEB Peb;
    00671         PROCESS_BASIC_INFORMATION BasicInfo;
    00672         PLDR_DATA_TABLE_ENTRY LdrEntry;
    00673         LDR_DATA_TABLE_ENTRY LdrEntryData;
    00674         PLIST_ENTRY LdrHead, LdrNext;
    00675         PPEB_LDR_DATA Ldr;
    00676         PVOID ImageBaseAddress;
    00677         PWSTR ClientApplicationName;
    00678
    00679         /*
    00680          * This is cumbersome, but basically, we locate the processes
    00681          * loader data table and get it's name directly out of the
    00682          * loader table
    00683          */
    00684
    00685         Status = NtQueryInformationProcess(hClientProcess, ProcessBasicInformation,
    00686                     &BasicInfo, sizeof(BasicInfo), NULL);
    00687
    00688         if (!NT_SUCCESS(Status)) {
    00689             fErrorIsFromSystem = TRUE;
    00690             goto noname;
    00691         }
    00692
    00693         Peb = BasicInfo.PebBaseAddress;
    00694         if (Peb == NULL) {
    00695             fErrorIsFromSystem = TRUE;
    00696             goto noname;
    00697         }
    00698
    00699         /*
    00700          * ldr = Peb->Ldr
    00701          */
    00702         Status = NtReadVirtualMemory(hClientProcess, &Peb->Ldr, &Ldr,
    00703                     sizeof(Ldr), NULL);
    00704
    00705         if (!NT_SUCCESS(Status)) {
    00706             goto noname;
    00707         }
    00708
    00709         LdrHead = &Ldr->InLoadOrderModuleList;
    00710
    00711         /*
    00712          * LdrNext = Head->Flink;
    00713          */
    00714         Status = NtReadVirtualMemory(hClientProcess, &LdrHead->Flink,
    00715                     &LdrNext, sizeof(LdrNext), NULL );
    00716
    00717         if (!NT_SUCCESS(Status)) {
    00718             goto noname;
    00719         }
    00720
    00721         if (LdrNext == LdrHead) {
    00722             goto noname;
    00723         }
    00724         /*
    00725          * This is the entry data for the image.
    00726          */
    00727         LdrEntry = CONTAINING_RECORD(LdrNext, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
    00728         Status = NtReadVirtualMemory(hClientProcess, LdrEntry,
    00729                     &LdrEntryData, sizeof(LdrEntryData), NULL);
    00730
    00731         if (!NT_SUCCESS(Status)) {
    00732             goto noname;
    00733         }
    00734
    00735         Status = NtReadVirtualMemory(hClientProcess, &Peb->ImageBaseAddress,
    00736                     &ImageBaseAddress, sizeof(ImageBaseAddress), NULL);
    00737
    00738         if (!NT_SUCCESS(Status)) {
    00739             goto noname;
    00740         }
    00741
    00742         if (ImageBaseAddress != LdrEntryData.DllBase) {
    00743             goto noname;
    00744         }
    00745
    00746         LdrNext = LdrEntryData.InLoadOrderLinks.Flink;
    00747
    00748         ClientApplicationName = (PWSTR)LocalAlloc(LMEM_ZEROINIT, LdrEntryData.BaseDllName.MaximumLength);
    00749         if (ClientApplicationName == NULL) {
    00750             goto noname;
    00751         }
    00752
    00753         Status = NtReadVirtualMemory(hClientProcess, LdrEntryData.BaseDllName.Buffer,
    00754                     ClientApplicationName, LdrEntryData.BaseDllName.MaximumLength,
    00755                     NULL);
    00756
    00757         if (!NT_SUCCESS(Status)) {
    00758             LocalFree(ClientApplicationName);
    00759             goto noname;
    00760         }
    00761
    00762         pwszAppName = ClientApplicationName;
    00763         fFreeAppNameBuffer = TRUE;
    00764
    00765 noname:;
    00766     } /* if (!fErrorIsFromSystem) */
    00767
    00768     if (pwszAppName == NULL) {
    00769         /*
    00770          * Load default application name (to be used in the caption).
    00771          */
    00772         pwszAppName = ServerLoadString(ghModuleWin, STR_UNKNOWN_APPLICATION,
    00773                                         L"System Process", &fFreeAppNameBuffer);
    00774     }
    00775
    00776     /*
    00777      * Map status code to (optional) caption and format string.
    00778      * If a caption is provided, it's enclosed in {} and it's
    00779      *  the first thing in the format string
    00780      */
    00781     EnterCrit();
    00782     if (gNtDllHandle == NULL) {
    00783         gNtDllHandle = GetModuleHandle(TEXT("ntdll"));
    00784         UserAssert(gNtDllHandle != NULL);
    00785     }
    00786     LeaveCrit();
    00787
    00788     Status = RtlFindMessage((PVOID)gNtDllHandle, (ULONG_PTR)RT_MESSAGETABLE,
    00789                             LANG_NEUTRAL, phemsg->Status, &MessageEntry);
    00790
    00791     /*
    00792      * Parse the caption (if any) and the format string.
    00793      */
    00794     pwszCaption = NULL;
    00795     if (!NT_SUCCESS(Status)) {
    00796         pwszFormatString = wszUnknownHardError;
    00797     } else {
    00798         pwszFormatString = (PWSTR)MessageEntry->Text;
    00799         /*
    00800          * If the message starts with a '{', it has a caption.
    00801          */
    00802         if (*pwszFormatString == L'{') {
    00803             uCaptionLen = 0;
    00804             pwszFormatString++;
    00805             /*
    00806              * Find the closing bracket
    00807              */
    00808             while ((*pwszFormatString != (WCHAR)0) && (*pwszFormatString++ != L'}')) {
    00809                 uCaptionLen++;
    00810             }
    00811             /*
    00812              * Eat any non-printable stuff (\r\n), up to the NULL
    00813              */
    00814             while ((*pwszFormatString != (WCHAR)0) && (*pwszFormatString <= L' ')) {
    00815                 pwszFormatString++;
    00816             }
    00817             /*
    00818              * Allocate a buffer an copy the caption string
    00819              */
    00820             if ((uCaptionLen++ > 0)
    00821                 && ((pwszCaption = (PWSTR)LocalAlloc(LPTR, uCaptionLen * sizeof(WCHAR))) != NULL)) {
    00822
    00823                 RtlCopyMemory(pwszCaption, (PWSTR)MessageEntry->Text + 1, (uCaptionLen - 1) * sizeof(WCHAR));
    00824                 fFreeCaption = TRUE;
    00825             }
    00826         } /* if (*pszParsedCaption == '{') */
    00827
    00828         if (*pwszFormatString == (WCHAR)0) {
    00829             pwszFormatString = wszUnknownHardError;
    00830         }
    00831     } /* if (!NT_SUCCESS(Status))  (Failed to read caption/format string) */
    00832
    00833
    00834     /*
    00835      * If the message didn't include a caption (or we didn't find the message),
    00836      *  default to something
    00837      */
    00838     if (pwszCaption == NULL) {
    00839         switch (phemsg->Status & ERROR_SEVERITY_ERROR) {
    00840             case ERROR_SEVERITY_SUCCESS:
    00841                 pwszCaption = gpwszaSUCCESS;
    00842                 break;
    00843             case ERROR_SEVERITY_INFORMATIONAL:
    00844                 pwszCaption = gpwszaSYSTEM_INFORMATION;
    00845                 break;
    00846             case ERROR_SEVERITY_WARNING:
    00847                 pwszCaption = gpwszaSYSTEM_WARNING;
    00848                 break;
    00849             case ERROR_SEVERITY_ERROR:
    00850                 pwszCaption = gpwszaSYSTEM_ERROR;
    00851                 break;
    00852         }
    00853     }
    00854     UserAssert(pwszCaption != NULL);
    00855     /*
    00856      * If the client has a window, get its title so it can be added to
    00857      *  the caption.
    00858      */
    00859     hwndOwner = NULL;
    00860     EnumThreadWindows(HandleToUlong(phemsg->h.ClientId.UniqueThread),
    00861                         FindWindowFromThread, (LPARAM)&hwndOwner);
    00862     if (hwndOwner == NULL) {
    00863         uTitleLen = 0;
    00864     } else {
    00865         uTitleLen = GetWindowTextLength(hwndOwner);
    00866         if (uTitleLen != 0) {
    00867             pwszTitle = (PWSTR)LocalAlloc(LPTR, (uTitleLen + 3) * sizeof(WCHAR));
    00868             if (pwszTitle != NULL) {
    00869                 GetWindowText(hwndOwner, pwszTitle, uTitleLen + 1);
    00870                 /*
    00871                  * Add format chars.
    00872                  */
    00873                 *(pwszTitle + uTitleLen++) = (WCHAR)':';
    00874                 *(pwszTitle + uTitleLen++) = (WCHAR)' ';
    00875             } else {
    00876                 /*
    00877                  * We couldn't allocate a buffer to get the title
    00878                  */
    00879                 uTitleLen = 0;
    00880             }
    00881         } /* if (uTitleLen != 0) */
    00882     } /* else if (hwndOwner == NULL) */
    00883     /*
    00884      * If we don't have a window title, make it an empty string so we won't
    00885      *  have to special case it later.
    00886      */
    00887     if (uTitleLen == 0) {
    00888         pwszTitle = L"";
    00889     }
    00890     /*
    00891      * Finally we can build the caption string now.
    00892      * It looks like this: [WindowTile: ]ApplicationName - ErrorCaption
    00893      */
    00894     uCaptionLen = uTitleLen + wcslen(pwszAppName) + 3 + wcslen(pwszCaption) + 1;
    00895     pwszFullCaption = (PWSTR)LocalAlloc(LPTR, uCaptionLen * sizeof(WCHAR));
    00896     if (pwszFullCaption != NULL) {
    00897         #if DBG
    00898         int iLen =
    00899         #endif
    00900             wsprintfW(pwszFullCaption, L"%s%s - %s", pwszTitle, pwszAppName, pwszCaption);
    00901         UserAssert((UINT)iLen < uCaptionLen);
    00902         RtlCreateUnicodeString(&usCaption, pwszFullCaption);
    00903         LocalFree(pwszFullCaption);
    00904     }
    00905     /*
    00906      * Free caption working buffers, as appropriate.
    00907      */
    00908     if (fFreeCaption) {
    00909         LocalFree(pwszCaption);
    00910     }
    00911     if (fFreeAppNameBuffer) {
    00912         LocalFree(pwszAppName);
    00913     }
    00914     if (uTitleLen != 0) {
    00915         LocalFree(pwszTitle);
    00916     }
    00917     /*
    00918      * Build the error message using pszFormatString and adwParameterVector.
    00919      * Special case UAE
    00920      */
    00921     if (phemsg->Status == STATUS_UNHANDLED_EXCEPTION ) {
    00922         /*
    00923          * The first parameter has the exception status code. Map it to a
    00924          *  format string and build the error message with it and the
    00925          *  parameters.
    00926          */
    00927         Status = RtlFindMessage( (PVOID)gNtDllHandle, (ULONG_PTR)RT_MESSAGETABLE,
    00928                                  LANG_NEUTRAL, (ULONG)adwParameterVector[0], &MessageEntry);
    00929
    00930         if (!NT_SUCCESS(Status)) {
    00931             /*
    00932              * We couldn't read the exception name so let's use unknown.
    00933              */
    00934             pwszResBuffer = ServerLoadString(ghModuleWin, STR_UNKNOWN_EXCEPTION,
    00935                             wszUnkownSoftwareException, &fResAllocated);
    00936
    00937             wsprintfW(wszErrorMessage, pwszFormatString, pwszResBuffer,
    00938                       adwParameterVector[0], adwParameterVector[1]);
    00939
    00940             if (fResAllocated) {
    00941                 LocalFree(pwszResBuffer);
    00942             }
    00943
    00944             RtlCreateUnicodeString(&usMessage, wszErrorMessage);
    00945             UserAssert(usMessage.MaximumLength <= sizeof(wszErrorMessage));
    00946
    00947         } else {
    00948             /*
    00949              * Access Violations are handled a bit differently
    00950              */
    00951
    00952             if (adwParameterVector[0] == STATUS_ACCESS_VIOLATION ) {
    00953
    00954                 wsprintfW(wszErrorMessage, (PWSTR)MessageEntry->Text, adwParameterVector[1],
    00955                           adwParameterVector[3], adwParameterVector[2] ? L"written" : L"read");
    00956
    00957             } else if (adwParameterVector[0] == STATUS_IN_PAGE_ERROR) {
    00958                 wsprintfW(wszErrorMessage, (PWSTR)MessageEntry->Text, adwParameterVector[1],
    00959                           adwParameterVector[3], adwParameterVector[2]);
    00960
    00961             } else {
    00962                 /*
    00963                  * If this is a marked exception, skip the mark;
    00964                  *  the exception name follows it.
    00965                  */
    00966                 pwszCaption = (PWSTR)MessageEntry->Text;
    00967                 if (!wcsncmp(pwszCaption, wszException, ARRAY_SIZE(wszException) - 1)) {
    00968                     pwszCaption += ARRAY_SIZE(wszException) - 1;
    00969                     /*
    00970                      * Skip not printable stuff (\r\n)
    00971                      */
    00972                     while ((*pwszCaption != (WCHAR)0) && (*pwszCaption <= L' ')) {
    00973                         pwszCaption++;
    00974                     }
    00975
    00976                 } else {
    00977                     pwszCaption = wszUnkownSoftwareException;
    00978                 }
    00979
    00980                 wsprintfW(wszErrorMessage, pwszFormatString, pwszCaption,
    00981                           adwParameterVector[0], adwParameterVector[1]);
    00982             }
    00983
    00984             UserAssert(wcslen(wszErrorMessage) < ARRAY_SIZE(wszErrorMessage));
    00985
    00986             /*
    00987              * Add button(s) explanation text.
    00988              */
    00989             pwszResBuffer = ServerLoadString(ghModuleWin, STR_OK_TO_TERMINATE,
    00990                             L"Click on OK to terminate the application",
    00991                             &fResAllocated);
    00992
    00993
    00994             if (phemsg->ValidResponseOptions == OptionOkCancel ) {
    00995                 pwszResBuffer1 = ServerLoadString(ghModuleWin,
    00996                                 STR_CANCEL_TO_DEBUG, L"Click on CANCEL xx to debug the application",
    00997                                 &fResAllocated1);
    00998             } else {
    00999                 pwszResBuffer1 = NULL;
    01000                 fResAllocated1 = FALSE;
    01001             }
    01002
    01003             /*
    01004              * Conncatenate all strings, one per line.
    01005              */
    01006             uMsgLen = wcslen(wszErrorMessage)
    01007                         + wcslen(pwszResBuffer) + 1
    01008                         + (pwszResBuffer1 == NULL ? 0 : wcslen(pwszResBuffer1) + 1)
    01009                         + 1;
    01010
    01011             pwszMsg = (PWSTR) LocalAlloc(LPTR, uMsgLen * sizeof(WCHAR));
    01012             if (pwszMsg != NULL) {
    01013                 #if DBG
    01014                 int iLen =
    01015                 #endif
    01016                     wsprintfW(pwszMsg, L"%s\n%s%s%s", wszErrorMessage, pwszResBuffer,
    01017                               (pwszResBuffer1 == NULL ? L"" : L"\n"),
    01018                               (pwszResBuffer1 == NULL ? L"" : pwszResBuffer1));
    01019
    01020                 UserAssert((UINT)iLen < uMsgLen);
    01021
    01022                 RtlCreateUnicodeString(&usMessage, pwszMsg);
    01023                 LocalFree(pwszMsg);
    01024             }
    01025
    01026             /*
    01027              * Free ServerLoadString allocations.
    01028              */
    01029             if (fResAllocated) {
    01030                 LocalFree(pwszResBuffer);
    01031             }
    01032
    01033             if (fResAllocated1) {
    01034                 LocalFree(pwszResBuffer1);
    01035             }
    01036
    01037
    01038         }
    01039
    01040     } else {
    01041         /*
    01042          * Default message text generation for all other status codes
    01043          */
    01044         try {
    01045             #if DBG
    01046             int iLen =
    01047             #endif
    01048                 wsprintfW(wszErrorMessage, pwszFormatString, adwParameterVector[0],
    01049                                               adwParameterVector[1],
    01050                                               adwParameterVector[2],
    01051                                               adwParameterVector[3]);
    01052             UserAssert((UINT)iLen <  ARRAY_SIZE(wszErrorMessage));
    01053
    01054             /*
    01055              * Remove \r\n
    01056              */
    01057             pwszFormatString = wszErrorMessage;
    01058             while (*pwszFormatString != (WCHAR)0) {
    01059                 if (*pwszFormatString == (WCHAR)0xd) {
    01060                     *pwszFormatString = L' ';
    01061                     /*
    01062                      * Move everything up if a CR LF sequence is found
    01063                      */
    01064                     if (*(pwszFormatString+1) == (WCHAR)0xa) {
    01065                         UINT uSize = (wcslen(pwszFormatString+1) + 1) * sizeof(WCHAR);
    01066                         RtlMoveMemory(pwszFormatString, pwszFormatString+1, uSize);
    01067                     }
    01068                  }
    01069
    01070                 if (*pwszFormatString == (WCHAR)0xa) {
    01071                     *pwszFormatString = L' ';
    01072                 }
    01073
    01074                 pwszFormatString++;
    01075             }
    01076
    01077             RtlCreateUnicodeString(&usMessage, wszErrorMessage);
    01078             UserAssert(usMessage.MaximumLength <= sizeof(wszErrorMessage));
    01079         } except(EXCEPTION_EXECUTE_HANDLER) {
    01080
    01081             wsprintfW(wszErrorMessage, L"Exception Processing Message %lx Parameters %lx %lx %lx %lx",
    01082                       phemsg->Status, adwParameterVector[0], adwParameterVector[1],
    01083                       adwParameterVector[2], adwParameterVector[3]);
    01084
    01085             RtlFreeUnicodeString(&usMessage);
    01086             RtlCreateUnicodeString(&usMessage, wszErrorMessage);
    01087             UserAssert(usMessage.MaximumLength <= sizeof(wszErrorMessage));
    01088
    01089         } /* try */
    01090
    01091     } /* else if (phemsg->Status == STATUS_UNHANDLED_EXCEPTION) */
    01092
    01093
    01094 CleanUpAndSaveParams:
    01095      if (hClientProcess != NULL) {
    01096          NtClose(hClientProcess);
    01097      }
    01098     /*
    01099      * Free string parameters.
    01100      * Note that we're supposed to call RtlFreeAnsiString since these were
    01101      *  allocated by RtlUnicodeStringToAnsiString.... but we only saved the buffers...
    01102      */
    01103     if (dwStringsToFreeMask != 0) {
    01104         for (dwCounter = 0; dwCounter < phemsg->NumberOfParameters; dwCounter++) {
    01105             if (dwStringsToFreeMask & (1 << dwCounter)) {
    01106                 RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)adwParameterVector[dwCounter]);
    01107             }
    01108         }
    01109     }
    01110     /*
    01111      * Save MessageBox Parameters in phi to be used and freed later.
    01112      */
    01113     if (fErrorIsFromSystem) {
    01114         phi->dwHEIFFlags |= HEIF_SYSTEMERROR;
    01115     }
    01116     phi->usText = usMessage;
    01117     phi->usCaption = usCaption;
    01118     phi->dwMBFlags = dwMBFlags;
    01119     return;
    01120 }
    01121 /***************************************************************************\
    01122 * HardErrorHandler
    01123 *
    01124 * This routine processes hard error requests from the CSR exception port
    01125 *
    01126 * History:
    01127 * 07-03-91 JimA             Created.
    01128 \***************************************************************************/
    01129 VOID HardErrorHandler(void)
    01130 {
    01131     int idResponse;
    01132     PHARDERRORINFO phi, *pphi;
    01133     DWORD dwResponse;
    01134     DESKRESTOREDATA drdRestore;
    01135     BOOL fNuked;
    01136     UINT uHECRet;
    01137     DWORD dwCmd;
    01138     HANDLE hThread;
    01139     int aidButton[3], cButtons;
    01140     LPWSTR apstrButton[3];
    01141     MSGBOXDATA mbd;
    01142     BOOL bDoBlock;
    01143     PCTXHARDERRORINFO pCtxHEInfo = NULL;
    01144     MSG msg;
    01145
    01146 #if DBG
    01147     /*
    01148      * We should have only one error handler at the time.
    01149      */
    01150     static long glReentered = -1;
    01151     UserAssert(InterlockedIncrement(&glReentered) == 0);
    01152 #endif
    01153
    01154     if (ISTS()) {
    01155         bDoBlock = (gbExitInProgress || (HEC_ERROR == NtUserHardErrorControl(HardErrorSetup, NULL, NULL)));
    01156     } else {
    01157         bDoBlock = (HEC_ERROR == NtUserHardErrorControl(HardErrorSetup, NULL, NULL));
    01158     }
    01159
    01160     drdRestore.pdeskRestore = NULL;
    01161
    01162     if (bDoBlock) {
    01163         /*
    01164          * We failed to set up to process hard errors.  Acknowledge all
    01165          * pending errors as NotHandled.
    01166          */
    01167         EnterCrit();
    01168         while (gphiList != NULL) {
    01169             phi = gphiList;
    01170             gphiList = phi->phiNext;
    01171             LeaveCrit();
    01172             ReplyHardError(phi, ResponseNotHandled);
    01173             EnterCrit();
    01174         }
    01175         UserAssert(InterlockedDecrement(&glReentered) < 0);
    01176         UserAssert(gdwHardErrorThreadId == HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread));
    01177         gdwHardErrorThreadId = 0;
    01178         LeaveCrit();
    01179         return;
    01180     }
    01181
    01182     /*
    01183      * Process all hard error requests.
    01184      */
    01185
    01186     for (;;) {
    01187         /*
    01188          * Grab the next request (for the current desktop)
    01189          * If we're done, reset gdwHardErrorThreadId so any request
    01190          *  after this point will be handled by someone else
    01191          */
    01192         EnterCrit();
    01193         phi = gphiList;
    01194         if (phi == NULL) {
    01195             UserAssert(InterlockedDecrement(&glReentered) < 0);
    01196             UserAssert(gdwHardErrorThreadId == HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread));
    01197             gdwHardErrorThreadId = 0;
    01198         } else {
    01199             while ((phi != NULL) && (phi->dwHEIFFlags & HEIF_WRONGDESKTOP)) {
    01200                 phi = phi->phiNext;
    01201             }
    01202             if (phi != NULL) {
    01203                 /*
    01204                  * We're going to show this one.
    01205                  */
    01206                 phi->dwHEIFFlags |= HEIF_ACTIVE;
    01207             } else {
    01208                 /*
    01209                  * We have some requests pending but they are not
    01210                  *  for the current desktop. Let's wait for another
    01211                  *  request (WM_NULL posted) or a desktop switch (PostQuitMessage)
    01212                  */
    01213                 LeaveCrit();
    01214                 MsgWaitForMultipleObjects(0, NULL, FALSE, INFINITE, QS_POSTMESSAGE);
    01215                 PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
    01216                 CheckDefaultDesktop();
    01217                 continue;
    01218             }
    01219         }
    01220         LeaveCrit();
    01221         /*
    01222          * If no messages are pending, we're done.
    01223          */
    01224         if (phi == NULL) {
    01225             NtUserHardErrorControl(HardErrorCleanup, NULL, NULL);
    01226             return;
    01227         }
    01228
    01229         /*
    01230          * The Boost routine can mess with the list, so must get citrix info now.
    01231          */
    01232         if (ISTS()) {
    01233             pCtxHEInfo = phi->pCtxHEInfo;
    01234             if (gbExitInProgress) {
    01235                 dwResponse = ResponseOk;
    01236                 goto Reply;
    01237             }
    01238         }
    01239
    01240         /*
    01241          * Get win32k attach parameters.
    01242          */
    01243         dwCmd = (phi->dwMBFlags & MB_DEFAULT_DESKTOP_ONLY) ? HardErrorAttachUser : HardErrorAttach;
    01244         hThread = (phi->pthread != NULL) ? phi->pthread->ThreadHandle : NULL;
    01245         /*
    01246          * We have already handled the MB_SERVICE_NOTIFICATION flags.
    01247          * Clear it to prevent recursion.
    01248          * Also, don't let hard error boxes steal the foreground
    01249          */
    01250         phi->dwMBFlags &= ~(MB_SERVICE_NOTIFICATION | MB_SETFOREGROUND | MB_SYSTEMMODAL);
    01251         /*
    01252          * If this is a VDM error, figure out buttons, default id, style, etc
    01253          */
    01254         if (phi->dwHEIFFlags & HEIF_VDMERROR) {
    01255             int i;
    01256             WORD rgwBtn[3], wBtn;
    01257             /*
    01258              * Initialize MSGBOXDATA with the information we
    01259              *  have already figured out.
    01260              */
    01261             RtlZeroMemory(&mbd, sizeof(MSGBOXDATA));
    01262             mbd.cbSize = sizeof(MSGBOXPARAMS);
    01263             mbd.lpszText = phi->usText.Buffer;
    01264             mbd.lpszCaption = phi->usCaption.Buffer;
    01265             /*
    01266              * phi->dwVDMParam0 = (fForWOW << 16) | wBtn1;
    01267              * phi->dwVDMParam1 = (wBtn2   << 16) | wBtn3;
    01268              * Right now, only WOW does this.  If NTVDM does it,
    01269              * fForWOW will be false.
    01270              */
    01271             rgwBtn[0] = LOWORD(phi->dwVDMParam0);
    01272             rgwBtn[1] = HIWORD(phi->dwVDMParam1);
    01273             rgwBtn[2] = LOWORD(phi->dwVDMParam1);
    01274             cButtons = 0;
    01275             for (i = 0; i < 3; i++) {
    01276                 wBtn = rgwBtn[i] & ~SEB_DEFBUTTON;
    01277                 if (wBtn && wBtn <= MAX_SEB_STYLES) {
    01278                     apstrButton[cButtons] = MB_GetString(wBtn-1);
    01279                     aidButton[cButtons] = i + 1;
    01280                     if (rgwBtn[i] & SEB_DEFBUTTON) {
    01281                         mbd.DefButton = cButtons;
    01282                     }
    01283                     if (wBtn == SEB_CANCEL) {
    01284                         mbd.CancelId = cButtons;
    01285                     }
    01286                     cButtons++;
    01287                 }
    01288             }
    01289             mbd.dwStyle = MB_TOPMOST;
    01290             if ((cButtons != 1) || (aidButton[0] != 1)) {
    01291                 mbd.dwStyle |= MB_OKCANCEL;
    01292             }
    01293             mbd.ppszButtonText = apstrButton;
    01294             mbd.pidButton = aidButton;
    01295             mbd.cButtons = cButtons;
    01296         }
    01297         /*
    01298          * Attach to win32k and show the dialog.
    01299          * If we switch desktops, (loop and) show it on the new desktop (if applicable)
    01300          */
    01301         do {
    01302             phi->pmsg->Response = ResponseNotHandled;
    01303
    01304             uHECRet = NtUserHardErrorControl(dwCmd, hThread, &drdRestore);
    01305
    01306             if (uHECRet == HEC_SUCCESS) {
    01307                 if (phi->dwHEIFFlags & HEIF_VDMERROR) {
    01308                     idResponse = SoftModalMessageBox(&mbd);
    01309                 } else {
    01310                     /*
    01311                      * Bring up the message box. Or in MB_TOPMOST so
    01312                      * it comes up on top.
    01313                      * We want to preserve the MB_DEFAULT_DESKTOP_ONLY flag
    01314                      *  but don't want to pass it to MessageBox or we'll
    01315                      *  recurse due to a compatibility hack
    01316                      */
    01317
    01318                     /*
    01319                      *  Really a Terminal Server message
    01320                      */
    01321                     if (pCtxHEInfo != NULL) {
    01322
    01323                         /*
    01324                          * If timeout is not (-1), or 0, then we must queue
    01325                          * a system timer to call our timer callback function
    01326                          * to cancel the message box.
    01327                          */
    01328                         if ((pCtxHEInfo->Timeout != (-1)) && (pCtxHEInfo->Timeout != 0)) {
    01329
    01330                             DWORD Timeout;
    01331
    01332                             if (((DWORD)pCtxHEInfo->Timeout) < (MAXLONG/1000)) {
    01333                                 Timeout = (DWORD)pCtxHEInfo->Timeout * 1000L;
    01334                             } else {
    01335                                 Timeout = MAXLONG;
    01336                             }
    01337
    01338                             gfTimedOut = FALSE;
    01339                             gTimerId = SetTimer((HWND)0,
    01340                                                 (UINT)0,
    01341                                                 Timeout,
    01342                                                 MsgBoxTimerFunc);
    01343                             if (gTimerId == 0) {
    01344                                 RIPMSG0(RIP_WARNING, "HardErrorHandler: Could not set system timer");
    01345                             }
    01346                         }
    01347
    01348                         RIPMSG2(RIP_WARNING, "HardErrorHandler: MessageBoxEx( %S, %S )",
    01349                                 phi->usText.Buffer, phi->usCaption.Buffer);
    01350                     } else {
    01351                         RIPMSG2(RIP_WARNING, "HardErrorHandler: MessageBoxEx( %S, %S )",
    01352                                 phi->usText.Buffer, phi->usCaption.Buffer);
    01353                     }
    01354
    01355                     idResponse = MessageBoxEx(NULL, phi->usText.Buffer, phi->usCaption.Buffer,
    01356                         (phi->dwMBFlags | MB_TOPMOST) & ~MB_DEFAULT_DESKTOP_ONLY, 0);
    01357                 }
    01358                 /*
    01359                  * Restore hard error handler desktop; this will also
    01360                  *  tell us if the input desktop has changed; if so,
    01361                  *  we want to bring the error box again on the new
    01362                  *  desktop.
    01363                  */
    01364                 uHECRet = NtUserHardErrorControl(HardErrorDetach, NULL, &drdRestore);
    01365
    01366                 if (ISTS()) {
    01367                     /*
    01368                      * Kill the timer if set
    01369                      */
    01370                     if (gTimerId) {
    01371                         KillTimer((HWND)0, gTimerId);
    01372                         gTimerId = 0;
    01373                     }
    01374                     /*
    01375                      *  Really a citrix message
    01376                      */
    01377                     if (uHECRet != HEC_DESKTOPSWITCH && pCtxHEInfo != NULL) {
    01378
    01379                         /*
    01380                          * Check for message box timeout
    01381                          */
    01382                         if (gfTimedOut) {
    01383                            uHECRet = HEC_SUCCESS;
    01384                            gfTimedOut = FALSE;
    01385                            pCtxHEInfo->Response = IDTIMEOUT;
    01386                         } else {
    01387                            pCtxHEInfo->Response = idResponse;
    01388                         }
    01389
    01390                     }
    01391                     if (dwResponses[idResponse] == ResponseNotHandled &&
    01392                         uHECRet == HEC_DESKTOPSWITCH && gSessionId == 0) {
    01393
    01394                         RIPMSG2(RIP_WARNING, "HardErrorHandler: abort harderror, idResponse %u, uHECRet %u",
    01395                                     idResponse, uHECRet);
    01396
    01397                         break;
    01398                     }
    01399                 }
    01400             } else {
    01401                 idResponse = 0;
    01402             }
    01403             UserAssert((UINT)idResponse < ARRAY_SIZE(dwResponses));
    01404             dwResponse = dwResponses[idResponse];
    01405             /*
    01406              * If we don't want to reshow this box, done
    01407              */
    01408             if (uHECRet != HEC_DESKTOPSWITCH) {
    01409                 break;
    01410             } else {
    01411                 /*
    01412                  * We've switched desktops; if we're in the default one
    01413                  *  now, then we can show all MB_DEFAULT_DESKTOP_ONLY
    01414                  *  requests.
    01415                  */
    01416                 CheckDefaultDesktop();
    01417             }
    01418             /*
    01419              * If BoostHardError nuked it, don't re-show it
    01420              */
    01421             EnterCrit();
    01422             fNuked = (phi->dwHEIFFlags & HEIF_NUKED);
    01423             LeaveCrit();
    01424         } while (!fNuked);
    01425
    01426         /*
    01427          * If we didn't show this box because we're not in the
    01428          *  default desktop, mark this phi and continue
    01429          */
    01430         if (uHECRet == HEC_WRONGDESKTOP) {
    01431             UserAssert(phi->dwMBFlags & MB_DEFAULT_DESKTOP_ONLY);
    01432             EnterCrit();
    01433             COPY_FLAG(phi->dwHEIFFlags, HEIF_WRONGDESKTOP, HEIF_ACTIVE | HEIF_WRONGDESKTOP);
    01434             LeaveCrit();
    01435             continue;
    01436         }
    01437
    01438 Reply:
    01439         /*
    01440          * We're done with this phi.
    01441          * Unlink it if BoostHardError haven't done so already;
    01442          *  If unlinked, it is marked as nuked.
    01443          */
    01444         EnterCrit();
    01445         UserAssert(phi->dwHEIFFlags & HEIF_ACTIVE);
    01446         fNuked = (phi->dwHEIFFlags & HEIF_NUKED);
    01447         if (!fNuked) {
    01448             pphi = &gphiList;
    01449             while ((*pphi != phi) && (*pphi != NULL)) {
    01450                 pphi = &(*pphi)->phiNext;
    01451             }
    01452             UserAssert(*pphi != NULL);
    01453             *pphi = phi->phiNext;
    01454         }
    01455
    01456 #if DBG
    01457          else {
    01458             /*
    01459              * Let's make sure it was unlinked.
    01460              */
    01461             pphi = &gphiList;
    01462             while ((*pphi != phi) && (*pphi != NULL)) {
    01463                 UserAssert(!((*pphi)->dwHEIFFlags & (HEIF_ACTIVE | HEIF_NUKED)));
    01464                 pphi = &(*pphi)->phiNext;
    01465             }
    01466             UserAssert(*pphi == NULL);
    01467          }
    01468 #endif
    01469
    01470         if (phi->pCtxHEInfo) {
    01471
    01472             /*
    01473              * Clean up
    01474              */
    01475             HardErrorRemove(phi->pCtxHEInfo);
    01476
    01477             /*
    01478              * Done
    01479              */
    01480             phi->pCtxHEInfo = NULL;
    01481         }
    01482
    01483         LeaveCrit();
    01484
    01485         /*
    01486          * Save the response, reply and free phi
    01487          */
    01488         ReplyHardError(phi, (fNuked ? ResponseNotHandled : dwResponse));
    01489
    01490     } /* for (;;) */
    01491
    01492     /*
    01493      * Nobody should break out of the loop.
    01494      */
    01495     UserAssert(FALSE);
    01496 }
    01497
    01498
    01499 LPWSTR RtlLoadStringOrError(
    01500     HANDLE hModule,
    01501     UINT wID,
    01502     LPWSTR lpDefault,
    01503     PBOOL pAllocated,
    01504     BOOL bAnsi
    01505     )
    01506 {
    01507     LPTSTR lpsz;
    01508     int cch;
    01509     LPWSTR lpw;
    01510     PMESSAGE_RESOURCE_ENTRY MessageEntry;
    01511     NTSTATUS Status;
    01512
    01513     cch = 0;
    01514     lpw = NULL;
    01515
    01516     Status = RtlFindMessage((PVOID)hModule, (ULONG_PTR)RT_MESSAGETABLE,
    01517             0, wID, &MessageEntry);
    01518     if (NT_SUCCESS(Status)) {
    01519
    01520         /*
    01521          * Return two fewer chars so the crlf in the message will be
    01522          * stripped out.
    01523          */
    01524         cch = wcslen((PWCHAR)MessageEntry->Text) - 2;
    01525         lpsz = (LPWSTR)MessageEntry->Text;
    01526
    01527         if (bAnsi) {
    01528             int ich;
    01529
    01530             /*
    01531              * Add one to zero terminate then force the termination
    01532              */
    01533             ich = WCSToMB(lpsz, cch+1, (CHAR **)&lpw, -1, TRUE);
    01534             ((LPSTR)lpw)[ich-1] = 0;
    01535
    01536             }
    01537         else {
    01538             lpw = (LPWSTR)LocalAlloc(LMEM_ZEROINIT,(cch+1)*sizeof(WCHAR));
    01539             if ( lpw ) {
    01540
    01541                 /*
    01542                  * Copy the string into the buffer.
    01543                  */
    01544                     RtlCopyMemory(lpw, lpsz, cch*sizeof(WCHAR));
    01545                 }
    01546             }
    01547         }
    01548
    01549     if ( !lpw ) {
    01550         lpw = lpDefault;
    01551         *pAllocated = FALSE;
    01552         } else {
    01553         *pAllocated = TRUE;
    01554         }
    01555
    01556     return lpw;
    01557 }
    01558
    01559 /***************************************************************************\
    01560 * HardErrorWorkerThread
    01561 *
    01562 * Worker thread to handle hard error requests.
    01563 *
    01564 * History:
    01565 * 05-01-98 JerrySh      Created.
    01566 \***************************************************************************/
    01567
    01568 NTSTATUS
    01569 HardErrorWorkerThread(
    01570     PVOID ThreadParameter
    01571     )
    01572 {
    01573     PCSR_THREAD pt;
    01574     UNREFERENCED_PARAMETER(ThreadParameter);
    01575
    01576     pt = CsrConnectToUser();
    01577     ProcessHardErrorRequest(FALSE);
    01578     if (pt) {
    01579         CsrDereferenceThread(pt);
    01580     }
    01581     UserExitWorkerThread();
    01582
    01583     return STATUS_SUCCESS;
    01584 }
    01585
    01586 /***************************************************************************\
    01587 * ProcessHardErrorRequest
    01588 *
    01589 * Figures out who should process the hard error. There are 3 possible cases.
    01590 * - If there is already a hard error thread, hand it off to him.
    01591 * - If not and we don't want to wait, create a worker thread to deal with it.
    01592 * - If we want to wait or thread creation fails, deal with it ourselves.
    01593 *
    01594 * History:
    01595 * 05-01-98 JerrySh      Created.
    01596 \***************************************************************************/
    01597
    01598 VOID
    01599 ProcessHardErrorRequest(
    01600     BOOL fNewThread
    01601     )
    01602 {
    01603     NTSTATUS Status;
    01604     CLIENT_ID ClientId;
    01605     HANDLE hThread;
    01606
    01607     EnterCrit();
    01608
    01609     /*
    01610      * If there's already a hard error handler, make sure he's awake.
    01611      */
    01612     if (gdwHardErrorThreadId) {
    01613         DWORD dwHardErrorHandler = gdwHardErrorThreadId;
    01614         LeaveCrit();
    01615         PostThreadMessage(dwHardErrorHandler, WM_NULL, 0, 0);
    01616         return;
    01617     }
    01618
    01619     /*
    01620      * Create a worker thread to handle the hard error.
    01621      */
    01622     if (fNewThread) {
    01623         LeaveCrit();
    01624         Status = RtlCreateUserThread(NtCurrentProcess(),
    01625                                      NULL,
    01626                                      TRUE,
    01627                                      0,
    01628                                      0,
    01629                                      0,
    01630                                      HardErrorWorkerThread,
    01631                                      NULL,
    01632                                      &hThread,
    01633                                      &ClientId);
    01634         if (NT_SUCCESS(Status)) {
    01635             CsrAddStaticServerThread(hThread, &ClientId, 0);
    01636             NtResumeThread(hThread, NULL);
    01637             return;
    01638         }
    01639         EnterCrit();
    01640     }
    01641
    01642     /*
    01643      * Let this thread handle the hard error.
    01644      */
    01645     gdwHardErrorThreadId = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread);
    01646     LeaveCrit();
    01647     HardErrorHandler();
    01648
    01649     return;
    01650 }
    01651
    01652 /***************************************************************************\
    01653 * UserHardError
    01654 *
    01655 * Called from CSR to pop up hard error messages
    01656 *
    01657 * History:
    01658 * 03/12/97 GerardoB         Rewritten to support OptionOkNoWait
    01659 * 07-03-91 JimA             Created.
    01660 \***************************************************************************/
    01661
    01662 VOID UserHardError(
    01663     PCSR_THREAD pt,
    01664     PHARDERROR_MSG pmsg)
    01665 {
    01666     UserHardErrorEx(pt, pmsg, NULL);
    01667 }
    01668
    01669 VOID HardErrorInsert(
    01670     PCSR_THREAD pt,
    01671     PHARDERROR_MSG pmsg,
    01672     PCTXHARDERRORINFO pCtxHEInfo)
    01673 {
    01674     UserHardErrorEx(pt, pmsg, pCtxHEInfo);
    01675 }
    01676
    01677 /***************************************************************************\
    01678 * UserHardErrorEx
    01679 *
    01680 * Called from CSR to pop up hard error messages
    01681 *
    01682 * History:
    01683 * 07-03-91 JimA             Created.
    01684 \***************************************************************************/
    01685
    01686 VOID UserHardErrorEx(
    01687     PCSR_THREAD pt,
    01688     PHARDERROR_MSG pmsg,
    01689     PCTXHARDERRORINFO pCtxHEInfo)
    01690 {
    01691     BOOL fClientPort, fNoWait, fMsgBox, fLogEvent;
    01692     PHARDERRORINFO phi = NULL, *pphiLast;
    01693     HANDLE hEvent;
    01694     DWORD dwReportMode, dwResponse;
    01695
    01696     UserAssert((ULONG)pmsg->NumberOfParameters <= MAXIMUM_HARDERROR_PARAMETERS);
    01697     /*
    01698      * Allocate memory to queue request.
    01699      */
    01700     phi = (PHARDERRORINFO)LocalAlloc(LPTR, sizeof(HARDERRORINFO));
    01701     if (phi == NULL) {
    01702         goto ErrorExit;
    01703     }
    01704     phi->pthread = pt;
    01705
    01706     /*
    01707      * Set up citrix specific stuff
    01708      */
    01709     if (ISTS()) {
    01710         phi->pCtxHEInfo = pCtxHEInfo;
    01711     }
    01712
    01713     /*
    01714      * Determine reply type
    01715      */
    01716     fClientPort = ((pt != NULL) && (pt->Process->ClientPort != NULL));
    01717     fNoWait = (pmsg->ValidResponseOptions == OptionOkNoWait);
    01718
    01719     /*
    01720      * Capture HARDERROR_MSG data or create wait event as needed
    01721      */
    01722     if (fClientPort || fNoWait) {
    01723         phi->pmsg = (PHARDERROR_MSG)LocalAlloc(LPTR, pmsg->h.u1.s1.TotalLength);
    01724         if (phi->pmsg == NULL) {
    01725             goto ErrorExit;
    01726         }
    01727         phi->dwHEIFFlags |= HEIF_ALLOCATEDMSG;
    01728         RtlCopyMemory(phi->pmsg, pmsg, pmsg->h.u1.s1.TotalLength);
    01729         hEvent = NULL;
    01730         /*
    01731          * Set the magic response value (-1) to let CsrApiRequestThread know
    01732          * that we'll take care of dereferencing and replying.
    01733          */
    01734         if (pt != NULL) {
    01735             phi->dwHEIFFlags |= HEIF_DEREFTHREAD;
    01736         }
    01737         pmsg->Response = (ULONG)-1;
    01738         if (fNoWait) {
    01739             phi->pmsg->ValidResponseOptions = OptionOk;
    01740         }
    01741     } else {
    01742         phi->pmsg = pmsg;
    01743         /*
    01744          * There is no reply port but we need to wait; create an event.
    01745          */
    01746         hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    01747         if (hEvent == NULL) {
    01748             goto ErrorExit;
    01749         }
    01750         phi->hEventHardError = hEvent;
    01751     }
    01752
    01753     /*
    01754      * Build hard error title, message and flags. Then log the event.
    01755      */
    01756     GetHardErrorText(phi);
    01757
    01758     /*
    01759      * Reply now if we're not going to wait.
    01760      */
    01761     if (fNoWait) {
    01762         phi->dwHEIFFlags |= HEIF_REPLIED;
    01763         phi->pmsg->Response = ResponseOk;
    01764         if (fClientPort) {
    01765             NtReplyPort(pt->Process->ClientPort, (PPORT_MESSAGE)phi->pmsg);
    01766         } else {
    01767             /*
    01768              * Must let CsrApiRequestThread reply since we don't have a port
    01769              */
    01770             pmsg->Response = ResponseOk;
    01771             /*
    01772              * If we have a thread, reference it because we're telling
    01773              *  CsrApiRequestThread that we're done with it.
    01774              */
    01775             if (pt != NULL) {
    01776                 /*
    01777                  * Later5.0 GerardoB. Let's stop to see how this happens.
    01778                  */
    01779                 UserAssert(pt == NULL);
    01780                 CsrReferenceThread(pt);
    01781             }
    01782         }
    01783     }
    01784
    01785     /*
    01786      * Register the event if we haven't done so already.
    01787      * Since RegisterEventSource is supported by a service, we must not hold
    01788      *  any locks while making this call. Hence we might have several threads
    01789      *  registering the event simultaneously.
    01790      */
    01791     fLogEvent = (gEventSource != NULL);
    01792     if (!fLogEvent) {
    01793         HANDLE hEventSource;
    01794         hEventSource = UserRegisterEventSource(L"Application Popup");
    01795         /*
    01796          * Save the first handle, deregister all others.
    01797          */
    01798         if (InterlockedCompareExchangePointer(&gEventSource, hEventSource, NULL) == NULL) {
    01799             /*
    01800              * This is the first handle. If valid, we can log events.
    01801              */
    01802             fLogEvent = (hEventSource != NULL);
    01803         } else {
    01804             /*
    01805              * We had already saved another handle (so we can log events). Deregister this one.
    01806              */
    01807             if (hEventSource != NULL) {
    01808                 UserVerify(gfnDeregisterEventSource(hEventSource));
    01809             }
    01810             fLogEvent = TRUE;
    01811         }
    01812     }
    01813
    01814     dwReportMode = (fLogEvent ? GetErrorMode() : 0);
    01815     if (fLogEvent) {
    01816         LogErrorPopup(phi->usCaption.Buffer, phi->usText.Buffer);
    01817     }
    01818
    01819     /*
    01820      * Determine if we need to display a message box.
    01821      */
    01822     if ((phi->pmsg->Status == STATUS_SERVICE_NOTIFICATION) || (dwReportMode == 0)) {
    01823         fMsgBox = TRUE;
    01824     } else if (phi->pmsg->Status == STATUS_VDM_HARD_ERROR) {
    01825         fMsgBox = (dwReportMode == 1);
    01826         if (!fMsgBox) {
    01827             dwResponse = ResponseOk;
    01828         }
    01829     } else {
    01830         fMsgBox = ((dwReportMode == 1) && !(phi->dwHEIFFlags & HEIF_SYSTEMERROR));
    01831         if (!fMsgBox) {
    01832             UserAssert((UINT)phi->pmsg->ValidResponseOptions < ARRAY_SIZE(dwResponseDefault));
    01833             dwResponse = dwResponseDefault[phi->pmsg->ValidResponseOptions];
    01834         }
    01835     }
    01836     /*
    01837      * If we don't have to display a message box, we're done.
    01838      */
    01839     if (!fMsgBox) {
    01840         goto DontNeedErrorHandler;
    01841     }
    01842
    01843     /*
    01844      * We want to display a message box. Queue the request and go for it.
    01845      */
    01846     EnterCrit();
    01847     /*
    01848      * Never mind if the process has terminated. Got to check this holding the
    01849      * critical section to make sure that no other thread makes it to BoostHardError
    01850      * before we add this phi to the list.
    01851      */
    01852     if ((pt != NULL) && (pt->Process->Flags & CSR_PROCESS_TERMINATED)) {
    01853         LeaveCrit();
    01854 DontNeedErrorHandler:
    01855         ReplyHardError(phi, dwResponse);
    01856         if (hEvent != NULL) {
    01857             NtClose(hEvent);
    01858         }
    01859         return;
    01860     }
    01861     /*
    01862      * Add it to the end of the list.
    01863      */
    01864     pphiLast = &gphiList;
    01865     while (*pphiLast != NULL) {
    01866         pphiLast = &(*pphiLast)->phiNext;
    01867     }
    01868     *pphiLast = phi;
    01869     LeaveCrit();
    01870
    01871     /*
    01872      * Process the hard error request. If this is a NoWait request and there
    01873      * is no reply port, then we'll try to launch a new worker thread so this
    01874      * one can return.
    01875      */
    01876     ProcessHardErrorRequest(fNoWait && !fClientPort);
    01877
    01878     /*
    01879      * If there is an event handle, wait for it.
    01880      */
    01881     if (hEvent != NULL) {
    01882         NtWaitForSingleObject(hEvent, FALSE, NULL);
    01883         NtClose(hEvent);
    01884     }
    01885     return;
    01886
    01887 ErrorExit:
    01888     if (phi != NULL) {
    01889         FreePhi(phi);
    01890     }
    01891     pmsg->Response = ResponseNotHandled;
    01892 }
    01893
    01894 /***************************************************************************\
    01895 * BoostHardError
    01896 *
    01897 * If one or more hard errors exist for the specified process, remove
    01898 * them from the list if forced, otherwise bring the first one to the
    01899 * top of the hard error list and display it.  Return TRUE if there
    01900 * is a hard error.
    01901 *
    01902 * History:
    01903 * 11-02-91 JimA             Created.
    01904 \***************************************************************************/
    01905
    01906 BOOL BoostHardError(
    01907     ULONG_PTR dwProcessId,
    01908     DWORD dwCode)
    01909 {
    01910     DESKRESTOREDATA drdRestore;
    01911     PHARDERRORINFO phi, *pphi;
    01912     BOOL fHasError = FALSE;
    01913
    01914     EnterCrit();
    01915     /*
    01916      * If the list is empty, nothing do to here.
    01917      */
    01918     if (gphiList == NULL) {
    01919         LeaveCrit();
    01920         return FALSE;
    01921     }
    01922     drdRestore.pdeskRestore = NULL;
    01923     /*
    01924      * Walk the hard error list
    01925      */
    01926     pphi = &gphiList;
    01927     while (*pphi != NULL) {
    01928         /*
    01929          * If not not nuking all and not owned by dwProcessId, continue walking
    01930          */
    01931         if (dwProcessId != (ULONG_PTR)-1) {
    01932             if (((*pphi)->pthread == NULL)
    01933                     || ((ULONG_PTR)((*pphi)->pthread->ClientId.UniqueProcess) != dwProcessId)) {
    01934
    01935                 pphi = &(*pphi)->phiNext;
    01936                 continue;
    01937             }
    01938         } else {
    01939             UserAssert(dwCode == BHE_FORCE);
    01940         }
    01941         /*
    01942          * Got one so we want to return TRUE
    01943          */
    01944         fHasError = TRUE;
    01945         /*
    01946          * If nuking the request
    01947          */
    01948         if (dwCode == BHE_FORCE) {
    01949             /*
    01950              * Unlink it from the list.
    01951              */
    01952             phi = *pphi;
    01953             *pphi = phi->phiNext;
    01954
    01955             /*
    01956              * If this box is being shown right now, signal it to go away.
    01957              * Otherwise, nuke it
    01958              */
    01959             if (phi->dwHEIFFlags & HEIF_ACTIVE) {
    01960                 DWORD dwHardErrorHandler = gdwHardErrorThreadId;
    01961                 phi->dwHEIFFlags |= HEIF_NUKED;
    01962                 LeaveCrit();
    01963                 PostThreadMessage(dwHardErrorHandler, WM_QUIT, 0, 0);
    01964             } else {
    01965                 /*
    01966                  * Acknowledge the error as not handled, reply and free
    01967                  */
    01968                 LeaveCrit();
    01969                 ReplyHardError(phi, ResponseNotHandled);
    01970             }
    01971
    01972             /*
    01973              * Restart the search because we left the crit sect.
    01974              */
    01975             EnterCrit();
    01976             pphi = &gphiList;
    01977
    01978             /* continue */
    01979
    01980         } else if (dwCode == BHE_ACTIVATE) {
    01981             /*
    01982              * If it's active, find it and show it.
    01983              */
    01984             phi = *pphi;
    01985             if (phi->dwHEIFFlags & HEIF_ACTIVE) {
    01986                 HWND hwndError = NULL;
    01987                 DWORD dwHardErrorHandler = gdwHardErrorThreadId;
    01988
    01989                 LeaveCrit();
    01990                 EnumThreadWindows(dwHardErrorHandler, FindWindowFromThread, (LPARAM)&hwndError);
    01991
    01992                 if ((hwndError != NULL)
    01993                         && (HEC_SUCCESS == NtUserHardErrorControl(HardErrorAttachNoQueue, NULL, &drdRestore))) {
    01994
    01995                     SetForegroundWindow(hwndError);
    01996
    01997                     NtUserHardErrorControl(HardErrorDetachNoQueue, NULL, &drdRestore);
    01998                 }
    01999                 return TRUE;
    02000             }
    02001
    02002             /*
    02003              * It's not active so move it to the head of the list
    02004              *  to make it show up next.
    02005              */
    02006             *pphi = phi->phiNext;
    02007             phi->phiNext = gphiList;
    02008             gphiList = phi;
    02009             break;
    02010
    02011         } else { /* BHE_TEST */
    02012             /*
    02013              * The caller just want to know if this process owns a hard error
    02014              */
    02015             break;
    02016         }
    02017     } /*  while (*pphi != NULL) */
    02018
    02019     LeaveCrit();
    02020
    02021     /*
    02022      * Bug 284468. Wake up the hard error handler
    02023      */
    02024     if (dwCode == BHE_FORCE && gdwHardErrorThreadId != 0) {
    02025         PostThreadMessage(gdwHardErrorThreadId, WM_NULL, 0, 0);
    02026     }
    02027
    02028     return fHasError;
    02029 }