[WINSRV] Implement sending the hard error balloon package to explorer

[EXPLORER] Implement showing the hard error balloon
This commit is contained in:
Giannis Adamopoulos 2018-02-22 19:15:45 +02:00
parent 40bd09a2ce
commit ec91188fff
4 changed files with 209 additions and 4 deletions

View 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)

View 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)

View 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

View 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;
}