[WIN32K:NTUSER] Add a temporary winsta/desktop-connection hack for CSRSS/USERSRV...
[reactos.git] / win32ss / user / winsrv / usersrv / harderror.c
index 9a1d2c7..6ff336a 100644 (file)
@@ -61,6 +61,28 @@ RtlLoadUnicodeString(
 }
 
 
+/*
+ * NOTE: _scwprintf() is NOT exported by ntdll.dll,
+ * only _vscwprintf() is, so we need to implement it here.
+ * Code comes from sdk/lib/crt/printf/_scwprintf.c .
+ */
+int
+__cdecl
+_scwprintf(
+    const wchar_t *format,
+    ...)
+{
+    int len;
+    va_list args;
+
+    va_start(args, format);
+    len = _vscwprintf(format, args);
+    va_end(args);
+
+    return len;
+}
+
+
 /* FIXME */
 int
 WINAPI
@@ -153,8 +175,8 @@ UserpCaptureStringParameters(
             }
             else
             {
-                /* Allocate a buffer for converted to ANSI string */
-                TempStringA.MaximumLength = RtlUnicodeStringToAnsiSize(&TempStringU);
+                /* Allocate a buffer for conversion to ANSI string */
+                TempStringA.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&TempStringU);
                 TempStringA.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
                                                      HEAP_ZERO_MEMORY,
                                                      TempStringA.MaximumLength);
