Thursday, July 26, 2012

How to update text box from MFC Worker Thread



I had to write an MFC application in which I was using a second thread to perform some time consuming process. The main UI thread was waiting for the completion of that event by calling ::WaitForSingleObject(). During execution, I always noticed that the cursor keeps circling and the UI does not respond. How can this be avoided?

1. Create an MFC Worker Thread to handle a synchronous/blocking call.

CWinThread *thread = AfxBeginThread(DelegateThread, this, THREAD_PRIORITY_NORMAL, 0, 0, NULL);

2. In DelegateThread(), invoke the blocking call. After this, lets say you want to update a text box from the result of the blocking call. This can be done in the following way. Define the following function in main Cwnd (i.e., main UI thread)

MainCwnd::UpdateTextBox(BSTR bstr)
{
    CEdit *pEdit = (CEdit *)GetDlgItem(IDC_EDIT);
    pEdit->SetWindowTextW(bstr);
}

3. Make the following call from DelegateThread()

BSTR test = SysAllocString(L"Test String");
MainCwnd->UpdateTextBox(test);
SysFreeString(test);

If all is right, this will update your text box! Also, this will avoid calling ::WaitForSingleObject() which gives a better UI feel. However, this is useful only when you need to display the result got from calling the blocking call in DelegateThread(). If there is some extra processing to be done after invoking the blocking call (eg:creating another thread that needs this result), then I cannot guarantee that this method will work.

Note: It is VERY important to note that you cannot make the call to edit the text box from the worker thread. However, you can INVOKE the function to edit the text box from the worker thread. This function should belong to the main dialog box class.