From 87a716926b9ec1dd7b3cb1cbafa55a18d371a11c Mon Sep 17 00:00:00 2001 From: Mark Jansen Date: Sun, 4 Sep 2016 14:17:22 +0000 Subject: [PATCH] [MSGINA] Implement ShellDimScreen. CORE-11422 svn path=/trunk/; revision=72572 --- reactos/dll/win32/msgina/CMakeLists.txt | 18 +- reactos/dll/win32/msgina/dimmedwindow.cpp | 269 ++++++++++++++++++++++ reactos/dll/win32/msgina/msgina.h | 8 + reactos/dll/win32/msgina/stubs.c | 7 - 4 files changed, 289 insertions(+), 13 deletions(-) create mode 100644 reactos/dll/win32/msgina/dimmedwindow.cpp diff --git a/reactos/dll/win32/msgina/CMakeLists.txt b/reactos/dll/win32/msgina/CMakeLists.txt index b3d67625e7f..7c6b5618f22 100644 --- a/reactos/dll/win32/msgina/CMakeLists.txt +++ b/reactos/dll/win32/msgina/CMakeLists.txt @@ -1,11 +1,13 @@ +set_cpp(WITH_RUNTIME) + include_directories( - include + ${REACTOS_SOURCE_DIR}/sdk/lib/atl ${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine) spec2def(msgina.dll msgina.spec) -list(APPEND SOURCE +list(APPEND C_SOURCE gui.c lsa.c msgina.c @@ -14,15 +16,19 @@ list(APPEND SOURCE tui.c msgina.h) +list(APPEND CPP_SOURCE + dimmedwindow.cpp) + add_library(msgina SHARED - ${SOURCE} + ${C_SOURCE} + ${CPP_SOURCE} msgina.rc ${CMAKE_CURRENT_BINARY_DIR}/msgina_stubs.c ${CMAKE_CURRENT_BINARY_DIR}/msgina.def) -set_module_type(msgina win32dll) -target_link_libraries(msgina wine) +set_module_type(msgina win32dll UNICODE) +target_link_libraries(msgina atlnew wine uuid ${PSEH_LIB}) add_delay_importlibs(msgina secur32) add_importlibs(msgina advapi32 user32 gdi32 powrprof userenv msvcrt kernel32 ntdll) -add_pch(msgina msgina.h SOURCE) +add_pch(msgina msgina.h CPP_SOURCE) add_cd_file(TARGET msgina DESTINATION reactos/system32 FOR all) diff --git a/reactos/dll/win32/msgina/dimmedwindow.cpp b/reactos/dll/win32/msgina/dimmedwindow.cpp new file mode 100644 index 00000000000..d12fda42031 --- /dev/null +++ b/reactos/dll/win32/msgina/dimmedwindow.cpp @@ -0,0 +1,269 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS msgina.dll + * FILE: dll/win32/msgina/dimmedwindow.cpp + * PURPOSE: Implementation of ShellDimScreen + * PROGRAMMER: Mark Jansen + */ + +#define COM_NO_WINDOWS_H +#include "msgina.h" +#include +#include +#include +#include + +CComModule gModule; + +// Please note: The INIT_TIMER is a workaround because ReactOS does not redraw the desktop in time, +// so the start menu is still visible on the dimmed screen. +#define INIT_TIMER_ID 0x112233 +#define FADE_TIMER_ID 0x12345 + +class CDimmedWindow : + public CComObjectRootEx, + IUnknown +{ +private: + HWND m_hwnd; + HDC m_hdc; + HBITMAP m_hbitmap; + HGDIOBJ m_oldbitmap; + LONG m_width; + LONG m_height; + BITMAPINFO m_bi; + UCHAR* m_bytes; + int m_step; + + static LRESULT WINAPI Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +public: + CDimmedWindow() + : m_hwnd(NULL) + , m_hdc(NULL) + , m_hbitmap(NULL) + , m_oldbitmap(NULL) + , m_width(0) + , m_height(0) + , m_bytes(NULL) + , m_step(0) + { + WNDCLASSEXW wndclass = {sizeof(wndclass)}; + wndclass.lpfnWndProc = Proc; + wndclass.hInstance = hDllInstance; + wndclass.hCursor = LoadCursor(0, IDC_ARROW); + wndclass.lpszClassName = L"DimmedWindowClass"; + + if (!RegisterClassExW(&wndclass)) + return; + + m_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); + m_height = GetSystemMetrics(SM_CYVIRTUALSCREEN); + + memset(&m_bi, 0, sizeof(m_bi)); + m_bi.bmiHeader.biSize = sizeof(m_bi); + m_bi.bmiHeader.biWidth = m_width; + m_bi.bmiHeader.biHeight = m_height; + m_bi.bmiHeader.biPlanes = 1; + m_bi.bmiHeader.biBitCount = 32; + m_bi.bmiHeader.biCompression = BI_RGB; + m_bi.bmiHeader.biSizeImage = m_width * 4 * m_height; + m_bytes = new UCHAR[m_width * 4 * m_height]; + + LONG x = GetSystemMetrics(SM_XVIRTUALSCREEN); + LONG y = GetSystemMetrics(SM_YVIRTUALSCREEN); + + m_hwnd = CreateWindowExW(WS_EX_TOPMOST, L"DimmedWindowClass", NULL, WS_POPUP, + x, y, m_width, m_height, + NULL, NULL, hDllInstance, (LPVOID)this); + } + + ~CDimmedWindow() + { + if (m_hwnd) + DestroyWindow(m_hwnd); + UnregisterClassW(L"DimmedWindowClass", hDllInstance); + if (m_oldbitmap) + SelectObject(m_hdc, m_oldbitmap); + if (m_hbitmap) + DeleteObject(m_hbitmap); + if (m_hdc) + DeleteObject(m_hdc); + if (m_bytes) + delete[] m_bytes; + } + + // This is needed so that we do not capture the start menu while it's closing. + void WaitForInit() + { + MSG msg; + + while (!IsWindowVisible(m_hwnd)) + { + while (::PeekMessage(&msg, m_hwnd, 0, 0, PM_REMOVE)) + { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + + if (IsWindowVisible(m_hwnd)) + break; + } + } + } + + void Init() + { + Capture(); + + ShowWindow(m_hwnd, SW_SHOWNA); + EnableWindow(m_hwnd, FALSE); + + SetTimer(m_hwnd, FADE_TIMER_ID, 200, NULL); + } + + void Capture() + { + HWND desktopWnd = GetDesktopWindow(); + HDC desktopDC = GetDC(desktopWnd); + + m_hdc = CreateCompatibleDC(desktopDC); + + m_hbitmap = CreateCompatibleBitmap(desktopDC, m_width, m_height); + m_oldbitmap = SelectObject(m_hdc, m_hbitmap); + BitBlt(m_hdc, 0, 0, m_width, m_height, desktopDC, 0, 0, SRCCOPY); + + ReleaseDC(desktopWnd, desktopDC); + } + + bool Step() + { + // Stop after 10 steps + if (m_step++ > 10 || !m_bytes) + return false; + + int lines = GetDIBits(m_hdc, m_hbitmap, 0, m_height, m_bytes, &m_bi, DIB_RGB_COLORS); + if (lines) + { + for (int xh = 0; xh < m_height; ++xh) + { + int h = m_width * 4 * xh; + for (int w = 0; w < m_width; ++w) + { + UCHAR b = m_bytes[(h + w * 4) + 0]; + UCHAR g = m_bytes[(h + w * 4) + 1]; + UCHAR r = m_bytes[(h + w * 4) + 2]; + + // Standard formula to convert a color. + int gray = (r * 30 + g * 59 + b * 11) / 100; + if (gray < 0) + gray = 0; + + // Do not fade too fast. + r = (r*2 + gray) / 3; + g = (g*2 + gray) / 3; + b = (b*2 + gray) / 3; + + m_bytes[(h + w * 4) + 0] = b; + m_bytes[(h + w * 4) + 1] = g; + m_bytes[(h + w * 4) + 2] = r; + } + } + SetDIBits(m_hdc, m_hbitmap, 0, lines, m_bytes, &m_bi, DIB_RGB_COLORS); + } + return true; + } + + void Blt(HDC hdc) + { + BitBlt(hdc, 0, 0, m_width, m_height, m_hdc, 0, 0, SRCCOPY); + } + + HWND Wnd() + { + return m_hwnd; + } + + + BEGIN_COM_MAP(CDimmedWindow) + COM_INTERFACE_ENTRY_IID(IID_IUnknown, IUnknown) + END_COM_MAP() + +}; + + +LRESULT WINAPI CDimmedWindow::Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_NCCREATE: + { + LPCREATESTRUCT lpcs = reinterpret_cast(lParam); + CDimmedWindow* info = static_cast(lpcs->lpCreateParams); + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)info); + SetTimer(hWnd, INIT_TIMER_ID, 50, NULL); + break; + } + case WM_PAINT: + { + CDimmedWindow* info = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); + if (info) + { + PAINTSTRUCT paint; + HDC hdc = BeginPaint(hWnd, &paint); + info->Blt(hdc); + EndPaint(hWnd, &paint); + } + return 0; + } + case WM_TIMER: + if (wParam == INIT_TIMER_ID) + { + CDimmedWindow* info = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); + KillTimer(hWnd, INIT_TIMER_ID); + info->Init(); + return 0; + } + if (wParam == FADE_TIMER_ID) + { + CDimmedWindow* info = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); + if (info && info->Step()) + InvalidateRect(hWnd, NULL, TRUE); + else + KillTimer(hWnd, FADE_TIMER_ID); + return 0; + } + break; + default: + break; + } + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + + +extern "C" +HRESULT WINAPI +ShellDimScreen (void** pUnknown, HWND* hWindow) +{ + CComObject *pWindow; + HRESULT hr = CComObject::CreateInstance(&pWindow); + ULONG refcount; + + pWindow->WaitForInit(); + + _SEH2_TRY + { + hr = pWindow->QueryInterface(IID_IUnknown, pUnknown); + *hWindow = pWindow->Wnd(); + hr = S_OK; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + hr = E_INVALIDARG; + refcount = pWindow->AddRef(); + while (refcount) + refcount = pWindow->Release(); + } + _SEH2_END + + return hr; +} diff --git a/reactos/dll/win32/msgina/msgina.h b/reactos/dll/win32/msgina/msgina.h index 97deda195c0..e9d19353346 100644 --- a/reactos/dll/win32/msgina/msgina.h +++ b/reactos/dll/win32/msgina/msgina.h @@ -1,6 +1,10 @@ #ifndef _MSGINA_H #define _MSGINA_H +#ifdef __cplusplus +extern "C" { +#endif + #include #define WIN32_NO_STATUS @@ -125,4 +129,8 @@ CreateProfile( IN PWSTR Domain, IN PWSTR Password); +#ifdef __cplusplus +} // extern "C" +#endif + #endif /* _MSGINA_H */ diff --git a/reactos/dll/win32/msgina/stubs.c b/reactos/dll/win32/msgina/stubs.c index 3a7b7a64055..69921cff92a 100644 --- a/reactos/dll/win32/msgina/stubs.c +++ b/reactos/dll/win32/msgina/stubs.c @@ -116,10 +116,3 @@ WlxGetConsoleSwitchCredentials( UNIMPLEMENTED; return FALSE; } - -HRESULT WINAPI -ShellDimScreen (void* Unknown, HWND* hWindow) -{ - UNIMPLEMENTED; - return E_FAIL; -}