简体   繁体   English

在 std::thread 中打开 MFC 对话框

[英]Open a MFC dialog in a std::thread

I would like to show a dialog to inform the user that the application is busy.我想显示一个对话框来通知用户应用程序正忙。 To avoid blocking of the main thread, I was thinking to use a std::thread to show the dialog.为了避免阻塞主线程,我想使用 std::thread 来显示对话框。 Consider the following code:考虑以下代码:

InProcDlg inProcess;
std::thread t([ &inProcess ] {      
    inProcess.DoModal();
    delete inProcess;
});
// wait till process has finished 
::PostMessage(inProcess.m_hWnd, WM_USER + 1, 0, 0);
if (t.joinable()){
    t.join();
}

InProcDlg.cpp InProcDlg.cpp

BEGIN_MESSAGE_MAP(InProcDlg, CDialogEx)
  ...
  ON_MESSAGE(WM_USER + 1, &InProcDlg::close)
END_MESSAGE_MAP()

LRESULT InProcDlg::close(WPARAM wParam, LPARAM lParam)
{
  UNREFERENCED_PARAMETER(wParam, lParam);
  EndDialog(1);
  return 0;
}

Running this code the dialog is shown properly.运行此代码,对话框显示正确。 The dialog is also closed, but the main dialog is not shown, the application hangs in CreateRunDlgIndirect() .该对话框也已关闭,但未显示主对话框,应用程序挂在CreateRunDlgIndirect() Trying to step in, while setting some breakpoints the main dialog is shown properly back again.尝试介入,同时设置一些断点,主对话框再次正确显示。 Very strange.很奇怪。 I would be very happy for any advices where I have to dive deeper in.对于我必须深入研究的任何建议,我将非常高兴。

In the next step I would also like to show the process to the user, by sending an integer indicating the current state of process.在下一步中,我还想通过发送一个指示进程当前状态的整数向用户展示进程。

int *percent;
::PostMessage(inProcess.m_hWnd, WM_USER + 2, 0, reinterpret_cast<LPARAM>(percent));

How I can gain evidence that the dialog is already existing, before sending or posting a message?在发送或发布消息之前,我如何获得对话已经存在的证据? I'm using Visual Studio 2013.我正在使用 Visual Studio 2013。

I can think of two ways to do that:我可以想到两种方法来做到这一点:

Modeless dialog无模式对话框

https://www.codeproject.com/Articles/1651/Tutorial-Modeless-Dialogs-with-MFC https://www.codeproject.com/Articles/1651/Tutorial-Modeless-Dialogs-with-MFC

User thread (UI thread)用户线程(UI线程)

Creating a brother to the main UI thread (CWinApp) by using CWinThread.使用 CWinThread 创建主 UI 线程 (CWinApp) 的兄弟。 Most important is to assign CWinThread::m_pMainWnd member, with a pointer to a Dialog.最重要的是为 CWinThread::m_pMainWnd 成员分配一个指向 Dialog 的指针。 If the dialog is Modal you return FALSE right after the call to DoModal, and return TRUE for Modeless.如果对话框是模态的,则在调用 DoModal 后立即返回 FALSE,对于无模态返回 TRUE。

class CMainFrame : public CFrameWnd {
    // pointer to thread
    CWinThread* m_pUserThread;
}

start thread开始线程

m_pUserThread = AfxBeginThread(RUNTIME_CLASS(CUserThread), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED );
m_pUserThread->m_bAutoDelete = TRUE;
m_pUserThread->ResumeThread();

headr file**头文件**

class CUserThread : public CWinThread
{
    DECLARE_DYNCREATE(CUserThread)
public:
    CUserThread();

    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CUserThread)
    public:
    virtual BOOL InitInstance();
    virtual int ExitInstance();
    //}}AFX_VIRTUAL

protected:
    virtual ~CUserThread();
    // Generated message map functions
    //{{AFX_MSG(CUserThread)
        // NOTE - the ClassWizard will add and remove member functions here.
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
private:
    CUserMsg* m_pDlg;
}

source file源文件

#define DO_MODAL
BOOL CUserThread::InitInstance()
{

    #ifdef DO_MODAL
    // create and assign Modeless dialog
    CUserMsg dlg;
    m_pMainWnd = &m_pDlg;
    dlg.DoModal();
    return FALSE;
    #endif

    #ifdnef DO_MODAL
    // create and assign Modal dialog
    m_pDlg = new CUserMsg();
    m_pDlg->Create( IDD_USER_DLG, AfxGetMainWnd() );
    m_pMainWnd = m_pDlg;
    return TRUE;
    #endif
}

int CUserThread::ExitInstance()
{
    // check for null
    m_pDlg->SendMessage( WM_CLOSE ) ;
    delete m_pDlg;

    return CWinThread::ExitInstance();
}

to terminate the thread终止线程

// post quit message to thread
m_pUserThread->PostThreadMessage(WM_QUIT,0,0);

// wait until thread termineates
::WaitForSingleObject(m_pUserThread->m_hThread,INFINITE);

For both ways I would highly recommend making the dialog as a top most window:对于这两种方式,我强烈建议将对话框设为最顶部的窗口:

BOOL CLicenseGenDlg::OnInitDialog() {
    CDialog::OnInitDialog();

    // TODO: Add extra initialization here
    SetWindowPos( &wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | WS_EX_TOPMOST );
    return TRUE;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM