c++windowswinapiwndproccreatewindowex

Specifying a Window Procedure for child Windows


I would like to know if its possible to specify a WndProc for a Child Window created by CreateWindowEx.

I have created a Window Class, the Main Window, the Window Procedure and a Message Loop already. The code works and I decided to keep it out for the clarity of my question.

This is my Window Proc, so far:

LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        // Creation of the Win32 Window
        case WM_CREATE:
            // Add an Edit Field
            CreateWindowEx(
                WS_EX_CLIENTEDGE,
                "EDIT",
                "",
                WS_CHILD | WS_VISIBLE,
                5, 5, 200, 24,
                hwnd,
                (HMENU)100,
                g_Instance, // Comming from WinMain
                NULL
            );
            return DefWindowProc(hwnd, uMsg, lParam, wParam);
        case WM_KEYDOWN:
            // Track key presses on the edit field
            std::cout << "The key with the code " << wParam << " was pressed." << std::endl;
            return 0;
        case WM_PAINT:
            // Some painting code...
            return DefWindowProc(hwnd, uMsg, lParam, wParam);
        default:
            return DefWindowProc(hwnd, uMsg, lParam, wParam);
    }
}

I expected key presses on the child Edit Field that I created to throw a WM_KEYDOWN message, but they dont! The keys just get added to the Edit Field in my Window but do not cause a WM_KEYDOWN message.

It seems that the created Edit Window does not use my WndProc. How can I change that?


Solution

  • Your WndProc don't get WM_KEYDOWN messages because, if the user is typing inside the edit control, it means that it has the focus (not your window), so they are sent to the edit control window proc, not yours. However, the edit control window proc will send notifications to your WndProc (his parent window proc).

    So, if you only want to react to the user changing the content of your child edit control, you don't need another window procedure. Your current WndProc will receive EN_CHANGE notification code through a WM_COMMAND message.

    See https://msdn.microsoft.com/en-us/library/windows/desktop/bb761676(v=vs.85).aspx


    If you really want to catch WM_KEYDOWN messages, you need to subclass the edit control, like this:

    OldWndProc = (WNDPROC)SetWindowLongPtr (hButton, GWLP_WNDPROC, (LONG_PTR)NewWndProc);
    

    You also need to define a new windows procedure (the NewWndProc), that should handle WM_KEYDOWN message (and any other message you want to handle). You also need to call OldWndProc as you would call DefWndProc in a standard WndProc, unless you want to prevent the edit control to do its normal processing.

    For details on subclassing, see https://msdn.microsoft.com/en-us/library/windows/desktop/bb773183(v=vs.85).aspx

    Edit

    Responding to OP comment here.

    If your window is a dialog box, you should be notified of enter key, in your WndProc:

     case WM_COMMAND:
    
          if(wParam == IDOFDEFBUTTON || wParam == IDOK) ...
    

    See https://support2.microsoft.com/Default.aspx?scid=kb;en-us;Q102589

    To be honest, I never took the time to understand what a dialog box really is. But if I recall correctly, you can get your window to get theses special notifications by calling IsDialogMessage in your message pump:

    if(!IsDialogMessage(hWnd,&msg)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
     }
    

    For interesting information about IsDialogMessage, see http://blogs.msdn.com/b/oldnewthing/archive/2012/04/16/10293933.aspx

    If this doesn't give you enough control, you probably have to subclass the edit control.