[MSGINA] Implement ShellDimScreen. CORE-11422
authorMark Jansen <mark.jansen@reactos.org>
Sun, 4 Sep 2016 14:17:22 +0000 (14:17 +0000)
committerMark Jansen <mark.jansen@reactos.org>
Sun, 4 Sep 2016 14:17:22 +0000 (14:17 +0000)
svn path=/trunk/; revision=72572

reactos/dll/win32/msgina/CMakeLists.txt
reactos/dll/win32/msgina/dimmedwindow.cpp [new file with mode: 0644]
reactos/dll/win32/msgina/msgina.h
reactos/dll/win32/msgina/stubs.c

index b3d6762..7c6b561 100644 (file)
@@ -1,11 +1,13 @@
 
 
+set_cpp(WITH_RUNTIME)
+
 include_directories(
 include_directories(
-    include
+    ${REACTOS_SOURCE_DIR}/sdk/lib/atl
     ${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine)
 
 spec2def(msgina.dll msgina.spec)
 
     ${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
     gui.c
     lsa.c
     msgina.c
@@ -14,15 +16,19 @@ list(APPEND SOURCE
     tui.c
     msgina.h)
 
     tui.c
     msgina.h)
 
+list(APPEND CPP_SOURCE
+    dimmedwindow.cpp)
+
 add_library(msgina SHARED
 add_library(msgina SHARED
-    ${SOURCE}
+    ${C_SOURCE}
+    ${CPP_SOURCE}
     msgina.rc
     ${CMAKE_CURRENT_BINARY_DIR}/msgina_stubs.c
     ${CMAKE_CURRENT_BINARY_DIR}/msgina.def)
 
     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_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)
 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 (file)
index 0000000..d12fda4
--- /dev/null
@@ -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 <wingdi.h>
+#include <atlbase.h>
+#include <atlcom.h>
+#include <pseh/pseh2.h>
+
+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<CComMultiThreadModelNoCS>,
+    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<LPCREATESTRUCT>(lParam);
+        CDimmedWindow* info = static_cast<CDimmedWindow*>(lpcs->lpCreateParams);
+        SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)info);
+        SetTimer(hWnd, INIT_TIMER_ID, 50, NULL);
+        break;
+    }
+    case WM_PAINT:
+    {
+        CDimmedWindow* info = reinterpret_cast<CDimmedWindow*>(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<CDimmedWindow*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
+            KillTimer(hWnd, INIT_TIMER_ID);
+            info->Init();
+            return 0;
+        }
+        if (wParam == FADE_TIMER_ID)
+        {
+            CDimmedWindow* info = reinterpret_cast<CDimmedWindow*>(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<CDimmedWindow> *pWindow;
+    HRESULT hr = CComObject<CDimmedWindow>::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;
+}
index 97deda1..e9d1935 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef _MSGINA_H
 #define _MSGINA_H
 
 #ifndef _MSGINA_H
 #define _MSGINA_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include <stdarg.h>
 
 #define WIN32_NO_STATUS
 #include <stdarg.h>
 
 #define WIN32_NO_STATUS
@@ -125,4 +129,8 @@ CreateProfile(
     IN PWSTR Domain,
     IN PWSTR Password);
 
     IN PWSTR Domain,
     IN PWSTR Password);
 
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
 #endif /* _MSGINA_H */
 #endif /* _MSGINA_H */
index 3a7b7a6..69921cf 100644 (file)
@@ -116,10 +116,3 @@ WlxGetConsoleSwitchCredentials(
     UNIMPLEMENTED;
     return FALSE;
 }
     UNIMPLEMENTED;
     return FALSE;
 }
-
-HRESULT WINAPI 
-ShellDimScreen (void* Unknown, HWND* hWindow)
-{
-    UNIMPLEMENTED;
-    return E_FAIL;
-}