跟踪开放的子对话

时间:2017-06-12 12:07:26

标签: c++ winapi parent-child c++builder-xe2 window-messages

在C ++程序(embarcadero XE2,vcl)中,我想从父窗口向所有子窗口发送窗口消息。 为此,我注册了一个windowMessage,在所有句柄的循环中发送带有PostMessage(handle,msg,wparam,lparam)的消息,并在WndProc(TMessage& Message)的每个对话框中接收它。

我的问题是跟踪打开的窗口句柄。由于大多数对话框都是通过Show()打开的,因此其中多个对话框可以同时运行。

到目前为止,我使用std::vector<HWND>来存储Window-Handles。但是,这需要我跟踪哪个句柄一次仍然有效。 我可以通过在对话框中添加onClose处理程序并使用对话框的句柄作为参数调用主线程中的过程来解决这个问题,因此可以从向量中删除...

是否有更好的解决方案,如Application.OpenForms(.NET)中的自更新列表?或者也许是从主对话框中通知子事件的更好方法?

2 个答案:

答案 0 :(得分:4)

窗口已经在内部跟踪其子项,因此您只需要点击它。如果你想向所有窗口的子窗口发送消息,那么你只需要递归遍历所有窗口的子窗口,并将消息发送给每个窗口。

起点是GetTopWindow function,它返回Z顺序顶部的子窗口。然后,通过调用GetNextWindow function迭代子窗口。

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,则该邮件将仅发布给其直接子女。

答案 1 :(得分:0)

Cody Gray为我提出的问题提供了正确的解决方案。

但是,如评论中所示,我提出了错误的问题。

我的对话框是由Owl TForms打开的vcl 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
}

因此,结果可能是儿童和拥有对话的混合。

对于我来说,将Window Messages发送到从主窗口打开的所有对话框是有用的:

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迭代所有应用程序中的所有窗口。
  • 为了确保只获取我自己的应用程序窗口的句柄,我使用变量msgCheck来存储顶层句柄和我想要发送的消息。
  • 现在我使用GetParent检索所有者或父,如果找不到则返回NULL。
  • 在回调函数中,将存储的顶层句柄与找到的窗口的顶层句柄进行比较,如果它们匹配,则将窗口消息发送到找到的窗口的句柄