WM_VSCROLL / WM_HSCROLL 来自 TrackBar 的消息未发送到子类 MessageHandler。为什么?

WM_VSCROLL / WM_HSCROLL message from TrackBar is not sent to the subclassed MessageHandler. Why?

我有一个疯狂的问题。我对按钮、richedits、复选框进行了子类化,.. 一切似乎都工作正常。但是在我对 trackbar 进行子类化之后,我现在遇到了一些麻烦。问题是我的子类消息处理程序没有收到 WM_VSCROLL / WM_HSCROLL 消息。它们仍然被发送到父级的消息处理程序。 WM_PAINT 消息和其他一些消息已成功发送到子类消息处理程序。 有人知道我做错了什么吗? ......也许知道如何解决这个问题?我使用以下所需代码创建了一个干净的项目:

#include <windows.h>
#include <CommCtrl.h>
#pragma comment(lib,"comctl32.lib")

//Prototyps
HWND CreateMainWindow(HINSTANCE hInstance);
LRESULT CALLBACK MessageHandler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
LRESULT CALLBACK SubMessageHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
WNDPROC oldWndProc;
HWND hWnd = 0;
HWND hTrackBar = 0;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){        
    WNDCLASSEXA wndClass = {sizeof(WNDCLASSEX), CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW, MessageHandler, 0,0, hInstance, LoadIcon(NULL, IDI_WINLOGO),
                            LoadCursor(NULL, IDC_ARROW),(HBRUSH)GetStockObject(WHITE_BRUSH), NULL, "WindowClass", LoadIcon(NULL, IDI_WINLOGO)};
    RegisterClassExA(&wndClass);
    //Creat MainWindow
    hWnd = CreateWindowExA(NULL, "WindowClass", "Test Windows", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,             
                            100, 100, 400, 300, NULL, NULL, hInstance, NULL);              
    //Creat Trackbar
    INITCOMMONCONTROLSEX initCtrlEx;
    initCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
    initCtrlEx.dwICC = ICC_BAR_CLASSES;
    if (InitCommonControlsEx(&initCtrlEx)){
        hTrackBar = CreateWindowExA(NULL,TRACKBAR_CLASSA, "TrackBar_Test",  WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | TBS_AUTOTICKS | 
                                    TBS_ENABLESELRANGE | TBS_VERT | TBS_BOTH, 10, 10, 50, 200, hWnd, NULL, hInstance, NULL); 
        oldWndProc = (WNDPROC)SetWindowLongPtrA(hTrackBar, GWLP_WNDPROC, (LONG_PTR)SubMessageHandler);  //Subclassing messagehandler
    }
    //Message loop
    MSG msg;
    while (GetMessageA(&msg, NULL, 0, 0))   {   
        TranslateMessage(&msg);
        DispatchMessageA(&msg);
    }
    return 0;
}

LRESULT CALLBACK SubMessageHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
    switch (msg){
        case WM_VSCROLL: //callback is subclassed but WM_VSCROLL is not send. why?
            MessageBoxA(hWnd, "WM_VSCROLL sent (to SubMessageHandler)", "Test", MB_OK);
            break;
    }
    if (oldWndProc != 0)
        return CallWindowProcA(oldWndProc, hwnd, msg, wParam, lParam);
    else
        return DefWindowProcA(hwnd, msg, wParam, lParam);
}

LRESULT CALLBACK MessageHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
    switch (msg){       
        case WM_VSCROLL:  //Why the hell is the Trackbar WM_VSCROLL still sent here to the parent callback!?!?
            MessageBoxA(hWnd, "WM_VSCROLL sent (to Parent)", "Test", MB_OK);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
            break;
    }   
    return DefWindowProcA(hwnd, msg, wParam, lParam);
}

来自 the MSDN documentation on Trackbar controls:

A trackbar notifies its parent window of user actions by sending the parent a WM_HSCROLL or WM_VSCROLL message.

Trackbar 的合同是用 WM_HSCROLL/WM_VSCROLL 通知父级 window。 Trackbar 控件生成并发送 这些消息;它不接收它们。

另请注意,Default Trackbar Message Processing section 未列出 WM_HSCROLL/WM_VSCROLL(但列出了 WM_LBUTTONDOWNWM_MOUSEMOVEWM_LBUTTONUPWM_KEYDOWNWM_KEYUP,这是处理交互所需处理的原始消息)。

至于怎么办,这可能完全取决于你想做什么。您可以尝试子类化并拦截所有用户输入消息,但这似乎需要大量工作并且可能很脆弱。我的建议是让父级 window 明确反映 WM_HSCROLL/WM_VSCROLL 回到您的自定义 Trackbar 控件。