[WINSRV] Implement sending the hard error balloon package to explorer
authorGiannis Adamopoulos <gadamopoulos@reactos.org>
Thu, 22 Feb 2018 17:15:45 +0000 (19:15 +0200)
committerGiannis Adamopoulos <gadamopoulos@reactos.org>
Mon, 26 Feb 2018 14:51:59 +0000 (16:51 +0200)
[EXPLORER] Implement showing the hard error balloon

base/shell/explorer/syspager.cpp
base/shell/explorer/taskswnd.cpp
sdk/include/reactos/undocuser.h
win32ss/user/winsrv/usersrv/harderror.c

index 7be7eeb..fa2aa73 100644 (file)
@@ -1207,6 +1207,7 @@ void CNotifyToolbar::Initialize(HWND hWndParent, CBalloonQueue * queue)
 const WCHAR szSysPagerWndClass[] = L"SysPager";
 
 CSysPagerWnd::CSysPagerWnd() {}
+
 CSysPagerWnd::~CSysPagerWnd() {}
 
 LRESULT CSysPagerWnd::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
index 590dc40..60b047a 100644 (file)
@@ -99,6 +99,103 @@ typedef struct _TASK_ITEM
     };
 } TASK_ITEM, *PTASK_ITEM;
 
+
+class CHardErrorThread
+{
+    DWORD m_ThreadId;
+    HANDLE m_hThread;
+    LONG m_bThreadRunning;
+    DWORD m_Status;
+    DWORD m_dwType;
+    CStringW m_Title;
+    CStringW m_Text;
+public:
+
+    CHardErrorThread():
+        m_ThreadId(0),
+        m_hThread(NULL),
+        m_bThreadRunning(FALSE),
+        m_Status(NULL),
+        m_dwType(NULL)
+    {
+    }
+
+    ~CHardErrorThread()
+    {
+        if (m_bThreadRunning)
+        {
+            /* Try to unstuck Show */
+            PostThreadMessage(m_ThreadId, WM_QUIT, 0, 0);   
+            DWORD ret = WaitForSingleObject(m_hThread, 3*1000);
+            if (ret == WAIT_TIMEOUT)
+                TerminateThread(m_hThread, 0);
+            CloseHandle(m_hThread);
+        }
+    }
+
+    HRESULT ThreadProc()
+    {
+        HRESULT hr;
+        CComPtr<IUserNotification> pnotification;
+
+        hr = OleInitialize(NULL);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        hr = CoCreateInstance(CLSID_UserNotification,
+                              NULL,
+                              CLSCTX_INPROC_SERVER,
+                              IID_PPV_ARG(IUserNotification, &pnotification));
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        hr = pnotification->SetBalloonInfo(m_Title, m_Text, NIIF_WARNING);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        hr = pnotification->SetIconInfo(NULL, NULL);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        /* Show will block until the balloon closes */
+        hr = pnotification->Show(NULL, 0);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        return S_OK;
+    }
+
+    static DWORD CALLBACK s_HardErrorThreadProc(IN OUT LPVOID lpParameter)
+    {
+        CHardErrorThread* pThis = reinterpret_cast<CHardErrorThread*>(lpParameter);
+        pThis->ThreadProc();
+        CloseHandle(pThis->m_hThread);
+        OleUninitialize();
+        InterlockedExchange(&pThis->m_bThreadRunning, FALSE);
+        return 0;
+    }
+
+    void StartThread(PBALLOON_HARD_ERROR_DATA pData)
+    {
+        BOOL bIsRunning = InterlockedExchange(&m_bThreadRunning, TRUE);
+
+        /* Ignore the new message if we are already showing one */
+        if (bIsRunning)
+            return;
+
+        m_Status = pData->Status;
+        m_dwType = pData->dwType;
+        m_Title = (PWCHAR)((ULONG_PTR)pData + pData->TitleOffset);
+        m_Text = (PWCHAR)((ULONG_PTR)pData + pData->MessageOffset);
+        m_hThread = CreateThread(NULL, 0, s_HardErrorThreadProc, this, 0, &m_ThreadId);
+        if (!m_hThread)
+        {
+            m_bThreadRunning = FALSE;
+            CloseHandle(m_hThread);
+        }
+    }
+};
+
 class CTaskToolbar :
     public CWindowImplBaseT< CToolbar<TASK_ITEM>, CControlWinTraits >
 {
@@ -222,6 +319,9 @@ class CTaskSwitchWnd :
 
     SIZE m_ButtonSize;
 
+    UINT m_uHardErrorMsg;
+    CHardErrorThread m_HardErrorThread;
+
 public:
     CTaskSwitchWnd() :
         m_ShellHookMsg(NULL),
@@ -238,6 +338,7 @@ public:
         m_IsDestroying(FALSE)
     {
         ZeroMemory(&m_ButtonSize, sizeof(m_ButtonSize));
+        m_uHardErrorMsg = RegisterWindowMessageW(L"HardError");
     }
     virtual ~CTaskSwitchWnd() { }
 
@@ -1821,6 +1922,22 @@ public:
         return 0;
     }
 
