更改 window 的 WndProc

Change WndProc of the window

我尝试更改标准 WndProc 函数。我有这个代码:

HWND btn = CreateWindowEx(WS_EX_TRANSPARENT | WS_EX_CLIENTEDGE, L"BUTTON", L"Window title", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON
    , 50, 50, 50, 50, (HWND)XApplicationMainWindow->window->_wnd, (HMENU)123,
    (HINSTANCE)GetWindowLongPtr(XApplicationMainWindow->window->_wnd, GWLP_HINSTANCE), NULL);

SetWindowLongPtrW(btn, GWLP_WNDPROC, (LONG_PTR)SubclassWindowProc);

我可以使用 L"BUTTON" class 名称,但是当我更改 WndProc 功能时我会遇到问题。

在这张图片上,你可以看到空白的方块和普通的按钮。如果我尝试创建新的 WNDCLASS or WNDCLASSEX,我将一无所有...为什么?

如果我使用 L"BUTTON" class 名称,如何更改标准 WndProc 函数?

这是我的第二个WndProc:

LRESULT CALLBACK SubclassWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_CREATE:
        break;
    case WM_COMMAND:

        //Event click
        switch (LOWORD(wParam))
        {
        case 123:
            OutputDebugStringA("Subclass click2");
            break;
        default:
            break;
        }

        break;
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}

DefWindowProc() 是您 SubclassWindowProc() 调用的错误 window 程序。

您需要调用要替换的 previous window 过程 - window 过程处理按钮的所有默认行为(如绘图按钮,所以它实际上看起来像一个按钮,并像按钮一样响应用户输入,等等)。 SetWindowLongPtr() returns 向您提供指向该过程的指针,但您目前正在忽略它。

有关详细信息,请参阅 MSDN 上的 Subclassing Controls

试试这个:

WNDPROC btnWndProc;

LRESULT CALLBACK SubclassWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_COMMAND:
            //Event click
            switch (LOWORD(wParam))
            {
                case 123:
                    OutputDebugStringA("Subclass click2");
                    break;
            }

            break;
    }

    return CallWindowProc(hWnd, btnWndProc, uMsg, wParam, lParam);
}

...

HWND btn = CreateWindowEx(...);

btnWndProc = (WNDPROC) SetWindowLongPtrW(btn, GWLP_WNDPROC, (LONG_PTR)SubclassWindowProc);

或者,使用SetWindowSubclass(), which is safer than using SetWindowsLongPtr(),例如:

LRESULT CALLBACK SubclassWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {
    switch (uMsg) {
        case WM_NCDESTROY:
            RemoveWindowSubclass(hWnd, SubclassWindowProc, uIdSubclass);
            break;

        case WM_COMMAND:
            //Event click
            switch (LOWORD(wParam))
            {
                case 123:
                    OutputDebugStringA("Subclass click2");
                    break;
            }

            break;
    }

    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

...

HWND btn = CreateWindowEx(...);

SetWindowSubclass(btn, SubclassWindowProc, 1, 0);

话虽如此,您的子类永远不会调用 OutputDebugStringA(),因为它永远不会收到您期望的 WM_COMMAND 消息。单击按钮时,不会向按钮本身发送 WM_COMMAND 消息。该按钮将 WM_COMMAND 消息发送到按钮的 父级 window(在本例中为 XApplicationMainWindow->window->_wnd)。因此,您需要在 parent window 的 window 过程中处理 WM_COMMAND 消息,而不是在 window 的 window 过程中按钮本身。

否则,如果您仍想子类化按钮本身,则必须处理按钮接收到的 WM_LBUTTON(DOWN|UP)WM_KEY(DOWN|UP)/WM_CHAR 消息,然后将其转换为一个 WM_COMMAND 消息给它的父 window.