~ubuntu-branches/ubuntu/saucy/openvpn/saucy-proposed

« back to all changes in this revision

Viewing changes to service-win32/service.c

  • Committer: Package Import Robot
  • Author(s): Stéphane Graber
  • Date: 2013-05-24 17:42:45 UTC
  • mfrom: (1.1.19) (10.2.22 sid)
  • Revision ID: package-import@ubuntu.com-20130524174245-g9y6wlforycufqy5
Tags: 2.3.1-2ubuntu1
* Merge from Debian unstable. Remaining changes:
  - debian/openvpn.init.d:
    + Do not use start-stop-daemon and </dev/null to avoid blocking boot.
    + Show per-VPN result messages.
    + Add "--script-security 2" by default for backwards compatabliity.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*---------------------------------------------------------------------------
2
 
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
3
 
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
4
 
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
5
 
PARTICULAR PURPOSE.
6
 
 
7
 
Copyright (C) 1993 - 2000.  Microsoft Corporation.  All rights reserved.
8
 
 
9
 
MODULE:   service.c
10
 
 
11
 
PURPOSE:  Implements functions required by all Windows NT services
12
 
 
13
 
FUNCTIONS:
14
 
  main(int argc, char **argv);
15
 
  service_ctrl(DWORD dwCtrlCode);
16
 
  service_main(DWORD dwArgc, LPTSTR *lpszArgv);
17
 
  CmdInstallService();
18
 
  CmdRemoveService();
19
 
  CmdStartService();
20
 
  CmdDebugService(int argc, char **argv);
21
 
  ControlHandler ( DWORD dwCtrlType );
22
 
  GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
23
 
 
24
 
---------------------------------------------------------------------------*/
25
 
 
26
 
#include <windows.h>
27
 
#include <stdio.h>
28
 
#include <stdlib.h>
29
 
#include <process.h>
30
 
#include <tchar.h>
31
 
 
32
 
#include "service.h"
33
 
 
34
 
// internal variables
35
 
SERVICE_STATUS          ssStatus;       // current status of the service
36
 
SERVICE_STATUS_HANDLE   sshStatusHandle;
37
 
DWORD                   dwErr = 0;
38
 
BOOL                    bDebug = FALSE;
39
 
TCHAR                   szErr[256];
40
 
 
41
 
// internal function prototypes
42
 
VOID WINAPI service_ctrl(DWORD dwCtrlCode);
43
 
VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv);
44
 
int CmdInstallService();
45
 
int CmdRemoveService();
46
 
int CmdStartService();
47
 
VOID CmdDebugService(int argc, char **argv);
48
 
BOOL WINAPI ControlHandler ( DWORD dwCtrlType );
49
 
LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
50
 
 
51
 
//
52
 
//  FUNCTION: main
53
 
//
54
 
//  PURPOSE: entrypoint for service
55
 
//
56
 
//  PARAMETERS:
57
 
//    argc - number of command line arguments
58
 
//    argv - array of command line arguments
59
 
//
60
 
//  RETURN VALUE:
61
 
//    none
62
 
//
63
 
//  COMMENTS:
64
 
//    main() either performs the command line task, or
65
 
//    call StartServiceCtrlDispatcher to register the
66
 
//    main service thread.  When the this call returns,
67
 
//    the service has stopped, so exit.
68
 
//
69
 
int __cdecl main(int argc, char **argv)
70
 
{
71
 
   SERVICE_TABLE_ENTRY dispatchTable[] =
72
 
   {
73
 
      { TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)service_main},
74
 
      { NULL, NULL}
75
 
   };
76
 
 
77
 
   if ( (argc > 1) &&
78
 
        ((*argv[1] == '-') || (*argv[1] == '/')) )
79
 
   {
80
 
      if ( _stricmp( "install", argv[1]+1 ) == 0 )
81
 
      {
82
 
         return CmdInstallService();
83
 
      }
84
 
      else if ( _stricmp( "remove", argv[1]+1 ) == 0 )
85
 
      {
86
 
         return CmdRemoveService();
87
 
      }
88
 
          else if ( _stricmp( "start", argv[1]+1 ) == 0)
89
 
          {
90
 
                  return CmdStartService();
91
 
      }
92
 
      else if ( _stricmp( "debug", argv[1]+1 ) == 0 )
93
 
      {
94
 
         bDebug = TRUE;
95
 
         CmdDebugService(argc, argv);
96
 
      }
97
 
      else
98
 
      {
99
 
         goto dispatch;
100
 
      }
101
 
      return 0;
102
 
   }
