Q: How to access UI elements from a thread in MFC?
A: Since the MFC is not thread-safe at object level (only at class level) one have to be careful when UI elements (like edit controls, listboxes etc.) should be accessed from inside the thread. The safest way is to pass a windows object handle and uses this inside the thread to post messages to the object.
The following sample shows this technique assuming that the created dialog contains a static text control named 'IDC_THREAD_TEXT'. The object handle of the dialog will be passed to the thread. Inside the thread this handle will be used to post ten messages to the dialog causing it to update the static control.
Code:// StdAfx.h #define WM_UPDATE_CONTROL WM_APP + 0x10 // MyDialog.h class CMyDialog : public CDialog { public: CMyDialog(CWnd* pParent = NULL); private: CWinThread *m_pThread; LRESULT OnUpdateControl(WPARAM wParam, LPARAM lParam); static UINT ThreadFunc(LPVOID pvParam); }; // MyDialog.cpp CMyDialog::CMyDialog(CWnd* pParent /*=NULL*/) : CDialog(CMyDialog::IDD, pParent) { //{{AFX_DATA_INIT(CMyDialog) //}}AFX_DATA_INIT m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_pThread = 0; } BEGIN_MESSAGE_MAP(CMyDialog, CDialog) //{{AFX_MSG_MAP(CMyDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP ON_MESSAGE(WM_UPDATE_CONTROL, OnUpdateControl) END_MESSAGE_MAP() BOOL CMyDialog::OnInitDialog() { CDialog::OnInitDialog(); //... // Set object handle for thread HWND *phObjectHandle = new HWND; *phObjectHandle = GetSafeHwnd(); // Create thread m_pThread = AfxBeginThread(ThreadFunc, phObjectHandle); if(!m_pThread) { // Could not create thread EndDialog(IDCANCEL); } return TRUE; } LRESULT CMyDialog::OnUpdateControl(WPARAM wParam, LPARAM lParam) { static int iCounter = 0; CString strText; strText.Format("Message %d", ++iCounter); GetDlgItem(IDC_THREAD_TEXT)->SetWindowText(strText); return 0; } UINT CMyDialog::ThreadFunc(LPVOID pvParam) { HWND *phObjectHandle = static_cast<HWND *>(pvParam); for(int iCnt = 0; iCnt < 10; ++iCnt) { ::PostMessage(*phObjectHandle, WM_UPDATE_CONTROL, 0, 0); ::Sleep(2000); } // Release memory delete phObjectHandle; return 0; }


Reply With Quote
Bookmarks