@@ -346,11 +368,21 @@ UserpFormatMessages(
     IN OUT PUNICODE_STRING TextStringU,
     IN OUT PUNICODE_STRING CaptionStringU,
     OUT PUINT pdwType,
+    OUT PULONG pdwTimeout,
     IN PHARDERROR_MSG Message)
 {
+    /* Special hardcoded messages */
+    static const PCWSTR pszUnknownHardError =
+        L"Unknown Hard Error 0x%08lx\n"
+        L"Parameters: 0x%p 0x%p 0x%p 0x%p";
+    static const PCWSTR pszExceptionHardError =
+        L"Exception processing message 0x%08lx\n"
+        L"Parameters: 0x%p 0x%p 0x%p 0x%p";
+
     NTSTATUS Status;
     OBJECT_ATTRIBUTES ObjectAttributes;
     HANDLE hProcess;
+    ULONG Severity = (ULONG)(Message->Status) >> 30;
     ULONG SizeOfStrings;
     ULONG_PTR Parameters[MAXIMUM_HARDERROR_PARAMETERS] = {0};
     ULONG_PTR CopyParameters[MAXIMUM_HARDERROR_PARAMETERS];
@@ -360,8 +392,6 @@ UserpFormatMessages(
     PMESSAGE_RESOURCE_ENTRY MessageResource;
     PWSTR FormatString, pszBuffer;
     size_t cszBuffer;
-    ULONG Severity = (ULONG)(Message->Status) >> 30;
-    ULONG Size;
 
     /* Open client process */
     InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
@@ -378,6 +408,13 @@ UserpFormatMessages(
     /* Capture all string parameters from the process memory */
     UserpCaptureStringParameters(Parameters, &SizeOfStrings, Message, hProcess);
 
+    /* Initialize the output strings */
+    TextStringU->Length = 0;
+    TextStringU->Buffer[0] = UNICODE_NULL;
+
+    CaptionStringU->Length = 0;
+    CaptionStringU->Buffer[0] = UNICODE_NULL;
+
     /*
      * Check whether it is a service notification, in which case
      * we format the parameters and take the short route.
@@ -394,29 +431,21 @@ UserpFormatMessages(
          */
         *pdwType = (UINT)Parameters[2] & ~MB_SERVICE_NOTIFICATION;
 
-        /* Duplicate the UNICODE text message */
+        /*
+         * Duplicate the UNICODE text message and caption.
+         * If no strings or invalid ones have been provided, keep
+         * the original buffers and reset the string lengths to zero.
+         */
         if (Message->UnicodeStringParameterMask & 0x1)
-        {
-            /* A string has been provided: duplicate it */
             UserpDuplicateParamStringToUnicodeString(TextStringU, (PCWSTR)Parameters[0]);
-        }
-        else
-        {
-            /* No string (or invalid one) has been provided: keep the original buffer and reset the string length to zero */
-            TextStringU->Length = 0;
-        }
-
-        /* Duplicate the UNICODE caption */
         if (Message->UnicodeStringParameterMask & 0x2)
-        {
-            /* A string has been provided: duplicate it */
             UserpDuplicateParamStringToUnicodeString(CaptionStringU, (PCWSTR)Parameters[1]);
-        }
+
+        /* Set the timeout */
+        if (Message->NumberOfParameters >= 4)
+            *pdwTimeout = (ULONG)Parameters[3];
         else
-        {
-            /* No string (or invalid one) has been provided: keep the original buffer and reset the string length to zero */
-            CaptionStringU->Length = 0;
-        }
+            *pdwTimeout = INFINITE;
 
         goto Quit;
     }
@@ -462,6 +491,9 @@ UserpFormatMessages(
 
     *pdwType |= MB_SYSTEMMODAL | MB_SETFOREGROUND;
 
+    /* Set the timeout */
+    *pdwTimeout = INFINITE;
+
     /* Copy the Parameters array locally */
     RtlCopyMemory(&CopyParameters, Parameters, sizeof(CopyParameters));
 
@@ -483,7 +515,8 @@ UserpFormatMessages(
         FileNameU = g_SystemProcessU;
     }
 
-    /* Get text string of the error code */
+    /* Retrieve the description of the error code */
+    FormatA.Buffer = NULL;
     Status = RtlFindMessage(GetModuleHandleW(L"ntdll"),
                             (ULONG_PTR)RT_MESSAGETABLE,
                             LANG_NEUTRAL,
@@ -501,41 +534,40 @@ UserpFormatMessages(
             RtlInitAnsiString(&FormatA, (PSTR)MessageResource->Text);
             /* Status = */ RtlAnsiStringToUnicodeString(&FormatU, &FormatA, TRUE);
         }
+        ASSERT(FormatU.Buffer);
     }
     else
     {
         /*
-         * Fall back to hardcoded value.
+         * Fall back to unknown hard error format string.
          * NOTE: The value used here is ReactOS-specific: it allows specifying
-         * the exact hard error status value and the parameters. The version
-         * used on Windows only says "Unknown Hard Error".
+         * the exact hard error status value and the parameters, contrary to
+         * the one on Windows that only says: "Unknown Hard Error".
          */
-#if 0
-        RtlInitUnicodeString(&FormatU, L"Unknown Hard Error 0x%08lx\n"
-                                       L"Parameters: 0x%p 0x%p 0x%p 0x%p");
-#else
-        RtlInitUnicodeString(&FormatU, L"Unknown Hard Error 0x%08lx");
-        CopyParameters[0] = Message->Status;
-#endif
+        RtlInitEmptyUnicodeString(&FormatU, NULL, 0);
         FormatA.Buffer = NULL;
     }
 
     FormatString = FormatU.Buffer;
 
-    /* Check whether a caption exists */
-    if (FormatString[0] == L'{')
+    /* Check whether a caption is specified in the format string */
+    if (FormatString && FormatString[0] == L'{')
     {
         /* Set caption start */
         TempStringU.Buffer = ++FormatString;
 
-        /* Get size of the caption */
-        for (Size = 0; *FormatString != UNICODE_NULL && *FormatString != L'}'; Size++)
-            FormatString++;
+        /* Get the caption size and find where the format string really starts */
+        for (TempStringU.Length = 0;
+             *FormatString != UNICODE_NULL && *FormatString != L'}';
+             ++TempStringU.Length)
+        {
+            ++FormatString;
+        }
 
         /* Skip '}', '\r', '\n' */
         FormatString += 3;
 
-        TempStringU.Length = (USHORT)(Size * sizeof(WCHAR));
+        TempStringU.Length *= sizeof(WCHAR);
         TempStringU.MaximumLength = TempStringU.Length;
     }
     else
@@ -553,7 +585,7 @@ UserpFormatMessages(
     }
 
     /* Retrieve the window title of the client, if it has one */
-    RtlInitEmptyUnicodeString(&WindowTitleU, NULL, 0);
+    RtlInitEmptyUnicodeString(&WindowTitleU, L"", 0);
     hwndOwner = NULL;
     EnumThreadWindows(HandleToUlong(Message->h.ClientId.UniqueThread),
                       FindTopLevelWnd, (LPARAM)&hwndOwner);
@@ -563,22 +595,19 @@ UserpFormatMessages(
         if (cszBuffer != 0)
         {
             cszBuffer += 3; // 2 characters for ": " and a NULL terminator.
-            WindowTitleU.MaximumLength = (USHORT)(cszBuffer * sizeof(WCHAR));
-            WindowTitleU.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
-                                                  HEAP_ZERO_MEMORY,
-                                                  WindowTitleU.MaximumLength);
-            if (WindowTitleU.Buffer)
+            cszBuffer *= sizeof(WCHAR);
+            pszBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
+                                        HEAP_ZERO_MEMORY,
+                                        cszBuffer);
+            if (pszBuffer)
             {
+                RtlInitEmptyUnicodeString(&WindowTitleU, pszBuffer, (USHORT)cszBuffer);
                 cszBuffer = GetWindowTextW(hwndOwner,
                                            WindowTitleU.Buffer,
                                            WindowTitleU.MaximumLength / sizeof(WCHAR));
                 WindowTitleU.Length = (USHORT)(cszBuffer * sizeof(WCHAR));
                 RtlAppendUnicodeToString(&WindowTitleU, L": ");
             }
-            else
-            {
-                RtlInitEmptyUnicodeString(&WindowTitleU, NULL, 0);
-            }
         }
     }
 
@@ -602,27 +631,33 @@ UserpFormatMessages(
         }
     }
     CaptionStringU->Length = 0;
