我有一个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;
}
}
答案 0 :(得分:1)
像这样从下载线程向您的主GUI线程发布application-defined message:
Sub addSchoolRunToCalendar()
Dim datStart As Date
Dim datEnd As Date
Dim oView As Outlook.View
Dim oCalView As Outlook.CalendarView
Dim oExpl As Outlook.Explorer
Dim oFolder As Outlook.folder
Dim oAppt As Outlook.AppointmentItem
Const datNull As Date = #1/1/4501#
Set oExpl = Application.ActiveExplorer
Set oFolder = Application.ActiveExplorer.CurrentFolder
Set oView = oExpl.CurrentView
' Check whether the active explorer is displaying a calendar view.
If oView.ViewType = olCalendarView Then
Set oCalView = oExpl.CurrentView
datStart = oCalView.SelectedStartTime
datStart = Format(datStart, "dd/mm/yyyy") & " " & Format("07:00", "hh:mm")
Set oAppt = oFolder.Items.Add("IPM.Appointment")
If datStart <> datNull And datEnd <> datNull Then
oAppt.Subject = "School Run"
oAppt.Location = "Home"
oAppt.BusyStatus = olOutOfOffice
oAppt.Start = datStart
oAppt.Duration = "150"
oAppt.ReminderSet = False
End If
oAppt.Save
End If
End Sub
注意1:我正在使用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;
}
启动线程,因为OnInitDialog()
是一个非常糟糕的选择,因为它将被多次调用。 DoDataExchange()
将只被调用一次。
注意2::无捕获lambda用于更好地将下载线程与GUI线程解耦。将OnInitDialog()
从GUI对话框传递到工作线程是灾难的秘诀,因为它很容易只写GUI线程变量,而忽略了必需的同步。除此之外,更少的耦合和更少的依赖关系总是一件好事。
什么是this
?这是我的application-defined message ID,通常这样定义:
WM_APP_DOWNLOAD_FINISHED
添加消息映射条目:
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()
析构函数中的崩溃,这要求线程已经加入。
答案 1 :(得分:0)
也许这是一种解决方法。
Can I return a custom value from a dialog box's DoModal function?
不要使用DoModal的返回值。只需为CProgressBarTest
添加一个成员函数。