All the code for handling the (very simple) data used by the add-in is in MtBackground.h.
The data posted to the main thread is simply a topic string and a number. The message class is therefore as follows:
class CMtBackgroundMsg : public CXllMtMsg { public: CMtBackgroundMsg(LPCSTR pszTopic, double dValue) : m_strTopic(pszTopic), m_dValue(dValue) {} // Framework requires a virtual destructor virtual ~CMtBackgroundMsg() {} // Public data members CString m_strTopic; double m_dValue; };
The data cache is equally simple. It just maps topic strings to values.
#include <map> class MtBackgroundDataCache { public: void Set(LPCSTR pszTopic, double dValue) { m_map[pszTopic] = dValue; } BOOL Lookup(LPCSTR pszTopic, double& value) const { map_type::const_iterator itF = m_map.find(pszTopic); if (itF == m_map.end()) return FALSE; value = itF->second; return TRUE; } protected: typedef std::map<CString, double> map_type; map_type m_map; };
Most of the application class, CMtBackgroundApp, is shown below. The areas that have been changed from the AppWizard-produced original are shown in grey.
class CMtBackgroundApp : public CXllPushApp { public: CMtBackgroundApp(); public: // Data Members // Background thread HANDLE m_thread; long m_lTickPeriod; // Data cache MtBackgroundDataCache m_cache; // Accessors long GetTickPeriod() const { return m_lTickPeriod; } void SetTickPeriod(long lTickPeriod) { m_lTickPeriod = lTickPeriod; } // Names public: static LPCSTR m_pszDefName; // Overrides virtual BOOL OnXllOpenEx(); virtual void OnXllClose(); virtual void ProcessAsyncMessage(CXllMtMsg* msg); // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMtBackgroundApp) public: virtual int ExitInstance(); virtual BOOL InitInstance(); //}}AFX_VIRTUAL ... };
Let us examine each of these changes in turn.
// Background thread HANDLE m_thread; long m_lTickPeriod;
The data member m_thread is a handle to a background thread. It is set when the thread is started, and it used at closedown to kill the thread. m_lTickPeriod controls the period of the background thread events, in millisecs. It is set by the main thread and read by the background thread
// Data cache MtBackgroundDataCache m_cache;
The data cache is a data member of the application, and shares its lifetime.
// Accessors long GetTickPeriod() const { return m_lTickPeriod; } void SetTickPeriod(long lTickPeriod) { m_lTickPeriod = lTickPeriod; }
These accessor functions are used to get and set the value of the background thread's tick period. In a more sophisticated implementation, these methods would be thread-safe, because they use data that is shared between both threads.
(In our implementation they are not thread-safe, to reduce complexity, and because the Set and Get methods are atomic in this case.)
// Overrides virtual BOOL OnXllOpenEx(); virtual void OnXllClose(); virtual void ProcessAsyncMessage(CXllMtMsg* msg);
These three overrides handle the three major events of the add-in's life: creation, destruction and the arrival of asynchronous data. We will examine them in detail later.