c++winapisubclassingeditboxedit-control

Edit control cannot get focus or set text after subclassing


I had created an editbox and it was working just fine but after I added a custom WndProc for it, the text "my edit" is not visible and won't take focus when clicked.

HWND handle=CreateWindowExW(0,L"Edit",L"my edit",WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_CENTER | ES_MULTILINE | ES_AUTOVSCROLL,
                         0,0,200,200,window.handle,0,GetModuleHandle(NULL),0);

Until here it was working just fine
After I set this window procedure, the edit control is not working anymore as expected

SetWindowLongPtr(handle,GWLP_WNDPROC,(LRESULT)staticWndProc); 
LRESULT CALLBACK staticWndProc(HWND handle, UINT uMsg, WPARAM wParam, LPARAM lParam){
    switch (uMsg){
        case WM_LBUTTONDOWN:
            std::wcout << handle << L" click\n"; //click event works
            break;
        default:
            return DefWindowProcW(handle,uMsg,wParam,lParam);
    }
    return 0;  
}

Do I have to handle manually some event or change my construction style flags?


Solution

  • Sub-classing involves intercepting messages for a window, possibly handling some of them, and passing those you don't handle to the original window procedure.

    You're not doing that - you're passing everything you don't handle through to DefWindowProc. DefWindowProc doesn't have any of the specialised behaviour for an edit control (or indeed for any type of control). So you've effectively turned an edit control into a generic window.

    Using SetWindowLongPtr to sub-class a window is discouraged these days, but if you do use that method, the return value from the call to SetWindowLongPtr gives you the old window procedure, and you're meant to use the CallWndProc function instead of DefWindowProc to call it.

    However, the modern way to subclass a window is using the SetWindowSubclass function, which handles calling the original proc for you - all you need to do is call the DefSubclassProc function, as shown here:

    LRESULT CALLBACK staticWndProc(HWND handle, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR, DWORD_PTR){
        switch (uMsg){
            case WM_LBUTTONDOWN:
                std::wcout << handle << L" click\n"; //click event works
                break;
            case WM_NCDESTROY:
                RemoveWindowSubclass(handle, staticWndProc, 0);
                // fall through
            default:
                return DefSubclassProc(handle,uMsg,wParam,lParam);
        }
        return 0;  
    }
    
    SetWindowSubclass(handle, staticWndProc, 0, 0);
    

    Note that the subclass function shown above removes itself when WM_NCDESTROY is received.