如何从工作线程访问 MFC 控件?
Posted
技术标签:
【中文标题】如何从工作线程访问 MFC 控件?【英文标题】:How to access an MFC control from a worker thread? 【发布时间】:2011-08-25 12:10:48 【问题描述】:从工作线程访问 MFC 控件的最佳方式是什么?
什么是访问控件的 MFC 惯用方式?
我在这里读到http://www.flounder.com/workerthreads.htm 以下方法,但我不太喜欢CString
的new
,我怎么能确定CString
会正确deleted
?
typedef struct tagTP
HWND hwnd;
int n;
TP;
BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
// ...
ON_MESSAGE( UWM_UPDATE_RESULTS, OnUpdateResults )
END_MESSAGE_MAP()
void CMyDlg::OnBnClickedDoWork()
TP* tp = new TP;
tp->hwnd = m_hWnd;
tp->n = 42;
AfxBeginThread( doWork, tp );
UINT CMyDlg::doWork(LPVOID p)
TP* tp = reinterpret_cast< TP* >(p);
CWnd* dlg = FromHandle( tp->hwnd );
if ( tp->n == 42 )
CString* s = new CString( "Is the Answer to the Ultimate Question of Life, the Universe, and Everything" );
dlg->PostMessage( UWM_UPDATE_STATUS, 0, reinterpret_cast< LPARAM >(s) );
return 0;
LRESULT CMyDlg::OnUpdateResults(WPARAM,LPARAM lParam)
CString* s = reinterpret_cast<CString *>(lParam);
m_result.AddString( *s );// m_result is a CListBox
delete s;
UpdateData( FALSE );
return 0;
【问题讨论】:
您应该将 CString 指针存储在 OnUpdateResults() 中的智能指针中,以确保在处理过程中出现异常时将其销毁。 【参考方案1】:使用PostMessage(..) 是正确的。考虑使用SendMessage(..) - 直到完成为止。 传递指向新对象的指针很常见 - 检查 PostMessage(..) 的返回值以检查它是否已发布。
如何确定 CString 将被正确删除?
如前所述,检查 PostMessage(..) 的返回值并处理整个消息队列以防退出消息循环。
【讨论】:
【参考方案2】:作为一般规则,只能从创建它们的线程访问 MFC 控件。这就是为什么您找到的样本要经过传递消息的额外步骤的原因。消息由创建控件的线程接收和处理。
在 OnUpdateResults() 中正确删除了 CString。
【讨论】:
【参考方案3】:除了@Simon 的回答之外,如果您有一个更复杂的场景,即很难确定谁应该删除 CString(或任何类型),请考虑 std::tr1::shared_ptr。它将负责删除。
【讨论】:
您可以在发布之前(然后释放指针)和在消息处理程序中接收它之后(使用智能指针分配它)执行此操作。这只是关于异常安全。您不能直接发布智能指针。shared_ptr
在这种情况下会做什么?它是一个 C++ 对象,不能仅以 sizeof(void*)
字节传递。它必须被分配然后释放。一点用都没有。
@dgnorton 谢谢,我对shared_ptr不熟悉,怎么用?以上是关于如何从工作线程访问 MFC 控件?的主要内容,如果未能解决你的问题,请参考以下文章
c ++ MFC从工作线程设置/附加文本到richedit控件
从 MFC 中的工作线程调用 Beginwaitcursor 函数