1 // This file is part of BOINC.
2 // http://boinc.berkeley.edu
3 // Copyright (C) 2008 University of California
4 //
5 // BOINC is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License
7 // as published by the Free Software Foundation,
8 // either version 3 of the License, or (at your option) any later version.
9 //
10 // BOINC is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 // See the GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with BOINC. If not, see <http://www.gnu.org/licenses/>.
17
18 #include "boinc_win.h"
19
20 #ifdef _MSC_VER
21 #define snprintf _snprintf
22 #endif
23
24 #include "diagnostics.h"
25 #include "error_numbers.h"
26 #include "filesys.h"
27 #include "network.h"
28 #include "prefs.h"
29 #include "str_replace.h"
30 #include "url.h"
31 #include "util.h"
32 #include "win_util.h"
33
34 #include "client_state.h"
35 #include "log_flags.h"
36 #include "client_msgs.h"
37 #include "http_curl.h"
38 #include "sandbox.h"
39 #include "main.h"
40 #include "cs_proxy.h"
41 #include "net_stats.h"
42
43 #include "sysmon_win.h"
44
45
46 static HANDLE g_hWindowsMonitorSystemPowerThread = NULL;
47 static HWND g_hWndWindowsMonitorSystemPower = NULL;
48 static HANDLE g_hWindowsMonitorSystemProxyThread = NULL;
49
50
51 // return true if running under remote desktop
52 // (in which case CUDA and Stream apps don't work)
53 //
is_remote_desktop()54 bool is_remote_desktop() {
55 LPTSTR pBuf = NULL;
56 DWORD dwLength;
57 USHORT usProtocol=0, usConnectionState=0;
58
59 if (WTSQuerySessionInformation(
60 WTS_CURRENT_SERVER_HANDLE,
61 WTS_CURRENT_SESSION,
62 WTSClientProtocolType,
63 &pBuf,
64 &dwLength
65 )) {
66 usProtocol = *(USHORT*)pBuf;
67 WTSFreeMemory(pBuf);
68 }
69
70 if (WTSQuerySessionInformation(
71 WTS_CURRENT_SERVER_HANDLE,
72 WTS_CURRENT_SESSION,
73 WTSConnectState,
74 &pBuf,
75 &dwLength
76 )) {
77 usConnectionState = *(USHORT*)pBuf;
78 WTSFreeMemory(pBuf);
79 }
80
81 // RDP Session implies Remote Desktop
82 if (usProtocol == 2) return true;
83
84 // Fast User Switching keeps the protocol set to the console but changes
85 // the connected state to disconnected.
86 if ((usProtocol == 0) && (usConnectionState == 4)) return true;
87
88 return false;
89 }
90
91 // The following 3 functions are called in a separate thread,
92 // so we can't do anything directly.
93 // Set flags telling the main thread what to do.
94 //
95
96 // Quit operations
quit_client()97 static void quit_client() {
98 gstate.requested_exit = true;
99 while (1) {
100 boinc_sleep(1.0);
101 if (gstate.cleanup_completed) break;
102 }
103 }
104
105 // Suspend client operations
suspend_client()106 static void suspend_client() {
107 gstate.os_requested_suspend = true;
108 gstate.os_requested_suspend_time = dtime();
109 }
110
111 // Resume client operations
resume_client()112 static void resume_client() {
113 gstate.os_requested_suspend = false;
114 }
115
116 // Process console messages sent by the system
console_control_handler(DWORD dwCtrlType)117 static BOOL WINAPI console_control_handler( DWORD dwCtrlType ){
118 BOOL bReturnStatus = FALSE;
119 BOINCTRACE("***** Console Event Detected *****\n");
120 switch( dwCtrlType ){
121 case CTRL_LOGOFF_EVENT:
122 BOINCTRACE("Event: CTRL-LOGOFF Event\n");
123 if (!gstate.executing_as_daemon) {
124 quit_client();
125 }
126 bReturnStatus = TRUE;
127 break;
128 case CTRL_C_EVENT:
129 case CTRL_BREAK_EVENT:
130 BOINCTRACE("Event: CTRL-C or CTRL-BREAK Event\n");
131 quit_client();
132 bReturnStatus = TRUE;
133 break;
134 case CTRL_CLOSE_EVENT:
135 case CTRL_SHUTDOWN_EVENT:
136 BOINCTRACE("Event: CTRL-CLOSE or CTRL-SHUTDOWN Event\n");
137 quit_client();
138 break;
139 }
140 return bReturnStatus;
141 }
142
post_sysmon_msg(const char * msg)143 static void post_sysmon_msg(const char* msg) {
144 if (gstate.have_sysmon_msg) return;
145 safe_strcpy(gstate.sysmon_msg, msg);
146 gstate.have_sysmon_msg = true;
147 }
148
149 // Trap events on Windows so we can clean ourselves up.
150 // NOTE: this runs in a separate thread.
151 // Be careful accessing global data structures.
152 //
WindowsMonitorSystemPowerWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)153 static LRESULT CALLBACK WindowsMonitorSystemPowerWndProc(
154 HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam
155 ) {
156 switch(uMsg) {
157 // If we are not installed as a service, begin the task shutdown process
158 // when we are notified that the system is going down. If we are installed
159 // as a service, wait until the service control manager tells us to shutdown.
160 //
161 // The console handler happens a little to late in the cycle and leads
162 // to BOINC attempting to start new tasks, which fail, when the OS has
163 // shutdown some of the ones that were executing.
164 //
165 case WM_QUERYENDSESSION:
166 if (!gstate.executing_as_daemon) {
167 quit_client();
168 }
169 return TRUE;
170 break;
171
172 // On Windows power events are broadcast via the WM_POWERBROADCAST
173 // window message. It has the following parameters:
174 // PBT_APMQUERYSUSPEND
175 // PBT_APMQUERYSUSPENDFAILED
176 // PBT_APMSUSPEND
177 // PBT_APMRESUMECRITICAL
178 // PBT_APMRESUMESUSPEND
179 // PBT_APMBATTERYLOW
180 // PBT_APMPOWERSTATUSCHANGE
181 // PBT_APMOEMEVENT
182 // PBT_APMRESUMEAUTOMATIC
183 case WM_POWERBROADCAST:
184 switch(wParam) {
185 // System is preparing to suspend. This is valid on
186 // Windows versions older than Vista
187 case PBT_APMQUERYSUSPEND:
188 return TRUE;
189 break;
190
191 // System is resuming from a failed request to suspend
192 // activity. This is only valid on Windows versions
193 // older than Vista
194 case PBT_APMQUERYSUSPENDFAILED:
195 resume_client();
196 break;
197
198 // System is critically low on battery power. This is
199 // only valid on Windows versions older than Vista
200 case PBT_APMBATTERYLOW:
201 post_sysmon_msg("Critical battery alarm, Windows is suspending operations");
202 suspend_client();
203 break;
204
205 // System is suspending
206 case PBT_APMSUSPEND:
207 post_sysmon_msg("Windows is suspending operations");
208 suspend_client();
209 break;
210
211 // System is resuming from a normal power event
212 case PBT_APMRESUMESUSPEND:
213 gstate.set_now();
214 post_sysmon_msg("Windows is resuming operations");
215
216 // Check for a proxy
217 working_proxy_info.need_autodetect_proxy_settings = true;
218
219 resume_client();
220 break;
221 }
222 break;
223 default:
224 break;
225 }
226 return (DefWindowProc(hWnd, uMsg, wParam, lParam));
227 }
228
229 // Create a thread to monitor system events
WindowsMonitorSystemPowerThread(LPVOID)230 static DWORD WINAPI WindowsMonitorSystemPowerThread( LPVOID ) {
231 WNDCLASS wc;
232 MSG msg;
233
234 // Initialize diagnostics framework for this thread
235 //
236 diagnostics_thread_init();
237
238 wc.style = CS_GLOBALCLASS;
239 wc.lpfnWndProc = (WNDPROC)WindowsMonitorSystemPowerWndProc;
240 wc.cbClsExtra = 0;
241 wc.cbWndExtra = 0;
242 wc.hInstance = NULL;
243 wc.hIcon = NULL;
244 wc.hCursor = NULL;
245 wc.hbrBackground = NULL;
246 wc.lpszMenuName = NULL;
247 wc.lpszClassName = "BOINCWindowsMonitorSystemPower";
248
249 if (!RegisterClass(&wc)) {
250 log_message_error("Failed to register the WindowsMonitorSystem window class.");
251 return 1;
252 }
253
254 g_hWndWindowsMonitorSystemPower = CreateWindow(
255 wc.lpszClassName,
256 "BOINC Monitor System (Power)",
257 WS_OVERLAPPEDWINDOW & ~WS_VISIBLE,
258 CW_USEDEFAULT,
259 CW_USEDEFAULT,
260 CW_USEDEFAULT,
261 CW_USEDEFAULT,
262 NULL,
263 NULL,
264 NULL,
265 NULL);
266
267 if (!g_hWndWindowsMonitorSystemPower) {
268 log_message_error("Failed to create the WindowsMonitorSystem window.");
269 return 0;
270 }
271
272 while (GetMessage(&msg, NULL, 0, 0)) {
273 TranslateMessage(&msg);
274 DispatchMessage(&msg);
275 }
276 return 0;
277 }
278
279 // Detect any proxy configuration settings automatically.
280 //
windows_detect_autoproxy_settings()281 static void windows_detect_autoproxy_settings() {
282 if (log_flags.proxy_debug) {
283 post_sysmon_msg("[proxy] automatic proxy check in progress");
284 }
285
286 HINTERNET hWinHttp = NULL;
287 WINHTTP_AUTOPROXY_OPTIONS autoproxy_options;
288 WINHTTP_PROXY_INFO proxy_info;
289 PARSED_URL purl;
290 std::wstring network_test_url;
291 size_t pos;
292
293
294 memset(&autoproxy_options, 0, sizeof(autoproxy_options));
295 memset(&proxy_info, 0, sizeof(proxy_info));
296
297 autoproxy_options.dwFlags =
298 WINHTTP_AUTOPROXY_AUTO_DETECT;
299 autoproxy_options.dwAutoDetectFlags =
300 WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
301 autoproxy_options.fAutoLogonIfChallenged = TRUE;
302
303 network_test_url = boinc_ascii_to_wide(cc_config.network_test_url).c_str();
304
305 hWinHttp = WinHttpOpen(
306 L"BOINC client",
307 WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
308 WINHTTP_NO_PROXY_NAME,
309 WINHTTP_NO_PROXY_BYPASS,
310 NULL
311 );
312
313 char msg[1024], buf[1024];
314 safe_strcpy(msg, "[proxy] ");
315
316 if (WinHttpGetProxyForUrl(hWinHttp, network_test_url.c_str(), &autoproxy_options, &proxy_info)) {
317
318 // Apparently there are some conditions where WinHttpGetProxyForUrl can return
319 // success but where proxy_info.lpszProxy is null. Maybe related to UPNP?
320 //
321 // For the time being check to see if proxy_info.lpszProxy is non-null.
322 //
323 if (proxy_info.lpszProxy) {
324 std::string proxy(boinc_wide_to_ascii(std::wstring(proxy_info.lpszProxy)));
325 std::string new_proxy;
326
327 if (log_flags.proxy_debug) {
328 safe_strcat(msg, "proxy list: ");
329 safe_strcat(msg, proxy.c_str());
330 }
331
332 if (!proxy.empty()) {
333 // Trim string if more than one proxy is defined
334 // proxy list is defined as:
335 // ([<scheme>=][<scheme>"://"]<server>[":"<port>])
336
337 // Find and erase first delimeter type.
338 pos = proxy.find(';');
339 if (pos != -1 ) {
340 new_proxy = proxy.erase(pos);
341 proxy = new_proxy;
342 }
343
344 // Find and erase second delimeter type.
345 pos = proxy.find(' ');
346 if (pos != -1 ) {
347 new_proxy = proxy.erase(pos);
348 proxy = new_proxy;
349 }
350
351 // Parse the remaining url
352 parse_url(proxy.c_str(), purl);
353
354 // Store the results for future use.
355 if (0 != strcmp(working_proxy_info.autodetect_server_name, purl.host)) {
356 // Reset clients connection error detection path
357 net_status.need_physical_connection = false;
358
359 working_proxy_info.autodetect_protocol = purl.protocol;
360 safe_strcpy(working_proxy_info.autodetect_server_name, purl.host);
361 working_proxy_info.autodetect_port = purl.port;
362 }
363
364 if (log_flags.proxy_debug) {
365 snprintf(buf, sizeof(buf), "proxy detected %s:%d", purl.host, purl.port);
366 safe_strcat(msg, buf);
367 }
368 }
369 }
370
371 // Clean up
372 if (proxy_info.lpszProxy) GlobalFree(proxy_info.lpszProxy);
373 if (proxy_info.lpszProxyBypass) GlobalFree(proxy_info.lpszProxyBypass);
374 } else {
375 // We can get here if the user is switching from a network that
376 // requires a proxy to one that does not require a proxy.
377 working_proxy_info.autodetect_protocol = 0;
378 safe_strcpy(working_proxy_info.autodetect_server_name, "");
379 working_proxy_info.autodetect_port = 0;
380 if (log_flags.proxy_debug) {
381 safe_strcat(msg, "no automatic proxy detected");
382 }
383 }
384 if (hWinHttp) WinHttpCloseHandle(hWinHttp);
385 if (log_flags.proxy_debug) {
386 post_sysmon_msg(msg);
387 }
388 }
389
WindowsMonitorSystemProxyThread(LPVOID)390 static DWORD WINAPI WindowsMonitorSystemProxyThread( LPVOID ) {
391
392 // Initialize diagnostics framework for this thread
393 //
394 diagnostics_thread_init();
395
396 // notify the main client thread that detecting proxies is
397 // supported.
398 working_proxy_info.autodetect_proxy_supported = true;
399
400 while (1) {
401
402 if (working_proxy_info.need_autodetect_proxy_settings) {
403 working_proxy_info.have_autodetect_proxy_settings = false;
404 windows_detect_autoproxy_settings();
405 working_proxy_info.need_autodetect_proxy_settings = false;
406 working_proxy_info.have_autodetect_proxy_settings = true;
407 }
408
409 Sleep(1000);
410 }
411
412 return 0;
413 }
414
415 // Setup the client software to monitor various system events
initialize_system_monitor(int,char **)416 int initialize_system_monitor(int /*argc*/, char** /*argv*/) {
417
418 // Windows: install console controls, the service control manager will send us
419 // the needed events when we are running as a service.
420 //
421 if (!gstate.executing_as_daemon) {
422 if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)console_control_handler, TRUE)){
423 log_message_error("Failed to register the console control handler.");
424 return ERR_IO;
425 }
426 }
427
428 // Create a thread to receive system power events.
429 //
430 g_hWindowsMonitorSystemPowerThread = CreateThread(
431 NULL,
432 0,
433 WindowsMonitorSystemPowerThread,
434 NULL,
435 0,
436 NULL
437 );
438
439 if (!g_hWindowsMonitorSystemPowerThread) {
440 g_hWindowsMonitorSystemPowerThread = NULL;
441 g_hWndWindowsMonitorSystemPower = NULL;
442 }
443
444 // Create a thread to handle proxy auto-detection.
445 //
446 if (!cc_config.proxy_info.no_autodetect) {
447 g_hWindowsMonitorSystemProxyThread = CreateThread(
448 NULL,
449 0,
450 WindowsMonitorSystemProxyThread,
451 NULL,
452 0,
453 NULL
454 );
455
456 if (!g_hWindowsMonitorSystemProxyThread) {
457 g_hWindowsMonitorSystemProxyThread = NULL;
458 }
459 }
460
461 return 0;
462 }
463
464 // Cleanup the system event monitor
cleanup_system_monitor()465 int cleanup_system_monitor() {
466
467 if (g_hWindowsMonitorSystemPowerThread) {
468 TerminateThread(g_hWindowsMonitorSystemPowerThread, 0);
469 CloseHandle(g_hWindowsMonitorSystemPowerThread);
470 g_hWindowsMonitorSystemPowerThread = NULL;
471 g_hWndWindowsMonitorSystemPower = NULL;
472 }
473
474 if (g_hWindowsMonitorSystemProxyThread) {
475 TerminateThread(g_hWindowsMonitorSystemProxyThread, 0);
476 CloseHandle(g_hWindowsMonitorSystemProxyThread);
477 g_hWindowsMonitorSystemProxyThread = NULL;
478 }
479
480 return 0;
481 }
482
483 // internal variables for managing the service
484 SERVICE_STATUS ssStatus; // current status of the service
485 SERVICE_STATUS_HANDLE sshStatusHandle;
486 DWORD dwErr = 0;
487 TCHAR szErr[1024];
488
489 SERVICE_TABLE_ENTRY service_dispatch_table[] = {
490 { TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)BOINCServiceMain },
491 { NULL, NULL }
492 };
493
494 // Inform the service control manager that the service is about to
495 // start.
initialize_service_dispatcher(int,char **)496 int initialize_service_dispatcher(int /*argc*/, char** /*argv*/) {
497 fprintf(stdout, "\nStartServiceCtrlDispatcher being called.\n");
498 fprintf(stdout, "This may take several seconds. Please wait.\n");
499
500 if (!StartServiceCtrlDispatcher(service_dispatch_table)) {
501 log_message_error("StartServiceCtrlDispatcher failed.");
502 return ERR_IO;
503 }
504 return 0;
505 }
506
507 //
508 // FUNCTION: BOINCServiceMain
509 //
510 // PURPOSE: To perform actual initialization of the service
511 //
512 // PARAMETERS:
513 // dwArgc - number of command line arguments
514 // lpszArgv - array of command line arguments
515 //
516 // RETURN VALUE:
517 // none
518 //
519 // COMMENTS:
520 // This routine performs the service initialization and then calls
521 // the user defined main() routine to perform majority
522 // of the work.
523 //
BOINCServiceMain(DWORD,LPTSTR *)524 void WINAPI BOINCServiceMain(DWORD /*dwArgc*/, LPTSTR * /*lpszArgv*/) {
525 // SERVICE_STATUS members that don't change in example
526 //
527 ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
528 ssStatus.dwControlsAccepted = SERVICE_ACCEPTED_ACTIONS;
529 ssStatus.dwServiceSpecificExitCode = 0;
530
531
532 // register our service control handler:
533 //
534 sshStatusHandle = RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), BOINCServiceCtrl);
535 if (!sshStatusHandle) {
536 goto cleanup;
537 }
538
539 if (!ReportStatus(
540 SERVICE_RUNNING, // service state
541 ERROR_SUCCESS, // exit code
542 0) // wait hint
543 ){
544 goto cleanup;
545 }
546
547 dwErr = boinc_main_loop();
548
549 cleanup:
550
551 // try to report the stopped status to the service control manager.
552 //
553 if (sshStatusHandle) {
554 (VOID)ReportStatus(
555 SERVICE_STOPPED,
556 dwErr,
557 0
558 );
559 }
560 }
561
562
563 //
564 // FUNCTION: BOINCServiceCtrl
565 //
566 // PURPOSE: This function is called by the SCM whenever
567 // ControlService() is called on this service.
568 //
569 // PARAMETERS:
570 // dwCtrlCode - type of control requested
571 //
572 // RETURN VALUE:
573 // none
574 //
575 // COMMENTS:
576 //
BOINCServiceCtrl(DWORD dwCtrlCode)577 VOID WINAPI BOINCServiceCtrl(DWORD dwCtrlCode) {
578 // Handle the requested control code.
579 //
580 switch(dwCtrlCode) {
581 // Stop the service.
582 //
583 // SERVICE_STOP_PENDING should be reported before
584 // setting the Stop Event - hServerStopEvent - in
585 // ServiceStop(). This avoids a race condition
586 // which may result in a 1053 - The Service did not respond...
587 // error.
588 case SERVICE_CONTROL_STOP:
589 case SERVICE_CONTROL_SHUTDOWN:
590 ReportStatus(SERVICE_STOP_PENDING, ERROR_SUCCESS, 30000);
591 quit_client();
592 return;
593
594 // Pause the service.
595 //
596 case SERVICE_CONTROL_PAUSE:
597 ReportStatus(SERVICE_PAUSE_PENDING, ERROR_SUCCESS, 10000);
598 suspend_client();
599 ReportStatus(SERVICE_PAUSED, ERROR_SUCCESS, 10000);
600 return;
601
602 // Continue the service.
603 //
604 case SERVICE_CONTROL_CONTINUE:
605 ReportStatus(SERVICE_CONTINUE_PENDING, ERROR_SUCCESS, 10000);
606 resume_client();
607 ReportStatus(SERVICE_RUNNING, ERROR_SUCCESS, 10000);
608 return;
609
610 // Update the service status.
611 //
612 case SERVICE_CONTROL_INTERROGATE:
613 break;
614
615 // invalid control code
616 //
617 default:
618 break;
619
620 }
621
622 ReportStatus(ssStatus.dwCurrentState, ERROR_SUCCESS, 1000);
623 }
624
625
626 //
627 // FUNCTION: ReportStatus()
628 //
629 // PURPOSE: Sets the current status of the service and
630 // reports it to the Service Control Manager
631 //
632 // PARAMETERS:
633 // dwCurrentState - the state of the service
634 // dwWin32ExitCode - error code to report
635 // dwWaitHint - worst case estimate to next checkpoint
636 //
637 // RETURN VALUE:
638 // TRUE - success
639 // FALSE - failure
640 //
641 // COMMENTS:
642 //
ReportStatus(DWORD dwCurrentState,DWORD dwWin32ExitCode,DWORD dwWaitHint)643 BOOL ReportStatus(
644 DWORD dwCurrentState,
645 DWORD dwWin32ExitCode,
646 DWORD dwWaitHint
647 ) {
648 static DWORD dwCheckPoint = 1;
649 BOOL fResult = TRUE;
650
651 if (dwCurrentState == SERVICE_START_PENDING) {
652 ssStatus.dwControlsAccepted = 0;
653 } else {
654 ssStatus.dwControlsAccepted = SERVICE_ACCEPTED_ACTIONS;
655 }
656
657 ssStatus.dwCurrentState = dwCurrentState;
658 ssStatus.dwWin32ExitCode = dwWin32ExitCode;
659 ssStatus.dwWaitHint = dwWaitHint;
660
661 if ( ( dwCurrentState == SERVICE_RUNNING ) ||
662 ( dwCurrentState == SERVICE_STOPPED )
663 ) {
664 ssStatus.dwCheckPoint = 0;
665 } else {
666 ssStatus.dwCheckPoint = dwCheckPoint++;
667 }
668
669
670 // Report the status of the service to the service control manager.
671 //
672 fResult = SetServiceStatus( sshStatusHandle, &ssStatus);
673 if (!fResult) {
674 LogEventErrorMessage(TEXT("SetServiceStatus"));
675 }
676 return fResult;
677 }
678
679
680
681 //
682 // FUNCTION: LogEventErrorMessage(LPTSTR lpszMsg)
683 //
684 // PURPOSE: Allows any thread to log an error message
685 //
686 // PARAMETERS:
687 // lpszMsg - text for message
688 //
689 // RETURN VALUE:
690 // none
691 //
692 // COMMENTS:
693 //
LogEventErrorMessage(LPTSTR lpszMsg)694 VOID LogEventErrorMessage(LPTSTR lpszMsg) {
695 TCHAR szMsg[1024];
696 HANDLE hEventSource;
697 LPTSTR lpszStrings[2];
698
699 dwErr = GetLastError();
700
701 // Use event logging to log the error.
702 //
703 hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));
704
705 _stprintf_s(szMsg, TEXT("%s error: %d"), TEXT(SZSERVICENAME), dwErr);
706 lpszStrings[0] = szMsg;
707 lpszStrings[1] = lpszMsg;
708
709 if (hEventSource != NULL) {
710 ReportEvent(hEventSource, // handle of event source
711 EVENTLOG_ERROR_TYPE, // event type
712 0, // event category
713 1, // event ID
714 NULL, // current user's SID
715 2, // strings in lpszStrings
716 0, // no bytes of raw data
717 (LPCSTR*)lpszStrings, // array of error strings
718 NULL // no raw data
719 );
720
721 (VOID) DeregisterEventSource(hEventSource);
722 }
723 }
724
725
726 //
727 // FUNCTION: LogEventWarningMessage(LPTSTR lpszMsg)
728 //
729 // PURPOSE: Allows any thread to log an warning message
730 //
731 // PARAMETERS:
732 // lpszMsg - text for message
733 //
734 // RETURN VALUE:
735 // none
736 //
737 // COMMENTS:
738 //
LogEventWarningMessage(LPTSTR lpszMsg)739 VOID LogEventWarningMessage(LPTSTR lpszMsg) {
740 HANDLE hEventSource;
741 LPTSTR lpszStrings[2];
742
743 // Use event logging to log the error.
744 //
745 hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));
746
747 lpszStrings[0] = lpszMsg;
748 lpszStrings[1] = '\0';
749
750 if (hEventSource != NULL) {
751 ReportEvent(hEventSource, // handle of event source
752 EVENTLOG_WARNING_TYPE,// event type
753 0, // event category
754 1, // event ID
755 NULL, // current user's SID
756 2, // strings in lpszStrings
757 0, // no bytes of raw data
758 (LPCSTR*)lpszStrings, // array of error strings
759 NULL // no raw data
760 );
761
762 (VOID) DeregisterEventSource(hEventSource);
763 }
764 }
765
766
767 //
768 // FUNCTION: LogEventInfoMessage(LPTSTR lpszMsg)
769 //
770 // PURPOSE: Allows any thread to log an info message
771 //
772 // PARAMETERS:
773 // lpszMsg - text for message
774 //
775 // RETURN VALUE:
776 // none
777 //
778 // COMMENTS:
779 //
LogEventInfoMessage(LPTSTR lpszMsg)780 VOID LogEventInfoMessage(LPTSTR lpszMsg) {
781 HANDLE hEventSource;
782 LPTSTR lpszStrings[2];
783
784 // Use event logging to log the error.
785 //
786 hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));
787
788 lpszStrings[0] = lpszMsg;
789 lpszStrings[1] = '\0';
790
791 if (hEventSource != NULL) {
792 ReportEvent(hEventSource, // handle of event source
793 EVENTLOG_INFORMATION_TYPE,// event type
794 0, // event category
795 1, // event ID
796 NULL, // current user's SID
797 2, // strings in lpszStrings
798 0, // no bytes of raw data
799 (LPCSTR*)lpszStrings, // array of error strings
800 NULL // no raw data
801 );
802
803 (VOID) DeregisterEventSource(hEventSource);
804 }
805 }
806