Изменить WndProc окна

Я пытаюсь изменить стандартную функцию 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", но когда я изменю функцию WndProc, у меня возникнут проблемы.введите здесь описание изображения

На этой картинке вы видите пустой квадрат и обычную кнопку. Если я попытаюсь создать новый WNDCLASS or WNDCLASSEX, у меня ничего не будет... Почему?

Как я могу изменить стандартную функцию WndProc, если я использую имя класса L"BUTTON"?

Это мой второй 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;
}

person lostsky25    schedule 28.07.2020    source источник
comment
сначала вам нужен кал не DefWindowProc а предыдущий wndproc, который вернул SetWindowLongPtrW, затем вам нужно передать ему все сообщения, которые вы не обрабатываете специально, WM_CREATE например. и напоследок - для чего вообще менять кнопку proc   -  person RbMm    schedule 29.07.2020
comment
Управление подклассами.   -  person IInspectable    schedule 29.07.2020
comment


Ответы (1)


DefWindowProc() - это неправильная оконная процедура, которую должен вызывать ваш SubclassWindowProc().

Вам нужно вызвать предыдущую оконную процедуру, которую вы заменяете — оконную процедуру, которая обрабатывает все действия кнопки по умолчанию (например, рисование кнопки, чтобы она действительно выглядела как кнопка, и реакция на ввод пользователя, например кнопка и др.). SetWindowLongPtr() возвращает вам указатель на эту процедуру, но в настоящее время вы его игнорируете.

Дополнительные сведения см. в разделе Подкласс элементов управления в MSDN.

Попробуйте это вместо этого:

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(), который безопаснее, чем использование 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 в родительское окно кнопки (в данном случае в XApplicationMainWindow->window->_wnd). Итак, вам нужно обрабатывать сообщение WM_COMMAND в оконной процедуре родительского окна, а не в оконной процедуре самой кнопки.

В противном случае, если вы все еще хотите создать подкласс самой кнопки, вам придется обрабатывать сообщения WM_LBUTTON(DOWN|UP) и WM_KEY(DOWN|UP)/WM_CHAR, которые кнопка получает, а затем преобразует в сообщение WM_COMMAND для своего родительского окна.

person Remy Lebeau    schedule 28.07.2020
comment
Я использовал DefSubclassProc() и WM_LBUTTONDOWN в SubclassWindowProc(). Это работает. - person lostsky25; 29.07.2020