c++winapiparent-childc++builder-xe2window-messages

Keeping track of open child dialogs


In a C++ program (embarcadero XE2, vcl) I would like to send window-messages from parent to all child windows. For this, I registered a windowMessage, send the message with PostMessage(handle,msg,wparam,lparam) in a loop for all handles and receive it on each dialog with WndProc(TMessage& Message).

My problem is to keep track of the open window handles. Since most dialogs are opened via Show(), multiple of them can run at the same time.

So far I used a std::vector<HWND> to store the Window-Handles. However, this would require me to keep track of which handle is still valid at a time. I could solve this by adding a onClose Handler to the dialogs and call a procedure in the main thread with the dialog's handle as a parameter, so it can be removed from the vector...

Is there a nicer solution, like a self-updating list as in Application.OpenForms (.NET)? Or maybe a better way to notify child-dialog of an event from the main dialog?


Solution

  • A window already tracks its children internally, so you just need to tap into that. If you want to send a message to all of a window's child windows, then you just need to recursively iterate through all of that window's children, sending the message to each one.

    The starting point is the GetTopWindow function, which returns the child window at the top of the Z order. Then, you iterate through the child windows by calling the GetNextWindow function.

    MFC actually includes a method that does this, called SendMessageToDescendants. You can write the equivalent yourself, and replace SendMessage with PostMessage, if you'd prefer those semantics.

    void PostMessageToDescendants(HWND   hwndParent,
                                  UINT   uMsg,
                                  WPARAM wParam,
                                  LPARAM lParam,
                                  BOOL   bRecursive)
    {
       // Walk through all child windows of the specified parent.
       for (HWND hwndChild = GetTopWindow(hwndParent);
            hwndChild     != NULL;
            hwndChild      = GetNextWindow(hwndChild, GW_HWNDNEXT))
       {
          // Post the message to this window.
          PostMessage(hwndChild, uMsg, wParam, lParam);
    
          // Then, if necessary, call this function recursively to post the message
          // to all levels of descendant windows.
          if (bRecursive && (GetTopWindow(hwndChild) != NULL))
          {
             PostMessageToDescendants(hwndChild, uMsg, wParam, lParam, bRecursive);
          }
       }
    }
    

    The arguments are the same as the PostMessage function, except for the last one: bRecursive. This parameter means just what its name suggests. If TRUE, the search of child windows will be recursive, so that the message will be posted to all descendants of the parent window (its children, its children's children, etc.). If FALSE, the message will be posted only to its immediate children.