4

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

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

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

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

4

2 回答 2

4

一个窗口已经在内部跟踪它的孩子,所以你只需要利用它。如果您想向一个窗口的所有子窗口发送消息,那么您只需要递归地遍历该窗口的所有子窗口,将消息发送给每个子窗口。

起点是GetTopWindow函数,它返回 Z 顺序顶部的子窗口。GetNextWindow然后,您通过调用函数遍历子窗口。

MFC 实际上包含一个执行此操作的方法,称为SendMessageToDescendants. 如果您更喜欢这些语义,您可以自己编写等价物,并用 替换SendMessagePostMessage

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,则该消息将仅发布给其直系子级。

于 2017-06-12T12:21:20.493 回答
0

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

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

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

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

对我来说,从主窗口打开的所有对话框中获取窗口消息的方法是:

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来存储顶层句柄和我想要发送的消息。
  • 现在我使用GetParentwhich 检索Owner 或 Parent或者如果两者都没有找到则返回 NULL。
  • 在回调函数中,将存储的顶级句柄与找到的窗口的顶级句柄进行比较,如果它们匹配,则将窗口消息发送到找到的窗口的句柄
于 2017-06-12T15:05:03.767 回答