如何在另一个线程中关闭 MFC 模式对话框并获取对话框返回值?
How do I close a MFC Modal Dialog in another thread and can get the dialog return value?
我有一个MFC对话框项目。主对话框中有一个下载按钮,单击它将提示进度条并开始下载。下载完成后,我希望它自动关闭。
void CProgressBarTest::DoDataExchange(CDataExchange* pDX)
{
static auto funDownload = [&]() {
m_downloadRetValue = ::SomeDownloadAPI(funDownloadCallback);
//When download finished, close the current dialog (progress bar). Here are two options:
//EndDialog(IDYES); // causes crash
//::PostMessage(this->GetSafeHwnd(), WM_CLOSE, 0, 0);// doesn't crash, but without return valud IDYES.
};
m_thDownload = std::thread(funDownload);
}
以下是关闭进度条的两种方法:
EndDialog(IDYES)
:它会导致崩溃。
::PostMessage(this->GetSafeHwnd(), WM_CLOSE, 0, 0)
:它可以关闭窗口而不会崩溃,但也没有返回值(IDYES)。
我想在外面做这样的检查,
void CGUIThreadTestDlg::OnBnClickedButton3()
{
CProgressBarTest dlg(this);
INT_PTR nRet = dlg.DoModal();
switch (nRet)
{
case -1:
AfxMessageBox(_T("Dialog box could not be created!"));
break;
case IDYES:
AfxMessageBox(_T("Yes!"));
break;
case IDOK:
// Do something
break;
case IDCANCEL:
AfxMessageBox(_T("IDCANCEL!"));
break;
default:
// Do something
break;
}
}
将应用程序定义的消息从下载线程发布到主 GUI 线程,如下所示:
BOOL CProgressBarTest::OnInitDialog()
{
CDialog::OnInitDialog();
auto funDownload = []( HWND hwnd ){
auto const downloadRetValue = ::SomeDownloadAPI(funDownloadCallback);
::PostMessage( hwnd, WM_APP_DOWNLOAD_FINISHED, static_cast<WPARAM>( downloadRetValue ), 0 );
};
m_thDownload = std::thread(funDownload, GetSafeHwnd());
return TRUE;
}
注意1:我正在使用OnInitDialog()
来启动线程,因为这是一个非常糟糕的选择DoDataExchange()
因为它会被多次调用。OnInitDialog()
将只调用一次。
注意 2:无捕获 lambda 用于更好地将下载线程与 GUI 线程分离。将this
从 GUI 对话框传递到工作线程会导致灾难,因为它使得只写入 GUI 线程变量而忽略所需的同步变得如此诱人。除此之外,更少的耦合伴随着更少的依赖,这总是一件好事。
什么是WM_APP_DOWNLOAD_FINISHED
?这是我的应用程序定义的消息 ID,我通常这样定义:
enum {
WM_APP_0 = WM_APP,
WM_APP_DOWNLOAD_FINISHED
// for future extension...
};
添加消息映射条目:
BEGIN_MESSAGE_MAP(CProgressBarTest, CDialog)
ON_MESSAGE( WM_APP_DOWNLOAD_FINISHED, &CProgressBarTest::OnDownloadFinished )
END_MESSAGE_MAP()
并定义消息处理程序以从依赖于下载结果的对话框中返回一个值:
LRESULT CProgressBarTest::OnDownloadFinished( WPARAM wp, LPARAM lp )
{
m_thDownload.join();
auto const downloadRetValue = wp;
EndDialog( downloadRetValue == ERROR_SUCCESS ? IDYES : IDCANCEL );
return 0;
}
确保像我上面所做的那样join()
线程,以避免std::thread
析构函数崩溃,这需要线程已连接。
也许这是一种解决方法。
是否可以从对话框的 DoModal 函数返回自定义值?
不要使用 Domodal 的返回值。只需为CProgressBarTest
添加一个成员函数即可。
相关文章:
- 如何检测窗口当前是否正在运行模式对话框?
- wxWidgets - 阻止 OS X 上的窗口模式对话框
- 如何在另一个线程中关闭 MFC 模式对话框并获取对话框返回值?
- 防止模式对话框中的事件循环阻塞
- 从模式对话框中退出 MFC 应用
- 当主GUI线程被阻塞时,如何从工作线程创建无模式对话框
- MFC 结束对话框崩溃时模式对话框没有焦点
- 将焦点设置在MFC视图中托管的无模式对话框上
- 模式对话框不会作为最上面的窗口打开
- 从无模式对话框启动CFileDialog时会冻结
- 使用ESC键取消Carbon模式对话框
- 为什么MFC中的模式对话框实际上是内部无模式的
- 当另一个窗口关闭时关闭无模式对话框
- 设计模式保存MFC对话框控件状态的步骤
- 如何在 WTL 中删除指向无模式对话框的指针
- 线程退出时 DLL 中的 MFC 无模式对话框被销毁
- Qt:关闭模式对话框关闭程序
- 如何在 QModelView 中组合模式对话框编辑器和就地小组件编辑器
- C++ 使用 WINAPI 启动多个无模式对话框(无 MFC)
- 模式对话框处于活动状态时隐藏MFC主窗口