1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS msgina.dll 4 * FILE: dll/win32/msgina/dimmedwindow.cpp 5 * PURPOSE: Implementation of ShellDimScreen 6 * PROGRAMMER: Mark Jansen 7 */ 8 9 #define COM_NO_WINDOWS_H 10 #include "msgina.h" 11 #include <wingdi.h> 12 #include <atlbase.h> 13 #include <atlcom.h> 14 #include <pseh/pseh2.h> 15 16 CComModule gModule; 17 18 // Please note: The INIT_TIMER is a workaround because ReactOS does not redraw the desktop in time, 19 // so the start menu is still visible on the dimmed screen. 20 #define INIT_TIMER_ID 0x112233 21 #define FADE_TIMER_ID 0x12345 22 23 class CDimmedWindow : 24 public CComObjectRootEx<CComMultiThreadModelNoCS>, 25 IUnknown 26 { 27 private: 28 HWND m_hwnd; 29 HDC m_hdc; 30 HBITMAP m_hbitmap; 31 HGDIOBJ m_oldbitmap; 32 LONG m_width; 33 LONG m_height; 34 BITMAPINFO m_bi; 35 UCHAR* m_bytes; 36 int m_step; 37 38 static LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 39 40 public: 41 CDimmedWindow() 42 : m_hwnd(NULL) 43 , m_hdc(NULL) 44 , m_hbitmap(NULL) 45 , m_oldbitmap(NULL) 46 , m_width(0) 47 , m_height(0) 48 , m_bytes(NULL) 49 , m_step(0) 50 { 51 WNDCLASSEXW wndclass = {sizeof(wndclass)}; 52 wndclass.lpfnWndProc = WndProc; 53 wndclass.hInstance = hDllInstance; 54 wndclass.hCursor = LoadCursor(0, IDC_ARROW); 55 wndclass.lpszClassName = L"DimmedWindowClass"; 56 57 if (!RegisterClassExW(&wndclass)) 58 return; 59 60 m_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); 61 m_height = GetSystemMetrics(SM_CYVIRTUALSCREEN); 62 63 memset(&m_bi, 0, sizeof(m_bi)); 64 m_bi.bmiHeader.biSize = sizeof(m_bi); 65 m_bi.bmiHeader.biWidth = m_width; 66 m_bi.bmiHeader.biHeight = m_height; 67 m_bi.bmiHeader.biPlanes = 1; 68 m_bi.bmiHeader.biBitCount = 32; 69 m_bi.bmiHeader.biCompression = BI_RGB; 70 m_bi.bmiHeader.biSizeImage = m_width * 4 * m_height; 71 m_bytes = new UCHAR[m_width * 4 * m_height]; 72 73 LONG x = GetSystemMetrics(SM_XVIRTUALSCREEN); 74 LONG y = GetSystemMetrics(SM_YVIRTUALSCREEN); 75 76 m_hwnd = CreateWindowExW(WS_EX_TOPMOST, 77 L"DimmedWindowClass", 78 NULL, 79 WS_POPUP, 80 x, y, 81 m_width, m_height, 82 NULL, NULL, 83 hDllInstance, 84 (LPVOID)this); 85 } 86 87 ~CDimmedWindow() 88 { 89 if (m_hwnd) 90 DestroyWindow(m_hwnd); 91 UnregisterClassW(L"DimmedWindowClass", hDllInstance); 92 if (m_oldbitmap) 93 SelectObject(m_hdc, m_oldbitmap); 94 if (m_hbitmap) 95 DeleteObject(m_hbitmap); 96 if (m_hdc) 97 DeleteObject(m_hdc); 98 if (m_bytes) 99 delete[] m_bytes; 100 } 101 102 // This is needed so that we do not capture the start menu while it's closing. 103 void WaitForInit() 104 { 105 MSG msg; 106 107 while (IsWindow(m_hwnd) && !IsWindowVisible(m_hwnd)) 108 { 109 while (::PeekMessage(&msg, m_hwnd, 0, 0, PM_REMOVE)) 110 { 111 ::TranslateMessage(&msg); 112 ::DispatchMessage(&msg); 113 114 if (IsWindowVisible(m_hwnd)) 115 break; 116 } 117 } 118 } 119 120 void Init() 121 { 122 Capture(); 123 124 ShowWindow(m_hwnd, SW_SHOW); 125 SetForegroundWindow(m_hwnd); 126 EnableWindow(m_hwnd, FALSE); 127 128 SetTimer(m_hwnd, FADE_TIMER_ID, 200, NULL); 129 } 130 131 void Capture() 132 { 133 HWND desktopWnd = GetDesktopWindow(); 134 HDC desktopDC = GetDC(desktopWnd); 135 136 m_hdc = CreateCompatibleDC(desktopDC); 137 138 m_hbitmap = CreateCompatibleBitmap(desktopDC, m_width, m_height); 139 m_oldbitmap = SelectObject(m_hdc, m_hbitmap); 140 BitBlt(m_hdc, 0, 0, m_width, m_height, desktopDC, 0, 0, SRCCOPY); 141 142 ReleaseDC(desktopWnd, desktopDC); 143 } 144 145 bool Step() 146 { 147 // Stop after 10 steps 148 if (m_step++ > 10 || !m_bytes) 149 return false; 150 151 int lines = GetDIBits(m_hdc, m_hbitmap, 0, m_height, m_bytes, &m_bi, DIB_RGB_COLORS); 152 if (lines) 153 { 154 for (int xh = 0; xh < m_height; ++xh) 155 { 156 int h = m_width * 4 * xh; 157 for (int w = 0; w < m_width; ++w) 158 { 159 UCHAR b = m_bytes[(h + w * 4) + 0]; 160 UCHAR g = m_bytes[(h + w * 4) + 1]; 161 UCHAR r = m_bytes[(h + w * 4) + 2]; 162 163 // Standard formula to convert a color. 164 int gray = (r * 30 + g * 59 + b * 11) / 100; 165 if (gray < 0) 166 gray = 0; 167 168 // Do not fade too fast. 169 r = (r*2 + gray) / 3; 170 g = (g*2 + gray) / 3; 171 b = (b*2 + gray) / 3; 172 173 m_bytes[(h + w * 4) + 0] = b; 174 m_bytes[(h + w * 4) + 1] = g; 175 m_bytes[(h + w * 4) + 2] = r; 176 } 177 } 178 SetDIBits(m_hdc, m_hbitmap, 0, lines, m_bytes, &m_bi, DIB_RGB_COLORS); 179 } 180 return true; 181 } 182 183 void Blt(HDC hdc) 184 { 185 BitBlt(hdc, 0, 0, m_width, m_height, m_hdc, 0, 0, SRCCOPY); 186 } 187 188 HWND Wnd() 189 { 190 return m_hwnd; 191 } 192 193 194 BEGIN_COM_MAP(CDimmedWindow) 195 COM_INTERFACE_ENTRY_IID(IID_IUnknown, IUnknown) 196 END_COM_MAP() 197 198 }; 199 200 201 LRESULT WINAPI CDimmedWindow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 202 { 203 switch (uMsg) 204 { 205 case WM_NCCREATE: 206 { 207 LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam); 208 CDimmedWindow* info = static_cast<CDimmedWindow*>(lpcs->lpCreateParams); 209 SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)info); 210 SetTimer(hWnd, INIT_TIMER_ID, 50, NULL); 211 break; 212 } 213 214 case WM_PAINT: 215 { 216 CDimmedWindow* info = reinterpret_cast<CDimmedWindow*>(GetWindowLongPtrW(hWnd, GWLP_USERDATA)); 217 if (info) 218 { 219 PAINTSTRUCT ps; 220 BeginPaint(hWnd, &ps); 221 info->Blt(ps.hdc); 222 EndPaint(hWnd, &ps); 223 } 224 return 0; 225 } 226 227 case WM_TIMER: 228 { 229 if (wParam == INIT_TIMER_ID) 230 { 231 CDimmedWindow* info = reinterpret_cast<CDimmedWindow*>(GetWindowLongPtrW(hWnd, GWLP_USERDATA)); 232 KillTimer(hWnd, INIT_TIMER_ID); 233 info->Init(); 234 } 235 else if (wParam == FADE_TIMER_ID) 236 { 237 CDimmedWindow* info = reinterpret_cast<CDimmedWindow*>(GetWindowLongPtrW(hWnd, GWLP_USERDATA)); 238 if (info && info->Step()) 239 InvalidateRect(hWnd, NULL, TRUE); 240 else 241 KillTimer(hWnd, FADE_TIMER_ID); 242 } 243 return 0; 244 } 245 246 default: 247 break; 248 } 249 250 return DefWindowProc(hWnd, uMsg, wParam, lParam); 251 } 252 253 254 extern "C" 255 HRESULT WINAPI 256 ShellDimScreen(void** pUnknown, HWND* hWindow) 257 { 258 CComObject<CDimmedWindow> *pWindow; 259 HRESULT hr = CComObject<CDimmedWindow>::CreateInstance(&pWindow); 260 ULONG refcount; 261 262 pWindow->WaitForInit(); 263 264 if (!IsWindow(pWindow->Wnd())) 265 { 266 refcount = pWindow->AddRef(); 267 while (refcount) 268 refcount = pWindow->Release(); 269 270 return E_FAIL; 271 } 272 273 _SEH2_TRY 274 { 275 hr = pWindow->QueryInterface(IID_IUnknown, pUnknown); 276 *hWindow = pWindow->Wnd(); 277 hr = S_OK; 278 } 279 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 280 { 281 hr = E_INVALIDARG; 282 refcount = pWindow->AddRef(); 283 while (refcount) 284 refcount = pWindow->Release(); 285 } 286 _SEH2_END 287 288 return hr; 289 } 290