2016-12-31 6 views
1

Я хотел бы показать диалоговое окно, информирующее пользователя о том, что приложение занято. Чтобы избежать блокировки основного потока, я думал использовать std :: thread, чтобы показать диалог. Рассмотрим следующий код:Откройте диалог MFC в std :: thread

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

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; 
} 

Выполнение этого кода диалоговое окно отображается правильно. Диалог также закрыт, но главное диалоговое окно не отображается, приложение зависает в CreateRunDlgIndirect(). Пытаясь вмешаться, при установке некоторых точек останова главное диалоговое окно отображается правильно снова. Очень странно. Я был бы очень рад за любые советы, где я должен погрузиться глубже.

На следующем шаге я также хотел бы показать процесс пользователю, отправив целое число, указывающее текущее состояние процесса.

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

Как я могу получить доказательства того, что диалог уже существует, перед отправкой или отправкой сообщения? Я использую Visual Studio 2013.

+1

Посмотрите: http://stackoverflow.com/questions/1669017/how-to-create- a-mfc-dialog-with-a-progress-bar-in-a-separate-thread – dwo

+0

Выполняет ли 'delete inProcess'' даже компиляцию? В любом случае, опустите его - это не имеет смысла. –

+1

Лучше, и обычно проще, сделать это наоборот - показать диалог в главном потоке пользовательского интерфейса, запустить занятую обработку в рабочем потоке. –

ответ

1

я могу думать о двух способах сделать это:

Немодальной диалога

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

Пользователь нить (UI нить)

Создание брата для основного потока пользовательского интерфейса (CWinApp) с помощью CWinThread. Самое главное - назначить член CWinThread :: m_pMainWnd с указателем на диалоговое окно. Если диалог Modal, вы возвращаете FALSE сразу после вызова DoModal и возвращаете TRUE для модели.

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

резьб

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

headr файл **

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; 
} 

исходный файл

#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(); 
} 

, чтобы прекратить действие нить

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

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

Для обоих способов я настоятельно рекомендую сделать диалог как самый верхний окна:

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; 
} 
+0

Боюсь, что это не сработает, как описано в [этом комментарии] (http://stackoverflow.com/questions/41407418/open-a-mfc-dialog-in-a-stdthread?noredirect=1#comment70025977_41407418). – IInspectable

 Смежные вопросы

  • Нет связанных вопросов^_^