Question

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

Was it helpful?

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.

OTHER TIPS

in your edit window proc you need to call some appropriate default message handling.

such as the original window proc.

the easiest way to do this, at the abstraction level of your code, is to instead use SetWindowSubclass to do the subclassing

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top