~ubuntu-branches/ubuntu/precise/boinc/precise

« back to all changes in this revision

Viewing changes to client/sysmon_win.cpp

Tags: 6.12.8+dfsg-1
* New upstream release.
* Simplified debian/rules

Show diffs side-by-side

added added

removed removed

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