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?
source to share
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.
source to share
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
source to share