窗口未最大化时丢失的WM_NCLBUTTONUP消息的奇怪问题

Mar*_*ram 5 c++ winapi mfc

我有一个窗口,我处理WM_NCLBUTTONUP消息,以处理标题栏中自定义按钮的点击.当窗口最大化时,这很有效,但是当窗口最大化时,WM_NCLBUTTONUP消息永远不会到达!我确实收到了WM_NCLBUTTONDOWN消息.奇怪的是WM_NCLBUTTONUP确实到了,如果我点击菜单栏的右边,但是在标题栏/窗口框架的任何地方,消息永远不会到达.

经过一段时间的调试后,我发现如果我在CMainFrame :: OnNcLButtonDown()上设置一个断点,点击标题栏,但按住鼠标按钮,让调试器在函数中断,点击F5继续调试,然后释放鼠标按钮 - 神奇地发送WM_NCLBUTTONUP !!

我的问题是双重的,(1)到底是怎么回事?(2)如何解决这个"问题".

我还注意到,互联网上还有其他几个人也有同样的问题(一个快速的谷歌显示很多其他人有同样的问题,但没有解决方案).

编辑
感谢前两个回复,我尝试在NCLButtonDown中调用ReleaseCapture,但它没有效果(事实上,它返回NULL,表示捕获不到位).我只能假设基类(def window proc)功能可以设置捕获.我将在星期一调查......

El *_*rko 5

我也遇到过同样的问题。问题确实是在窗口标题上单击左键会开始拖动,从而导致鼠标捕获,这会阻止 WM_NCLBUTTONUP 到达。

解决方案是覆盖 WM_NCHITTEST:

LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
    switch (nMsg)
    {
        ...
        case WM_NCHITTEST:
            Point p(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam);
            ScreenToClient(p);
            if (myButtonRect.Contains(p))
            {
                return HTBORDER;
            }
            break;
    }
    return DefWindowProc(hWnd, nMsg, wParam, lParam);
}
Run Code Online (Sandbox Code Playgroud)

所以基本上你通知 Windows 你的按钮占据的区域不是窗口标题的一部分,而是非客户区 (HTBORDER) 的非特定部分。

脚注:如果您在期望 WM_NCLBUTTONDOWN 消息进入时调用了 SetCapture() 而尚未调用 ReleaseCapture(),则即使进行了上述更改,它也不会到达。这可能会令人恼火,因为在与此类自定义按钮交互期间捕获鼠标是正常的,因此您可以在鼠标离开窗口时取消单击/突出显示。但是,作为使用捕获的替代方法,您可以考虑使用短(例如 100 毫秒)间隔的 SetTimer()/KillTimer(),这不会导致 WM_NCLBUTTONUP 消息消失。