两个-Window 一个有 WS_EX_NOACTIVATE 的应用

Two-Window App Where One Has WS_EX_NOACTIVATE

首先,this问题可能是重复的,但问题没有足够的信息来解决问题。

我的本机 Win32 应用程序中有两个 windows。第一个是带有 WS_EX_NOACTIVATE 扩展样式的分层 window,第二个是普通 window。我希望分层的是不可激活的。问题是,当我在同一个应用程序中有两个 window 时,必须不可激活的分层的在它们之间切换时会被激活。但是在两个外部 windows 之间切换时没有问题,一个不属于我的应用程序。我怎么解决这个问题?或者我能解决吗?有什么我错过的吗?以下是一个最小的可重现示例(不包括任何最小错误检查。)感谢您抽出时间。

#define WIN32_LEAN_AND_MEAN

#include <Windows.h>
#include <windowsx.h> 
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
 
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
void init_device_resources(int cx, int cy, void** rgb);
void update_content();
void set_window_size(int width, int height);

HWND layeredhWnd;
HWND otherhWnd;
WNDCLASSEX wc;
MSG msg;
HDC hdcDesktop;
HDC hdcContent;
POINT dstPoint = { 100, 100 };
SIZE windowSize = { 800, 600 };
BLENDFUNCTION bf;
BITMAPINFO bi;
BYTE* rgb_data = NULL;
HBITMAP hBitmap;
HBITMAP hOldBitmap; 

int WINAPI WinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow)
{ 
    
    ZeroMemory(&wc, sizeof(WNDCLASSEX));
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    wc.lpszClassName = L"LayeredWindowClass";

    RegisterClassEx(&wc);
     
    wc.lpszClassName = L"OtherWindowClass";

    RegisterClassEx(&wc);

    layeredhWnd = CreateWindowEx(WS_EX_LAYERED | WS_EX_NOACTIVATE,
        L"LayeredWindowClass",
        L"",
        WS_POPUP | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME,
        0, 0,
        800, 600,
        NULL,
        NULL,
        hInstance,
        NULL); 

    otherhWnd = CreateWindowEx(NULL,
        L"OtherWindowClass",
        L"",
        WS_OVERLAPPEDWINDOW,
        0, 0,
        800, 600,
        NULL,
        NULL,
        hInstance,
        NULL);

    init_device_resources(800, 600, &rgb_data);
    set_window_size(800, 600);
    ShowWindow(layeredhWnd, nCmdShow); 
    ShowWindow(otherhWnd, nCmdShow);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CLOSE:
    {
        DestroyWindow(hWnd);
        break;
    }
    case WM_DESTROY:
    {
        PostQuitMessage(0);
        break;
    }
    case WM_ACTIVATE:
    {
        if(hWnd == layeredhWnd)
            update_content();
        break;
    }
    case WM_PAINT:
    {
        if (hWnd == layeredhWnd)
            update_content();
        break;
    }
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}
void init_device_resources(int cx, int cy, void** rgb)
{
    hdcDesktop = GetDC(NULL);
    hdcContent = CreateCompatibleDC(hdcDesktop);

    bf.BlendOp = AC_SRC_OVER;
    bf.BlendFlags = 0;
    bf.SourceConstantAlpha = 255;
    bf.AlphaFormat = AC_SRC_ALPHA;
    bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bi.bmiHeader.biWidth = cx;
    bi.bmiHeader.biHeight = -cy;
    bi.bmiHeader.biPlanes = 1;
    bi.bmiHeader.biBitCount = 32;
    bi.bmiHeader.biCompression = BI_RGB;
    bi.bmiHeader.biSizeImage = cx * cy * 4;
    bi.bmiHeader.biXPelsPerMeter = 0;
    bi.bmiHeader.biYPelsPerMeter = 0;
    bi.bmiHeader.biClrUsed = 0;
    bi.bmiHeader.biClrImportant = 0;
    bi.bmiColors[0] = (RGBQUAD){ 0 };

    hBitmap = CreateDIBSection(hdcContent, &bi, DIB_RGB_COLORS, rgb, NULL, 0);
    for (int i = 0; i < cx * cy * 4; i++)
    {
        rgb_data[i] = 255;
    }
    hOldBitmap = SelectObject(hdcContent, hBitmap);
}
void update_content()
{
    UpdateLayeredWindow(layeredhWnd, hdcDesktop, &dstPoint,
        &windowSize, hdcContent, &(POINT){ 0, 0 }, RGB(0, 0, 0), & bf, ULW_ALPHA);
}
void set_window_size(int width, int height)
{
    SetWindowPos(layeredhWnd, NULL, 0, 0, width, height, SWP_NOMOVE);
    windowSize = (SIZE){ width, height };
}

虽然我仍然不明白问题的原因,但在@IInspectable 的指导和文档的帮助下,我能够通过处理 WM_MOUSEACTIVATE 来防止 window 被激活信息。更新后的window程序如下。

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CLOSE:
    {
        DestroyWindow(hWnd);
        break;
    }
    case WM_DESTROY:
    {
        PostQuitMessage(0);
        break;
    }
    case WM_MOUSEACTIVATE:
    {
        if (hWnd == layeredhWnd)
            return MA_NOACTIVATE;
        break;
    }
    case WM_ACTIVATE:
    {
        if(hWnd == layeredhWnd)
            update_content();
        break;
    }
    case WM_PAINT:
    {
        if (hWnd == layeredhWnd)
            update_content();
        break;
    }
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}