103
 
 
104
 
   // if it doesn't match any of the above parameters
105
 
   // the service control manager may be starting the service
106
 
   // so we must call StartServiceCtrlDispatcher
107
 
   dispatch:
108
 
   // this is just to be friendly
109
 
   printf( "%s -install          to install the service\n", SZAPPNAME );
110
 
   printf( "%s -start                    to start the service\n", SZAPPNAME );
111
 
   printf( "%s -remove           to remove the service\n", SZAPPNAME );
112
 
   printf( "%s -debug <params>   to run as a console app for debugging\n", SZAPPNAME );
113
 
   printf( "\nStartServiceCtrlDispatcher being called.\n" );
114
 
   printf( "This may take several seconds.  Please wait.\n" );
115
 
 
116
 
   if (!StartServiceCtrlDispatcher(dispatchTable))
117
 
      AddToMessageLog(MSG_FLAGS_ERROR, TEXT("StartServiceCtrlDispatcher failed."));
118
 
 
119
 
   return 0;
120
 
}
121
 
 
122
 
 
123
 
 
124
 
//
125
 
//  FUNCTION: service_main
126
 
//
127
 
//  PURPOSE: To perform actual initialization of the service
128
 
//
129
 
//  PARAMETERS:
130
 
//    dwArgc   - number of command line arguments
131
 
//    lpszArgv - array of command line arguments
132
 
//
133
 
//  RETURN VALUE:
134
 
//    none
135
 
//
136
 
//  COMMENTS:
137
 
//    This routine performs the service initialization and then calls
138
 
//    the user defined ServiceStart() routine to perform majority
139
 
//    of the work.
140
 
//
141
 
void WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv)
142
 
{
143
 
 
144
 
   // register our service control handler:
145
 
   //
146
 
   sshStatusHandle = RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), service_ctrl);
147
 
 
148
 
   if (!sshStatusHandle)
149
 
      goto cleanup;
150
 
 
151
 
   // SERVICE_STATUS members that don't change in example
152
 
   //
153
 
   ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
154
 
   ssStatus.dwServiceSpecificExitCode = 0;
155
 
 
156
 
 
157
 
   // report the status to the service control manager.
158
 
   //
159
 
   if (!ReportStatusToSCMgr(
160
 
                           SERVICE_START_PENDING, // service state
161
 
                           NO_ERROR,              // exit code
162
 
                           3000))                 // wait hint
163
 
      goto cleanup;
164
 
 
165
 
 
166
 
   ServiceStart( dwArgc, lpszArgv );
167
 
 
168
 
   cleanup:
169
 
 
170
 
   // try to report the stopped status to the service control manager.
171
 
   //
172
 
   if (sshStatusHandle)
173
 
      (VOID)ReportStatusToSCMgr(
174
 
                               SERVICE_STOPPED,
175
 
                               dwErr,
176
 
                               0);
177
 
 
178
 
   return;
179
 
}
180
 
 
181
 
 
182
 
 
183
 
//
184
 
//  FUNCTION: service_ctrl
185
 
//
186
 
//  PURPOSE: This function is called by the SCM whenever
187
 
//           ControlService() is called on this service.
188
 
//
189
 
//  PARAMETERS:
190
 
//    dwCtrlCode - type of control requested
191
 
//
192
 
//  RETURN VALUE:
193
 
//    none
194
 
//
195
 
//  COMMENTS:
196
 
//
197
 
VOID WINAPI service_ctrl(DWORD dwCtrlCode)
198
 
