我在WTL中有一个GUI窗口,它在CMessageLoop实例中的一个线程内运行,该实例已添加到应用程序实例并运行。现在,在主GUI中的按钮处理程序内,我创建了一个新窗口。一旦我单击该按钮并创建窗口并尝试将退出消息发布到主GUI循环。代码:
主窗口,有自己的主题:
CMessageLoop theLoop;
_MyppModule.AddMessageLoop(&theLoop);
if(m_pMyDlg == NULL) {
m_pMyDlg = new CMyDlg();
if(!IsWindow(*m_pMyDlg))
{
m_pMyDlg->Create(NULL);
m_pMyDlg->ShowWindow(SW_SHOW);
nRet = theLoop.Run();
_MyppModule.RemoveMessageLoop();
}
}
按钮处理程序&子窗口创建:
LRESULT CMyDlg::OnButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
ChildWindowDlg childDlg;
childDlg.Create(m_hWnd);
childDlg.ShowWindow(SW_SHOW);
CMessageLoop _loop;
);
_loop.Run();
::DestroyWindow(childDlg);
return S_OK;
}
现在,如果我单击MyDlg窗口中的Close按钮,将调用按钮的处理程序,在其中{I} ::PostQuitMessage
,但它永远不会从第一个代码片段到达theLoop messageloop。
这在我退出第二个循环后发生,因此_loop被破坏并且子对话框被销毁。
这里发生了什么?
答案 0 :(得分:2)
这里有两个消息循环,孩子的一个是嵌套的。另一方面,消息队列是每个线程一个,并由最内部的消息循环(GetMessage
)提取。因此,WM_QUIT
内部消息循环将检索CMyDlg::OnButtonClicked
消息。
答案 1 :(得分:0)
第二个代码段完全不自然。如果您的目标是弹出一个窗口,然后关闭,然后您想完成按钮单击处理程序的执行,那么您需要模态对话框:
LRESULT CMyDlg::OnButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl,
BOOL& bHandled)
{
ChildWindowDlg childDlg; // Add constructor parameters if needed
// Additional initlaization calls might go here
const INT_PTR nResult = childDlg.DoModal(m_hWnd); // DoModal handles it all
if(nResult == IDOK) { ... } // Hey's we even have result coming from `EndDialog`
return 0; // No S_OK here
}
没有消息循环,没有PostQuitMessage
,不需要单独的窗口创建/销毁调用。这就是模态对话框的用途。
如果您不想阻止“呼叫”窗口,并且想法是让主窗口和从属窗口并排运行(或者,一个是另一个的一部分,无论如何都要同时响应),那么你不想阻止你的消息处理程序。处理程序将创建窗口并进行设置(.Create
,.ShowWindow
),然后退出OnButtonClicked
函数。
两个窗口都已创建,两个窗口都处于活动状态,并通过顶级消息循环将消息发送给它们。这是正确的方法,每个线程通常不需要多个消息循环。有时它可能对特定操作有意义,但这种情况非常罕见。 Windows是被动实例。他们使用消息处理程序响应消息。线程消息循环服务于所有线程窗口,因为它所执行的是DispatchMessage
API调用,后者又查找目标窗口,取其WndProc
并调用它来处理消息详细信息。