Alarm application in Visual C++/MFC

This project shows the development of a class that is useful as a reminder or to perform some tasks at a given time or time interval. The class is developed using Visual C++ MFC and won’t work in an application that does not use MFC.

There are two classes. The main class is called CSchedule and the helper class is CAlarm. The schedule-class holds a collection of alarms and starts each one whenever needed.

Multi threaded Alarm proc:

This is a pointer to a function (void function (void)) that will be executed when the alarm is fired. You need to write this function and give it as a parameter when adding an alarm to the schedule.

Alarm IDs:
When you add an alarm to the list you will add it with an ID of you desire. Be careful not to add two alarms with same IDs! The ID is used to get an alarm. The IDs do not need to be
subsequent numbers. You can use just any integer value.

Schedule loop:
This loop needs to be started in order for the alarms to be fired. Only when you start the loop, the schedule class will check which alarms to fire.

So here are the methods of CSchedule and their use:


void addSingleAlarm(int ID, const CTime& start_time, CAlarm::alarm_proc proc);

Adds an alarm that will only be started once, at the time shown by start_time.

 void addMultiAlarm(int ID, const CTimeSpan& tspan, const CTime& since, CAlarm::
alarm_proc proc);

Adds an alarm that will be started in equal intervals shown by tspan, but only after the time shown by since.

void removeAlarm(int ID);

Removes the alarm with given ID.

 const CAlarm* alarm(int ID) const;
CAlarm* alarm(int ID);

Give the alarm with given ID.

 void startLoop();

Starts the main schedule loop.

 void stopLoop();

Stops the main schedule loop.

 bool isRunning();

Shows if the main schedule loop is running.

And here are the methods of CAlarm that you might want to use:

 void setTime(const CTime& time)

Sets the time in which to fire the alarm or before which multi-alarms wont be started.

const CTime& getTime() const

Retrieves the time when the alarm is supposed to be fired

const CTimeSpan& getTimeSpan() const

Retrieves the time-interval of two multi-alarms.

bool isSignle() const

Shows if the alarm is single-alarm or multi-alarm

bool isEnabled() const

Shows if the alarm is enabled

void fire() const

Fires the alarm (Executers the alarm proc)

void disable()

Disables the alarm.

void enable()

Enables the alarm. By default alarms are enabled.


The CSchedule class holds a collection of CAlarm objects in a CMap collection. We did this so the user can add alarms with different ids without having to make sure they are subsequent. The map is good when you need fast indexing and adding/removing.

The actual job of the scheduler is actually done in the startLoop function. There a new windows thread is started in which the alarms are checked and fired.

The new thread is defined in the function UINT ScheduleThreadProc( LPVOID pParam ) that takes as a parameter a CSchedule class pointer. So the startLoop function looks like this:


void CSchedule::startLoop()
{
	if(m_bIsRunning) return;
	m_bIsRunning = true;
	AfxBeginThread(ScheduleThreadProc, this);
}

Check if the loop is tuning if it is don?t start it again if not start it and give you as a parameter.The ScheduleThreadProc repeatedly iterates all the items in the map-member of the class and if some needs to be started it starts it.

So it first gets the current time, and then compares it to the time plus time span of the alarm. The time span of a single alarm should be zero so it won?t affect the result. If the
new result is bigger or equal to the current time that means that the alarm needs to be fired. We check if it?s enabled and if yes we fire it. Then we change the alarm’s time to
the alarm’s current time plus the time span so the multiple-alarm is started again the next time. If the alarm is single it shouldn?t be started again so we can remove it from the map.

That’s what this function does. And here it is with code:


UINT ScheduleThreadProc( LPVOID pParam )
{
	CSchedule* pSchedule = (CSchedule*)pParam;
	POSITION pos;
	int ID;
	CAlarm* pAlarm;

	CTime curTime;

	while(pSchedule->isRunning()) {
	if(pSchedule->m_mapAlarms.IsEmpty())

	continue;

	curTime = CTime::GetCurrentTime();

	pos = pSchedule->m_mapAlarms.GetStartPosition();

	while(pos!=NULL) {

	pSchedule->m_mapAlarms.GetNextAssoc(pos, ID, pAlarm);

	// pAlarm->getTimeSpan() should be 0 in single alarms

	if(pAlarm->getTime() + pAlarm->getTimeSpan() <= curTime) {

	if(pAlarm->isEnabled())

	pAlarm->fire();

	pAlarm->setTime(pAlarm->getTime() + pAlarm->getTimeSpan());

	if(pAlarm->isSignle()) {

	delete pAlarm;

	pSchedule->m_mapAlarms.RemoveKey(ID);

	}

	}

}

}

return 0;

}

In this particular sample project we set a time for a single alarm, which is added to the schedule-class. The alarm proc plays a short ?Hallelujah!? sound and pops a message box.

To use the Schedule class in your applications add Schedule.cpp and Schedule.h to your project, create an instance of CSchedule somewhere in your app where it would exist during the time you need it, and remember to call startLoop.

You can download the sample project and source files here.