{
199
 
   // Handle the requested control code.
200
 
   //
201
 
   switch (dwCtrlCode)
202
 
   {
203
 
   // Stop the service.
204
 
   //
205
 
   // SERVICE_STOP_PENDING should be reported before
206
 
   // setting the Stop Event - hServerStopEvent - in
207
 
   // ServiceStop().  This avoids a race condition
208
 
   // which may result in a 1053 - The Service did not respond...
209
 
   // error.
210
 
   case SERVICE_CONTROL_STOP:
211
 
      ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
212
 
      ServiceStop();
213
 
      return;
214
 
 
215
 
      // Update the service status.
216
 
      //
217
 
   case SERVICE_CONTROL_INTERROGATE:
218
 
      break;
219
 
 
220
 
      // invalid control code
221
 
      //
222
 
   default:
223
 
      break;
224
 
 
225
 
   }
226
 
 
227
 
   ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
228
 
}
229
 
 
230
 
 
231
 
 
232
 
//
233
 
//  FUNCTION: ReportStatusToSCMgr()
234
 
//
235
 
//  PURPOSE: Sets the current status of the service and
236
 
//           reports it to the Service Control Manager
237
 
//
238
 
//  PARAMETERS:
239
 
//    dwCurrentState - the state of the service
240
 
//    dwWin32ExitCode - error code to report
241
 
//    dwWaitHint - worst case estimate to next checkpoint
242
 
//
243
 
//  RETURN VALUE:
244
 
//    TRUE  - success
245
 
//    FALSE - failure
246
 
//
247
 
//  COMMENTS:
248
 
//
249
 
BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
250
 
                         DWORD dwWin32ExitCode,
251
 
                         DWORD dwWaitHint)
252
 
{
253
 
   static DWORD dwCheckPoint = 1;
254
 
   BOOL fResult = TRUE;
255
 
 
256
 
 
257
 
   if ( !bDebug ) // when debugging we don't report to the SCM
258
 
   {
259
 
      if (dwCurrentState == SERVICE_START_PENDING)
260
 
         ssStatus.dwControlsAccepted = 0;
261
 
      else
262
 
         ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
263
 
 
264
 
      ssStatus.dwCurrentState = dwCurrentState;
265
 
      ssStatus.dwWin32ExitCode = dwWin32ExitCode;
266
 
      ssStatus.dwWaitHint = dwWaitHint;
267
 
 
268
 
      if ( ( dwCurrentState == SERVICE_RUNNING ) ||
269
 
           ( dwCurrentState == SERVICE_STOPPED ) )
270
 
         ssStatus.dwCheckPoint = 0;
271
 
      else
272
 
         ssStatus.dwCheckPoint = dwCheckPoint++;
273
 
 
274
 
 
275
 
      // Report the status of the service to the service control manager.
276
 
      //
277
 
      if (!(fResult = SetServiceStatus( sshStatusHandle, &ssStatus)))
278
 
      {
279
 
         AddToMessageLog(MSG_FLAGS_ERROR, TEXT("SetServiceStatus"));
280
 
      }
281
 
   }
282
 
   return fResult;
283
 
}
284
 
 
285
 
 
286
 
 
287
 
//
288
 
//  FUNCTION: AddToMessageLog(LPTSTR lpszMsg)
289
 
//
290
 
//  PURPOSE: Allows any thread to log an error message
291
 
//
292
 
//  PARAMETERS:
293
 
//    lpszMsg - text for message
294
 
//
295
 
//  RETURN VALUE:
296
 
//    none
297
 
//
298
 
//  COMMENTS:
299
 
//
300
 
void AddToMessageLog(DWORD flags, LPTSTR lpszMsg)
301
 
{
302
 
   TCHAR szMsg [(sizeof(SZSERVICENAME) / sizeof(TCHAR)) + 100 ];
303
 
   HANDLE  hEventSource;
304
 
   LPCSTR  lpszStrings[2];
305
 
 
306
 
   if ( !bDebug )
307
 
   {
308
 
     if (flags & MSG_FLAGS_SYS_CODE)
309
 
      dwErr = GetLastError();
310
 
     else
311
 
       dwErr = 0;
312
 
 
313
 
      // Use event logging to log the error.
314
 
      //
315
 
      hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));
316
 
 
317
 
      _stprintf(szMsg, TEXT("%s error: %d"), TEXT(SZSERVICENAME), (int)dwErr);
318
 
      lpszStrings[0] = szMsg;
319
 
      lpszStrings[1] = lpszMsg;
320
 
 
321
 
      if (hEventSource != NULL)
