首页 > 解决方案 > 响应 WM_NCHITTEST 处理返回的任性行为

问题描述

我正在完全重绘非客户区,但愿意保留一些默认功能。Windows 不允许我在任何需要的地方放置关闭按钮。虽然当我对窗口说我希望整个窗口都是 HTCAPTION 而不是关闭按钮时,它非常有效。我知道我可以轻松地进行适当的直接 api 调用。但是总有一些疑问,如果windows做了一些我不知道的额外事情怎么办。为什么 Windows 会这样做?也许有一些你知道的解决方案。请分享。

#include <windows.h>

LRESULT CALLBACK msg_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE); // inform frame change
        break;
    case WM_NCCALCSIZE:
        if (wParam) return 0; // removing the standard frame
        break;
    case WM_NCHITTEST:
        return HTCLOSE; // HTCAPTION perfectly works 
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = msg_proc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    wcex.hCursor = 0;
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = L"huge close button";
    wcex.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);

    RegisterClassEx(&wcex);
    HWND hwnd = CreateWindowExW(
        WS_EX_TOPMOST,
        L"huge close button", L"huge close button", WS_OVERLAPPEDWINDOW,
        100, 100, 1000, 1000,
        NULL, NULL, hInstance, 0 );
    ShowWindow(hwnd, nCmdShow);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return (int)msg.wParam;
}

这段代码意味着无论用户按下鼠标按钮,应用程序都应该关闭。但事实并非如此。

标签: c++windowswinapi

解决方案


您需要单独处理WM_NCLBUTTONDOWN

参数

DefWindowProc 函数作为处理 WM_NCHITTEST 消息的结果返回的命中测试值。有关命中测试值的列表,请参阅 WM_NCHITTEST。

因此,您返回的值WM_NCHITTEST是在wParam其他消息中发送的,尤其是WM_NCLBUTTONDOWNWM_NCLBUTTONUP

像这样修改它:

LRESULT CALLBACK msg_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE); // inform frame change
        break;
    case WM_NCCALCSIZE:
        if (wParam) return 0; // removing the standard frame
        break;
    case WM_NCHITTEST:
        return HTCLOSE; // HTCAPTION perfectly works
    case WM_NCLBUTTONDOWN:
        if (wParam == HTCLOSE)
        {
            PostQuitMessage(0);
            return 0;
        }
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
...

推荐阅读