+    CaptionStringU->Buffer[0] = UNICODE_NULL;
 
-    /* Append the file name, the separator and the caption text */
+    /* Build the caption */
     RtlStringCbPrintfW(CaptionStringU->Buffer,
                        CaptionStringU->MaximumLength,
                        L"%wZ%wZ - %wZ",
                        &WindowTitleU, &FileNameU, &TempStringU);
     CaptionStringU->Length = (USHORT)(wcslen(CaptionStringU->Buffer) * sizeof(WCHAR));
 
-    /* Free string buffers if needed */
-    if (WindowTitleU.Buffer) RtlFreeUnicodeString(&WindowTitleU);
-    if (hProcess) RtlFreeUnicodeString(&FileNameU);
+    /* Free the strings if needed */
+    if (WindowTitleU.Buffer && (WindowTitleU.MaximumLength != 0))
+        RtlFreeUnicodeString(&WindowTitleU);
+    if (hProcess)
+        RtlFreeUnicodeString(&FileNameU);
+
+    Format2A.Buffer = NULL;
 
-    // FIXME: What is 42 == ??
-    Size = 42;
+    /* If we have an unknown hard error, skip the special cases handling */
+    if (!FormatString)
+        goto BuildMessage;
 
     /* Check if this is an exception message */
     if (Message->Status == STATUS_UNHANDLED_EXCEPTION)
     {
         ULONG ExceptionCode = CopyParameters[0];
 
-        /* Get text string of the exception code */
+        /* Retrieve the description of the exception code */
         Status = RtlFindMessage(GetModuleHandleW(L"ntdll"),
                                 (ULONG_PTR)RT_MESSAGETABLE,
                                 LANG_NEUTRAL,
@@ -640,10 +675,12 @@ UserpFormatMessages(
                 RtlInitAnsiString(&Format2A, (PSTR)MessageResource->Text);
                 /* Status = */ RtlAnsiStringToUnicodeString(&Format2U, &Format2A, TRUE);
             }
+            ASSERT(Format2U.Buffer);
 
             /* Handle special cases */
             if (ExceptionCode == STATUS_ACCESS_VIOLATION)
             {
+                /* Use a new FormatString */
                 FormatString = Format2U.Buffer;
                 CopyParameters[0] = CopyParameters[1];
                 CopyParameters[1] = CopyParameters[3];
@@ -654,6 +691,7 @@ UserpFormatMessages(
             }
             else if (ExceptionCode == STATUS_IN_PAGE_ERROR)
             {
+                /* Use a new FormatString */
                 FormatString = Format2U.Buffer;
                 CopyParameters[0] = CopyParameters[1];
                 CopyParameters[1] = CopyParameters[3];
@@ -692,24 +730,64 @@ UserpFormatMessages(
             CopyParameters[1] = CopyParameters[0];
             CopyParameters[0] = (ULONG_PTR)L"unknown software exception";
         }
+    }
 
-        /* Add explanation text for dialog buttons */
-        if (Message->ValidResponseOptions == OptionOk ||
-            Message->ValidResponseOptions == OptionOkCancel)
+BuildMessage:
+    /*
+     * Calculate buffer length for the text message. If FormatString
+     * is NULL this means we have an unknown hard error whose format
+     * string is in FormatU.
+     */
+    cszBuffer = 0;
+    /* Wrap in SEH to protect from invalid string parameters */
+    _SEH2_TRY
+    {
+        if (!FormatString)
         {
-            /* Reserve space for one newline and the OK-terminate-program string */
-            Size += 1 + (g_OKTerminateU.Length / sizeof(WCHAR));
+            /* Fall back to unknown hard error format string, and use the original parameters */
+            cszBuffer = _scwprintf(pszUnknownHardError,
+                                   Message->Status,
+                                   Parameters[0], Parameters[1],
+                                   Parameters[2], Parameters[3]);
+            cszBuffer *= sizeof(WCHAR);
         }
-        if (Message->ValidResponseOptions == OptionOkCancel)
+        else
         {
-            /* Reserve space for one newline and the CANCEL-debug-program string */
-            Size += 1 + (g_CancelDebugU.Length / sizeof(WCHAR));
+            cszBuffer = _scwprintf(FormatString,
+                                   CopyParameters[0], CopyParameters[1],
+                                   CopyParameters[2], CopyParameters[3]);
+            cszBuffer *= sizeof(WCHAR);
+
+            /* Add a description for the dialog buttons */
+            if (Message->Status == STATUS_UNHANDLED_EXCEPTION)
+            {
+                if (Message->ValidResponseOptions == OptionOk ||
+                    Message->ValidResponseOptions == OptionOkCancel)
+                {
+                    /* Reserve space for one newline and the OK-terminate-program string */
+                    cszBuffer += sizeof(WCHAR) + g_OKTerminateU.Length;
+                }
+                if (Message->ValidResponseOptions == OptionOkCancel)
+                {
+                    /* Reserve space for one newline and the CANCEL-debug-program string */
+                    cszBuffer += sizeof(WCHAR) + g_CancelDebugU.Length;
+                }
+            }
         }
     }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        /* An exception occurred, use a default string with the original parameters */
+        cszBuffer = _scwprintf(pszExceptionHardError,
+                               Message->Status,
+                               Parameters[0], Parameters[1],
+                               Parameters[2], Parameters[3]);
+        cszBuffer *= sizeof(WCHAR);
+    }
+    _SEH2_END;
+
+    cszBuffer += SizeOfStrings + sizeof(UNICODE_NULL);
 
-    /* Calculate buffer length for the text message */
-    cszBuffer = FormatU.Length + SizeOfStrings + Size * sizeof(WCHAR) +
-                sizeof(UNICODE_NULL);
     if (TextStringU->MaximumLength < cszBuffer)
     {
         /* Allocate a larger buffer for the text message */
@@ -727,6 +805,7 @@ UserpFormatMessages(
         }
     }
     TextStringU->Length = 0;
+    TextStringU->Buffer[0] = UNICODE_NULL;
 
     /* Wrap in SEH to protect from invalid string parameters */
     _SEH2_TRY
@@ -734,32 +813,45 @@ UserpFormatMessages(
         /* Print the string into the buffer */
         pszBuffer = TextStringU->Buffer;
         cszBuffer = TextStringU->MaximumLength;
-        RtlStringCbPrintfExW(pszBuffer, cszBuffer,
-                             &pszBuffer, &cszBuffer,
-                             STRSAFE_IGNORE_NULLS,
-                             FormatString,
-                             CopyParameters[0], CopyParameters[1],
-                             CopyParameters[2], CopyParameters[3]);
-
-        /* Add explanation text for dialog buttons */
-        if (Message->Status == STATUS_UNHANDLED_EXCEPTION)
+
+        if (!FormatString)
         {
-            if (Message->ValidResponseOptions == OptionOk ||
-                Message->ValidResponseOptions == OptionOkCancel)
-            {
-                RtlStringCbPrintfExW(pszBuffer, cszBuffer,
-                                     &pszBuffer, &cszBuffer,
-                                     STRSAFE_IGNORE_NULLS,
-                                     L"\n%wZ",
-                                     &g_OKTerminateU);
-            }
-            if (Message->ValidResponseOptions == OptionOkCancel)
+            /* Fall back to unknown hard error format string, and use the original parameters */
+            RtlStringCbPrintfW(pszBuffer, cszBuffer,
+                               pszUnknownHardError,
+                               Message->Status,
+                               Parameters[0], Parameters[1],
+                               Parameters[2], Parameters[3]);
+        }
+        else
+        {
+            RtlStringCbPrintfExW(pszBuffer, cszBuffer,
+                                 &pszBuffer, &cszBuffer,
+                                 0,
+                                 FormatString,
+                                 CopyParameters[0], CopyParameters[1],
+                                 CopyParameters[2], CopyParameters[3]);
+
+            /* Add a description for the dialog buttons */
+            if (Message->Status == STATUS_UNHANDLED_EXCEPTION)
             {
-                RtlStringCbPrintfExW(pszBuffer, cszBuffer,
-                                     &pszBuffer, &cszBuffer,
-                                     STRSAFE_IGNORE_NULLS,
-                                     L"\n%wZ",
-                                     &g_CancelDebugU);
+                if (Message->ValidResponseOptions == OptionOk ||
+                    Message->ValidResponseOptions == OptionOkCancel)
+                {
+                    RtlStringCbPrintfExW(pszBuffer, cszBuffer,
+                                         &pszBuffer, &cszBuffer,
+                                         0,
+                                         L"\n%wZ",
+                                         &g_OKTerminateU);
+                }
+                if (Message->ValidResponseOptions == OptionOkCancel)
+                {
+                    RtlStringCbPrintfExW(pszBuffer, cszBuffer,
+                                         &pszBuffer, &cszBuffer,
+                                         0,
+                                         L"\n%wZ",
+                                         &g_CancelDebugU);
+                }
             }
         }
     }
@@ -771,8 +863,7 @@ UserpFormatMessages(
 
         RtlStringCbPrintfW(TextStringU->Buffer,
                            TextStringU->MaximumLength,
-                           L"Exception processing message 0x%08lx\n"
-                           L"Parameters: 0x%p 0x%p 0x%p 0x%p",
+                           pszExceptionHardError,
                            Message->Status,
                            Parameters[0], Parameters[1],
                            Parameters[2], Parameters[3]);
@@ -781,12 +872,12 @@ UserpFormatMessages(
 
     TextStringU->Length = (USHORT)(wcslen(TextStringU->Buffer) * sizeof(WCHAR));
 
-    /* Free converted Unicode strings */
+    /* Free the converted UNICODE strings */
     if (Format2A.Buffer) RtlFreeUnicodeString(&Format2U);
     if (FormatA.Buffer) RtlFreeUnicodeString(&FormatU);
 
 Quit:
-    /* Final cleanup */
+    /* Free the captured parameters */
     UserpFreeStringParameters(Parameters, Message);
 }
 
@@ -840,40 +931,43 @@ GetRegInt(
 
 static BOOL
 UserpShowInformationBalloon(
-    IN PCWSTR Text,
-    IN PCWSTR Caption,
-    IN UINT   Type,
+    IN PUNICODE_STRING TextStringU,
+    IN PUNICODE_STRING CaptionStringU,
+    IN UINT Type,
     IN PHARDERROR_MSG Message)
 {
     ULONG ShellErrorMode;
-    HWND hwnd;
+    HWND hWndTaskman;
     COPYDATASTRUCT CopyData;
     PBALLOON_HARD_ERROR_DATA pdata;
     DWORD dwSize, cbTextLen, cbTitleLen;
     PWCHAR pText, pCaption;
-    DWORD ret, dwResult;
+    DWORD ret;
+    DWORD_PTR dwResult;
 
     /* Query the shell error mode value */
     ShellErrorMode = GetRegInt(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Windows",
                                L"ShellErrorMode", 0);
 
-    /* Make the shell display the hard error message in balloon only if necessary */
+    /* Make the shell display the hard error message only if necessary */
     if (ShellErrorMode != 1)
         return FALSE;
 
-    hwnd = GetTaskmanWindow();
-    if (!hwnd)
+    /* Retrieve the shell task window */
+    hWndTaskman = GetTaskmanWindow();
+    if (!hWndTaskman)
     {
         DPRINT1("Failed to find shell task window (last error %lu)\n", GetLastError());
         return FALSE;
     }
 
-    cbTextLen  = ((Text    ? wcslen(Text)    : 0) + 1) * sizeof(WCHAR);
-    cbTitleLen = ((Caption ? wcslen(Caption) : 0) + 1) * sizeof(WCHAR);
+    cbTextLen  = TextStringU->Length + sizeof(UNICODE_NULL);
+    cbTitleLen = CaptionStringU->Length + sizeof(UNICODE_NULL);
 
     dwSize = sizeof(BALLOON_HARD_ERROR_DATA);
     dwSize += cbTextLen + cbTitleLen;
 
+    /* Build the data buffer */
     pdata = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
     if (!pdata)
     {
@@ -883,31 +977,27 @@ UserpShowInformationBalloon(
 
     pdata->cbHeaderSize = sizeof(BALLOON_HARD_ERROR_DATA);
     pdata->Status = Message->Status;
+    pdata->dwType = Type;
 
-    if (NT_SUCCESS(Message->Status))
-        pdata->dwType = MB_OK;
-    else if (Message->Status == STATUS_SERVICE_NOTIFICATION)
-        pdata->dwType = Type;
-    else
-        pdata->dwType = MB_ICONINFORMATION;
-
-    pdata->TitleOffset = pdata->cbHeaderSize;
-    pdata->MessageOffset = pdata->TitleOffset;
-    pdata->MessageOffset += cbTitleLen;
+    pdata->TitleOffset   = pdata->cbHeaderSize;
+    pdata->MessageOffset = pdata->TitleOffset + cbTitleLen;
     pCaption = (PWCHAR)((ULONG_PTR)pdata + pdata->TitleOffset);
     pText = (PWCHAR)((ULONG_PTR)pdata + pdata->MessageOffset);
-    wcscpy(pCaption, Caption);
-    wcscpy(pText, Text);
+    RtlStringCbCopyNW(pCaption, cbTitleLen, CaptionStringU->Buffer, CaptionStringU->Length);
+    RtlStringCbCopyNW(pText, cbTextLen, TextStringU->Buffer, TextStringU->Length);
+
+    /* Send the message */
 
+    /* Retrieve a unique system-wide message to communicate hard error data with the shell */
     CopyData.dwData = RegisterWindowMessageW(L"HardError");
     CopyData.cbData = dwSize;
     CopyData.lpData = pdata;
 
     dwResult = FALSE;
-
-    ret = SendMessageTimeoutW(hwnd, WM_COPYDATA, 0, (LPARAM)&CopyData,
+    ret = SendMessageTimeoutW(hWndTaskman, WM_COPYDATA, 0, (LPARAM)&CopyData,
                               SMTO_NORMAL | SMTO_ABORTIFHUNG, 3000, &dwResult);
 
+    /* Free the buffer */
     RtlFreeHeap(RtlGetProcessHeap(), 0, pdata);
 
     return (ret && dwResult) ? TRUE : FALSE;
@@ -916,18 +1006,39 @@ UserpShowInformationBalloon(
 static
 HARDERROR_RESPONSE
 UserpMessageBox(
-    IN PCWSTR Text,
-    IN PCWSTR Caption,
-    IN UINT   Type,
-    IN ULONG  Timeout)
+    IN PUNICODE_STRING TextStringU,
+    IN PUNICODE_STRING CaptionStringU,
+    IN UINT  Type,
+    IN ULONG Timeout)
 {
     ULONG MessageBoxResponse;
+    HDESK hDesk, hOldDesk;
 
     DPRINT("Text = '%S', Caption = '%S', Type = 0x%lx\n",
-           Text, Caption, Type);
+           TextStringU->Buffer, CaptionStringU->Buffer, Type);
+
+    // TEMPORARY HACK to fix desktop assignment for harderror message boxes.
+    hDesk = OpenInputDesktop(0, FALSE, GENERIC_WRITE);
+    if (!hDesk)
+        return ResponseNotHandled;
+
+    /* Assign the desktop to this thread */
+    hOldDesk = GetThreadDesktop(GetCurrentThreadId());
+    if (!SetThreadDesktop(hDesk))
+    {
+        CloseDesktop(hDesk);
+        return ResponseNotHandled;
+    }
 
     /* Display a message box */
-    MessageBoxResponse = MessageBoxTimeoutW(NULL, Text, Caption, Type, 0, Timeout);
+    MessageBoxResponse = MessageBoxTimeoutW(NULL,
+                                            TextStringU->Buffer,
+                                            CaptionStringU->Buffer,
+                                            Type, 0, Timeout);
+
+    /* Restore the original desktop */
+    SetThreadDesktop(hOldDesk);
+    CloseDesktop(hDesk);
 
     /* Return response value */
     switch (MessageBoxResponse)
@@ -991,7 +1102,8 @@ UserServerHardError(
     IN PHARDERROR_MSG Message)
 {
     ULONG ErrorMode;
-    UINT dwType = 0;
+    UINT  dwType = 0;
+    ULONG Timeout = INFINITE;
     UNICODE_STRING TextU, CaptionU;
     WCHAR LocalTextBuffer[256];
     WCHAR LocalCaptionBuffer[256];
@@ -1017,7 +1129,8 @@ UserServerHardError(
     {
         if (Message->NumberOfParameters < 3)
         {
-            DPRINT1("Invalid NumberOfParameters = %d for STATUS_SERVICE_NOTIFICATION\n", Message->NumberOfParameters);
+            DPRINT1("Invalid NumberOfParameters = %d for STATUS_SERVICE_NOTIFICATION\n",
+                    Message->NumberOfParameters);
             return; // STATUS_INVALID_PARAMETER;
         }
         // (Message->UnicodeStringParameterMask & 0x3)
@@ -1029,7 +1142,7 @@ UserServerHardError(
     /* Format the message caption and text */
     RtlInitEmptyUnicodeString(&TextU, LocalTextBuffer, sizeof(LocalTextBuffer));
     RtlInitEmptyUnicodeString(&CaptionU, LocalCaptionBuffer, sizeof(LocalCaptionBuffer));
-    UserpFormatMessages(&TextU, &CaptionU, &dwType, /* &Timeout, */ Message);
+    UserpFormatMessages(&TextU, &CaptionU, &dwType, &Timeout, Message);
 
     /* Log the hard error message */
     UserpLogHardError(&TextU, &CaptionU);
@@ -1051,8 +1164,8 @@ UserServerHardError(
     {
         /* Display the balloon */
         Message->Response = ResponseOk;
-        if (UserpShowInformationBalloon(TextU.Buffer,
-                                        CaptionU.Buffer,
+        if (UserpShowInformationBalloon(&TextU,
+                                        &CaptionU,
                                         dwType,
                                         Message))
         {
@@ -1062,10 +1175,10 @@ UserServerHardError(
     }
 
     /* Display the message box */
-    Message->Response = UserpMessageBox(TextU.Buffer,
-                                        CaptionU.Buffer,
+    Message->Response = UserpMessageBox(&TextU,
+                                        &CaptionU,
                                         dwType,
-                                        (ULONG)-1);
+                                        Timeout);
 
 Quit:
     /* Free the strings if they have been reallocated */