322
 
      {
323
 
         ReportEvent(hEventSource, // handle of event source
324
 
                     // event type
325
 
                     (flags & MSG_FLAGS_ERROR)
326
 
                       ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
327
 
                     0,                    // event category
328
 
                     0,                    // event ID
329
 
                     NULL,                 // current user's SID
330
 
                     2,                    // strings in lpszStrings
331
 
                     0,                    // no bytes of raw data
332
 
                     lpszStrings,          // array of error strings
333
 
                     NULL);                // no raw data
334
 
 
335
 
         (VOID) DeregisterEventSource(hEventSource);
336
 
      }
337
 
   }
338
 
}
339
 
 
340
 
void ResetError (void)
341
 
{
342
 
  dwErr = 0;
343
 
}
344
 
 
345
 
///////////////////////////////////////////////////////////////////
346
 
//
347
 
//  The following code handles service installation and removal
348
 
//
349
 
 
350
 
 
351
 
//
352
 
//  FUNCTION: CmdInstallService()
353
 
//
354
 
//  PURPOSE: Installs the service
355
 
//
356
 
//  PARAMETERS:
357
 
//    none
358
 
//
359
 
//  RETURN VALUE:
360
 
//    0 if success
361
 
//
362
 
//  COMMENTS:
363
 
//
364
 
int CmdInstallService()
365
 
{
366
 
   SC_HANDLE   schService;
367
 
   SC_HANDLE   schSCManager;
368
 
 
369
 
   TCHAR szPath[512];
370
 
 
371
 
   int ret = 0;
372
 
 
373
 
   if ( GetModuleFileName( NULL, szPath+1, 510 ) == 0 )
374
 
   {
375
 
      _tprintf(TEXT("Unable to install %s - %s\n"), TEXT(SZSERVICEDISPLAYNAME), GetLastErrorText(szErr, 256));
376
 
      return 1;
377
 
   }
378
 
   szPath[0] = '\"';
379
 
   strcat(szPath, "\"");
380
 
 
381
 
   schSCManager = OpenSCManager(
382
 
                               NULL,                   // machine (NULL == local)
383
 
                               NULL,                   // database (NULL == default)
384
 
                               SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE  // access required
385
 
                               );
386
 
   if ( schSCManager )
387
 
   {
388
 
      schService = CreateService(
389
 
                                schSCManager,               // SCManager database
390
 
                                TEXT(SZSERVICENAME),        // name of service
391
 
                                TEXT(SZSERVICEDISPLAYNAME), // name to display
392
 
                                SERVICE_QUERY_STATUS,         // desired access
393
 
                                SERVICE_WIN32_OWN_PROCESS,  // service type
394
 
                                SERVICE_DEMAND_START,        // start type -- alternative: SERVICE_AUTO_START
395
 
                                SERVICE_ERROR_NORMAL,       // error control type
396
 
                                szPath,                     // service's binary
397
 
                                NULL,                       // no load ordering group
398
 
                                NULL,                       // no tag identifier
399
 
                                TEXT(SZDEPENDENCIES),       // dependencies
400
 
                                NULL,                       // LocalSystem account
401
 
                                NULL);                      // no password
402
 
 
403
 
      if ( schService )
404
 
      {
405
 
         _tprintf(TEXT("%s installed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
406
 
         CloseServiceHandle(schService);
407
 
      }
408
 
      else
409
 
      {
410
 
         _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(szErr, 256));
411
 
         ret = 1;
412
 
      }
413
 
 
414
 
      CloseServiceHandle(schSCManager);
415
 
   }
416
 
   else
417
 
     {
418
 
      _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
419
 
       ret = 1;
420
 
     }
421
 
   return ret;
422
 
}
423
 
 
424
 
//
425
 
//  FUNCTION: CmdStartService()
426
 
//
427
 
//  PURPOSE: Start the service
428
 
//
429
 
//  PARAMETERS:
430
 
//    none
431
 
//
432
 
//  RETURN VALUE:
433
 
//    0 if success
434
 
//
435
 
//  COMMENTS:
436
 
 
437
 
int CmdStartService()
438
 
{
439
 
  int ret = 0;
440
 
 
441
 
  SC_HANDLE schSCManager;
442
 
  SC_HANDLE schService;
443
 
 
444
 
 
445
 
    // Open a handle to the SC Manager database. 
446
 
    schSCManager = OpenSCManager( 
447
 
       NULL,                    // local machine 
448
 
       NULL,                    // ServicesActive database 
449
 
       SC_MANAGER_ALL_ACCESS);  // full access rights 
450
 
   
451
 
    if (NULL == schSCManager) {
452
 
       _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
453
 
       ret = 1;
454
 
    }
455
 
 
456
 
    schService = OpenService( 
457
 
        schSCManager,          // SCM database 
458
 
        SZSERVICENAME,         // service name
459
 
        SERVICE_ALL_ACCESS); 
460
 
 
461
 
    if (schService == NULL) {
462
 
      _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256));
463
 
       ret = 1;
464
 
    }
465
 
 
466
 
    if (!StartService(
467
 
            schService,  // handle to service 
468
 
            0,           // number of arguments 
469
 
            NULL) )      // no arguments 
470
 
    {
471
 
      _tprintf(TEXT("StartService failed - %s\n"), GetLastErrorText(szErr,256));
472
 
       ret = 1;
473
 
    }
474
 
    else
475
 
        {
476
 
                _tprintf(TEXT("Service Started\n"));
477
 
       ret = 0;
478
 
        }
479
 
    CloseServiceHandle(schService); 
480
 
    CloseServiceHandle(schSCManager);
481
 
    return ret;
482
 
}
483
 
 
484
 
//
485
 
//  FUNCTION: CmdRemoveService()
486
 
//
487
 
//  PURPOSE: Stops and removes the service
488
 
//
489
 
//  PARAMETERS:
490
 
//    none
491
 
//
492
 
//  RETURN VALUE:
493
 
//    0 if success
494
 
//
495
 
//  COMMENTS:
496
 
//
497
 
int CmdRemoveService()
498
 
{
499
 
   SC_HANDLE   schService;
500
 
   SC_HANDLE   schSCManager;
501
 
 
502
 
   int ret = 0;
503
 
 
504
 
   schSCManager = OpenSCManager(
505
 
                               NULL,                   // machine (NULL == local)
506
 
                               NULL,                   // database (NULL == default)
507
 
                               SC_MANAGER_CONNECT   // access required
508
 
                               );
509
 
   if ( schSCManager )
510
 
   {
511
 
      schService = OpenService(schSCManager, TEXT(SZSERVICENAME), DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS);
512
 
 
513
 
      if (schService)
514
 
      {
515
 
         // try to stop the service
516
 
         if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
517
 
         {
518
 
            _tprintf(TEXT("Stopping %s."), TEXT(SZSERVICEDISPLAYNAME));
519
 
            Sleep( 1000 );
520
 
 
521
 
            while ( QueryServiceStatus( schService, &ssStatus ) )
522
 
            {
523
 
               if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
524
 
               {
525
 
                  _tprintf(TEXT("."));
526
 
                  Sleep( 1000 );
527
 
               }
528
 
               else
529
 
                  break;
530
 
            }
531
 
 
532
 
            if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
533
 
               _tprintf(TEXT("\n%s stopped.\n"), TEXT(SZSERVICEDISPLAYNAME) );
534
 
            else
535
 
              {
536
 
               _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(SZSERVICEDISPLAYNAME) );
537
 
                ret = 1;
538
 
              }
539
 
 
540
 
         }
541
 
 
542
 
         // now remove the service
543
 
         if ( DeleteService(schService) )
544
 
            _tprintf(TEXT("%s removed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
545
 
         else
546
 
           {
547
 
            _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(szErr,256));
548
 
             ret = 1;
549
 
           }
550
 
 
551
 
 
552
 
         CloseServiceHandle(schService);
553
 
      }
554
 
      else
555
 
        {
556
 
         _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256));
557
 
          ret = 1;
558
 
        }
559
 
 
560
 
      CloseServiceHandle(schSCManager);
561
 
   }
562
 
   else
563
 
     {
564
 
      _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
565
 
       ret = 1;
566
 
     }
567
 
   return ret;
568
 
}
569
 
 
570
 
 
571
 
 
572
 
 
573
 
///////////////////////////////////////////////////////////////////
574
 
//
575
 
//  The following code is for running the service as a console app
576
 
