So what do you do when you want to update a GUI from a thread. There are two ways in MFC: you can either change the GUI control youself, but this will result in deadlocks 100% guarantee; you can either change the value (string/dword) behind the control and then call the UpdateData() method. But something that they forgot to say is that you cant call UpdateData() from a thread outside the GUI loop, doing that will result in deadlock 100% guarantee. MS only response is "threads are not allowed to touch GUI, you must send a message to the dialog that you want to update". Fair enough, but MS has failed to give such a functionality and if I want to update a tabbed dialog with data from the thread, there is no way but to implement a WM_USER message listener for every dialog that you want to update from the thread. Sheeeesh, I dont want to put more stuff into each one of the dialogs, for just make it "thread-safe" for the MFC GUI.
My solution to this problem is jsut to create a base CDialog class that will handle this problem, and is safe to update all values in a dialog. It took med 5 minutes to create it and test it. Whoah, that was easy, but that main point is IF IT WAS SO EASY, WHY HASNT MS DONE THIS IN THE FIRST PLACE? Why do I have to live with crap design eons after the MFC was "designed", why can't they extend the dialog class with such functionality so you dont have to sit and wonder why the application has locked. "Is it me or MFC?"
Im still amazed that MFC is still not thread safe, it was earlier one of the most commonly used application tools/API for creating applications. How could it survive for such a long time??
My solution, is as easy as pie. Here it is:
#include
#include
class CRefreshDialog : public CDialog
{
public:
CRefreshDialog(UINT nIDTemplate,CWnd* pParentWnd = NULL );
virtual ~CRefreshDialog();
virtual BOOL OnWndMsg( UINT message,WPARAM wParam, LPARAM lParam, LRESULT* pResult );
void RefreshDialog();
private:
CCriticalSection refreshMutex;
};
#define WM_REFRESH WM_USER + 0x9283
CRefreshDialog::CRefreshDialog(UINT nIDTemplate, CWnd* pParentWnd ) : CDialog(nIDTemplate, pParentWnd)
{
}
CRefreshDialog::~CRefreshDialog()
{
}
BOOL CRefreshDialog::OnWndMsg( UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult )
{
BOOL wasHandled = FALSE;
if (message == WM_REFRESH)
{
UpdateData(FALSE);
} else
{
wasHandled = CDialog::OnWndMsg(message, wParam, lParam, pResult);
}
return wasHandled;
}
void CRefreshDialog::RefreshDialog()
{
CSingleLock lock(&refreshMutex);
lock.Lock();
::PostMessage(m_hWnd, WM_REFRESH, 0, 0);
lock.Unlock();
}