为什么 SC_HSCROLL 和 SC_VSCROLL 似乎在 WM_SYSCOMMAND 中切换了?

Why are SC_HSCROLL and SC_VSCROLL seem to be switched in WM_SYSCOMMAND?

我知道这是一个非常古老的东西,但我正在为它绞尽脑汁。有谁知道为什么会这样?

说,当滚动条鼠标点击通知通过 WM_NCHITTEST -> WM_NCLBUTTONDOWN -> WM_SYSCOMMAND -> WM_HSCROLLWM_VSCROLL 传播时,所有此链中的参数似乎遵循文档,除了 SC_HSCROLLSC_VSCROLL 用于 WM_SYSCOMMAND。所以如果我这样做:

//From within WndProc
if(message == WM_SYSCOMMAND)
{
    UINT uiCmd = wParam & 0xFFF0;
    if(uiCmd == SC_HSCROLL)
    {
        TRACE(L"Horiz scroll\n");
    }
    else if(uiCmd == SC_VSCROLL)
    {
        TRACE(L"Vertical scroll\n");
    }
}

我似乎收到水平方向的垂直通知,反之亦然。

这是来自 Spy++ 的证据。如果我点击这个向下箭头:

这些是 window 收到的通知:

除了 SC_HSCROLL 之外,其他都正确。 WTF?

如果在调试器下查找 __int64 OnDwpNcLButtonDown(CThhemeWnd*, THEME_MSG*) 可见下一个代码:

wParam = HTVSCROLL != HitTest ? SC_VSCROLL : SC_HSCROLL;
SendMessage(*, WM_SYSCOMMAND, (wParam | HitTest), *)

WM_SYSCOMMANDSC_VSCROLLSC_HSCROLL 从此处发送,但明显的代码包含逻辑错误 - SC_VSCROLLSC_HSCROLL 混淆。

正确的代码必须是

wParam = HTVSCROLL == HitTest ? SC_VSCROLL : SC_HSCROLL;

还有

In WM_SYSCOMMAND messages, the four low-order bits of the wParam parameter are used internally by the system. To obtain the correct result when testing the value of wParam, an application must combine the value 0xFFF0 with the wParam value by using the bitwise AND operator.

这里可见,我们从 WM_NCLBUTTONDOWN message, which is from WM_NCHITTEST 消息 return

中命中了测试代码的四个低位

0xf087 - 这是 SC_HSCROLL | HTVSCROLL ,在 hscroll 上我们得到 0xf076SC_VSCROLL | HTHSCROLL

这只是 windows uxtheme.OnDwpNcLButtonDown

中的错误