//
577
 
 
578
 
 
579
 
//
580
 
//  FUNCTION: CmdDebugService(int argc, char ** argv)
581
 
//
582
 
//  PURPOSE: Runs the service as a console application
583
 
//
584
 
//  PARAMETERS:
585
 
//    argc - number of command line arguments
586
 
//    argv - array of command line arguments
587
 
//
588
 
//  RETURN VALUE:
589
 
//    none
590
 
//
591
 
//  COMMENTS:
592
 
//
593
 
void CmdDebugService(int argc, char ** argv)
594
 
{
595
 
   DWORD dwArgc;
596
 
   LPTSTR *lpszArgv;
597
 
 
598
 
#ifdef UNICODE
599
 
   lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc) );
600
 
   if (NULL == lpszArgv)
601
 
   {
602
 
       // CommandLineToArvW failed!!
603
 
       _tprintf(TEXT("CmdDebugService CommandLineToArgvW returned NULL\n"));
604
 
       return;
605
 
   }
606
 
#else
607
 
   dwArgc   = (DWORD) argc;
608
 
   lpszArgv = argv;
609
 
#endif
610
 
 
611
 
   _tprintf(TEXT("Debugging %s.\n"), TEXT(SZSERVICEDISPLAYNAME));
612
 
 
613
 
   SetConsoleCtrlHandler( ControlHandler, TRUE );
614
 
 
615
 
   ServiceStart( dwArgc, lpszArgv );
616
 
 
617
 
#ifdef UNICODE
618
 
// Must free memory allocated for arguments
619
 
 
620
 
   GlobalFree(lpszArgv);
621
 
#endif // UNICODE
622
 
 
623
 
}
624
 
 
625
 
 
626
 
//
627
 
//  FUNCTION: ControlHandler ( DWORD dwCtrlType )
628
 
//
629
 
//  PURPOSE: Handled console control events
630
 
//
631
 
//  PARAMETERS:
632
 
//    dwCtrlType - type of control event
633
 
//
634
 
//  RETURN VALUE:
635
 
//    True - handled
636
 
//    False - unhandled
637
 
//
638
 
//  COMMENTS:
639
 
//
640
 
BOOL WINAPI ControlHandler ( DWORD dwCtrlType )
641
 
{
642
 
   switch ( dwCtrlType )
643
 
   {
644
 
   case CTRL_BREAK_EVENT:  // use Ctrl+C or Ctrl+Break to simulate
645
 
   case CTRL_C_EVENT:      // SERVICE_CONTROL_STOP in debug mode
646
 
      _tprintf(TEXT("Stopping %s.\n"), TEXT(SZSERVICEDISPLAYNAME));
647
 
      ServiceStop();
648
 
      return TRUE;
649
 
      break;
650
 
 
651
 
   }
652
 
   return FALSE;
653
 
}
654
 
 
655
 
//
656
 
//  FUNCTION: GetLastErrorText
657
 
//
658
 
//  PURPOSE: copies error message text to string
659
 
//
660
 
//  PARAMETERS:
661
 
//    lpszBuf - destination buffer
662
 
//    dwSize - size of buffer
663
 
//
664
 
//  RETURN VALUE:
665
 
//    destination buffer
666
 
//
667
 
//  COMMENTS:
668
 
//
669
 
LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize )
670
 
{
671
 
   DWORD dwRet;
672
 
   LPTSTR lpszTemp = NULL;
673
 
 
674
 
   dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
675
 
                          NULL,
676
 
                          GetLastError(),
677
 
                          LANG_NEUTRAL,
678
 
                          (LPTSTR)&lpszTemp,
679
 
                          0,
680
 
                          NULL );
681
 
 
682
 
   // supplied buffer is not long enough
683
 
   if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
684
 
      lpszBuf[0] = TEXT('\0');
685
 
   else
686
 
   {
687
 
      lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0');  //remove cr and newline character
688
 
      _stprintf( lpszBuf, TEXT("%s (0x%x)"), lpszTemp, (int)GetLastError() );
689
 
   }
690
 
 
691
 
   if ( lpszTemp )
692
 
      LocalFree((HLOCAL) lpszTemp );
693
 
 
694
 
   return lpszBuf;
695
 
}