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.