Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

311 lines
9.0 KiB

  1. /* Copyright 1999 American Power Conversion, All Rights Reserved
  2. *
  3. * Description:
  4. * The file implements the Notifier. The Notifier is reponsible
  5. * for broadcasting power-related and shutdown messages to the
  6. * local machine.
  7. *
  8. *
  9. * Revision History:
  10. * sberard 30Mar1999 initial revision.
  11. * mholly 27Apr1999 create and recycle a single thread for repeat
  12. * notifications - use two separate events to signal
  13. * either pause or resume of the thread state
  14. * mholly 27Apr1999 make sure to clear the pause event when resuming
  15. * and to clear the resume event when pausing
  16. * mholly 28May1999 send all messages in _theNotifierThread, also
  17. * have this thread do any delaying for the callee,
  18. * and keep track of whether a power out message
  19. * was sent, so we know when to send a power restored
  20. */
  21. #include "notifier.h"
  22. #include "service.h"
  23. #include "upsmsg.h"
  24. //
  25. // Function prototypes
  26. //
  27. static void sendSingleNotification(DWORD aMsgId);
  28. static void sendRepeatingNotification(void);
  29. static void setupNotifierThread(void);
  30. //
  31. // Globals
  32. //
  33. static HANDLE _theNotifierThread = NULL;
  34. static HANDLE _theNotificationPause = NULL;
  35. static HANDLE _theNotificationResume = NULL;
  36. static DWORD _theMessageId;
  37. static DWORD _theNotificationInterval;
  38. static DWORD _theMessageDelay;
  39. static DWORD _theLastMessageSent = 0;
  40. //
  41. // Constats
  42. //
  43. static const int kMilliSeconds = 1000; // Used to convert seconds to milliseconds
  44. /**
  45. * SendNotification
  46. *
  47. * Description:
  48. * This function sends a broadcast message to the local machine. The
  49. * message is specified by aMsgId. The parameter anInterval specifies
  50. * the amount of time to wait between consecutive messages. If this
  51. * value is zero the message is only sent once, otherwise the message
  52. * will repeat until SendNotification(..) or CancelNotification() is
  53. * called. aDelay specifies that the message should be send aDelay
  54. * seconds in the future - note that this method will not block for aDelay
  55. * seconds, it returns immediately and sends the message on a separate
  56. * thread. Any current previously executing periodic notifications
  57. * are canceled as a result of this call.
  58. *
  59. * This method also keeps track of whether the power out message had
  60. * been sent to users. This is done in order to squelch a power return
  61. * message if a power out message had not already been sent.
  62. *
  63. * Parameters:
  64. * aMsgId - the message to send
  65. * anInterval - the amount of time, in seconds, between messages
  66. * aDelay - the amount of time, in seconds to wait to send message
  67. *
  68. * Returns:
  69. * nothing
  70. */
  71. void SendNotification(DWORD aMsgId, DWORD anInterval, DWORD aDelay)
  72. {
  73. //
  74. // Cancel any current periodic notifications
  75. //
  76. CancelNotification();
  77. //
  78. // only sent the power back message if
  79. // the power out message had already
  80. // been broadcast to the users
  81. //
  82. if ((APE2_UPS_POWER_BACK == aMsgId) &&
  83. (APE2_UPS_POWER_OUT != _theLastMessageSent)) {
  84. //
  85. // the last message sent was not power out
  86. // so simply return
  87. //
  88. return;
  89. }
  90. //
  91. // Set the message parameters for _theNotifierThread
  92. //
  93. _theMessageId = aMsgId;
  94. _theNotificationInterval = anInterval;
  95. _theMessageDelay = aDelay;
  96. //
  97. // setup the thread events and thread
  98. //
  99. setupNotifierThread();
  100. //
  101. // tell _theNotificationThread to run by
  102. // signalling the resume event - must make
  103. // sure to clear the pause event before
  104. // signalling the resume
  105. //
  106. ResetEvent(_theNotificationPause);
  107. SetEvent(_theNotificationResume);
  108. }
  109. /**
  110. * CancelNotification
  111. *
  112. * Description:
  113. * This function cancels the periodic messaging initiated through a call
  114. * to the SendNotification(..) function.
  115. *
  116. * Parameters:
  117. * none
  118. *
  119. * Returns:
  120. * nothing
  121. */
  122. void CancelNotification()
  123. {
  124. //
  125. // tell _theNotificationThread to pause
  126. // by signalling the pause event - must make
  127. // sure to clear the resume event before
  128. // signalling the pause event
  129. //
  130. ResetEvent(_theNotificationResume);
  131. SetEvent(_theNotificationPause);
  132. }
  133. /**
  134. * setupNotifierThread
  135. *
  136. * Description:
  137. * Creates the thread on which the notifications will
  138. * actually be sent. It also creates the events that
  139. * are used to signal the start and end of notifications
  140. *
  141. * Parameters:
  142. * none
  143. *
  144. * Returns:
  145. * nothing
  146. */
  147. void setupNotifierThread(void)
  148. {
  149. if (!_theNotificationPause) {
  150. //
  151. // Create the pause event
  152. //
  153. _theNotificationPause = CreateEvent(NULL, FALSE, FALSE, NULL);
  154. }
  155. if (!_theNotificationResume) {
  156. //
  157. // create the resume event
  158. //
  159. _theNotificationResume = CreateEvent(NULL, FALSE, FALSE, NULL);
  160. }
  161. if (!_theNotifierThread) {
  162. //
  163. // create the notification thread
  164. //
  165. _theNotifierThread = CreateThread(NULL, // no security attributes
  166. 0, // default stack
  167. (LPTHREAD_START_ROUTINE)
  168. sendRepeatingNotification,
  169. NULL,
  170. 0,
  171. NULL);
  172. }
  173. }
  174. /**
  175. * sendSingleNotification
  176. *
  177. * Description:
  178. * This function sends a single broadcast message to the local machine.
  179. * The message is specified by aMsgId.
  180. *
  181. * Parameters:
  182. * aMsgId - the message to send
  183. *
  184. * Returns:
  185. * nothing
  186. */
  187. static void sendSingleNotification(DWORD aMsgId)
  188. {
  189. DWORD status;
  190. TCHAR computer_name[MAX_COMPUTERNAME_LENGTH + 1];
  191. DWORD computer_name_len = MAX_COMPUTERNAME_LENGTH + 1;
  192. LPTSTR msg_buf, additional_args[1];
  193. DWORD buf_len;
  194. // Get the computer name and pass it as additional
  195. // information for the message
  196. GetComputerName(computer_name, &computer_name_len);
  197. additional_args[0] = computer_name;
  198. buf_len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  199. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  200. FORMAT_MESSAGE_FROM_SYSTEM ,
  201. NULL, // NULL means get message from system
  202. aMsgId,
  203. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  204. (LPTSTR) &msg_buf,
  205. 0, // buffer size
  206. (va_list *)additional_args); // additional arguements
  207. if (buf_len > 0) {
  208. _theLastMessageSent = aMsgId;
  209. // Display the message
  210. status = NetMessageBufferSend(NULL,
  211. computer_name,
  212. computer_name,
  213. (LPBYTE) msg_buf,
  214. buf_len * 2); // multiply by 2 because the string is Unicodeh
  215. // Free the memory allocated by FormatMessage
  216. LocalFree(msg_buf);
  217. }
  218. }
  219. /**
  220. * sendRepeatingNotification
  221. *
  222. * Description:
  223. * This function sends notifications repeatedly to the local machine.
  224. * This function calls sendSingleNotification(..) to perform the actual
  225. * notification. The message will be sent after _theMessageDelay seconds
  226. * has elapsed after _theNotificationResume event is signaled. If
  227. * _theMessageDelay is zero, a message is sent immediately. Messages are
  228. * repeated, if _theNotificationInterval is not zero, until the Event
  229. * _theNotificationPause is signaled. The message Id and the notification
  230. * interval are specified by the global variables _theMessageId and
  231. * _theNotificationInterval.
  232. *
  233. * To restart notifications using this thread signal _theNotificationResume
  234. * event. This thread will remain idle until this event is signalled
  235. *
  236. * Parameters:
  237. * none
  238. *
  239. * Returns:
  240. * nothing
  241. */
  242. static void sendRepeatingNotification(void)
  243. {
  244. //
  245. // wait for _theNotificationResume to become signaled
  246. // this becomes signaled when a notification should be sent
  247. //
  248. while (WAIT_OBJECT_0 ==
  249. WaitForSingleObject(_theNotificationResume, INFINITE)) {
  250. //
  251. // Send the initial message after the message delay
  252. // seconds has elapsed - if _theNotificationPause becomes
  253. // signaled before the delay seconds has elapsed then
  254. // this notification has been cancelled
  255. //
  256. if (WAIT_TIMEOUT == WaitForSingleObject(_theNotificationPause,
  257. _theMessageDelay * kMilliSeconds)) {
  258. //
  259. // send the message that was requested
  260. //
  261. sendSingleNotification(_theMessageId);
  262. //
  263. // now send repeating notifications
  264. // if necessary - if _theNotificationInterval
  265. // is set to zero, then only send the single
  266. // message above
  267. //
  268. if (0 != _theNotificationInterval) {
  269. //
  270. // wait for either _theNotificationPause to become
  271. // signalled or until it is time to notify again
  272. //
  273. DWORD interval = _theNotificationInterval * kMilliSeconds;
  274. while (WAIT_TIMEOUT ==
  275. WaitForSingleObject(_theNotificationPause, interval)) {
  276. sendSingleNotification(_theMessageId);
  277. }
  278. }
  279. }
  280. }
  281. }