В программе на C ++ (embarcadero XE2, vcl) я хотел бы отправлять оконные сообщения от родителя всем дочерним окнам.
Для этого я зарегистрировал окно сообщения, отправив сообщение с PostMessage(handle,msg,wparam,lparam)
в цикле для всех дескрипторов и получать его в каждом диалоге с WndProc(TMessage& Message)
,
Моя проблема состоит в том, чтобы следить за ручками открытого окна. Поскольку большинство диалогов открывается через Show()
Несколько из них могут работать одновременно.
До сих пор я использовал std::vector<HWND>
хранить оконные ручки Тем не менее, это потребовало бы от меня отслеживания, какой дескриптор все еще действителен одновременно.
Я мог бы решить это, добавив onClose
Обработчик диалогов и вызов процедуры в главном потоке с дескриптором диалога в качестве параметра, чтобы его можно было удалить из вектора …
Есть ли более приятное решение, например, самообновляющийся список, как в Application.OpenForms
(.СЕТЬ)? Или, может быть, лучший способ уведомить дочерний диалог о событии из основного диалога?
Окно уже отслеживает своих детей внутри, так что вам просто нужно подключиться к этому. Если вы хотите отправить сообщение всем дочерним окнам окна, вам просто нужно рекурсивно перебрать все дочерние окна этого окна, отправив сообщение каждому из них.
Отправной точкой является GetTopWindow
функция, который возвращает дочернее окно в верхней части Z-порядка. Затем вы перебираете дочерние окна, вызывая GetNextWindow
функция.
MFC на самом деле включает в себя метод, который делает это, называется SendMessageToDescendants
, Вы можете написать эквивалент самостоятельно и заменить SendMessage
с PostMessage
, если вы предпочитаете эту семантику.
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);
}
}
}
Аргументы такие же, как PostMessage
функция, кроме последней: bRecursive
, Этот параметр означает только то, что предполагает его название. Если TRUE
поиск дочерних окон будет рекурсивный, чтобы сообщение было отправлено всем потомкам родительского окна (его дочерним элементам, дочерним элементам и т. д.). Если FALSE
сообщение будет отправлено только его непосредственным детям.
Коди Грей дал правильное решение вопроса, который я задал.
Однако, как показано в комментариях, я задал не тот вопрос.
Мои диалоги были vcl TForms
которые были открыты Совой TWindow
, что означает, что я использую свойство ParentWindow диалоговых окон, чтобы получить модальное появление:
__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
}
Таким образом, результатом, вероятно, является сочетание дочерних и собственных диалогов.
Что помогло мне получить сообщения окна во всех диалоговых окнах, которые были открыты из главного окна, было так:
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 );
}
msgCheck
хранить дескриптор верхнего уровня и сообщение, которое я хочу отправить. GetParent
который извлекает Владелец или Родитель или возвращает NULL, если ничего не найдено.