You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

未公开BlurBehind导致WM_NCHITTEST响应迟缓问题求助

注:以下内容针对Windows 10。Windows 7也有相同功能,但代码略有不同


未公开背景模糊功能的窗口卡顿问题

若为WM_POPUP|WM_VISIBLE窗口应用未公开的背景模糊功能,代码示例如下:

void BlurBehind(HWND hwnd)
{
    struct ACCENTPOLICY
    {
        int na;
        int nf;
        int nc;
        int nA;
    };
    struct WINCOMPATTRDATA
    {
        int na;
        PVOID pd;
        ULONG ul;
    };

    int error = 0;

    const HINSTANCE hm = LoadLibrary(L"user32.dll");
    if (hm)
    {
        typedef BOOL(WINAPI* pSetWindowCompositionAttribute)(HWND, WINCOMPATTRDATA*);

        const pSetWindowCompositionAttribute SetWindowCompositionAttribute = (pSetWindowCompositionAttribute)GetProcAddress(hm, "SetWindowCompositionAttribute");
        if (SetWindowCompositionAttribute)
        {
            ACCENTPOLICY policy = { 4, 0, 155, 0 };
            WINCOMPATTRDATA data = { 19, &policy,sizeof(ACCENTPOLICY) };

            SetWindowCompositionAttribute(hwnd, &data);
            error = (GetLastError());
        }
        FreeLibrary(hm);
    }

}

int WINAPI WinMain(HINSTANCE hin, HINSTANCE, LPSTR, int)
{
    WNDCLASS c = {NULL};
    c.lpszClassName = L"Example";
    c.lpfnWndProc = WndProc;
    c.hInstance = hin;
    c.style = CS_VREDRAW | CS_HREDRAW;
    c.hCursor = LoadCursor(NULL, IDC_ARROW);
    c.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
    RegisterClass(&c);
    
    HWND hwnd = CreateWindowEx(NULL, L"Example", L"Example", WS_POPUP | WS_VISIBLE, 0, 0, 1000, 600, NULL, NULL, hin, 0);

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

    return 0;
}

同时按如下方式处理WM_NCHITTEST消息(该窗口无默认标题栏):

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{

switch (message)
{
case WM_NCHITTEST:
{
    RECT r;
    GetWindowRect(hwnd, &r);

    auto cp = MAKEPOINTS(lp);
    int dyn = 61;

    const LRESULT result = DefWindowProc(hwnd, message, wp, lp);

    if (result == HTCLIENT)
    {
        if (cp.x <= r.right - dyn && cp.y <= r.top + 31)
            return HTCAPTION;
        else
        {
            if (r.right - cp.x < 20 && r.bottom - cp.y < 20)
                return HTBOTTOMRIGHT;
            else if (r.right - cp.x < 20)
                return HTRIGHT;
            else if (cp.x - r.left < 20 && r.bottom - cp.y < 20)
                return HTBOTTOMLEFT;
            else if (r.bottom - cp.y < 20)
                return HTBOTTOM;
            else if (cp.x - r.left < 20)
                return HTLEFT;
            else
            {
                SetClassLong(hwnd, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW));
                return result;
            }

        }
        else
        {
            SetClassLong(hwnd, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW));
            return result;
        }
    }
    else
        return result;
}
    break;
default:
    return DefWindowProc(hwnd, message, wp, lp);
}
return 1;
}

此时HT_事件会出现响应缓慢、卡顿的情况。窗口无法跟随鼠标即时移动,比如晃动鼠标后松开,窗口仍会继续沿路径移动,存在明显延迟。

若不启用模糊效果,移动、调整窗口大小等所有事件都能即时响应鼠标操作。

请问有使用过此类未公开功能的开发者遇到过该问题吗?是否有解决方案?

我找到了一个拖动窗口的技巧(尚未测试),但我还需要实现窗口调整大小的功能。


更新

通过最小化示例测试发现,若完全移除WndProc中的WM_PAINT处理逻辑,卡顿现象会消失。此前WM_PAINT中绘制Direct2D内容,之前使用GDI+时也存在该问题。推测卡顿是因为Windows消息处理为同步模式,需等待绘制完成,但不清楚启用模糊后差异为何如此明显。

另外我发现自己在WM_PAINT和WM_SIZE中都调用了渲染函数(因为WM_SIZE中需要重建Direct2D渲染目标)。

目前我已完全移除WM_PAINT中的渲染调用,仅保留ValidateRect调用,情况有所改善,但调整窗口大小时仍有轻微卡顿。


更新2

但现在未做任何改动,卡顿现象再次出现,即使WM_PAINT和WM_SIZE处理为空。即使完全不处理WM_NCHITTEST,窗口移动或调整大小时仍会卡顿。

可能之前误以为卡顿消失是因为我无意中关闭了模糊效果。

我提供的示例具有代表性,请问其他开发者是否也会遇到相同情况(至少非高端配置设备会出现该问题)?


更新3

发现此前卡顿消失并非因为关闭了代码中的模糊效果,而是Surface Go电量低时Windows启用了节电模式,此时系统会关闭“设置-颜色”中的Transparency effects开关。

手动关闭设置中的Transparency effects后,卡顿也会消失。

但有趣的是,自定义窗口的模糊效果并未消失,而UWP应用、开始菜单等的透明效果则会消失。


内容的提问来源于stack exchange,提问作者isagsadvb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 23:09:33