Skip to content

Latest commit

 

History

History
225 lines (183 loc) · 7.88 KB

桌面分层窗口显示填充的位图.md

File metadata and controls

225 lines (183 loc) · 7.88 KB

桌面分层窗口显示填充的位图

Q:

Win32下如何使用分层窗口制作一个桌面遮罩层

A:

方法一、使用 SetLayeredWindowAttributes

#include <windows.h>

TCHAR szClassName[] = L"LayerWindowClass";

void RenderLayerWindow(HWND hwnd, HDC screenDC);
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
    WNDCLASSEX wincl;

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof(WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor(NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    wincl.hbrBackground = (HBRUSH)COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx(&wincl))
        return 0;

    int width = GetSystemMetrics(SM_CXSCREEN);
    int height = GetSystemMetrics(SM_CYSCREEN);

    HWND hwnd = CreateWindowEx(
        WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
        szClassName,           /* Classname */
        L"Layer Window",       /* Title Text */
        WS_POPUP | WS_VISIBLE, /* default window */
        0,                     /* Windows decides the position */
        0,                     /* where the window ends up on the screen */
        width,                 /* The programs width */
        height,                /* and height in pixels */
        HWND_DESKTOP,          /* The window is a child-window to desktop */
        NULL,                  /* No menu */
        hThisInstance,         /* Program Instance handler */
        NULL                   /* No Window Creation data */
    );

    SetLayeredWindowAttributes(hwnd, RGB(255, 255, 255), 100, LWA_ALPHA | LWA_COLORKEY);

    MSG messages;
    while (GetMessage(&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }

    return messages.wParam;
}

LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        {
            RenderLayerWindow(hwnd, hdc);
        }
        EndPaint(hwnd, &ps);

    }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);       /* send a WM_QUIT to the message queue */
        break;
    case WM_RBUTTONDOWN:
        PostQuitMessage(0);       /* send a WM_QUIT to the message queue */
        break;
    default:                      /* for messages that we don't deal with */
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

void RenderLayerWindow(HWND hwnd, HDC screenDC)
{
    RECT wndRect;
    ::GetWindowRect(hwnd, &wndRect);
    SIZE wndSize = { wndRect.right - wndRect.left,wndRect.bottom - wndRect.top };

    HDC bmpDC = ::CreateCompatibleDC(screenDC);
    HBITMAP bmp = (HBITMAP)LoadImage(NULL, L"logo.bmp", 0, 0, 0, LR_LOADFROMFILE);
    HBITMAP oldBmp = (HBITMAP)::SelectObject(bmpDC, bmp);

    BITMAP bitmap;
    GetObject(bmp, sizeof(bitmap), &bitmap);
    SIZE szBmp = { bitmap.bmWidth, bitmap.bmHeight };
    ::SetStretchBltMode(screenDC, HALFTONE);
    ::StretchBlt(screenDC, 0, 0, wndSize.cx, wndSize.cy, bmpDC, 0, 0, szBmp.cx, szBmp.cy, SRCCOPY);

    ::SelectObject(bmpDC, oldBmp);
    ::DeleteDC(bmpDC);
}

方法二、使用 UpdateLayeredWindow

#include <windows.h>

TCHAR szClassName[] = L"LayerWindowClass";

LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
    WNDCLASSEX wincl;

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof(WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor(NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    wincl.hbrBackground = (HBRUSH)COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx(&wincl))
        return 0;

    int width = GetSystemMetrics(SM_CXSCREEN);
    int height = GetSystemMetrics(SM_CYSCREEN);

    HWND hwnd = CreateWindowEx(
        WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
        szClassName,           /* Classname */
        L"Layer Window",       /* Title Text */
        WS_POPUP | WS_VISIBLE, /* default window */
        0,                     /* Windows decides the position */
        0,                     /* where the window ends up on the screen */
        width,                 /* The programs width */
        height,                /* and height in pixels */
        HWND_DESKTOP,          /* The window is a child-window to desktop */
        NULL,                  /* No menu */
        hThisInstance,         /* Program Instance handler */
        NULL                   /* No Window Creation data */
    );

    RECT wndRect;
    ::GetWindowRect(hwnd, &wndRect);
    SIZE wndSize = { wndRect.right - wndRect.left,wndRect.bottom - wndRect.top };
   
    HDC screenDC = ::GetDC(NULL);
    HDC memDC = ::CreateCompatibleDC(screenDC); // target DC
    HBITMAP memBitmap = ::CreateCompatibleBitmap(screenDC, wndSize.cx, wndSize.cy);
    ::SelectObject(memDC, memBitmap);

    HDC bmpDC = ::CreateCompatibleDC(screenDC);
    HBITMAP bmp = (HBITMAP)LoadImage(NULL, L"logo.bmp", 0, 0, 0, LR_LOADFROMFILE);
    HBITMAP oldBmp = (HBITMAP)::SelectObject(bmpDC, bmp);

    BITMAP bitmap;
    GetObject(bmp, sizeof(bitmap), &bitmap);
    SIZE szBmp = { bitmap.bmWidth, bitmap.bmHeight };
    ::SetStretchBltMode(bmpDC, HALFTONE);
    ::StretchBlt(memDC, 0, 0, wndSize.cx, wndSize.cy, bmpDC, 0, 0, szBmp.cx, szBmp.cy, SRCCOPY);

    POINT ptSrc = { 0,0 };
    BLENDFUNCTION blendFunction{ AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
    ::UpdateLayeredWindow(hwnd, screenDC, &ptSrc, &wndSize, memDC, &ptSrc, RGB(255, 255, 255), &blendFunction, ULW_ALPHA | ULW_COLORKEY);

    ::SelectObject(bmpDC, oldBmp);
    ::DeleteDC(bmpDC);
    ::DeleteDC(memDC);
    ::ReleaseDC(NULL, screenDC);

    MSG messages;
    while (GetMessage(&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }

    return messages.wParam;
}

LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_DESTROY:
        PostQuitMessage(0);       /* send a WM_QUIT to the message queue */
        break;
    case WM_RBUTTONDOWN:
        PostQuitMessage(0);       /* send a WM_QUIT to the message queue */
        break;
    default:                      /* for messages that we don't deal with */
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}