I have a dialog in MFC with a CStatusBar. In a separate thread, I want to change the pane text of status bar. However MFC complains with asserts? How is it done? An example code would be great.
Maybe this can help you: How to access UI elements from a thread in MFC.
I don't code C++/MFC myself but I had experienced the similar problem in C# which is known as Cross-thread GUI update.
You should use a message (either with Send- or PostMessage) to notify the UI thread that the status bar text should be updated. Don't try to update UI elements from a worker thread, it's bound to give you pain.
You could post a private message to the main frame window and 'ask' it to update the status bar. The thread would need the main window handle (don't use the CWnd object as it won't be thread safe). Here is some sample code:
static UINT CMainFrame::UpdateStatusBarProc(LPVOID pParam);
void CMainFrame::OnCreateTestThread()
{
// Create the thread and pass the window handle
AfxBeginThread(UpdateStatusBarProc, m_hWnd);
}
LRESULT CMainFrame::OnUser(WPARAM wParam, LPARAM)
{
// Load string and update status bar
CString str;
VERIFY(str.LoadString(wParam));
m_wndStatusBar.SetPaneText(0, str);
return 0;
}
// Thread proc
UINT CMainFrame::UpdateStatusBarProc(LPVOID pParam)
{
const HWND hMainFrame = reinterpret_cast<HWND>(pParam);
ASSERT(hMainFrame != NULL);
::PostMessage(hMainFrame, WM_USER, IDS_STATUS_STRING);
return 0;
}
The code is from memory as I don't have access to compiler here at home, so apologies now for any errors.
Instead of using WM_USER
you could register your own Windows message:
UINT WM_MY_MESSAGE = ::RegisterWindowsMessage(_T("WM_MY_MESSAGE"));
Make the above a static member of CMainFrame
for example.
If using string resources is too basic then have the thread allocate the string on the heap and make sure the CMainFrame update function deletes it, e.g.:
// Thread proc
UINT CMainFrame::UpdateStatusBarProc(LPVOID pParam)
{
const HWND hMainFrame = reinterpret_cast<HWND>(pParam);
ASSERT(hMainFrame != NULL);
CString* pString = new CString;
*pString = _T("Hello, world!");
::PostMessage(hMainFrame, WM_USER, 0, reinterpret_cast<LPARAM>(pString));
return 0;
}
LRESULT CMainFrame::OnUser(WPARAM, LPARAM lParam)
{
CString* pString = reinterpret_cast<CString*>(lParam);
ASSERT(pString != NULL);
m_wndStatusBar.SetPaneText(0, *pString);
delete pString;
return 0;
}
Not perfect, but it's a start.