(file) Return to service.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Server

  1 tony  1.1 //%/////////////////////////////////////////////////////////////////////////////
  2           //
  3           // Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM,
  4           // The Open Group, Tivoli Systems
  5           //
  6           // Permission is hereby granted, free of charge, to any person obtaining a copy
  7           // of this software and associated documentation files (the "Software"), to
  8           // deal in the Software without restriction, including without limitation the
  9           // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 10           // sell copies of the Software, and to permit persons to whom the Software is
 11           // furnished to do so, subject to the following conditions:
 12           // 
 13           // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
 14           // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
 15           // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 16           // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 17           // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 18           // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 19           // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 20           // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 21           //
 22 tony  1.1 //==============================================================================
 23           //
 24           // Author: Tony Fiorentino (fiorentino_tony@emc.com)
 25           //
 26           //%/////////////////////////////////////////////////////////////////////////////
 27           #include <time.h>
 28           #include <stdio.h>
 29           #include <windows.h>
 30           #include <process.h>
 31           
 32           #include "service.h"
 33           
 34           //-------------------------------------------------------------------------
 35           // G L O B A L S
 36           //-------------------------------------------------------------------------
 37           int                    Service::g_argc                  = 0;
 38           char                 **Service::g_argv                  = NULL;
 39           char                  *Service::g_service_name          = NULL;
 40           char                  *Service::g_event_source          = NULL;
 41           DWORD                  Service::g_flags                 = 0;
 42           DWORD                  Service::g_current_state         = 0;
 43 tony  1.1 SERVICE_STATUS_HANDLE  Service::g_service_status_handle = 0;
 44           SERVICE_MAIN_T         Service::g_service_main          = NULL;
 45           
 46           //-------------------------------------------------------------------------
 47           // P U B L I C
 48           //-------------------------------------------------------------------------
 49           Service::Service(void)
 50           {
 51           }
 52           
 53           Service::Service(char *service_name)
 54           {
 55             g_service_name = service_name;
 56           }
 57           
 58           Service::Service(char *service_name, char *event_source)
 59           {
 60             g_event_source = event_source;
 61             g_service_name = service_name;
 62           }
 63           
 64 tony  1.1 Service::~Service(void)
 65           {
 66           }
 67           
 68           /*-------------------------------------------------------------------------*
 69            * Method: Install                                                         *
 70            *                                                                         *
 71            * Args:                                                                   *
 72            *   display_name                                                          *
 73            *     The service's display name (hopefully more descriptive, will show   *
 74            *     up in the Win32 Services MMC snapin as "Service Name").             *
 75            *                                                                         *
 76            *   exe_name:                                                             *
 77            *     The service's executable name (full path, please)                   *
 78            *                                                                         *
 79            *   flags:                                                                *
 80            *     Reserved.  Currently unused.                                        *
 81            *                                                                         *
 82            * Description:                                                            *
 83            *     This function creates the service.                                  *
 84            *                                                                         *
 85 tony  1.1  * NOTE: If the process is successfully launched as a Win32 service, this  *
 86            *       function never returns, but calls exit() instead.                 *
 87            *-------------------------------------------------------------------------*/
 88           Service::ReturnCode
 89           Service::Install(
 90             char  *display_name,
 91             char  *description,
 92             char  *exe_name)
 93           {
 94             ReturnCode status = SERVICE_RETURN_SUCCESS;
 95             SC_HANDLE sch;
 96           
 97             if (g_service_name == NULL || display_name == NULL || exe_name == NULL)
 98               return SERVICE_ERROR_NOT_FOUND; // SERVICE_ERROR_NOT_FOUND
 99             else if ((sch = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL)
100               status = get_error(GetLastError(), "open");
101             else
102               {
103                 SC_HANDLE service = CreateService( 
104                   sch,                       // SCManager database 
105                   g_service_name,            // name of service 
106 tony  1.1         display_name,              // service name to display 
107                   SERVICE_ALL_ACCESS,        // desired access 
108                   SERVICE_WIN32_OWN_PROCESS, // service type 
109                   SERVICE_DEMAND_START,      // start type 
110                   SERVICE_ERROR_NORMAL,      // error control type 
111                   exe_name,                  // service's binary 
112                   NULL,                      // no load ordering group 
113                   NULL,                      // no tag identifier 
114                   NULL,                      // no dependencies 
115                   NULL,                      // LocalSystem account 
116                   NULL);                     // no password 
117            
118                 if (service == NULL) 
119                   {
120                     status = get_error(GetLastError(), "create");
121                     return status;
122                   }
123                 else 
124                   {
125                     change_service_description(service, description);
126                     CloseServiceHandle(service);
127 tony  1.1         }
128             
129                 CloseServiceHandle(sch);
130               }
131           
132             return status;
133           }
134           
135           /*-------------------------------------------------------------------------*
136            * Method: Remove                                                          *
137            *                                                                         *
138            * Description:                                                            *
139            *     Removes the service.                                                *
140            *-------------------------------------------------------------------------*/
141           Service::ReturnCode
142           Service::Remove(void)
143           {
144             ReturnCode status = SERVICE_RETURN_SUCCESS;
145             SC_HANDLE sch;
146           
147             if (g_service_name == NULL)
148 tony  1.1     return SERVICE_ERROR_NOT_FOUND; /* SERVICE_ERROR_NOT_FOUND */
149             else if ((sch = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL)
150               status = get_error(GetLastError(), "open");
151             else
152               {
153                 SC_HANDLE service = OpenService(sch, g_service_name, DELETE);
154            
155                 if (service == NULL) 
156                   {
157                     status = get_error(GetLastError(), "open");
158                   }
159                 else 
160                   {
161                     if (!DeleteService(service))
162                       {
163                         status = get_error(GetLastError(), "remove");
164                       }
165           
166                     CloseServiceHandle(service);
167                   }
168             
169 tony  1.1       CloseServiceHandle(sch);
170               }
171           
172             return status;
173           }
174           
175           /*-------------------------------------------------------------------------*
176            * Method: Start                                                           *
177            *                                                                         *
178            * Args:                                                                   *
179            *   wait_time:                                                            *
180            *     The user supplied wait (~1 second per QueryServiceStatus() attempt) *
181            *                                                                         *
182            * Description:                                                            *
183            *     Attempt to start the service.                                       *
184            *-------------------------------------------------------------------------*/
185           Service::ReturnCode
186           Service::Start(int wait_time)
187           {
188             ReturnCode      status = SERVICE_RETURN_SUCCESS;
189             SERVICE_STATUS  service_status;
190 tony  1.1   SC_HANDLE       sch;
191           
192             if (g_service_name == NULL)
193               return SERVICE_ERROR_NOT_FOUND; // SERVICE_ERROR_NOT_FOUND
194             else if ((sch = OpenSCManager(NULL, NULL, GENERIC_READ)) == NULL)
195               status = get_error(GetLastError(), "open");
196             else
197               {
198                 SC_HANDLE service = OpenService(sch, g_service_name, SERVICE_START | SERVICE_QUERY_STATUS);
199            
200                 if (service == NULL) 
201                   status = get_error(GetLastError(), "open");
202                 else if (!StartService(service, 0, NULL))
203                   status = get_error(GetLastError(), "start");
204                 else 
205                   {
206                     int i, max = (wait_time > 0) ? wait_time : 5;
207           
208                     // Loop up to max times waiting for the service 
209                     // state to change to RUNNING
210           
211 tony  1.1           for (i = 0; i < max; i++)
212                       {
213                         if (!QueryServiceStatus(service, &service_status))
214                           {
215                             status = get_error(GetLastError(), "query");
216                             return status; // QUERY_FAIL
217                           }
218           
219                         if (service_status.dwCurrentState == SERVICE_RUNNING)
220                           break;
221           
222                         Sleep(1 * CLOCKS_PER_SEC);
223                       }
224                     
225                     status = (i < max) ? SERVICE_RETURN_SUCCESS : SERVICE_ERROR_REQUEST_TIMEOUT;
226           
227                     CloseServiceHandle(service);
228                   }
229            
230                 CloseServiceHandle(sch); 
231               }
232 tony  1.1 
233             return status;
234           } 
235           
236           /*-------------------------------------------------------------------------*
237            * Method: Stop                                                            *
238            *                                                                         *
239            * Args:                                                                   *
240            *   wait_time:                                                            *
241            *     The user supplied wait (~1 second per QueryServiceStatus() attempt) *
242            *                                                                         *
243            * Description:                                                            *
244            *     Attempt to stop the service.                                        *
245            *-------------------------------------------------------------------------*/
246           Service::ReturnCode 
247           Service::Stop(int wait_time)
248           {
249             ReturnCode      status = SERVICE_RETURN_SUCCESS;
250             SERVICE_STATUS  service_status;
251             SC_HANDLE       sch;
252           
253 tony  1.1   if (g_service_name == NULL)
254               return SERVICE_ERROR_NOT_FOUND; // SERVICE_ERROR_NOT_FOUND
255             else if ((sch = OpenSCManager(NULL, NULL, GENERIC_READ)) == NULL)
256               status = get_error(GetLastError(), "open");
257            //   show_error("OpenSCMManager", "service", GetLastError());
258             else
259               {
260                 SC_HANDLE service = OpenService(sch, g_service_name, SERVICE_STOP | SERVICE_QUERY_STATUS);
261            
262                 if (service == NULL) 
263                   status = get_error(GetLastError(), "open");
264                 else if (!ControlService(service, SERVICE_CONTROL_STOP, &service_status))
265                   status = get_error(GetLastError(), "stop");
266                 else 
267                   {
268                     int i, max = (wait_time > 0) ? wait_time : 5;
269           
270                     // Loop up to max times waiting for the service 
271                     // state to change to STOPPED
272           
273                     for (i = 0; i < max; i++)
274 tony  1.1             {
275                         if (!QueryServiceStatus(service, &service_status))
276                           {
277                             status = get_error(GetLastError(), "query");
278                             return status; // QUERY_FAIL
279                           }
280           
281                         if (service_status.dwCurrentState == SERVICE_STOPPED)
282                           break;
283           
284                         Sleep(1 * CLOCKS_PER_SEC);
285                       }
286                     
287                     status = (i < max) ? SERVICE_RETURN_SUCCESS : SERVICE_ERROR_REQUEST_TIMEOUT;
288           
289                     CloseServiceHandle(service);
290                   }
291            
292                 CloseServiceHandle(sch); 
293               }
294           
295 tony  1.1   return status;
296           }
297           
298           /*-------------------------------------------------------------------------*
299            * Method: Run                                                             *
300            *                                                                         *
301            * Args:                                                                   *
302            *   service_main:                                                         *
303            *     The user supplied service_main function (not to be confused with    *
304            *     real_service_main above)                                            *
305            *                                                                         *
306            *   flags:                                                                *
307            *     Reserved.  Currently unused.                                        *
308            *                                                                         *
309            * Description:                                                            *
310            *     This function interacts with the SCM to run the current process     *
311            *     as a Win32 service.                                                 *
312            *                                                                         *
313            * NOTE: If the process is successfully launched as a Win32 service, this  *
314            *       function never returns, but calls exit() instead.                 *
315            *-------------------------------------------------------------------------*/
316 tony  1.1 
317           Service::ReturnCode 
318           Service::Run(SERVICE_MAIN_T service_main, DWORD flags)
319           {
320             ReturnCode status = SERVICE_RETURN_SUCCESS;
321           
322             SERVICE_TABLE_ENTRY dispatchTable[] = 
323             { 
324               { g_service_name, real_service_main },
325               { NULL,         NULL              } 
326             };
327           
328             // Validate the arguments as best we can 
329           
330             if (g_service_name == NULL || service_main == NULL)
331               return SERVICE_ERROR_NOT_FOUND; // SERVICE_ERROR_NOT_FOUND
332           
333             // Save parameters in global variables 
334           
335             g_flags        = flags;
336             g_service_main = service_main;
337 tony  1.1 
338             // Kick off the service 
339           
340             if (!StartServiceCtrlDispatcher(dispatchTable))
341               {
342                 status = get_error(GetLastError(), "start");
343                 return status; // FAIL
344               }
345           
346             // After the service shuts down, don't return.
347           
348             exit(status);
349           }
350           
351           /*-------------------------------------------------------------------------*
352            * Method: GetState                                                        *
353            *                                                                         *
354            * Description:                                                            *
355            *     Returns the state of the service into "state".                      *
356            *-------------------------------------------------------------------------*/
357           Service::ReturnCode 
358 tony  1.1 Service::GetState(State *state)
359           {
360             ReturnCode      status = SERVICE_RETURN_SUCCESS;
361             SERVICE_STATUS  service_status;
362             SC_HANDLE       sch;
363           
364             if (g_service_name == NULL)
365               return SERVICE_ERROR_NOT_FOUND; // SERVICE_ERROR_NOT_FOUND
366             else if ((sch = OpenSCManager(NULL, NULL, GENERIC_READ)) == NULL)
367               status = get_error(GetLastError(), "open");
368             else
369               {
370                 SC_HANDLE service = OpenService(sch, g_service_name, SERVICE_QUERY_STATUS);
371            
372                 if (service == NULL) 
373                   status = get_error(GetLastError(), "open");
374                 else if (!QueryServiceStatus(service, &service_status))
375                   status = get_error(GetLastError(), "query");
376                 else
377                   {
378                     *state = get_state(service_status.dwCurrentState);
379 tony  1.1           CloseServiceHandle(service);
380                   }
381             
382                 CloseServiceHandle(sch);
383               }
384           
385             return status;
386           }
387           
388           /*-------------------------------------------------------------------------*
389            * Method: LogEvent                                                        *
390            *                                                                         *
391            * Args:                                                                   *
392            *   event_type:                                                           *
393            *     The Win32 event type. Valid event types are:                        *
394            *      EVENTLOG_SUCCESS          : Success event                          *
395            *      EVENTLOG_ERROR_TYPE       : Error event                            *
396            *      EVENTLOG_WARNING_TYPE     : Warning event                          *
397            *      EVENTLOG_INFORMATION_TYPE : Information event                      *
398            *      EVENTLOG_AUDIT_SUCCESS    : Success audit event                    *
399            *      EVENTLOG_AUDIT_FAILURE    : Failure audit event                    *
400 tony  1.1  *                                                                         *
401            *   event_id:                                                             *
402            *     A fancy name for error code or error number.                        *
403            *                                                                         *
404            *   string:                                                               *
405            *     String to be logged or merged in with the error string in the       *
406            *     message DLL.                                                        *
407            *                                                                         *
408            * Description:                                                            *
409            *     This function provides a simple layer over the Win32 error logging  *
410            *     API's.                                                              *
411            *                                                                         *
412            * Returns:                                                                *
413            *     true  if event was successfully logged                              *
414            *     false if the event could not be logged                              *
415            *-------------------------------------------------------------------------*/
416           bool
417           Service::LogEvent(WORD event_type, DWORD event_id, const char *string)
418           {
419             BOOL   status;
420             HANDLE h_event_source = RegisterEventSource(NULL, g_event_source);
421 tony  1.1 
422             if (h_event_source == NULL)
423               FALSE;
424           
425             status = ReportEvent (h_event_source, 
426                                   event_type, 
427                                   0, 
428                                   event_id, 
429                                   NULL, 
430                                   1, 
431                                   0, 
432                                   &string, 
433                                   NULL);
434           
435             DeregisterEventSource(h_event_source);
436           
437             return (status == TRUE) ? true : false;
438           }
439           
440           //-------------------------------------------------------------------------
441           // P R I V A T E
442 tony  1.1 //-------------------------------------------------------------------------
443           /*-------------------------------------------------------------------------*
444            * Routine: real_service_main                                              *
445            *                                                                         *
446            * Args:                                                                   *
447            *   argc:                                                                 *
448            *     The number of arguments in the argv array                           *
449            *   argv:                                                                 *
450            *     An array of strings representing the command line arguments         *
451            *                                                                         *
452            * Description:                                                            *
453            *     This function is the real service main (as opposed to the user      *
454            *     supplied service main, which is called service_main).               *
455            *                                                                         *
456            * Returns:                                                                *
457            *     nothing                                                             *
458            *-------------------------------------------------------------------------*/
459           void __stdcall
460           Service::real_service_main(DWORD argc, LPTSTR *argv)
461           {
462             // Let the SCM know we're alive and kicking
463 tony  1.1 
464             report_status(SERVICE_START_PENDING, NO_ERROR, 0, 5000);
465           
466             // If the command line arguments include the string "-debug" then
467             // invoke the debugger
468           
469             if (check_args_for_string("-debug"))
470               DebugBreak();
471           
472             // Save copy of argc and argc in global variables
473           
474             g_argc = argc;
475             g_argv = argv;
476           
477             // Start service actions
478           
479             g_service_status_handle = RegisterServiceCtrlHandler (g_service_name, 
480                                                                   service_control_handler);
481           
482             if (g_service_status_handle == 0)
483               {
484 tony  1.1       show_error("register", "Service Control Handler", GetLastError());
485                 report_status(SERVICE_STOPPED, NO_ERROR, 0, 5000);
486                 return;
487               }
488           
489             // Change our state to RUNNING, then invoke the user supplied
490             // service_main function. After the user's service_main exits,
491             // change the service state to STOPPED.
492           
493             report_status(SERVICE_RUNNING, NO_ERROR, 0, 5000);
494             g_service_main(STARTUP_FLAG, argc, argv);
495             report_status(SERVICE_STOPPED, NO_ERROR, 0, 5000);
496           
497             return;
498           }
499           
500           /*-------------------------------------------------------------------------*
501            * Routine: check_args_for_string                                          *
502            *                                                                         *
503            * Args:                                                                   *
504            *   string:                                                               *
505 tony  1.1  *     The string to match.                                                *
506            *                                                                         *
507            * Description:                                                            *
508            *     This function iterates through the command line arguments searching *
509            *     for the string specified by the string parameter.                   *
510            *                                                                         *
511            * Returns:                                                                *
512            *     true  if the string was found                                       *
513            *     false if the string was not found                                   *
514            *-------------------------------------------------------------------------*/
515           bool
516           Service::check_args_for_string(char *string)
517           {
518             int i;
519           
520             for (i = 1; i < g_argc; i++)
521               {
522                 if (strcmp(g_argv[i], string) == 0)
523                   return true;
524               }
525           
526 tony  1.1   return false;
527           }
528           
529           /*-------------------------------------------------------------------------*
530            * Method: service_control_handler                                         *
531            *                                                                         *
532            * Args:                                                                   *
533            *   control:                                                              *
534            *     The control sent from the SCM telling us what action to take:       *
535            *     start, stop, pause, continue, etc.                                  *
536            *                                                                         *
537            * Description:                                                            *
538            *     This function handles control messages sent from the SCM. Currently *
539            *     the only message that is handled differently is the STOP message,   *
540            *     which invokes the user's service main function passing to it the    *
541            *     SHUTDOWN_FLAG. The user is then responsible to perform all shutdown *
542            *     related tasks.                                                      *
543            *                                                                         *
544            * Returns:                                                                *
545            *     Nothing                                                             *
546            *-------------------------------------------------------------------------*/
547 tony  1.1 
548           void WINAPI
549           Service::service_control_handler(DWORD control)
550           {
551             /* Currently, only the stop contol requires special handling */
552           
553             if (control == SERVICE_CONTROL_STOP)
554               {
555                 report_status(SERVICE_STOP_PENDING, NO_ERROR, 0, 5000);
556                 g_service_main(SHUTDOWN_FLAG, g_argc, g_argv);
557                 return;
558               }
559           
560             /* For every other control, just send back our current state */
561           
562             report_status(g_current_state, NO_ERROR, 0, 5000);
563           }
564           
565           /*-------------------------------------------------------------------------*
566            * Method: report_status                                                   *
567            *                                                                         *
568 tony  1.1  * Args:                                                                   *
569            *   current_state:                                                        *
570            *     The service's new state. May be any valid Win32 service state.      *
571            *                                                                         *
572            *   exit_code:                                                            *
573            *     This must be a Win32 exit code. If the server is exiting due to     *
574            *     an error returned from the Win32 API, then this is the place to     *
575            *     report the error status. Most of the time, this will be NO_ERROR.   *
576            *                                                                         *
577            *   check_point:                                                          *
578            *     An integer value that should start at zero and increment as each    *
579            *     discrete step within a phase is completed. For example, if startup  *
580            *     consists of 3 steps, then the startup will issue its first check-   *
581            *     point of zero, then increment up through and including 2 as each    *
582            *     step is finished.                                                   *
583            *                                                                         *
584            *   wait_hint:                                                            *
585            *     Tells the SCM how long to expect to wait for the next status        *
586            *     update.                                                             *
587            *                                                                         *
588            * Description:                                                            *
589 tony  1.1  *     This function provides an even higher level of abstraction over     *
590            *     the Win32 event logging API's.                                      *
591            *                                                                         *
592            * Returns:                                                                *
593            *     true  if the status was successfully reported                       *
594            *     false if the status could not be reported                           *
595            *-------------------------------------------------------------------------*/
596           bool
597           Service::report_status(
598             DWORD current_state, 
599             DWORD exit_code, 
600             DWORD check_point, 
601             DWORD wait_hint)
602           {
603             SERVICE_STATUS current_status = 
604             {
605               SERVICE_WIN32,
606               current_state,
607               SERVICE_CONTROL_INTERROGATE,
608               exit_code,
609               0,
610 tony  1.1     check_point,
611               wait_hint
612             };
613           
614             /* Wait until we're started before we accept a stop control */
615           
616             if (current_state == SERVICE_RUNNING)
617               current_status.dwControlsAccepted += SERVICE_ACCEPT_STOP;
618           
619             /* Save new state */
620           
621             g_current_state = current_state;
622             
623             return (SetServiceStatus(g_service_status_handle, &current_status) == TRUE) ? true : false;
624           }
625           
626           /*-------------------------------------------------------------------------*
627            * Method: change_service_description                                      *
628            *                                                                         *
629            * Args:                                                                   *
630            *   service:                                                              *
631 tony  1.1  *     Handle to the service                                               *
632            *                                                                         *
633            *   description:                                                          *
634            *     The service's description                                           *
635            *                                                                         *
636            * Description:                                                            *
637            *     This function sets the description for the service. The description *
638            *     text shows up in the Services mmc snapin. The description is added  *
639            *     as a benefit to users, but does not affect the service's operation. *
640            *     Therefore, if this function should fail for any reason, there is    *
641            *     no need to stop. That's why this function has no return value.      *
642            *                                                                         *
643            * Returns:                                                                *
644            *     Nothing                                                             *
645            *                                                                         *
646            * Notes:                                                                  *
647            *     This function uses the ChangeServiceConfig2() API function which    *
648            *     first appeared in Windows2000. Therefore, this code checks the      *
649            *     OS version, before calling ChangeServiceConfig2().                  *
650            *-------------------------------------------------------------------------*/
651           void 
652 tony  1.1 Service::change_service_description(SC_HANDLE service, char *description)
653           {
654             OSVERSIONINFO osvi;
655           
656             /* 
657              *  Test for Windows 2000 or greater
658              */ 
659             
660             osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
661           
662             if (GetVersionEx(&osvi) != 0                      && 
663                 osvi.dwPlatformId    == VER_PLATFORM_WIN32_NT && 
664                 osvi.dwMajorVersion  >= 5)
665               {
666                 typedef BOOL (WINAPI *CHANGE_SERVICE_CONFIG2_T)(SC_HANDLE, DWORD, LPVOID);
667           
668                 HINSTANCE hdll = LoadLibrary("advapi32.dll");
669           
670                 if (hdll != NULL)
671                   {
672                     SERVICE_DESCRIPTION      sd;
673 tony  1.1           CHANGE_SERVICE_CONFIG2_T csc;
674           
675                     csc = (CHANGE_SERVICE_CONFIG2_T) GetProcAddress(hdll, "ChangeServiceConfig2A");
676           
677                     if (csc)
678                       {
679                         sd.lpDescription = description;
680                         csc(service, SERVICE_CONFIG_DESCRIPTION, &sd);
681                       }
682           
683                     FreeLibrary(hdll);
684                   }
685               }
686           }
687           
688           /*-------------------------------------------------------------------------*
689            * Method: show_error                                                      *
690            *                                                                         *
691            * Args:                                                                   *
692            *   action:                                                               *
693            *     A single verb decribing the action going on when the error          *
694 tony  1.1  *     occurred. For example, "opening", "creating", etc.                  *
695            *                                                                         *
696            *   object:                                                               *
697            *     Description of the object on which was action occurred. Examples    *
698            *     are "file", "service", etc.                                         *
699            *                                                                         *
700            *   hr:                                                                   *
701            *     The error status. Can be an hresult, or Win32 error status.         *
702            *                                                                         *
703            * Description:                                                            *
704            *     This function provides an even higher level of abstraction over     *
705            *     the Win32 event logging API's.                                      *
706            *                                                                         *
707            * Returns:                                                                *
708            *     true  if event was successfully logged                              *
709            *     false if the event could not be logged                              *
710            *-------------------------------------------------------------------------*/
711           bool
712           Service::show_error(const char *action, const char *object, DWORD hr)
713           {
714             char console_title[_MAX_PATH] = {0};
715 tony  1.1   char  txt[_MAX_PATH]          = "";
716             char  msg[_MAX_PATH]          = "";
717             DWORD nchars;
718           
719             nchars = FormatMessage(
720               FORMAT_MESSAGE_FROM_SYSTEM,
721               NULL,
722               hr,
723               MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
724               msg,
725               sizeof(msg),
726               NULL);
727           
728             if (nchars == 0) 
729               sprintf(msg, "Unknown error code - %%X%x", hr);
730             else if (nchars > 1)
731               {
732                 if (msg[nchars - 1] == '\n') msg[nchars - 1] = '\0';
733                 if (msg[nchars - 2] == '\r') msg[nchars - 2] = '\0';
734               }
735           
736 tony  1.1   sprintf(txt, "Failed to %s %s %s. Reason: %s", action, object, g_service_name, msg);
737           
738             // Running from a console window
739             // send courtesy message txt to stderr
740             if (GetConsoleTitle(console_title, _MAX_PATH) > 0)
741               {
742                 cerr << txt << endl;
743               }
744           
745             return LogEvent(EVENTLOG_ERROR_TYPE, 1, txt);
746           }
747           
748           Service::State
749           Service::get_state(DWORD scm_state)
750           {
751             return (State)scm_state;
752           }
753           
754           Service::ReturnCode 
755           Service::get_error(DWORD error_status, const char *action)
756           {
757 tony  1.1   switch (error_status)
758               {
759               /*
760                 // INFO: Could add cases to suppress error message.
761                 case ERROR_SERVICE_DOES_NOT_EXIST:
762                 case ERROR_SERVICE_CANNOT_ACCEPT_CTRL:
763                   break;
764               */
765                 case SERVICE_RETURN_SUCCESS:
766                   break;
767           
768                 default:
769                   show_error(action, "service", error_status); 
770                   break;
771               }
772             return (ReturnCode)error_status;
773           }
774           

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2