//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1998 // // File: status.c // // Contents: Status UI // // History: 11-19-98 EricFlo Created // //---------------------------------------------------------------------------- #include "msgina.h" #define WM_HIDEOURSELVES (WM_USER + 1000) //************************************************************* // // StatusMessageDlgProc() // // Purpose: Dialog box procedure for the status dialog // // Parameters: hDlg - handle to the dialog box // uMsg - window message // wParam - wParam // lParam - lParam // // Return: TRUE if message was processed // FALSE if not // // Comments: // // History: Date Author Comment // 11/19/98 EricFlo Created // //************************************************************* INT_PTR APIENTRY StatusMessageDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: { RECT rc; DWORD dwAnimationTimeSlice; PGLOBALS pGlobals = (PGLOBALS) lParam; SetWindowLongPtr (hDlg, DWLP_USER, (LONG_PTR) pGlobals); SizeForBranding(hDlg, FALSE); CentreWindow (hDlg); pGlobals->xStatusBandOffset = 0; if (GetClientRect(hDlg, &rc)) { pGlobals->cxStatusBand = rc.right-rc.left; } else { pGlobals->cxStatusBand = 100; } if (_Shell_LogonStatus_Exists()) { SetWindowPos(hDlg, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER); PostMessage(hDlg, WM_HIDEOURSELVES, 0, 0); } if ((pGlobals->dwStatusOptions & STATUSMSG_OPTION_NOANIMATION) == 0) { dwAnimationTimeSlice = GetAnimationTimeInterval(pGlobals); SetTimer(hDlg, 0, dwAnimationTimeSlice, NULL); } } return TRUE; case WM_HIDEOURSELVES: ShowWindow(hDlg, SW_HIDE); break; case WM_TIMER: if (wParam == 0) { PGLOBALS pGlobals = (PGLOBALS) GetWindowLongPtr(hDlg, DWLP_USER); HDC hDC; if (pGlobals) { pGlobals->xStatusBandOffset = (pGlobals->xStatusBandOffset+5) % pGlobals->cxStatusBand; hDC = GetDC(hDlg); if ( hDC ) { PaintBranding(hDlg, hDC, pGlobals->xStatusBandOffset, TRUE, FALSE, COLOR_BTNFACE); ReleaseDC(hDlg, hDC); } } } break; case WM_ERASEBKGND: { PGLOBALS pGlobals = (PGLOBALS) GetWindowLongPtr(hDlg, DWLP_USER); if (pGlobals) { return PaintBranding(hDlg, (HDC)wParam, pGlobals->xStatusBandOffset, FALSE, FALSE, COLOR_BTNFACE); } return 0; } case WM_QUERYNEWPALETTE: return BrandingQueryNewPalete(hDlg); case WM_PALETTECHANGED: return BrandingPaletteChanged(hDlg, (HWND)wParam); case WM_DESTROY: KillTimer (hDlg, 0); break; default: break; } return FALSE; } //************************************************************* // // StatusMessageThread() // // Purpose: Status message thread // // Parameters: hDesktop - Desktop handle to put UI on // // Return: void // // History: Date Author Comment // 11/19/98 EricFlo Created // //************************************************************* void StatusMessageThread (PGLOBALS pGlobals) { HANDLE hInstDll; MSG msg; DWORD dwResult; HANDLE hObjects[2]; hInstDll = LoadLibrary (TEXT("msgina.dll")); if (pGlobals->hStatusDesktop) { SetThreadDesktop (pGlobals->hStatusDesktop); } pGlobals->hStatusDlg = CreateDialogParam (hDllInstance, MAKEINTRESOURCE(IDD_STATUS_MESSAGE_DIALOG), NULL, StatusMessageDlgProc, (LPARAM) pGlobals); SetEvent (pGlobals->hStatusInitEvent); if (pGlobals->hStatusDlg) { hObjects[0] = pGlobals->hStatusTermEvent; while (TRUE) { dwResult = MsgWaitForMultipleObjectsEx (1, hObjects, INFINITE, (QS_ALLPOSTMESSAGE | QS_ALLINPUT), MWMO_INPUTAVAILABLE); if (dwResult == WAIT_FAILED) { break; } if (dwResult == WAIT_OBJECT_0) { break; } while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (!IsDialogMessage (pGlobals->hStatusDlg, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } if (WaitForSingleObject (pGlobals->hStatusTermEvent, 0) == WAIT_OBJECT_0) { goto ExitLoop; } } } ExitLoop: DestroyWindow(pGlobals->hStatusDlg); pGlobals->hStatusDlg = NULL; } if (hInstDll) { FreeLibraryAndExitThread(hInstDll, TRUE); } else { ExitThread (TRUE); } } // // Creates and displays the initial status message // // Set in WlxInitialize DWORD g_dwMainThreadId = 0; // Creation or removal of the status dialog is not thread safe. // It is kind of difficult to fix with a critsec because of // the mix of objects and windows messages. one can't hold // a critsec accross a window message call as it would introduce // the possibility of deadlocks BOOL WINAPI WlxDisplayStatusMessage(PVOID pWlxContext, HDESK hDesktop, DWORD dwOptions, PWSTR pTitle, PWSTR pMessage) { PGLOBALS pGlobals = (PGLOBALS) pWlxContext; DWORD dwThreadId; HANDLE hProcess; if (!pGlobals) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (g_dwMainThreadId == GetCurrentThreadId()) // Denies creation/deletion on other threads { // than the main thread of winlogon if (!pGlobals->hStatusDlg) { if (!ReadWinlogonBoolValue(DISABLE_STATUS_MESSAGES, FALSE)) { pGlobals->hStatusInitEvent = CreateEvent (NULL, TRUE, FALSE, NULL); pGlobals->hStatusTermEvent = CreateEvent (NULL, TRUE, FALSE, NULL); if (pGlobals->hStatusInitEvent && pGlobals->hStatusTermEvent) { hProcess = GetCurrentProcess(); if ( FALSE == DuplicateHandle( hProcess, hDesktop, hProcess, &(pGlobals->hStatusDesktop), 0, // ignored, DUPLICATE_SAME_ACCESS is set FALSE, // no inherit on the handle DUPLICATE_SAME_ACCESS) ) { DebugLog((DEB_ERROR, "DuplicateHandle failed: %#x", GetLastError())); return FALSE; } // // Set the globals here so that StatusMessageDlgProc can look at them in WM_INITDIALOG. // pGlobals->dwStatusOptions = dwOptions; pGlobals->hStatusThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) StatusMessageThread, (LPVOID) pGlobals, 0, &dwThreadId); if (pGlobals->hStatusThread) { DWORD dwWaitResult; do { dwWaitResult = WaitForSingleObject(pGlobals->hStatusInitEvent, 0); if (dwWaitResult != WAIT_OBJECT_0) { dwWaitResult = MsgWaitForMultipleObjects(1, &pGlobals->hStatusInitEvent, FALSE, INFINITE, QS_ALLPOSTMESSAGE | QS_ALLINPUT); if (dwWaitResult == WAIT_OBJECT_0 + 1) { MSG msg; if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } } while (dwWaitResult == WAIT_OBJECT_0 + 1); } } } } } if (pGlobals->hStatusDlg) { if (pTitle) { SetWindowText (pGlobals->hStatusDlg, pTitle); } SetDlgItemText (pGlobals->hStatusDlg, IDC_STATUS_MESSAGE_TEXT, pMessage); _Shell_LogonStatus_ShowStatusMessage(pMessage); if (dwOptions & STATUSMSG_OPTION_SETFOREGROUND) { SetForegroundWindow (pGlobals->hStatusDlg); } } return TRUE; } // // Gets the current status message // BOOL WINAPI WlxGetStatusMessage(PVOID pWlxContext, DWORD *pdwOptions, PWSTR pMessage, DWORD dwBufferSize) { PGLOBALS pGlobals = (PGLOBALS) pWlxContext; DWORD dwLen; if (!pGlobals || !pMessage) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } dwLen = (DWORD) SendDlgItemMessage (pGlobals->hStatusDlg, IDC_STATUS_MESSAGE_TEXT, WM_GETTEXTLENGTH, 0, 0); if (dwBufferSize < dwLen) { SetLastError (ERROR_INSUFFICIENT_BUFFER); return FALSE; } GetDlgItemText (pGlobals->hStatusDlg, IDC_STATUS_MESSAGE_TEXT, pMessage, dwBufferSize); if (pdwOptions) { *pdwOptions = pGlobals->dwStatusOptions; } return TRUE; } // // Removes the status dialog // BOOL WINAPI WlxRemoveStatusMessage(PVOID pWlxContext) { PGLOBALS pGlobals = (PGLOBALS) pWlxContext; if (!pGlobals) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (g_dwMainThreadId != GetCurrentThreadId()) { // Denies creation/deletion on other threads return FALSE; } if (pGlobals->hStatusTermEvent) { SetEvent(pGlobals->hStatusTermEvent); if (pGlobals->hStatusThread) { if (pGlobals->hStatusDlg) { DWORD dwWaitResult; do { dwWaitResult = WaitForSingleObject(pGlobals->hStatusThread, 0); if (dwWaitResult != WAIT_OBJECT_0) { dwWaitResult = MsgWaitForMultipleObjects(1, &pGlobals->hStatusThread, FALSE, 10000, QS_ALLPOSTMESSAGE | QS_ALLINPUT); if (dwWaitResult == WAIT_OBJECT_0 + 1) { MSG msg; if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } } while (dwWaitResult == WAIT_OBJECT_0 + 1); } CloseHandle (pGlobals->hStatusThread); } CloseHandle (pGlobals->hStatusTermEvent); } if (pGlobals->hStatusInitEvent) { CloseHandle (pGlobals->hStatusInitEvent); } pGlobals->hStatusInitEvent = NULL; pGlobals->hStatusTermEvent = NULL; pGlobals->hStatusThread = NULL; if (pGlobals->hStatusDesktop) { // // We duplicate the handle so we should always close // // OLD COMMENT: // Close the desktop handle here. Since the status thread // was using it, Winlogon was unable to close the handle // itself so we have to do it now. // CloseDesktop(pGlobals->hStatusDesktop); pGlobals->hStatusDesktop = NULL; } pGlobals->hStatusDlg = NULL; return TRUE; }