Alarm - alarms and reminders for WindowsThis will remain free to use but if you make money from using it a small donation via Paypal to gb@bramblingbooks.co.uk would be useful to help pay hosting costs etc. There are no viruses ... present in the zipped source file. I know this because I wrote it. I am not to be held responsible in anyway for any of this freely given source code, resource scripts and icon. By downloading and using these files you understand this. The file is here and contains all the source files needed to build this project using MS Viz C/C++ V6. REMEMBER to set the multi-thread option! Included in the zipped file are alarm.wav and alarms.ini - these two should go into the paths you set in main.c and alarm.c noted below.
Here's main.c ...
// main.c
#include <windows.h>
#include <stdio.h>
#include <direct.h>
#include <shellapi.h>
#include <time.h>
#include "resource.h"
#include "alarming.h"
void AddTrayIcon(HWND hwnd, HICON hicon) // add a tray icon - this works on win 2003
{
NOTIFYICONDATA nid;
memset(&nid, 0, sizeof(nid));
nid.cbSize = sizeof(nid);
nid.hWnd = hwnd;
nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
nid.hIcon = hicon;
nid.uCallbackMessage = NIM_CALLBACK;
strcpy(nid.szTip, "Alarm Calls");
Shell_NotifyIcon(NIM_ADD, &nid);
}
void DelTrayIcon(HWND hwnd, HICON hicon) // remove tray icon
{
NOTIFYICONDATA nid;
memset(&nid, 0, sizeof(nid));
nid.cbSize = sizeof(nid);
nid.hWnd = hwnd;
nid.uFlags = NIF_ICON;
nid.hIcon = hicon;
Shell_NotifyIcon(NIM_DELETE, &nid);
}
// index into alarm data saved in file
enum {A_name, A_startdate, A_starttime, A_onceonly, A_neverend, A_enddate, A_endtime, A_gap, A_gapunits,
A_between1, A_between2, A_dayfilter, A_active, A_message, A_LAST};
typedef struct _alarm_line_ // alarm data
{
char things[A_LAST][MAX_ASTR];
long atime;
} ALARMLINE;
ALARMLINE AllAlarms[MAX_ALARMS]; // all allarms together
static int paused = 0; // an alarms paused when it's edited
static char *alarmFileName = "d:\\al4rming\\alarms.ini"; // where to find the data
void AddAlarm(ALARMLINE *pa) // add an alarm
{
int i;
for (i = 0;i < MAX_ALARMS;i++)
{
if (strlen(AllAlarms[i].things[A_name]) == 0)
{
memcpy(AllAlarms[i].things, pa, A_LAST * MAX_ASTR);
break;
}
}
}
void LoadAlarmList() // load from file - items are between #\n and #\n
{
FILE *f;
char buff[1024], *p;
int inalarm = 0, i;
ALARMLINE al;
memset(AllAlarms, 0, sizeof(AllAlarms));
f = fopen(alarmFileName, "r");
if (f)
{
while (memset(buff, 0, sizeof(buff)), fgets(buff, sizeof(buff), f) != NULL)
{
if (buff[0] == '#') // start end alarm line
{
if (inalarm)
{
inalarm = 0;
if (strlen(al.things[A_name]))
AddAlarm(&al);
} else
{
memset(&al, 0, sizeof(al));
inalarm = 1;
i = 0;
}
} else
{
if (inalarm)
{
p = strchr(buff, '\n'); if (p) *p = 0;
p = strchr(buff, '\r'); if (p) *p = 0;
if (i < A_LAST)
strncpy(al.things[i++], buff, MAX_ASTR);
}
}
}
fclose(f);
} else
{
_mkdir("d:\\al4rming"); // try creating the path incase its 1st time in
f = fopen(alarmFileName, "w");
if (f)
{
fputs("\n", f);
fclose(f);
}
}
}
void SaveAlarmList() // write them back to the file
{
FILE *f;
int a, i;
f = fopen(alarmFileName, "w");
if (f)
{
for (a = 0;a < MAX_ALARMS; a++)
{
if (strlen(AllAlarms[a].things[A_name]))
{
fprintf(f, "#\n");
for (i = 0;i < A_LAST;i++)
fprintf(f, "%s\n", AllAlarms[a].things[i]);
fprintf(f, "#\n\n");
}
}
fclose(f);
} else
MessageBox(NULL, "Failed to save alarms","Alarming", MB_ICONEXCLAMATION | MB_OK);
}
void DeleteAlarm(int n) // remove an alarm (having a blank name is the same as not existing)
{
memset(AllAlarms[n].things, 0, A_LAST * MAX_ASTR);
}
BOOL checkdatestr(char *pdate) // make sure its mm/dd/yyyy
{
int d,m,y;
char *p;
d = atoi(pdate);
p = strchr(pdate, '/');
if (p)
{
m = atoi(p+1);
p++;
p = strchr(p, '/');
if (p)
{
y = atoi(p+1);
sprintf(pdate, "%02d/%02d/%04d", d,m,y);
return 0;
}
}
strcpy(pdate, "01/01/2000");
return 1;
}
BOOL checktimestr(char *ptim) // make sure it's hh:mm
{
int h, m;
char *p;
h = atoi(ptim);
p = strchr(ptim, ':');
if (p)
{
m = atoi(p+1);
} else
m = 0;
sprintf(ptim, "%02d:%02d", h, m);
return 0;
}
int presavecheck() // quick check of time date formats - ranges NOT checked
{
int a;
ALARMLINE *pa;
for (a = 0;a < MAX_ALARMS;a++)
{
pa = &AllAlarms[a];
if (strlen(pa->things[A_name]))
{
if (pa->things[A_active][0] == 'Y')
{
if (toupper(pa->things[A_gapunits][0]) != 'H')
strcpy(pa->things[A_endtime], pa->things[A_starttime]);
if (atoi(pa->things[A_gap]) == 0)
strcpy(pa->things[A_gap], "1");
checkdatestr(pa->things[A_startdate]);
checktimestr(pa->things[A_starttime]);
checkdatestr(pa->things[A_enddate]);
checktimestr(pa->things[A_endtime]);
checktimestr(pa->things[A_between1]);
checktimestr(pa->things[A_between2]);
}
}
}
return 0;
}
/*
void GetMyDatePlus(LPSTR lpDest, long daystoadd)
get future date: now + extra days to add in format dd/mm/yyy
*/
void GetMyDatePlus(LPSTR lpDest, long daystoadd) // in dd/mm/yyyy format
{
time_t ltime;
struct tm *ptm;
time(<ime);
ltime += daystoadd * 24L * 60L * 60L;
ptm = localtime(<ime);
sprintf(lpDest,
"%02d/%02d/%04d",
ptm->tm_mday,
ptm->tm_mon+1,
ptm->tm_year + 1900);
}
int InitNewAlarm() // fill alarm with defaults
{
int na = -1;
for (na = 0;na < MAX_ALARMS;na++)
{
if (strlen(AllAlarms[na].things[A_name]) == 0)
break;
}
if (na == MAX_ALARMS)
return -1;
sprintf(AllAlarms[na].things[A_name], "Alarm %d", na+1);
GetMyDatePlus(AllAlarms[na].things[A_startdate],0);
strcpy(AllAlarms[na].things[A_starttime],"08:00");
strcpy(AllAlarms[na].things[A_onceonly], "N");
strcpy(AllAlarms[na].things[A_neverend], "N");
GetMyDatePlus(AllAlarms[na].things[A_enddate], 7);
strcpy(AllAlarms[na].things[A_endtime], "23:59");
strcpy(AllAlarms[na].things[A_gap], "1");
strcpy(AllAlarms[na].things[A_gapunits], "Day");
strcpy(AllAlarms[na].things[A_between1], "00:00");
strcpy(AllAlarms[na].things[A_between2], "23:59");
strcpy(AllAlarms[na].things[A_dayfilter], "YYYYYYY");
strcpy(AllAlarms[na].things[A_active], "Y");
sprintf(AllAlarms[na].things[A_message], "This is alarm %d", na+1);
return na;
}
void SetupDlgAlarmData(HWND hwnd, int iParam) // put indo dialog controls
{
ALARMLINE *a;
a = &AllAlarms[iParam];
SetDlgItemText(hwnd, IDC_NAME, a->things[A_name]);
SetDlgItemText(hwnd, IDC_STARTDATE, a->things[A_startdate]);
SetDlgItemText(hwnd, IDC_STARTTIME, a->things[A_starttime]);
CheckDlgButton(hwnd, IDC_ONCEONLY, (stricmp(a->things[A_onceonly], "Y") == 0));
CheckDlgButton(hwnd, IDC_NEVEREND, (stricmp(a->things[A_neverend], "Y") == 0));
SetDlgItemText(hwnd, IDC_ENDDATE, a->things[A_enddate]);
SetDlgItemText(hwnd, IDC_ENDTIME, a->things[A_endtime]);
SetDlgItemText(hwnd, IDC_GAPNUMBER, a->things[A_gap]);
SetDlgItemText(hwnd, IDC_GAPUNITS, a->things[A_gapunits]);
SetDlgItemText(hwnd, IDC_BETWEEN1, a->things[A_between1]);
SetDlgItemText(hwnd, IDC_BETWEEN2, a->things[A_between2]);
CheckDlgButton(hwnd, IDC_MONDAY, (a->things[A_dayfilter][0] == 'Y'));
CheckDlgButton(hwnd, IDC_TUESDAY, (a->things[A_dayfilter][1] == 'Y'));
CheckDlgButton(hwnd, IDC_WEDNESDAY, (a->things[A_dayfilter][2] == 'Y'));
CheckDlgButton(hwnd, IDC_THURSDAY, (a->things[A_dayfilter][3] == 'Y'));
CheckDlgButton(hwnd, IDC_FRIDAY, (a->things[A_dayfilter][4] == 'Y'));
CheckDlgButton(hwnd, IDC_SATURDAY, (a->things[A_dayfilter][5] == 'Y'));
CheckDlgButton(hwnd, IDC_SUNDAY, (a->things[A_dayfilter][6] == 'Y'));
SetDlgItemText(hwnd, IDC_MESSAGE, a->things[A_message]);
CheckDlgButton(hwnd, IDC_ACTIVE, (stricmp(a->things[A_active], "Y") == 0));
}
void makedayfilter(char *dest, HWND hwnd)
{
dest[0] = IsDlgButtonChecked(hwnd, IDC_MONDAY) ? 'Y' : '-';
dest[1] = IsDlgButtonChecked(hwnd, IDC_TUESDAY) ? 'Y' : '-';
dest[2] = IsDlgButtonChecked(hwnd, IDC_WEDNESDAY) ? 'Y' : '-';
dest[3] = IsDlgButtonChecked(hwnd, IDC_THURSDAY) ? 'Y' : '-';
dest[4] = IsDlgButtonChecked(hwnd, IDC_FRIDAY) ? 'Y' : '-';
dest[5] = IsDlgButtonChecked(hwnd, IDC_SATURDAY) ? 'Y' : '-';
dest[6] = IsDlgButtonChecked(hwnd, IDC_SUNDAY) ? 'Y' : '-';
dest[7] = 0;
}
void GrabDlgData(HWND hwnd, int iParam)
{
ALARMLINE *a;
a = &AllAlarms[iParam];
GetDlgItemText(hwnd, IDC_NAME, a->things[A_name], MAX_ASTR);
GetDlgItemText(hwnd, IDC_STARTDATE, a->things[A_startdate], MAX_ASTR);
GetDlgItemText(hwnd, IDC_STARTTIME, a->things[A_starttime], MAX_ASTR);
strcpy(a->things[A_onceonly], IsDlgButtonChecked(hwnd, IDC_ONCEONLY) ? "Y" : "N");
strcpy(a->things[A_neverend], IsDlgButtonChecked(hwnd, IDC_NEVEREND) ? "Y" : "N");
GetDlgItemText(hwnd, IDC_ENDDATE, a->things[A_enddate], MAX_ASTR);
GetDlgItemText(hwnd, IDC_ENDTIME, a->things[A_endtime], MAX_ASTR);
GetDlgItemText(hwnd, IDC_GAPNUMBER, a->things[A_gap], MAX_ASTR);
GetDlgItemText(hwnd, IDC_GAPUNITS, a->things[A_gapunits], MAX_ASTR);
GetDlgItemText(hwnd, IDC_BETWEEN1, a->things[A_between1], MAX_ASTR);
GetDlgItemText(hwnd, IDC_BETWEEN2, a->things[A_between2], MAX_ASTR);
makedayfilter(a->things[A_dayfilter], hwnd);
GetDlgItemText(hwnd, IDC_MESSAGE, a->things[A_message], MAX_ASTR);
strcpy(a->things[A_active], IsDlgButtonChecked(hwnd, IDC_ACTIVE) ? "Y" : "N");
}
BOOL CALLBACK dialog2func( // edit / creat an alarm entry
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
static int iParam;
char buff[MAX_ASTR], name[MAX_ASTR];
switch (uMsg)
{
case WM_INITDIALOG:
iParam = (int) lParam;
if (iParam == -1) // new alarm
{
iParam = InitNewAlarm();
if (iParam < 0)
{
MessageBox(hwnd, "Too many alarms","Alarming", MB_ICONEXCLAMATION | MB_OK);
EndDialog(hwnd, -1);
}
}
SetupDlgAlarmData(hwnd, iParam);
return 0;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_TEST:
GetDlgItemText(hwnd, IDC_NAME, name, sizeof(name));
GetDlgItemText(hwnd, IDC_MESSAGE, buff, sizeof(buff));
AlarmFunc(name, buff, iParam);
break;
case IDCANCEL: // quit dont save dont do updates
LoadAlarmList(); // reload to dispose of unwanted edits
EndDialog(hwnd, 0);
return 1;
case IDOK: // save settings
GrabDlgData( hwnd, iParam);
presavecheck();
SaveAlarmList();
LoadAlarmList(); // reload to dispose of deletions
EndDialog(hwnd, 1);
return 1;
default:
break;
}
break;
default:
break;
}
return 0;
}
void fillalarmlistbox(HWND hwnd)
{
int i;
char buff[MAX_ASTR];
int tabstops[] = {110, 0};
SendMessage(GetDlgItem(hwnd, IDC_ALARMLIST), LB_RESETCONTENT, 0, 0);
SendDlgItemMessage(hwnd, IDC_ALARMLIST, LB_SETTABSTOPS, 1, (LPARAM) tabstops); // so 'Active' lines up
for (i = 0;i < MAX_ALARMS;i++)
{
if (strlen(AllAlarms[i].things[A_name]) > 0)
{
if (AllAlarms[i].things[A_active][0] == 'Y')
{
sprintf(buff, "%-64.64s \tActive", AllAlarms[i].things[A_name]);
} else
{
sprintf(buff, "%-64.64s \t-", AllAlarms[i].things[A_name]);
}
SendMessage(GetDlgItem(hwnd, IDC_ALARMLIST), LB_ADDSTRING, 0, (LPARAM) (char *)buff);
}
}
}
BOOL CALLBACK dialog1func( // 1st dialog box showing drop down alarms and creation buttons
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
int i;
switch (uMsg)
{
case WM_INITDIALOG:
fillalarmlistbox(hwnd);
SendMessage(GetDlgItem(hwnd, IDC_ALARMLIST), LB_SETCURSEL, 0, 0);
return 0;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_ALARMLIST: // something's happened to the alarm list box
switch (HIWORD(wParam))
{
case LBN_DBLCLK: // double clicked
paused = 1;
i = SendMessage((HWND)GetDlgItem(hwnd, IDC_ALARMLIST), LB_GETCURSEL, 0, 0); // current selection
DialogBoxParam( (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
MAKEINTRESOURCE(IDD_DIALOG2),
hwnd,
dialog2func,
(LPARAM) i);
fillalarmlistbox(hwnd);
SendMessage(GetDlgItem(hwnd, IDC_ALARMLIST), LB_SETCURSEL, i, 0);
paused = 0;
break;
default:
break;
}
return 1;
case IDC_NEW: // new alarm
paused = 1;
DialogBoxParam( (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
MAKEINTRESOURCE(IDD_DIALOG2),
hwnd,
dialog2func,
(LPARAM) (int) -1);
fillalarmlistbox(hwnd);
paused = 0;
return 1;
case IDC_EXIT: // shut down
EndDialog(hwnd, -1);
return 1;
case IDCANCEL: // quit dont save dont do updates
EndDialog(hwnd, 0);
return 1;
case IDOK: // save settings
EndDialog(hwnd, 1);
return 1;
default:
break;
}
break;
default:
break;
}
return 0;
}
void SetOffAlarm(ALARMLINE *pa, int idx) // set one-offs to inactive and spawn alarm thread
{
if (pa->things[A_onceonly][0] == 'Y')
{
pa->things[A_active][0] = 'N';
SaveAlarmList();
}
AlarmFunc(pa->things[A_name], pa->things[A_message], idx);
}
int compareStrdat2Struct(char *strdat, struct tm *ptm) // -1 strdat < tm
{
int aday, amonth, ayear;
aday = atoi(strdat); // dd/mm/yyyy
amonth = atoi(strdat+3) - 1;
ayear = atoi(strdat+6) - 1900;
if (ayear < ptm->tm_year)
return -1;
if (ayear > ptm->tm_year)
return 1;
if (amonth < ptm->tm_mon)
return -1;
if (amonth > ptm->tm_mon)
return 1;
if (aday < ptm->tm_mday)
return -1;
if (aday > ptm->tm_mday)
return 1;
return 0;
}
int compareStrtim2Struct(char *strtim, struct tm *ptm) // -1 strtim < tm
{
int ahour, amin;
ahour = atoi(strtim); // HH:ss
amin = atoi(strtim + 3);
if (ahour < ptm->tm_hour)
return -1;
if (ahour > ptm->tm_hour)
return 1;
if (amin < ptm->tm_min)
return -1;
if (amin > ptm->tm_min)
return 1;
return 0;
}
BOOL StartDateOk(ALARMLINE *pa, struct tm *ptm)
{
return compareStrdat2Struct(pa->things[A_startdate], ptm) <= 0;
}
BOOL EndDateOk(ALARMLINE *pa, struct tm *ptm)
{
if (pa->things[A_neverend][0] == 'Y')
return 1;
return compareStrdat2Struct(pa->things[A_enddate], ptm) >= 0;
}
BOOL StartTimeOk(ALARMLINE *pa, struct tm *ptm)
{
int i;
i = compareStrdat2Struct(pa->things[A_startdate], ptm);
if (i == 0)
return compareStrtim2Struct(pa->things[A_starttime], ptm) <= 0;
return i < 0;
}
BOOL EndTimeOk(ALARMLINE *pa, struct tm *ptm)
{
int i;
if (pa->things[A_neverend][0] == 'Y')
return 1;
i = compareStrdat2Struct(pa->things[A_enddate], ptm);
if (i == 0)
return compareStrtim2Struct(pa->things[A_endtime], ptm) >= 0;
return i > 0;
}
BOOL BetweenTimesOk(ALARMLINE *pa, struct tm *ptm)
{
return compareStrtim2Struct(pa->things[A_between1], ptm) <= 0 &&
compareStrtim2Struct(pa->things[A_between2], ptm) >= 0;
}
BOOL DayFilterOk(ALARMLINE *pa, struct tm *ptm)
{
int d;
char c;
d = ptm->tm_wday; // days since sunday
d = (d + 6) % 7; // convert to mtwtfss
c = pa->things[A_dayfilter][d];
return c == 'Y';
}
BOOL IsLeapYear(long iYear)
{
int iQuotient;
BOOL fLeapYr = FALSE;
if(!(iYear%4) && (iYear%100))
fLeapYr = TRUE;
else
{
if(!(iYear % 4) && !(iYear % 100))
{
iQuotient = iYear / 100;
if(!(iQuotient % 4))
fLeapYr = TRUE;
}
}
return (fLeapYr);
}
long datetime2minutesfrom1970(char *pdate, char *ptim) // dd/mm/yyyy hh:mm
{
long ayear, y, d, h, m;
ayear = atoi(pdate + 6);
for (d = 0, y = 1970;y < ayear; y++)
{
if (IsLeapYear(y))
d += 366;
else
d += 365;
}
h = atoi(ptim);
m = atoi(ptim + 3);
return m + (h * 60) + (d * 24 * 60);
}
long gapinminutes(char *pn, char *punit)
{
long l, m;
l = atoi(pn);
switch (*punit)
{
case 'd':
case 'D':
m = 24 * 60;
break;
case 'w':
case 'W':
m = 24 * 7 * 60;
break;
case 'h':
case 'H':
default:
m = 60; // hours
break;
}
return m * l;
}
BOOL GapOk(ALARMLINE *pa, struct tm *ptm) // exact multiple of gap time passed?
{
BOOL bRet = 0;
long mSinceStart, mToNow, mGap;
char datenow[16], timnow[16];
sprintf(datenow, "%02d/%02d/%04d", ptm->tm_mday, ptm->tm_mon + 1, ptm->tm_year + 1900);
sprintf(timnow, "%02d:%02d", ptm->tm_hour, ptm->tm_min);
if (pa->things[A_gapunits][0] == 'M' || pa->things[A_gapunits][0] == 'm') // monthly gap same day?
{
bRet = atoi(pa->things[A_startdate]) == atoi(datenow);
} else
{
mSinceStart = datetime2minutesfrom1970(pa->things[A_startdate], pa->things[A_starttime]);
mToNow = datetime2minutesfrom1970(datenow, timnow);
mGap = gapinminutes(pa->things[A_gap], pa->things[A_gapunits]);
bRet = ((mToNow - mSinceStart) % mGap) == 0;
}
return bRet;
}
void CheckAlarm(ALARMLINE *pa, struct tm *ptm, int idx)
{
if (StartDateOk(pa, ptm))
if (EndDateOk(pa, ptm))
if (StartTimeOk(pa, ptm))
if (EndTimeOk(pa, ptm))
if (BetweenTimesOk(pa, ptm))
if (DayFilterOk(pa, ptm))
if (GapOk(pa, ptm))
SetOffAlarm(pa, idx);
}
void DoAlarmPoll()
{
int a;
ALARMLINE *al;
long tnow;
struct tm *ptm;
tnow = time(NULL);
ptm = localtime(&tnow);
for (a = 0;a < MAX_ALARMS;a++)
{
al = &AllAlarms[a];
if (strlen(al->things[A_name]))
{
if (al->things[A_active][0] == 'Y')
{
if (tnow > (al->atime + 50)) // at least 50 secs since last checked
{
CheckAlarm(al, ptm, a);
al->atime = tnow;
}
}
}
}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
int wmId, wmEvent;
static HICON hicon;
static int nimGate = 0;
PAINTSTRUCT ps;
switch (message)
{
case NIM_CALLBACK:
if (nimGate == 0)
{
nimGate++;
if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN)
{
if (DialogBox( (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
MAKEINTRESOURCE(IDD_DIALOG1),
hWnd,
dialog1func ) == -1)
{
PostMessage(hWnd, WM_CLOSE, 0, 0);
}
}
nimGate--;
} else
{
SetForegroundWindow(hWnd );
ShowOwnedPopups(hWnd, 1);
}
break;
case WM_CREATE:
AlarmsOn();
hicon = LoadIcon((HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), MAKEINTRESOURCE(IDI_ICON3));
AddTrayIcon( hWnd, hicon);
LoadAlarmList();
SetTimer(hWnd, 1, 5000, NULL);
break;
case WM_TIMER:
KillTimer(hWnd, 1);
if (paused == 0)
{
DoAlarmPoll();
}
SetTimer(hWnd, 1, 5000, NULL);
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId)
{
case WM_CLOSE:
PostMessage(hWnd, WM_DESTROY,0,0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
AlarmsOff();
PostQuitMessage(0);
DelTrayIcon( hWnd, hicon);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // pointer to command line
int nShowCmd // show state of window
)
{
static char *szWindowClass = "Alarming";
static char *szTitle = "Alarming";
WNDCLASSEX wcex;
HWND hWnd;
MSG msg;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = NULL;
RegisterClassEx(&wcex);
hWnd = CreateWindow(szWindowClass, szTitle,WS_OVERLAPPEDWINDOW,
10,10, 200, 300, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, SW_HIDE);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
Here's alarm.c ...
// alarm.c
#include <windows.h>
#include <stdio.h>
#include <process.h>
#include <mmsystem.h>
#include <time.h>
#include <process.h>
#include "alarming.h"
// a pale yellow background
#define POPBACKGROUND RGB(255,255,183)
#define SOUNDGAP 10000 // deleay between alarm noises
// the alarm noise which goes off every SOUNDGAP millisecs - this file should be kept small
static char *soundfile = "d:\\al4rming\\alarm.wav";
static char *szWindowClass = "Alarm";
static char *szTitle = "Alarm";
static unsigned long cReg = 0; // window class registered flag
static int aoff = 0; // alarms off flag
static int activea[MAX_ALARMS]; // which alarms are active
typedef struct _adata_ // data passed to each alarm window
{
int idx;
char msg[MAX_ASTR + MAX_ASTR + 32];
long tim;
} ADATA;
static CRITICAL_SECTION cs1; // for thread syncs
static int SoundOwner = -1; // I want only 1 alarm to play the sounds even if several are active
static BOOL GrabTheSound(int idx) // grab and keep ownership. retunr TRUE if okay to play sound
{
EnterCriticalSection(&cs1);
if (SoundOwner == -1)
SoundOwner = idx;
LeaveCriticalSection(&cs1);
return (SoundOwner == idx);
}
static void ReleaseTheSound(int idx) // release ownership for any other thread
{
EnterCriticalSection(&cs1);
if (SoundOwner == idx)
SoundOwner = -1;
LeaveCriticalSection(&cs1);
}
LRESULT CALLBACK AlarmWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) // callback function
{
HDC hdc;
PAINTSTRUCT ps;
RECT r;
ADATA *pa;
long tim;
int cx, x;
switch (message)
{
case WM_CREATE:
SetTimer(hwnd, 1, 100, NULL); // timer for window motion across screen
SetTimer(hwnd, 2, 200, NULL); // timer for playing sound
break;
case WM_TIMER:
if (aoff) // told to turn off
{
PostMessage(hwnd, WM_CLOSE, 0, 0);
break;
}
pa = (ADATA *) GetWindowLong(hwnd, GWL_USERDATA);
tim = time(NULL);
if (pa->tim < (tim - (60 * 15))) // 15 minutes has gone by so close it
PostMessage(hwnd, WM_CLOSE, 0, 0);
if (wParam == 2)
{
KillTimer(hwnd, 2);
if (GrabTheSound(pa->idx)) // play sound if this thread owns it
PlaySound(soundfile, NULL, SND_ASYNC | SND_FILENAME );
SetTimer(hwnd, 2, SOUNDGAP, NULL);
} else
if (wParam == 1)
{
KillTimer(hwnd, 1); // march window across screen
GetWindowRect(hwnd, &r);
cx = GetSystemMetrics(SM_CXSCREEN);
x = (r.right < cx) ? r.left + 1 : 1;
SetWindowPos(hwnd, HWND_TOPMOST, x, r.top, 0,0, SWP_SHOWWINDOW | SWP_NOSIZE);
SetTimer(hwnd, 1, 100, NULL);
}
break;
case WM_RBUTTONDOWN:
case WM_LBUTTONDOWN:
PostMessage(hwnd, WM_CLOSE, 0, 0); // any click in the area closes it
break;
case WM_PAINT:
pa = (ADATA *) GetWindowLong(hwnd, GWL_USERDATA);
GetClientRect(hwnd, &r);
hdc = BeginPaint(hwnd, &ps);
SelectObject (hdc, GetStockObject (ANSI_VAR_FONT));
SetBkColor(hdc, POPBACKGROUND);
TextOut(hdc, 2,2,pa->msg, strlen(pa->msg));
FrameRect(hdc, &r, GetStockObject(BLACK_BRUSH));
EndPaint(hwnd, &ps);
break;
case WM_CLOSE:
PostMessage(hwnd, WM_DESTROY,0,0);
break;
case WM_DESTROY:
pa = (ADATA *) GetWindowLong(hwnd, GWL_USERDATA);
ReleaseTheSound(pa->idx);
KillTimer(hwnd, 1);
KillTimer(hwnd, 2);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
void AlarmThread(void *pl) // the alarm thread itself
{
HWND hwnd;
MSG msg;
ADATA *pa;
SIZE si;
HDC hdc;
pa = (ADATA *) pl;
hwnd = CreateWindow(szWindowClass, szTitle, WS_POPUP, 10,10, 200, 300, NULL, NULL, NULL, NULL); // dummy poz and size
SetWindowLong(hwnd, GWL_USERDATA, (long) pa);
hdc = GetDC(hwnd);
SelectObject (hdc, GetStockObject (ANSI_VAR_FONT));
GetTextExtentPoint32(hdc, pa->msg, strlen(pa->msg), &si); // calculate size of window
ReleaseDC(hwnd, hdc);
MoveWindow(hwnd, 1, (pa->idx * (si.cy + 8)) + 2, si.cx + 8, si.cy + 6, 0); // place on screen
ShowWindow(hwnd, SW_SHOWDEFAULT);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
activea[pa->idx] = 0;
free(pa);
}
void AlarmFunc(char *pname, char *pmsg, int alarmindex)
{
static BOOL bFirst = 1;
ADATA *p;
WNDCLASSEX wcex;
char tbuff[16];
if (bFirst)
{
bFirst = 0;
InitializeCriticalSection(&cs1);
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)AlarmWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = NULL;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_UPARROW);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = NULL;
wcex.hbrBackground = CreateSolidBrush(POPBACKGROUND);
RegisterClassEx(&wcex);
}
if (activea[alarmindex] == 0) // if alarm is not already active
{
activea[alarmindex] = 1;
p = calloc(1, sizeof(ADATA)); // set up data
_strtime(tbuff);
sprintf(p->msg, "%s - %s: %s", tbuff, pname, pmsg);
p->idx = alarmindex;
p->tim = time(NULL);
_beginthread(AlarmThread, 0, (void *) p); // start alarm thread
}
}
void AlarmsOff()
{
aoff = 1;
Sleep(250);
}
void AlarmsOn()
{
aoff = 0;
}
Have fun ...
|