Search code examples
c++winapicontrolseditsubclassing

Window is empty when sub-classing EDIT control in C++ WINAPI


I have an EDIT control which I try to subclass and when I do so the entire window is empty:

// Global variables
HINSTANCE hInst;
WNDPROC oldEditWndProc;
INT_PTR CALLBACK EditWndProc(HWND, UINT, WPARAM, LPARAM);

// Messages handler of the parent window
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    HDC hDC;
    HWND myedit;

    switch (message)
    {
    case WM_CREATE:
        // Create the EDIT control
        myedit= CreateWindowEx(
                               WS_EX_CLIENTEDGE|WS_EX_CONTROLPARENT, 
                               L"EDIT", 
                               L"",
                               WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_LEFT, 
                               20, 120, 
                               160, 20, 
                               hWnd, 
                               NULL, 
                               hInst, 
                               NULL
                              );
        oldEditWndProc = (WNDPROC)GetWindowLongPtr (myedit, GWLP_WNDPROC);
        // This is the line where problems begin
        SetWindowLongPtr (myedit, GWLP_WNDPROC, (LONG_PTR)EditWndProc);
        break;
    case WM_PAINT:
        hDC = BeginPaint(hWnd, &ps);
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// EDIT control own handler
INT_PTR CALLBACK EditWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_GETDLGCODE:
            return DLGC_WANTTAB;
            break;
    }
    return (INT_PTR)FALSE;
}

I just can't figure out why the entire window is empty when calling SetWindowLongPtr


Solution

  • By "empty" you mean it's not showing on screen?

    If yes, it's because when you subclass a Window, all it's messages will be sent to the new MessageProc, which doesn't have all the functions to properly show it in it's defaultProc function (such as WM_PAINT, or even a button click).

    So you need something like this:

    //store the old window proc somewhere
    WNDPROC oldWindowProc = (WNDPROC)SetWindowLong(subWindowHandle, GWL_WNDPROC, long(NewMessageProc));
    
    //and in the message proc
    switch(uMsg)
    {
        //your "case"s here
        default:
        {
            CallWindowProc(oldWindowProc, windowHandle, uMsg, wParam, lParam);
        }
    }
    

    This will call the proper WM_PAINT and other messages to the messageProc that is responsible for drawing and clicking and other functions (the DefWindowProc() of the subclassed window).

    Alternatively you can also just implement the WM_PAINT in your NewMessageProc for all your subclassed windows, but without calling their DefWindowProc you'll need to do for every event they might receive (mousemove, mouse clicks, button clicks, everything), so using their original DefWindowProc is easier.