+    LRESULT OnCopyData(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        PCOPYDATASTRUCT cpData = (PCOPYDATASTRUCT)lParam;
+        if (cpData->dwData == m_uHardErrorMsg)
+        {
+            /* A hard error balloon message */
+            PBALLOON_HARD_ERROR_DATA pData = (PBALLOON_HARD_ERROR_DATA)cpData->lpData;
+            ERR("Got balloon data 0x%x, 0x%x, %S, %S!\n", pData->Status, pData->dwType, (WCHAR*)((ULONG_PTR)pData + pData->TitleOffset), (WCHAR*)((ULONG_PTR)pData + pData->MessageOffset));
+            if (pData->cbHeaderSize == sizeof(BALLOON_HARD_ERROR_DATA))
+                m_HardErrorThread.StartThread(pData);
+            return TRUE;
+        }
+
+        return FALSE;
+    }
+
     HRESULT Initialize(IN HWND hWndParent, IN OUT ITrayWindow *tray)
     {
         m_Tray = tray;
@@ -1864,6 +1981,7 @@ public:
         MESSAGE_HANDLER(m_ShellHookMsg, OnShellHook)
         MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
         MESSAGE_HANDLER(WM_KLUDGEMINRECT, OnKludgeItemRect)
+        MESSAGE_HANDLER(WM_COPYDATA, OnCopyData)
     END_MSG_MAP()
 
     DECLARE_NOT_AGGREGATABLE(CTaskSwitchWnd)
index dea8556..dbe93b2 100644 (file)
@@ -204,6 +204,17 @@ BOOL WINAPI PaintMenuBar(HWND hWnd, HDC hDC, ULONG left, ULONG right, ULONG top,
 #define DrawCaptionTemp DrawCaptionTempA
 #endif
 
+//
+// Hard error balloon package
+//
+typedef struct _BALLOON_HARD_ERROR_DATA
+{
+    DWORD cbHeaderSize;
+    DWORD Status;
+    DWORD dwType; /* any combination of the MB_ message box types */
+    ULONG_PTR TitleOffset;
+    ULONG_PTR MessageOffset;
+} BALLOON_HARD_ERROR_DATA, *PBALLOON_HARD_ERROR_DATA;
 
 //
 // User api hook
index 52e22a8..54d4b52 100644 (file)
@@ -439,6 +439,69 @@ UserpFormatMessages(
     return Status;
 }
 
+static BOOL
+UserpShowInformationBalloon(PWSTR Text, 
+                            PWSTR Caption,
+                            PHARDERROR_MSG Message)
+{
+    HWND hwnd;
+    COPYDATASTRUCT CopyData;
+    PBALLOON_HARD_ERROR_DATA pdata;
+    DWORD dwSize, cchText, cchCaption;
+    PWCHAR pText, pCaption;
+    DWORD ret, dwResult;
+
+    hwnd = GetTaskmanWindow();
+    if (!hwnd)
+    {
+        DPRINT1("Failed to find Shell_TrayWnd\n");
+        return FALSE;
+    }
+
+    cchText = wcslen(Text);
+    cchCaption = wcslen(Caption);
+
+    dwSize = sizeof(BALLOON_HARD_ERROR_DATA);
+    dwSize += (cchText + 1) * sizeof(WCHAR);
+    dwSize += (cchCaption + 1) * sizeof(WCHAR);
+
+    pdata = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
+    if (!pdata)
+    {
+        DPRINT1("Failed to allocate balloon package\n");
+        return FALSE;
+    }
+
+    pdata->cbHeaderSize = sizeof(BALLOON_HARD_ERROR_DATA);
+    pdata->Status = Message->Status;
+    if (NT_SUCCESS(Message->Status))
+        pdata->dwType = MB_OK;
+    else if (Message->Status == STATUS_SERVICE_NOTIFICATION)
+        pdata->dwType = Message->Parameters[2];
+    else
+        pdata->dwType = MB_ICONINFORMATION;
+    pdata->TitleOffset = pdata->cbHeaderSize;
+    pdata->MessageOffset = pdata->TitleOffset;
+    pdata->MessageOffset += (cchCaption + 1) * sizeof(WCHAR);
+    pCaption = (PWCHAR)((ULONG_PTR)pdata + pdata->TitleOffset);
+    pText = (PWCHAR)((ULONG_PTR)pdata + pdata->MessageOffset);
+    wcscpy(pCaption, Caption);
+    wcscpy(pText, Text);
+
+    CopyData.dwData = RegisterWindowMessageW(L"HardError");
+    CopyData.cbData = dwSize;
+    CopyData.lpData = pdata;
+
+    dwResult = FALSE;
+
+    ret = SendMessageTimeoutW(hwnd, WM_COPYDATA, 0, (LPARAM)&CopyData,
+                              SMTO_NORMAL | SMTO_ABORTIFHUNG, 3000, &dwResult);
+
+    RtlFreeHeap(RtlGetProcessHeap(), 0, pdata);
+
+    return (ret && dwResult) ? TRUE : FALSE;
+}
+
 static
 ULONG
 UserpMessageBox(
@@ -475,10 +538,9 @@ UserpMessageBox(
             break;
         case OptionOkNoWait:
             /*
-             * This gives a balloon notification.
-             * See rostests/kmtests/ntos_ex/ExHardError.c
+             * At that point showing the balloon failed. Is that correct?
              */
-            Type = MB_YESNO; // FIXME!
+            Type = MB_OK; // FIXME!
             break;
         case OptionCancelTryContinue:
             Type = MB_CANCELTRYCONTINUE;
@@ -583,6 +645,20 @@ UserServerHardError(
         return;
     }
 
+    if (Message->ValidResponseOptions == OptionOkNoWait)
+    {
+        /* Display the balloon */
+        if (UserpShowInformationBalloon(TextU.Buffer, 
+                                        CaptionU.Buffer, 
+                                        Message))
+        {
+            Message->Response = ResponseOk;
+            RtlFreeUnicodeString(&TextU);
+            RtlFreeUnicodeString(&CaptionU);
+            return;
+        }
+    }
+
     /* Display the message box */
     Message->Response = UserpMessageBox(TextU.Buffer,
                                         CaptionU.Buffer,
@@ -591,7 +667,6 @@ UserServerHardError(
 
     RtlFreeUnicodeString(&TextU);
     RtlFreeUnicodeString(&CaptionU);
-
     return;
 }