Home > Back-end >  Two-Window App Where One Has WS_EX_NOACTIVATE
Two-Window App Where One Has WS_EX_NOACTIVATE

Time:01-07

First of all, this question can be a duplicate but the question doesnt have enough information to solve the problem.

I have two windows in my native Win32 application. The first is a layered window with WS_EX_NOACTIVATE extended style and the second is a normal window. I want the layered one to be non-activatable. The problem is that, when I have two window in the same application, the layered one which must be non-activatable, gets activated when switching between them. But there is no problem when switching between two external windows, one being not belong to my application. How can I solve this problem? Or Can I solve that? Is there anything I missed? The following is a minimal reproducable example (didn't include any error checking for minimality.) Thank you for taking time.

#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 };
}

CodePudding user response:

Although I still don't understand the cause of the problem, with the help of @IInspectable's guidance and documentation, I was able to prevent the window from being activated by processing the WM_MOUSEACTIVATE message. The updated window procedure is as follows.

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);
}
  •  Tags:  
  • Related