|
|
/* Copyright 1999 American Power Conversion, All Rights Reserved
* * Description: * The file implements the Notifier. The Notifier is reponsible * for broadcasting power-related and shutdown messages to the * local machine. * * * Revision History: * sberard 30Mar1999 initial revision. * mholly 27Apr1999 create and recycle a single thread for repeat * notifications - use two separate events to signal * either pause or resume of the thread state * mholly 27Apr1999 make sure to clear the pause event when resuming * and to clear the resume event when pausing * mholly 28May1999 send all messages in _theNotifierThread, also * have this thread do any delaying for the callee, * and keep track of whether a power out message * was sent, so we know when to send a power restored */
#include "notifier.h"
#include "service.h"
#include "upsmsg.h"
//
// Function prototypes
//
static void sendSingleNotification(DWORD aMsgId); static void sendRepeatingNotification(void); static void setupNotifierThread(void);
//
// Globals
//
static HANDLE _theNotifierThread = NULL; static HANDLE _theNotificationPause = NULL; static HANDLE _theNotificationResume = NULL; static DWORD _theMessageId; static DWORD _theNotificationInterval; static DWORD _theMessageDelay; static DWORD _theLastMessageSent = 0;
//
// Constats
//
static const int kMilliSeconds = 1000; // Used to convert seconds to milliseconds
/**
* SendNotification * * Description: * This function sends a broadcast message to the local machine. The * message is specified by aMsgId. The parameter anInterval specifies * the amount of time to wait between consecutive messages. If this * value is zero the message is only sent once, otherwise the message * will repeat until SendNotification(..) or CancelNotification() is * called. aDelay specifies that the message should be send aDelay * seconds in the future - note that this method will not block for aDelay * seconds, it returns immediately and sends the message on a separate * thread. Any current previously executing periodic notifications * are canceled as a result of this call. * * This method also keeps track of whether the power out message had * been sent to users. This is done in order to squelch a power return * message if a power out message had not already been sent. * * Parameters: * aMsgId - the message to send * anInterval - the amount of time, in seconds, between messages * aDelay - the amount of time, in seconds to wait to send message * * Returns: * nothing */ void SendNotification(DWORD aMsgId, DWORD anInterval, DWORD aDelay) { //
// Cancel any current periodic notifications
//
CancelNotification();
//
// only sent the power back message if
// the power out message had already
// been broadcast to the users
//
if ((APE2_UPS_POWER_BACK == aMsgId) && (APE2_UPS_POWER_OUT != _theLastMessageSent)) { //
// the last message sent was not power out
// so simply return
//
return; } //
// Set the message parameters for _theNotifierThread
//
_theMessageId = aMsgId; _theNotificationInterval = anInterval; _theMessageDelay = aDelay; //
// setup the thread events and thread
//
setupNotifierThread();
//
// tell _theNotificationThread to run by
// signalling the resume event - must make
// sure to clear the pause event before
// signalling the resume
//
ResetEvent(_theNotificationPause); SetEvent(_theNotificationResume); }
/**
* CancelNotification * * Description: * This function cancels the periodic messaging initiated through a call * to the SendNotification(..) function. * * Parameters: * none * * Returns: * nothing */ void CancelNotification() { //
// tell _theNotificationThread to pause
// by signalling the pause event - must make
// sure to clear the resume event before
// signalling the pause event
//
ResetEvent(_theNotificationResume); SetEvent(_theNotificationPause); }
/**
* setupNotifierThread * * Description: * Creates the thread on which the notifications will * actually be sent. It also creates the events that * are used to signal the start and end of notifications * * Parameters: * none * * Returns: * nothing
*/ void setupNotifierThread(void) { if (!_theNotificationPause) { //
// Create the pause event
//
_theNotificationPause = CreateEvent(NULL, FALSE, FALSE, NULL); }
if (!_theNotificationResume) { //
// create the resume event
//
_theNotificationResume = CreateEvent(NULL, FALSE, FALSE, NULL); }
if (!_theNotifierThread) { //
// create the notification thread
//
_theNotifierThread = CreateThread(NULL, // no security attributes
0, // default stack
(LPTHREAD_START_ROUTINE) sendRepeatingNotification, NULL, 0, NULL); } }
/**
* sendSingleNotification * * Description: * This function sends a single broadcast message to the local machine. * The message is specified by aMsgId. * * Parameters: * aMsgId - the message to send * * Returns: * nothing */ static void sendSingleNotification(DWORD aMsgId) { DWORD status; TCHAR computer_name[MAX_COMPUTERNAME_LENGTH + 1]; DWORD computer_name_len = MAX_COMPUTERNAME_LENGTH + 1; LPTSTR msg_buf, additional_args[1]; DWORD buf_len; // Get the computer name and pass it as additional
// information for the message
GetComputerName(computer_name, &computer_name_len); additional_args[0] = computer_name; buf_len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_SYSTEM , NULL, // NULL means get message from system
aMsgId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &msg_buf, 0, // buffer size
(va_list *)additional_args); // additional arguements
if (buf_len > 0) { _theLastMessageSent = aMsgId; // Display the message
status = NetMessageBufferSend(NULL, computer_name, computer_name, (LPBYTE) msg_buf, buf_len * 2); // multiply by 2 because the string is Unicodeh
// Free the memory allocated by FormatMessage
LocalFree(msg_buf); } }
/**
* sendRepeatingNotification * * Description: * This function sends notifications repeatedly to the local machine. * This function calls sendSingleNotification(..) to perform the actual * notification. The message will be sent after _theMessageDelay seconds * has elapsed after _theNotificationResume event is signaled. If * _theMessageDelay is zero, a message is sent immediately. Messages are * repeated, if _theNotificationInterval is not zero, until the Event * _theNotificationPause is signaled. The message Id and the notification * interval are specified by the global variables _theMessageId and * _theNotificationInterval. * * To restart notifications using this thread signal _theNotificationResume * event. This thread will remain idle until this event is signalled * * Parameters: * none * * Returns: * nothing */ static void sendRepeatingNotification(void) { //
// wait for _theNotificationResume to become signaled
// this becomes signaled when a notification should be sent
//
while (WAIT_OBJECT_0 == WaitForSingleObject(_theNotificationResume, INFINITE)) { //
// Send the initial message after the message delay
// seconds has elapsed - if _theNotificationPause becomes
// signaled before the delay seconds has elapsed then
// this notification has been cancelled
//
if (WAIT_TIMEOUT == WaitForSingleObject(_theNotificationPause, _theMessageDelay * kMilliSeconds)) {
//
// send the message that was requested
//
sendSingleNotification(_theMessageId);
//
// now send repeating notifications
// if necessary - if _theNotificationInterval
// is set to zero, then only send the single
// message above
//
if (0 != _theNotificationInterval) { //
// wait for either _theNotificationPause to become
// signalled or until it is time to notify again
//
DWORD interval = _theNotificationInterval * kMilliSeconds;
while (WAIT_TIMEOUT == WaitForSingleObject(_theNotificationPause, interval)) { sendSingleNotification(_theMessageId); } } } } }
|