Code Snippet - Manipulate Control from WorkerThread

MFC多线程开发经常碰到需要在线程中对主窗口的控件进行处理的情况,比如设置控件状态,修改控件文字等,用AfxBeginThread()来创建工作者线程(WorkerThread)

CWinThread *pThread = AfxBeginThread(ThreadFunc, (LPVOID)this);

线程函数

static UINT ThreadFunc(LPVOID lpParam);

UINT CDemoDlg::ThreadFunc(LPVOID lpParam)
{
    CDemoDlg *pMainDlg = (CDemoDlg *)lpParam;
    
    pMainDlg->GetDlgItem(IDC_EDIT1)->SetWindowText(_T("DEMODEMO"));
    
    return 0;
}

上面的写法可以编译通过,大部分情况下也能正常运行,但在工作者线程中直接访问主线程(即UI线程)是不安全的,某些情况会导致线程死锁,甚至程序崩溃。

标准的做法是,将主窗口句柄传给工作者线程,工作者线程发送消息通知主线程对控件进行处理。

自定义消息

CDemoDlg.h

    #define WM_UPDATE_EDIT (WM_USER + 1)

消息映射函数声明

CDemoDlg.h

    afx_msg LRESULT OnUpdateEdit(WPARAM wParam, LPARAM lParam);

消息映射函数实现

CDemoDlg.cpp

    LRESULT CDemoDlg::OnUpdateEdit(WPARAM wParam, LPARAM lParam)
    {
        ((CEdit *)GetDlgItem(IDC_EDIT1))->SetWindowText((LPCTSTR)lParam);
    
        return 0;
    }

绑定消息及响应函数

CDemoDlg.cpp

    ON_MESSAGE(WM_UPDATE_EDIT, &CDemoDlg::OnUpdateEdit)

启动线程

CDemoDlg.cpp

    CWinThread *pThread = AfxBeginThread(ThreadFunc, (LPVOID)this);

    UINT CDemoDlg::ThreadFunc(LPVOID lpParam)
    {
        CDemoDlg *pMainDlg = (CDemoDlg *)lpParam;
    
        ::PostMessage(pMainDlg->m_hWnd, WM_UPDATE_EDIT, (WPARAM)0, (LPARAM)_T("DEMODEMO"));
    
        return 0;
    }

参考资料

1. Updating A Progress Control in a MFC Dialog From a Worker Thread
http://www.visualcquestion.info/Updating_A_Progress_Control_in_a_MFC_Dialog_From_a_Worker_Thread.html

2. MFC子线程访问主线程对话框程序的控件对象
http://blog.csdn.net/xbmoxia/article/details/16981243

添加新评论