在C++程序(embarcadero XE2,vcl)中,我想将窗口消息从父窗口发送到所有子窗口。 为此,我注册了一个 windowMessage,在所有句柄的循环中发送带有PostMessage(handle,msg,wparam,lparam)
的消息,并在每个带有WndProc(TMessage& Message)
的对话框中接收它。
我的问题是跟踪打开的窗口句柄。由于大多数对话框都是通过Show()
打开的,因此可以同时运行多个对话框。
到目前为止,我使用std::vector<HWND>
来存储窗口句柄。但是,这需要我一次跟踪哪个句柄仍然有效。 我可以通过向对话框添加一个onClose
处理程序并在主线程中调用一个过程来解决这个问题,并将对话框的句柄作为参数,因此可以从向量中删除它......
是否有更好的解决方案,例如Application.OpenForms
(.NET) 中的自我更新列表?或者也许是从主对话通知子对话事件更好的方法?
窗口已经在内部跟踪其子窗口,因此您只需要利用它即可。如果要将消息发送到窗口的所有子窗口,则只需递归遍历该窗口的所有子窗口,并将消息发送到每个子窗口。
起点是GetTopWindow
函数,该函数返回位于 Z 顺序顶部的子窗口。然后,通过调用GetNextWindow
函数循环访问子窗口。
MFC 实际上包括一个执行此操作的方法,称为SendMessageToDescendants
。您可以自己编写等效的语义,并用PostMessage
替换SendMessage
,如果您更喜欢这些语义。
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
,则消息将仅发布到其直接子级。
Cody Gray 为我提出的问题给出了正确的解决方案。
但是,如评论所示,我问错了问题。
我的对话框是 vclTForms
由 OwlTWindow
打开的,这意味着我使用对话框的 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
来存储顶级句柄和我要发送的消息。 - 现在我使用
GetParent
它检索所有者或父级,或者在都找不到时返回 NULL。
在回调函数中,将存储的顶级句柄与找到的窗口的顶级句柄 - 进行比较,如果它们匹配,则窗口消息将发送到找到的窗口的句柄