Click here to Skip to main content
15,884,425 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
I don't know if what I am asking is possible but let me see if I can describe it. I have several utility functions that are put together to do a task. Each function outputs string data to a text file. I would like to use each of these functions in a worker thread, and have my thread post messages to the main UI rich textbox. The same data I am writing to the text file.

My question is, what is the best way to implement this without coding post messages everywhere in my utility functions. Since all the worker thread sees is "StartTask()" it won't know when to post the message to the UI. My idea was to pass the pointer of a class to the utility functions that would contain the string data, but I still don't know how I can have the worker thread post messages to the UI everytime text is available.

Here is some more clarification:
I want to add the class Analysis which already has code to output text to a file. I want to find a way to use my NotifyUI inside the Analysis class.


In my UI I have code to handle PostMessages from my thread:
LRESULT CMappingAnalysisDialog::OnUpdateStatus(WPARAM, LPARAM lParam)
{
    // Put in shared_ptr so it is automatically destroyed.
	CString* msg = reinterpret_cast<CString*>(lParam);
	SetDlgItemText(IDC_STATIC_STATUS_TEXT, *msg);
	
	delete msg;
	return 0;
}


In my WorkerThread I have:

void NotifyUI( UINT uNotificationType )
	{
		// Check if the hWnd is still valid before posting the message
		// Note: use PostMessage instead of SendMessage because PostMessage
		// performs an asynchronous post; whereas SendMessage sends synchronously
		// (sending synchronously would kind of defeat the purpose of using a
		// worker thread)
		if( ::IsWindow( m_hWnd ) )
		{
			switch( uNotificationType )
			{
			case NOTIFY_INC_PROGRESS:
				::PostMessage( m_hWnd, WM_USER_INC_PROGRESS, 0, 0);//LPARAM data goes here);
				break;
			case NOTIFY_UPDATE_STATUS_TEXT:
				::PostMessage(m_hWnd, WM_USER_UPDATE_STATUS_TEXT, 0, reinterpret_cast<LPARAM>(new CString(updateMessage)));
				break;
			case NOTIFY_UPDATE_EVENT_TEXT:
				::PostMessage( m_hWnd, WM_USER_UPDATE_EVENT_TEXT, 0, reinterpret_cast<LPARAM>(new CString(updateMessage)));
				break;
			case NOTIFY_UPDATE_OUTPUT:
				::PostMessage( m_hWnd, WM_USER_UPDATE_OUTPUT, 0, reinterpret_cast<LPARAM>(new CString(updateMessage)));
				break;
			case NOTIFY_THREAD_COMPLETED:
				::PostMessage( m_hWnd, WM_USER_THREAD_COMPLETED, 0, 0 );
				break;
			default:
				ASSERT( 0 );
			}
		}
	}



static UINT WINAPI ThreadProc( LPVOID lpContext )
	{
		// Turn the passed in 'this' pointer back into a CMappingLog instance
		CMapFaultAnalysis* pThis = reinterpret_cast< CMapFaultAnalysis* >( lpContext );
                CAnalysis analysis;
		CString output;
		CString status;
		//Thread work
		for(int j = 0; j < 3; j++)
		{
			pThis->updateMessage = "Starting Analysis";
		        pThis->NotifyUI(NOTIFY_UPDATE_EVENT_TEXT);

			for(int i = 0; i < 20; i++)
			{
                             anaysis.RunAnalysis()
			}
		}
		//REPORT END OF THREAD
		pThis->NotifyUI(NOTIFY_THREAD_COMPLETED);
		return 1;
	}
Posted
Updated 8-Oct-12 8:39am
v3
Comments
pasztorpisti 7-Oct-12 20:24pm    
You will definitely need some kind of thread safe message queue to pass data between the threads and the per-thread message queue of the gui thread is a logical choice. Why isn't PostMessage() good for you?
Briti Sundar 8-Oct-12 0:58am    
I think, you need to provide more clarification.
Nelek 8-Oct-12 14:39pm    
"code" tags changed to "pre" tags to improve readability

I am not sure that I understood your question correctly. You might want to let Windows do the synchronization for you and use SendMessage from your worker thread to send display messages to your UI thread. The sending thread will be synchronized with the receiving thread by Windows. But be aware that the sending thread will block until SendMessage returns.

Amended in response to the amended question:

I would change two things:

(1) Replace the PostMessage calls by SendMessage. That allows you to use a local buffer (allocated on the stack) for the message string. And that will get rid of all the hassle with the "new CString", then passing ownership to the UI thread, and finally deleting the CString in the UIThread. As I said above, Windows will hold your worker thread until the SendMessage call returns, which seems acceptable in your case.

(2) I would create a small class object that holds the window handle of your display window and that wraps the SendMessage calls in a member function. If you like, you could even override "operator <<" and create your own streaming interface. Pass this class object to your Analyze function and then you can generate log messages from there. You could even create a second class object, derived from the same base class, that writes your messages into a file - as you have been doing so far. That way, your Analyze function does not need to know, where the log message go. You simple pass the one or the other logger object.
 
Share this answer
 
v2
Comments
Espen Harlinn 8-Oct-12 10:31am    
5'ed!
nv3 8-Oct-12 10:36am    
thanks!
Have a look at: SendMessageCallback[^], it's highly useful when you want to pass a dynamically allocated buffer, since you can have the callback release the memory once the message has been processed.

Best regards
Espen Harlinn
 
Share this answer
 
Are you trying to say like this..
C++
//inside thread ---
PostMessage(WM_MYMSG, 0, 0);
// and receive it inside UI in a synchronized way like this
BEGIN_MSG_MAP(MyWnd)
MESSAGE_HANDLER(WM_MYMSG, OnMymethod);
END_MSG_MAP()
//do your work inside onMymethod() function
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900