簡體   English   中英

如何在另一個線程中關閉MFC Modal對話框並獲得對話框的返回值?

[英]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添加一個成員函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM