Windows 消息广播器






4.52/5 (14投票s)
使用此类,您可以在无需知道窗口句柄的情况下将消息广播到窗口。您还可以同时将同一消息广播到多个窗口。
引言
在使用 MFC 开发文档/视图应用程序时,我经常发现需要将消息从一个视图或窗口发送到另一个窗口,而这些视图并不共享一个公共文档。例如,可以在一个视图中显示某个对象的属性,并在属性窗口中显示。正如任何尝试过这样做的人都知道,这涉及一个痛苦的过程:在创建时获取属性窗口的句柄,然后将其传递给所有需要使用该属性窗口的其他窗口。或者,您可以广播消息,任何人都可能告诉您 Microsoft Windows 没有有效的广播机制。我的 CBroadcaster
类可以轻松地处理消息广播。它还可以通过一次调用将同一消息发送到多个窗口。
工作原理
通过调用 CBroadcaster::InitBroadcaster();
来初始化 broadcaster
类。该方法目前什么都不做。它只是一个占位符,与 CBroadcaster::UninitBroadcaster()
配对。
注册接收
对接收广播消息感兴趣的窗口只需通过 CBroadcaster::Register(…)
向 broadcast
类注册自己。该方法允许一个窗口通过重复调用并传入新的 Message
值来注册多个消息。
注意:一个好的做法是在窗口类的析构函数中调用 CBroadcaster::Unregister(this)
。
发送消息
有两种发送消息的方法。一种方法允许调用者检查每个窗口处理过的消息的返回值,另一种方法则只将消息发送到所有已注册的窗口并忽略返回值。
为了检查每个发送/发布消息的返回值,调用者必须调用 CBoardcaster::StartSend
或 CBoardcaster::StartPost
来初始化发送/发布过程。然后,用户可以调用 CBoardcaster::SendNext
或 CBoardcaster::PostNext
来发送消息。当这些方法返回 true
时,表示找到了感兴趣于指定消息的窗口,并且消息已发送。返回 FALSE
表示收件人列表的结束。
要直接广播消息而不考虑返回值,请调用 CBroadcaster::SendToAll()
或 CBroadcaster::PostToAll()
。
清理。
在程序退出之前,不要忘记调用 CBroadcaster::UninitBroadCaster()
。由于这是一个 static
类,不需要实例化,因此析构函数不会被调用。该方法将在窗口未从 CBroadcaster
Unregister
自身的情况下进行所有必要的清理。
示例代码:
BOOL CMyApp::InitInstance()
{
...
CBroadcaster::InitBroadcaster();
...
}
int CMyApp::ExitInstance()
{
...
CBroadcaster::UninitBroadcaster();
...
}
void CView1::OnInitalUpdate()
{
CView::OnInitalUpdate();
CBroadcaster::Register(this,WM_MYMESSAGE);
}
void CView2::OnInitalUpdate()
{
CView::OnInitalUpdate();
CBroadcaster::Register(this,WM_MYMESSAGE);
CBroadcaster::Register(this,WM_ANOTHERMESSAGE);
}
void CView3::OnItemSelected()
{
LRESULT Result
CBoardcaster::StartSend(WM_MYMESSAGE,0,pItem,Result);
while (CBroadcaster::SendNext(Result))
{
if (Result == 0)
{
MessageBox(“The result was not good”);
}
}
}
void CView4::OnListSelChanged()
{
CBroadcaster::PostToAll(WM_ANOTHERMESSAGE,0,ItemIndex);
}
更新 - 版本 2
CBroadcaster
类的第一个版本存在一个弱点。当一个窗口在响应由 CBroadcaster
发送的消息时取消注册自身时,该问题就会暴露出来,当它向某个窗口发送消息,而该窗口正在迭代其内部的 CRegisteredWindows
列表时。当它向某个窗口发送消息,而该窗口因此取消注册了自身,取消注册可能会从列表中删除 CRegisteredWindow
对象,这将导致“消息发送”函数的迭代器处于不良状态,因为当前它所指向的项目已不再存在。
解决此问题的唯一方法是不要删除实际的 CRegisteredWindow
对象,而是将其标记为已删除,然后在稍后进行实际删除。因此,在版本 2 中,有一个名为 CheckDeleted
的新函数,它将遍历已注册的窗口,并删除那些被标记为已删除的窗口。此方法可以调用在代码中的任何位置(当然,除了在响应 CBroadcaster
的消息时)。如果您更喜欢使用版本 2,我建议将对此方法的调用放在应用程序的 OnIdle
方法中。