DirectComposition click through in transparent areas

Vitor Hugo Gomes 0 Reputation points
2025-01-31T22:57:11.4266667+00:00

I have an application with DirectComposition and Direct2D that I do have a window bigger than the drawings to handle somethings like shadows underneath the rectangles. The issue that I'm having is in the transparent areas, the click-through is not working as intended. I've tried to change the WM_NCHITTEST to something like this:

case WM_NCHITTEST: {
	POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };	
	ScreenToClient(hWindow, &pt);                         

	if (!IsPointInRoundedRect(pt.x, pt.y, drawResources.roundedRect)) {                
		return HTNOWHERE;            
	}              
	return HTCLIENT;        
} 

And even tried to return HTNOWHERE in all cases, but still without success.

void Candlelight_Window::Initialize(WNDPROC windowProc, HINSTANCE hInstance, LPCSTR className, float width, float height, SharedResources *pSharedResources) {
    WNDCLASS windowClass = { 0 };
    windowClass.style         = CS_HREDRAW | CS_VREDRAW;
    windowClass.lpfnWndProc   = windowProc;
    windowClass.cbClsExtra    = 0;
    windowClass.cbWndExtra    = 0;
    windowClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    windowClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
    windowClass.hbrBackground = NULL;
    windowClass.lpszMenuName  = NULL;
    windowClass.lpszClassName = className;
    RegisterClass(&windowClass);

    RECT rect;
    MONITORINFO monitorInfo;

    monitorInfo.cbSize = sizeof(MONITORINFO);
    HWND activeWindow = GetForegroundWindow();

    HMONITOR activeMonitor = MonitorFromWindow(activeWindow, MONITOR_DEFAULTTONEAREST);

    int xPos = CW_USEDEFAULT;
    int yPos = CW_USEDEFAULT;

    if (GetMonitorInfoA(activeMonitor, &monitorInfo)) { // TODO: Make its own function
        xPos = (monitorInfo.rcWork.right - width) / 2;
        yPos = (monitorInfo.rcWork.bottom - height) / 2 - 150;
    }

    hWindow = CreateWindowEx(
        WS_EX_NOREDIRECTIONBITMAP,
        className,
        nullptr, WS_POPUP,
        xPos, yPos,
        width, height,
        nullptr, nullptr,
        hInstance,
        pSharedResources
    );

    float dpi = GetDpiForWindow(hWindow);

    SetWindowPos( // TODO: Check if needed to still use SetWindowPos
        hWindow,
        HWND_TOP, 0, 0,
        (int)(ceil(width * dpi / 96.f)),
        (int)(ceil(height * dpi / 96.f)),
        SWP_NOMOVE
    );

    ShowWindow(hWindow, true);
    UpdateWindow(hWindow);
    InvalidateRect(hWindow, NULL, TRUE);
}

Below is my Direct2D and DirectComposition setup function:

HRESULT WindowResources::Initialize(HWND hWindow, SharedResources *pSharedResources, D2D1_SIZE_U actualSize) {
        HRESULT hResult = S_OK;
        if (lastSize.width == actualSize.width && lastSize.height == actualSize.height)
            return hResult;
        if (pSwapchain) WIN_SAFE_RELEASE(pSwapchain);
        if (pDeviceContext) WIN_SAFE_RELEASE(pDeviceContext);
        if (pSurface) WIN_SAFE_RELEASE(pSurface);
        DXGI_SWAP_CHAIN_DESC1 swapchainDesc = { 0 };
        swapchainDesc.Width            = actualSize.width;
        swapchainDesc.Height           = actualSize.height;
        swapchainDesc.Format           = DXGI_FORMAT_B8G8R8A8_UNORM;
        swapchainDesc.SampleDesc.Count = 1;
        swapchainDesc.BufferUsage      = DXGI_USAGE_RENDER_TARGET_OUTPUT;
        swapchainDesc.BufferCount      = 2;
        swapchainDesc.SwapEffect       = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
        swapchainDesc.AlphaMode        = DXGI_ALPHA_MODE_PREMULTIPLIED;

        hResult = pSharedResources->pDXGIFactory->CreateSwapChainForComposition(
            pSharedResources->pDXGIDevice,
            &swapchainDesc,
            nullptr,
            &pSwapchain
        );
        if (FAILED(hResult)) return hResult;
        hResult = pSharedResources->pD2D1Device->CreateDeviceContext(
            D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
            &pDeviceContext
        );
        if (FAILED(hResult)) return hResult;
        hResult = pDeviceContext->QueryInterface(__uuidof(ID2D1DeviceContext5), (void**)&pDeviceContext5);
        if (FAILED(hResult)) return hResult;
        hResult = pSwapchain->GetBuffer(0, __uuidof(pSurface), (void**)&pSurface);
        if (FAILED(hResult)) return hResult;
        D2D1_BITMAP_PROPERTIES1 bitmapProps = {};
        bitmapProps.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
        bitmapProps.pixelFormat.format    = DXGI_FORMAT_B8G8R8A8_UNORM;
        bitmapProps.bitmapOptions         = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
        bitmapProps.dpiX = 96;
        bitmapProps.dpiY = 96;
        hResult = pDeviceContext->CreateBitmapFromDxgiSurface(pSurface, bitmapProps, &pBitmap);
        if (FAILED(hResult)) return hResult;
        D2D1_BITMAP_PROPERTIES1 intermediateProps = {};
        intermediateProps.pixelFormat = bitmapProps.pixelFormat;
        intermediateProps.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET;
        intermediateProps.dpiX = 96;
        intermediateProps.dpiY = 96;
        hResult = pDeviceContext->CreateBitmap(
            actualSize,
            nullptr, 0,
            &intermediateProps,
            &pIntermediateBitmap
        );
        if (FAILED(hResult)) return hResult;
        pDeviceContext->SetTarget(pBitmap);
        hResult = pSharedResources->pDCompositionDevice->CreateTargetForHwnd(hWindow, true, &pTarget);
        if (FAILED(hResult)) return hResult;
        hResult = pSharedResources->pDCompositionDevice->CreateVisual(&pVisual);
        if (FAILED(hResult)) return hResult;
        hResult = pVisual->SetContent(pSwapchain);
        if (FAILED(hResult)) return hResult;
        hResult = pTarget->SetRoot(pVisual);
        if (FAILED(hResult)) return hResult;
        lastSize = actualSize;
        return hResult;
}

Is important to note that I've already used things like WS_EX_TRANSPARENT, but I had no success. With this one I even got the inverse behaviour, all my window as acting as transparent, but never got any WM_NCHITTEST event, so became unusable

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,718 questions
0 comments No comments
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.