#include "priv.h" #include "CoverWnd.h" #include #undef IDB_BACKGROUND_24 #define IDB_BACKGROUND_24 0x3812 #undef IDB_FLAG_24 #define IDB_FLAG_24 0x3813 const TCHAR g_szWindowClassName[] = TEXT("CoverWindowClass"); const TCHAR g_szPleaseWaitName[] = TEXT("PleaseWaitWindowClass"); #define CHUNK_SIZE 20 #define IDT_KILLYOURSELF 1 #define IDT_UPDATE 2 #define WM_DESTORYYOURSELF (WM_USER + 0) void DimPixels(ULONG* pulSrc, int cLen, int Amount) { for (int i = cLen - 1; i >= 0; i--) { ULONG ulR = GetRValue(*pulSrc); ULONG ulG = GetGValue(*pulSrc); ULONG ulB = GetBValue(*pulSrc); ULONG ulGray = (54 * ulR + 183 * ulG + 19 * ulB) >> 8; ULONG ulTemp = ulGray * (0xff - Amount); ulR = (ulR * Amount + ulTemp) >> 8; ulG = (ulG * Amount + ulTemp) >> 8; ulB = (ulB * Amount + ulTemp) >> 8; *pulSrc = (*pulSrc & 0xff000000) | RGB(ulR, ulG, ulB); pulSrc++; } } LRESULT CALLBACK PleaseWaitWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lParam) { switch ( msg ) { case WM_CREATE: { CREATESTRUCT* pCS = (CREATESTRUCT*)lParam; SetWindowLongPtr( hwnd, GWLP_USERDATA, (LPARAM) pCS->lpCreateParams ); HBITMAP hbmBackground = (HBITMAP) pCS->lpCreateParams; BITMAP bm; if ( GetObject( hbmBackground, sizeof(bm), &bm ) ) { RECT rc; HWND hwndParent = GetParent( hwnd ); GetClientRect( hwndParent, &rc ); POINT pt = {0,0}; HMONITOR hmon = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY); if (hmon) { MONITORINFO mi = {sizeof(mi)}; GetMonitorInfo(hmon, &mi); rc = mi.rcMonitor; MapWindowPoints(HWND_DESKTOP, hwndParent, (LPPOINT)&rc, 2); } // Center dialog in the center of the virtual screen int x = ( rc.right - rc.left - bm.bmWidth ) / 2; int y = ( rc.bottom - rc.top - bm.bmHeight ) / 2; SetWindowPos( hwnd, NULL, x, y, bm.bmWidth, bm.bmHeight, SWP_NOZORDER | SWP_NOACTIVATE ); } } return TRUE; case WM_PAINT: { HBITMAP hbmBackground = (HBITMAP) GetWindowLongPtr( hwnd, GWLP_USERDATA ); PAINTSTRUCT ps; HDC hdc = BeginPaint( hwnd, &ps ); BITMAP bm; if ( hbmBackground ) { DWORD dwLayout = SetLayout(hdc, LAYOUT_BITMAPORIENTATIONPRESERVED); if ( GetObject( hbmBackground, sizeof(bm), &bm ) ) { HDC hdcBackground = CreateCompatibleDC( hdc ); if (hdcBackground) { HBITMAP hbmOld = (HBITMAP) SelectObject( hdcBackground, hbmBackground ); BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcBackground, 0, 0, SRCCOPY); SelectObject( hdcBackground, hbmOld ); DeleteDC( hdcBackground ); } } SetLayout(hdc, dwLayout); // Don't draw more the once, no one will be on top of us DeleteObject(hbmBackground); SetWindowLongPtr( hwnd, GWLP_USERDATA, NULL ); HFONT hfntSelected = NULL; HFONT hfntButton = NULL; HINSTANCE hMsGina = LoadLibrary( L"msgina.dll" ); if ( hMsGina ) { CHAR szPixelSize[ 32 ]; if (LoadStringA(hMsGina, IDS_TURNOFF_TITLE_FACESIZE, szPixelSize, ARRAYSIZE(szPixelSize)) != 0) { LOGFONT logFont = { 0 }; logFont.lfHeight = -MulDiv(atoi(szPixelSize), GetDeviceCaps(hdc, LOGPIXELSY), 72); if (LoadString(hMsGina, IDS_TURNOFF_TITLE_FACENAME, logFont.lfFaceName, LF_FACESIZE) != 0) { logFont.lfWeight = FW_BOLD; logFont.lfQuality = DEFAULT_QUALITY; hfntButton = CreateFontIndirect(&logFont); hfntSelected = static_cast(SelectObject(hdc, hfntButton)); } } } COLORREF colorButtonText = RGB(255, 255, 255); COLORREF colorText = SetTextColor(hdc, colorButtonText); int iBkMode = SetBkMode(hdc, TRANSPARENT); WCHAR szText[MAX_PATH]; szText[0] = 0; LoadString((HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), IDS_PLEASEWAIT, szText, ARRAYSIZE(szText)); RECT rcText; RECT rcClient; RECT rc; TBOOL(GetClientRect( hwnd, &rcClient )); TBOOL(CopyRect(&rcText, &rcClient)); DWORD dwFlags = DT_HIDEPREFIX | (IS_MIRRORING_ENABLED() ? DT_RTLREADING : 0); int iPixelHeight = DrawText( hdc, szText, -1, &rcText, DT_CALCRECT | dwFlags); TBOOL(CopyRect(&rc, &rcClient)); TBOOL(InflateRect(&rc, -((rc.right - rc.left - (rcText.right - rcText.left)) / 2), -((rc.bottom - rc.top - iPixelHeight) / 2))); (int)DrawText(hdc, szText, -1, &rc, dwFlags ); (int)SetBkMode(hdc, iBkMode); (COLORREF)SetTextColor(hdc, colorText); if ( hfntButton ) { (HGDIOBJ)SelectObject(hdc, hfntSelected); DeleteObject( hfntButton ); } } EndPaint( hwnd, &ps ); } break; case WM_ERASEBKGND: return TRUE; default: return DefWindowProc( hwnd, msg, wp, lParam ); break; } return 0; } CDimmedWindow::CDimmedWindow (HINSTANCE hInstance) : _lReferenceCount(1), _hInstance(hInstance) { WNDCLASSEX wndClassEx; ZeroMemory(&wndClassEx, sizeof(wndClassEx)); wndClassEx.cbSize = sizeof(wndClassEx); wndClassEx.lpfnWndProc = WndProc; wndClassEx.hInstance = hInstance; wndClassEx.lpszClassName = g_szWindowClassName; wndClassEx.hCursor = LoadCursor(NULL, IDC_WAIT); _atom = RegisterClassEx(&wndClassEx); wndClassEx.lpszClassName = g_szPleaseWaitName; wndClassEx.lpfnWndProc = PleaseWaitWndProc; _atomPleaseWait = RegisterClassEx(&wndClassEx); } CDimmedWindow::~CDimmedWindow (void) { if (_hwnd) { PostMessage(_hwnd, WM_DESTORYYOURSELF, 0, 0); } if (_atom != 0) { TBOOL(UnregisterClass(MAKEINTRESOURCE(_atom), _hInstance)); } if (_atomPleaseWait != 0 ) { TBOOL(UnregisterClass(MAKEINTRESOURCE(_atomPleaseWait), _hInstance)); } } ULONG CDimmedWindow::AddRef (void) { return(InterlockedIncrement(&_lReferenceCount)); } ULONG CDimmedWindow::Release (void) { LONG lReferenceCount; lReferenceCount = InterlockedDecrement(&_lReferenceCount); ASSERTMSG(lReferenceCount >= 0, "Reference count negative or zero in CDimmedWindow::Release"); if (lReferenceCount == 0) { delete this; } return(lReferenceCount); } DWORD CDimmedWindow::WorkerThread(IN void *pv) { ASSERT(pv); HWND hwnd = NULL; CDimmedWindow* pDimmedWindow = (CDimmedWindow*)pv; BOOL fScreenReader; bool fNoDebuggerPresent, fNoScreenReaderPresent; BOOL fUserTurnedOffWindow = SHRegGetBoolUSValue(SZ_THEMES, L"NoCoverWindow", FALSE, FALSE); // Needed for perf testing fNoDebuggerPresent = !IsDebuggerPresent(); fNoScreenReaderPresent = ((SystemParametersInfo(SPI_GETSCREENREADER, 0, &fScreenReader, 0) == FALSE) || (fScreenReader == FALSE)); if (fNoDebuggerPresent && fNoScreenReaderPresent && !fUserTurnedOffWindow) { int xVirtualScreen = GetSystemMetrics(SM_XVIRTUALSCREEN); int yVirtualScreen = GetSystemMetrics(SM_YVIRTUALSCREEN); int cxVirtualScreen = GetSystemMetrics(SM_CXVIRTUALSCREEN); int cyVirtualScreen = GetSystemMetrics(SM_CYVIRTUALSCREEN); HWND hwnd = CreateWindowEx(WS_EX_TOPMOST, g_szWindowClassName, NULL, WS_POPUP | WS_CLIPCHILDREN, xVirtualScreen, yVirtualScreen, cxVirtualScreen, cyVirtualScreen, NULL, NULL, pDimmedWindow->_hInstance, NULL); if (hwnd != NULL) { bool fDimmed; HBITMAP hbmBackground = NULL; fDimmed = false; (BOOL)ShowWindow(hwnd, SW_SHOW); TBOOL(SetForegroundWindow(hwnd)); (BOOL)EnableWindow(hwnd, FALSE); SetTimer(hwnd, IDT_KILLYOURSELF, pDimmedWindow->_ulKillTimer, NULL); // Now create bitmap with background image and the windows flag HINSTANCE hShell32 = LoadLibrary( L"shell32.dll" ); if ( NULL != hShell32 ) { hbmBackground = (HBITMAP) LoadImage( hShell32, MAKEINTRESOURCE( IDB_BACKGROUND_24 ), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE ); if (hbmBackground) { HDC hdcMem1 = CreateCompatibleDC(NULL); if (hdcMem1) { HDC hdcMem2 = CreateCompatibleDC(NULL); if (hdcMem2) { HBITMAP hbmFlag = (HBITMAP) LoadImage( hShell32, MAKEINTRESOURCE( IDB_FLAG_24 ), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE ); if (hbmFlag) { HBITMAP hbmOld1 = (HBITMAP)SelectObject(hdcMem1, hbmBackground); HBITMAP hbmOld2 = (HBITMAP)SelectObject(hdcMem2, hbmFlag); BITMAP bm1; if (GetObject(hbmBackground, sizeof(bm1), &bm1)) { BITMAP bm2; if (GetObject(hbmFlag, sizeof(bm2), &bm2)) { BitBlt(hdcMem1, bm1.bmWidth - bm2.bmWidth - 8, 0, bm2.bmWidth, bm2.bmHeight, hdcMem2, 0, 0, SRCCOPY); } } SelectObject(hdcMem1, hbmOld1); SelectObject(hdcMem2, hbmOld2); DeleteObject(hbmFlag); } DeleteDC(hdcMem2); } DeleteDC(hdcMem1); } } FreeLibrary( hShell32 ); } HWND hwndPleaseWait = CreateWindowEx( 0 , g_szPleaseWaitName , NULL , WS_CHILD | WS_VISIBLE | WS_BORDER , 0 , 0 , 100 , 100 , hwnd , NULL , pDimmedWindow->_hInstance , hbmBackground // the window is responsible for freeing it. ); if ( NULL == hwndPleaseWait ) { DeleteObject( hbmBackground ); } pDimmedWindow->_hwnd = hwnd; // This Release matches the addref during ::Create to guarantee that the object does not die before the HWND // is created. pDimmedWindow->Release(); MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); if ((msg.message == WM_DESTORYYOURSELF) && (msg.hwnd == hwnd)) { break; } } } } return (hwnd == NULL ? E_FAIL : S_OK); } HRESULT CDimmedWindow::Create (UINT ulKillTimer) { BOOL fSucceeded = FALSE; if (!_hwnd) { _ulKillTimer = ulKillTimer; AddRef(); fSucceeded = SHCreateThread(CDimmedWindow::WorkerThread, (void *)this, CTF_INSIST, NULL); if (!fSucceeded) { Release(); } } return fSucceeded ? S_OK : E_FAIL; } typedef struct { HDC hdcDimmed; HBITMAP hbmDimmed; HBITMAP hbmOldDimmed; HDC hdcTemp; HBITMAP hbmTemp; HBITMAP hbmOldTemp; ULONG* pulSrc; int idxSaturation; int idxChunk; int idxProgress; } DIMMEDWINDOWDATA; LRESULT CALLBACK CDimmedWindow::WndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lResult = 0; DIMMEDWINDOWDATA *pData; pData = (DIMMEDWINDOWDATA *)GetWindowLongPtr(hwnd, GWLP_USERDATA); switch (uMsg) { case WM_CREATE: { CREATESTRUCT* pCS = (CREATESTRUCT*)lParam; if (pCS) { pData = new DIMMEDWINDOWDATA; if (pData) { SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pData); // On remote session we don't gray out the screen, yeah :-) if (!GetSystemMetrics(SM_REMOTESESSION)) { HDC hdcWindow = GetDC(hwnd); if (hdcWindow != NULL ) { pData->hdcDimmed = CreateCompatibleDC(hdcWindow); if (pData->hdcDimmed) { BITMAPINFO bmi; ZeroMemory(&bmi, sizeof(bmi)); bmi.bmiHeader.biSize = sizeof(bmi); bmi.bmiHeader.biWidth = pCS->cx; bmi.bmiHeader.biHeight = pCS->cy; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; bmi.bmiHeader.biSizeImage = 0; pData->hbmDimmed = CreateDIBSection(pData->hdcDimmed, &bmi, DIB_RGB_COLORS, (LPVOID*)&pData->pulSrc, NULL, 0); if (pData->hbmDimmed != NULL) { pData->hbmOldDimmed = (HBITMAP) SelectObject(pData->hdcDimmed, pData->hbmDimmed); pData->idxSaturation = 8; pData->idxChunk = pCS->cy / CHUNK_SIZE; } else { DeleteDC(pData->hdcDimmed); pData->hdcDimmed = NULL; } } pData->hdcTemp = CreateCompatibleDC(hdcWindow); if (pData->hdcTemp) { pData->hbmTemp = CreateCompatibleBitmap(hdcWindow, pCS->cx, pCS->cy); if (pData->hbmTemp) { pData->hbmOldTemp = (HBITMAP) SelectObject(pData->hdcTemp, pData->hbmTemp); } else { DeleteDC(pData->hdcTemp); pData->hdcTemp = NULL; } } ReleaseDC(hwnd, hdcWindow); } } if (pData->hdcDimmed) { SetTimer(hwnd, IDT_UPDATE, 30, NULL); } } } break; } case WM_DESTORYYOURSELF: { DestroyWindow(hwnd); break; } case WM_DESTROY: { if (pData) { SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL); KillTimer(hwnd, IDT_UPDATE); KillTimer(hwnd, IDT_KILLYOURSELF); if (pData->hdcDimmed) { SelectObject(pData->hdcDimmed, pData->hbmOldDimmed); DeleteDC(pData->hdcDimmed); pData->hdcDimmed = NULL; } if (pData->hbmDimmed) { DeleteObject(pData->hbmDimmed); pData->hbmDimmed = NULL; } if (pData->hdcTemp) { SelectObject(pData->hdcTemp, pData->hbmOldTemp); DeleteDC(pData->hdcTemp); pData->hdcTemp = NULL; } if (pData->hbmTemp) { DeleteObject(pData->hbmTemp); pData->hbmTemp = NULL; } delete pData; } break; } case WM_TIMER: if (pData) { BOOL fDestroyBitmaps = FALSE; if (wParam == IDT_KILLYOURSELF) { ShowWindow(hwnd, SW_HIDE); fDestroyBitmaps = TRUE; } else if (pData->hdcDimmed && pData->hbmDimmed) { HDC hdcWindow = GetDC(hwnd); BITMAP bm; GetObject(pData->hbmDimmed, sizeof(BITMAP), &bm); if (pData->idxChunk >= 0 ) { // // In the first couple of passes, we slowly collect the screen // into our bitmap. We do this because Blt-ing the whole thing // causes the system to hang. By doing it this way, we continue // to pump messages, the UI stays responsive and it keeps the // mouse alive. // int y = pData->idxChunk * CHUNK_SIZE; if (pData->hdcTemp) { BitBlt(pData->hdcTemp, 0, y, bm.bmWidth, CHUNK_SIZE, hdcWindow, 0, y, SRCCOPY); BitBlt(pData->hdcDimmed, 0, y, bm.bmWidth, CHUNK_SIZE, pData->hdcTemp, 0, y, SRCCOPY); } else { BitBlt(pData->hdcDimmed, 0, y, bm.bmWidth, CHUNK_SIZE, hdcWindow, 0, y, SRCCOPY); } pData->idxChunk--; if (pData->idxChunk < 0) { // // We're done getting the bitmap, now reset the timer // so we slowly fade to grey. // SetTimer(hwnd, IDT_UPDATE, 250, NULL); pData->idxSaturation = 16; } } else { // // In these passes, we are making the image more and more grey and // then Blt-ing the result to the screen. // DimPixels(pData->pulSrc, bm.bmWidth * bm.bmHeight, 0xd5); BitBlt(hdcWindow, 0, 0, bm.bmWidth, bm.bmHeight, pData->hdcDimmed, 0, 0, SRCCOPY); pData->idxSaturation--; if (pData->idxSaturation <= 0) // when we hit zero, kill the timer. { KillTimer(hwnd, IDT_UPDATE); fDestroyBitmaps = TRUE; } } } if (fDestroyBitmaps) { if (pData->hdcDimmed) { SelectObject(pData->hdcDimmed, pData->hbmOldDimmed); DeleteDC(pData->hdcDimmed); pData->hdcDimmed = NULL; } if (pData->hbmDimmed) { DeleteObject(pData->hbmDimmed); pData->hbmDimmed = NULL; } if (pData->hdcTemp) { SelectObject(pData->hdcTemp, pData->hbmOldTemp); DeleteDC(pData->hdcTemp); pData->hdcTemp = NULL; } if (pData->hbmTemp) { DeleteObject(pData->hbmTemp); pData->hbmTemp = NULL; } } } break; case WM_WINDOWPOSCHANGING: { LPWINDOWPOS pwp = (LPWINDOWPOS) lParam; pwp->flags |= SWP_NOSIZE | SWP_NOMOVE; } break; case WM_PAINT: { HDC hdcPaint; PAINTSTRUCT ps; hdcPaint = BeginPaint(hwnd, &ps); TBOOL(EndPaint(hwnd, &ps)); lResult = 0; break; } default: lResult = DefWindowProc(hwnd, uMsg, wParam, lParam); break; } return(lResult); }