当窗口被拖动时,WindowFromPoint 不会触发 WM_NCHITTEST [英] WindowFromPoint doesn't trigger WM_NCHITTEST when window is being dragged

查看:21
本文介绍了当窗口被拖动时,WindowFromPoint 不会触发 WM_NCHITTEST的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试按照 this 答案中提供的说明操作,以便找到点下方的窗口,aside 当前正在拖动的窗口.

I'm trying to follow the instructions provided in this answer in order to find the window beneath a point, aside from a window that's currently being dragged.

我尝试的问题是在拖动操作期间调用 WindowFromPoint 时,WM_NCHITTEST 消息显然没有被触发.所以整个事情都不起作用,我无法获得被拖动的窗口下方的窗口.

The problem with my attempt is that when calling WindowFromPoint during the drag operation, the WM_NCHITTEST message is apparently not being triggered. And so the entire thing doesn't work, and I can't obtain the window underneath the one being dragged.

这是一个最小的可重现示例.如果您运行它并通过其标题栏拖动其中一个窗口,您会注意到OnNcHitTest"不会显示到调试控制台,即使正在处理 WM_WINDOWPOSCHANGED 并且正在调用 WindowFromPoint.

Here is a minimal reproducible example. If you run this and drag one of the windows by its title bar, you'll notice that "OnNcHitTest" is not displayed to the debug console, even though WM_WINDOWPOSCHANGED is being handled and WindowFromPoint is being called.

#include <windows.h>
#include <atlbase.h>
#include <atlwin.h>
#include <atltypes.h>

using namespace ATL;

class CMyWindow :
    public CWindowImpl<CMyWindow, CWindow, CWinTraits<WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME, WS_EX_TOOLWINDOW>>
{
public:
    CMyWindow() : m_fDragging(FALSE)
    {
    }

BEGIN_MSG_MAP(CMyWindow)
    MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, OnWindowPosChanged)
    MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
    MESSAGE_HANDLER(WM_EXITSIZEMOVE, OnExitSizeMove)
    MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand)
    COMMAND_HANDLER(IDCANCEL, BN_CLICKED, OnClickedCancel)
END_MSG_MAP()

private:
    LRESULT OnSysCommand(UINT, WPARAM wParam, LPARAM, BOOL& bHandled)
    {
        bHandled = FALSE;

        if ((wParam & 0xFFF0) == SC_MOVE)
        {
            m_fDragging = TRUE;
            ATLTRACE(L"\nDrag begin\n");
        }
            
        return 0;
    }

    LRESULT OnExitSizeMove(UINT, WPARAM, LPARAM, BOOL& bHandled)
    {
        bHandled = FALSE;
        
        m_fDragging = FALSE;
        ATLTRACE(L"\nDrag end\n");
        
        return 0;
    }

    LRESULT OnNcHitTest(UINT, WPARAM, LPARAM, BOOL& bHandled)
    {
        ATLTRACE(L"\nOnNcHitTest\n");
        
        if (m_fDragging)
            return HTTRANSPARENT;

        bHandled = FALSE;
        return 0;
    }

    LRESULT OnWindowPosChanged(UINT, WPARAM, LPARAM, BOOL& bHandled)
    {
        ATLTRACE(L"\nOnWindowPosChanged\n");
        
        bHandled = FALSE;

        if (m_fDragging)
        {
            CPoint pt;
            if (GetCursorPos(&pt))
            {
                ATLTRACE(L"\nCalling WindowFromPoint\n");
                HWND hwndFromPoint = WindowFromPoint(pt);
            }
        }

        return 0;
    }

    LRESULT OnClickedCancel(WORD, WORD, HWND, BOOL&)
    {
        DestroyWindow();
        return 0;
    }

    void OnFinalMessage(HWND)
    {
        delete this;
    }

    BOOL m_fDragging;
};

INT APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, INT)
{
    for (UINT i = 0; i < 3; ++i)
    {
        CMyWindow* pwnd = new CMyWindow();
        if (pwnd)
        {
            CRect rc(0, 0, 500, 500);
            if (pwnd->Create(NULL, &rc))
            {
                pwnd->CenterWindow(NULL);
                pwnd->ShowWindow(SW_SHOW);
            }
        }
    }

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

    return (INT)msg.wParam;
}

谁能解释一下我做错了什么?这是否与移动/大小模态循环有关?我不认为这是问题所在,因为只要 WM_WINDOWPOSCHANGED 被触发并且 WindowFromPoint 被调用,那么我认为 WM_NCHITTEST 会被发送.但也许我错了.

Can anyone explain what I'm doing wrong? Does this have to do with the move/size modal loop or something? I wouldn't think that's the problem, because as long as WM_WINDOWPOSCHANGED is being triggered and WindowFromPoint is being called, then I would think WM_NCHITTEST would be sent. But maybe I'm wrong.

或者问题是否与鼠标位于非客户区有关?

Or does the issue have to do with the mouse being in a non-client area perhaps?

感谢您的帮助.

推荐答案

我最终放弃了 WM_NCHITTEST 处理程序,而是实现了自定义的 WindowFromPoint 方法,如下所示:

I wound up ditching the WM_NCHITTEST handler and instead implementing a custom WindowFromPoint method, like this:

HWND CMyWindow::WindowFromPoint(LPPOINT ppt)
{
    for (CWindow wnd = GetWindow(GW_HWNDNEXT); wnd.IsWindow() && wnd.GetWindowThreadID() == GetCurrentThreadId(); wnd = wnd.GetWindow(GW_HWNDNEXT))
    {
        if (wnd.SendMessage(WM_NCHITTEST, NULL, MAKELPARAM(ppt->x, ppt->y)) == HTCLIENT)
            return wnd;
    }

    return NULL;
}

它可能需要改进,但就目前而言,它似乎可以解决问题.

It may need to be refined, but for the time being, it seems to do the trick.

这篇关于当窗口被拖动时,WindowFromPoint 不会触发 WM_NCHITTEST的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