Tracking open child dialogs

In a C ++ program (embarcadero XE2, vcl), I would like to send window messages from parent to all child windows. To do this, I registered windowMessage, sent a message with PostMessage(handle,msg,wparam,lparam)

in a loop for all handles, and received it in every dialog with WndProc(TMessage& Message)

.

My problem is keeping track of open window handles. Since most dialogs open through Show()

, several of them can be launched at the same time.

So far I have used std::vector<HWND>

to store window handles. However, this would require me to keep track of which descriptor is still valid at the same time. I could solve this by adding a handler onClose

to the dialogs and calling the procedure on the main thread using the dialog handle as a parameter, so it can be removed from the vector ...

Is there a nicer solution like a self-refresh list like in Application.OpenForms

(.NET)? Or maybe a better way to notify the child dialog of an event from the main dialog?

+3


source to share


2 answers


The window is already keeping track of its children inside, so you just have to use that. If you want to send a message to all window child windows, you just need to recursively iterate over all the child windows of that window, sending a message to each of them.

The starting point is GetTopWindow

function
, which returns a child window at the top of the Z-order. Then you iterate over the child windows by calling the function GetNextWindow

.

MFC actually includes a method that does this, called SendMessageToDescendants

. You can write the equivalent yourself and replace SendMessage

with PostMessage

if you prefer these 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 function PostMessage

except the last: bRecursive

. This parameter only means what its name suggests. If TRUE

, the search for child windows will be recursive so that the message is sent to all descendants of the parent window (its children, child children, etc.). If FALSE

, the message will be published only to his immediate children.

+3


source


Cody Gray gave the correct solution to the question I asked.

However, as shown in the comments, I asked the wrong question.

My dialogs were vcl TForms

which were opened by Owl TWindow

, which means I am using the ParentWindow property of the dialogs to get the modal view:

__fastcall TMyDialog::MyDialog(owl::TWindow* Owner) :TForm(HWND(NULL)){
    tf = new TForm(Owner->Handle); //TForm*, Mainwindow calls this dialog
    tf->ParentWindow = Owner->Handle; // workaround: owl calls vcl
    this->PopupParent = tf; // workaround: owl calls vcl
}

      



So the result is most likely a mixture of children and owned dialogues.

What worked for me to get Window messages in all dialogs that were opened from the main window was this:

struct checkMSG{
    HWND handle; UINT msg; WPARAM wparam; LPARAM lparam;
};
checkMSG msgCheck;

BOOL CALLBACK enumWindowsProc(__in  HWND hWnd,__in  LPARAM lParam) {
     HWND owner= ::GetParent(hWnd);
     if(owner==msgCheck.handle)
        ::PostMessage(hWnd, msgCheck.msg, msgCheck.wparam, msgCheck.lparam);
     return TRUE;
}

void SendToAllWindows(HWND handle, UINT msg, WPARAM wparam, LPARAM lparam){
    msgCheck.handle=::GetParent(handle);
    msgCheck.msg=msg;
    msgCheck.wparam= wparam;
    msgCheck.lparam= lparam;
    BOOL enumeratingWindowsSucceeded = ::EnumWindows( enumWindowsProc, NULL );
}

      

  • EnumWindows iterates over all windows in all applications.
  • To get just my own application window handles, I used a variable msgCheck

    to store the top-level handle and the message I want to send.
  • Now I am using GetParent

    which returns owner or parent or returns NULL if not found.
  • In the callback function, the stored top-level descriptor is compared with the top-level descriptor of the found window and, if they match, the window message is sent to the found window's descriptor
0


source







All Articles