Click here to Skip to main content
15,896,372 members
Articles / Desktop Programming / MFC

SyncInvoker: Keep Your GUI Responsive During Lengthy Synchronous Calls

Rate me:
Please Sign up or sign in to vote.
4.93/5 (20 votes)
16 Apr 2007CPOL4 min read 68.6K   462   54  
Keep your GUI responsive when making blocking synchronous calls. Dave offers a technique using SyncInvoker,
#ifndef __SYNCINVOKE_H__
#define __SYNCINVOKE_H__

#include "atlbase.h"

namespace SyncInvoker
{
	class Thread
	{
		public :
			Thread(UINT uThrdDeadMsg = 0) : m_uThreadDeadMsg(uThrdDeadMsg) {}
			virtual ~Thread() {CloseHandle(m_hThread);}

			virtual Thread &Create(LPSECURITY_ATTRIBUTES lpThreadAttributes = 0, DWORD dwStackSize = 0, DWORD dwCreationFlags = 0, UINT uThrdDeadMsg = 0)
			{	
				if (uThrdDeadMsg) m_uThreadDeadMsg = uThrdDeadMsg;
				m_dwCreatingThreadID = GetCurrentThreadId();
				m_hThread = CreateThread(lpThreadAttributes, dwStackSize, ThreadProc, reinterpret_cast<LPVOID>(this), dwCreationFlags, &m_dwThreadId); 
				return *this; 
			}

			bool Valid() const {return m_hThread != NULL;}
			DWORD ThreadId() const {return m_dwThreadId;}
			HANDLE ThreadHandle() const {return m_hThread;}

		protected :
			virtual DWORD ThreadProc() {return 0;}

			DWORD m_dwThreadId;
			HANDLE m_hThread;
			DWORD m_dwCreatingThreadID;
			UINT m_uThreadDeadMsg;

			static DWORD WINAPI ThreadProc(LPVOID pv)
			{
				if (!pv) return 0;
				DWORD dwRet = reinterpret_cast<Thread*>(pv)->ThreadProc(); 
				if (reinterpret_cast<Thread*>(pv)->m_uThreadDeadMsg) 
						PostThreadMessage(reinterpret_cast<Thread*>(pv)->m_dwCreatingThreadID, reinterpret_cast<Thread*>(pv)->m_uThreadDeadMsg, 0, dwRet); 
				return dwRet; 
			}
	};

	template <class T_OWNER>
	class CSyncCall : public Thread
	{
	public:
		CSyncCall():m_owner(NULL), m_method(NULL),m_param(0){}

		typedef void (T_OWNER::*METHOD_PTR)(LPVOID);

		bool Call(T_OWNER *owner,METHOD_PTR method,LPVOID param) 
		{
			m_owner = owner;
			m_method = method;
			m_param = param;
			return Create().Valid();
		}

		virtual DWORD ThreadProc()
		{
			if(m_owner)
				(m_owner->*m_method)(m_param);
			return 0;
		}
	private:
		T_OWNER *m_owner;
		METHOD_PTR m_method;
		LPVOID m_param;
	};
}

#define SyncInvoke(cls, method, param) \
{ \
	SyncInvoker::CSyncCall<cls> syncCall; \
	syncCall.Call(this, method, param); \
	AtlWaitWithMessageLoop(syncCall.ThreadHandle()); \
}
#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Technical Lead
United Kingdom United Kingdom
When Dave isn't trying to play drums, fly helicopters or race cars, he can be found coding hard and herding cats at JoinIn Networks He must try harder!

You can read Dave's ramblings in his blog Aliens Ate My GUI

Or, if you can be bothered, he twitters on BoomerDave

Comments and Discussions