(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 s.hills 1.2   // Don't call exit()
347               return status;
348 tony    1.1 }
349             
350             /*-------------------------------------------------------------------------*
351              * Method: GetState                                                        *
352              *                                                                         *
353              * Description:                                                            *
354              *     Returns the state of the service into "state".                      *
355              *-------------------------------------------------------------------------*/
356             Service::ReturnCode 
357             Service::GetState(State *state)
358             {
359               ReturnCode      status = SERVICE_RETURN_SUCCESS;
360               SERVICE_STATUS  service_status;
361               SC_HANDLE       sch;
362             
363               if (g_service_name == NULL)
364                 return SERVICE_ERROR_NOT_FOUND; // SERVICE_ERROR_NOT_FOUND
365               else if ((sch = OpenSCManager(NULL, NULL, GENERIC_READ)) == NULL)
366                 status = get_error(GetLastError(), "open");
367               else
368                 {
369 tony    1.1       SC_HANDLE service = OpenService(sch, g_service_name, SERVICE_QUERY_STATUS);
370              
371                   if (service == NULL) 
372                     status = get_error(GetLastError(), "open");
373                   else if (!QueryServiceStatus(service, &service_status))
374                     status = get_error(GetLastError(), "query");
375                   else
376                     {
377                       *state = get_state(service_status.dwCurrentState);
378                       CloseServiceHandle(service);
379                     }
380               
381                   CloseServiceHandle(sch);
382                 }
383             
384               return status;
385             }
386             
387             /*-------------------------------------------------------------------------*
388              * Method: LogEvent                                                        *
389              *                                                                         *
390 tony    1.1  * Args:                                                                   *
391              *   event_type:                                                           *
392              *     The Win32 event type. Valid event types are:                        *
393              *      EVENTLOG_SUCCESS          : Success event                          *
394              *      EVENTLOG_ERROR_TYPE       : Error event                            *
395              *      EVENTLOG_WARNING_TYPE     : Warning event                          *
396              *      EVENTLOG_INFORMATION_TYPE : Information event                      *
397              *      EVENTLOG_AUDIT_SUCCESS    : Success audit event                    *
398              *      EVENTLOG_AUDIT_FAILURE    : Failure audit event                    *
399              *                                                                         *
400              *   event_id:                                                             *
401              *     A fancy name for error code or error number.                        *
402              *                                                                         *
403              *   string:                                                               *
404              *     String to be logged or merged in with the error string in the       *
405              *     message DLL.                                                        *
406              *                                                                         *
407              * Description:                                                            *
408              *     This function provides a simple layer over the Win32 error logging  *
409              *     API's.                                                              *
410              *                                                                         *
411 tony    1.1  * Returns:                                                                *
412              *     true  if event was successfully logged                              *
413              *     false if the event could not be logged                              *
414              *-------------------------------------------------------------------------*/
415             bool
416             Service::LogEvent(WORD event_type, DWORD event_id, const char *string)
417             {
418               BOOL   status;
419               HANDLE h_event_source = RegisterEventSource(NULL, g_event_source);
420             
421               if (h_event_source == NULL)
422                 FALSE;
423             
424               status = ReportEvent (h_event_source, 
425                                     event_type, 
426                                     0, 
427                                     event_id, 
428                                     NULL, 
429                                     1, 
430                                     0, 
431                                     &string, 
432 tony    1.1                         NULL);
433             
434               DeregisterEventSource(h_event_source);
435             
436               return (status == TRUE) ? true : false;
437             }
438             
439             //-------------------------------------------------------------------------
440             // P R I V A T E
441             //-------------------------------------------------------------------------
442             /*-------------------------------------------------------------------------*
443              * Routine: real_service_main                                              *
444              *                                                                         *
445              * Args:                                                                   *
446              *   argc:                                                                 *
447              *     The number of arguments in the argv array                           *
448              *   argv:                                                                 *
449              *     An array of strings representing the command line arguments         *
450              *                                                                         *
451              * Description:                                                            *
452              *     This function is the real service main (as opposed to the user      *
453 tony    1.1  *     supplied service main, which is called service_main).               *
454              *                                                                         *
455              * Returns:                                                                *
456              *     nothing                                                             *
457              *-------------------------------------------------------------------------*/
458             void __stdcall
459             Service::real_service_main(DWORD argc, LPTSTR *argv)
460             {
461               // Let the SCM know we're alive and kicking
462             
463               report_status(SERVICE_START_PENDING, NO_ERROR, 0, 5000);
464             
465               // If the command line arguments include the string "-debug" then
466               // invoke the debugger
467             
468               if (check_args_for_string("-debug"))
469                 DebugBreak();
470             
471               // Save copy of argc and argc in global variables
472             
473               g_argc = argc;
474 tony    1.1   g_argv = argv;
475             
476               // Start service actions
477             
478               g_service_status_handle = RegisterServiceCtrlHandler (g_service_name, 
479                                                                     service_control_handler);
480             
481               if (g_service_status_handle == 0)
482                 {
483                   show_error("register", "Service Control Handler", GetLastError());
484                   report_status(SERVICE_STOPPED, NO_ERROR, 0, 5000);
485                   return;
486                 }
487             
488               // Change our state to RUNNING, then invoke the user supplied
489               // service_main function. After the user's service_main exits,
490               // change the service state to STOPPED.
491             
492               report_status(SERVICE_RUNNING, NO_ERROR, 0, 5000);
493               g_service_main(STARTUP_FLAG, argc, argv);
494               report_status(SERVICE_STOPPED, NO_ERROR, 0, 5000);
495 tony    1.1 
496               return;
497             }
498             
499             /*-------------------------------------------------------------------------*
500              * Routine: check_args_for_string                                          *
501              *                                                                         *
502              * Args:                                                                   *
503              *   string:                                                               *
504              *     The string to match.                                                *
505              *                                                                         *
506              * Description:                                                            *
507              *     This function iterates through the command line arguments searching *
508              *     for the string specified by the string parameter.                   *
509              *                                                                         *
510              * Returns:                                                                *
511              *     true  if the string was found                                       *
512              *     false if the string was not found                                   *
513              *-------------------------------------------------------------------------*/
514             bool
515             Service::check_args_for_string(char *string)
516 tony    1.1 {
517               int i;
518             
519               for (i = 1; i < g_argc; i++)
520                 {
521                   if (strcmp(g_argv[i], string) == 0)
522                     return true;
523                 }
524             
525               return false;
526             }
527             
528             /*-------------------------------------------------------------------------*
529              * Method: service_control_handler                                         *
530              *                                                                         *
531              * Args:                                                                   *
532              *   control:                                                              *
533              *     The control sent from the SCM telling us what action to take:       *
534              *     start, stop, pause, continue, etc.                                  *
535              *                                                                         *
536              * Description:                                                            *
537 tony    1.1  *     This function handles control messages sent from the SCM. Currently *
538              *     the only message that is handled differently is the STOP message,   *
539              *     which invokes the user's service main function passing to it the    *
540              *     SHUTDOWN_FLAG. The user is then responsible to perform all shutdown *
541              *     related tasks.                                                      *
542              *                                                                         *
543              * Returns:                                                                *
544              *     Nothing                                                             *
545              *-------------------------------------------------------------------------*/
546             
547             void WINAPI
548             Service::service_control_handler(DWORD control)
549             {
550               /* Currently, only the stop contol requires special handling */
551             
552               if (control == SERVICE_CONTROL_STOP)
553                 {
554                   report_status(SERVICE_STOP_PENDING, NO_ERROR, 0, 5000);
555                   g_service_main(SHUTDOWN_FLAG, g_argc, g_argv);
556                   return;
557                 }
558 tony    1.1 
559               /* For every other control, just send back our current state */
560             
561               report_status(g_current_state, NO_ERROR, 0, 5000);
562             }
563             
564             /*-------------------------------------------------------------------------*
565              * Method: report_status                                                   *
566              *                                                                         *
567              * Args:                                                                   *
568              *   current_state:                                                        *
569              *     The service's new state. May be any valid Win32 service state.      *
570              *                                                                         *
571              *   exit_code:                                                            *
572              *     This must be a Win32 exit code. If the server is exiting due to     *
573              *     an error returned from the Win32 API, then this is the place to     *
574              *     report the error status. Most of the time, this will be NO_ERROR.   *
575              *                                                                         *
576              *   check_point:                                                          *
577              *     An integer value that should start at zero and increment as each    *
578              *     discrete step within a phase is completed. For example, if startup  *
579 tony    1.1  *     consists of 3 steps, then the startup will issue its first check-   *
580              *     point of zero, then increment up through and including 2 as each    *
581              *     step is finished.                                                   *
582              *                                                                         *
583              *   wait_hint:                                                            *
584              *     Tells the SCM how long to expect to wait for the next status        *
585              *     update.                                                             *
586              *                                                                         *
587              * Description:                                                            *
588              *     This function provides an even higher level of abstraction over     *
589              *     the Win32 event logging API's.                                      *
590              *                                                                         *
591              * Returns:                                                                *
592              *     true  if the status was successfully reported                       *
593              *     false if the status could not be reported                           *
594              *-------------------------------------------------------------------------*/
595             bool
596             Service::report_status(
597               DWORD current_state, 
598               DWORD exit_code, 
599               DWORD check_point, 
600 tony    1.1   DWORD wait_hint)
601             {
602               SERVICE_STATUS current_status = 
603               {
604                 SERVICE_WIN32,
605                 current_state,
606                 SERVICE_CONTROL_INTERROGATE,
607                 exit_code,
608                 0,
609                 check_point,
610                 wait_hint
611               };
612             
613               /* Wait until we're started before we accept a stop control */
614             
615               if (current_state == SERVICE_RUNNING)
616                 current_status.dwControlsAccepted += SERVICE_ACCEPT_STOP;
617             
618               /* Save new state */
619             
620               g_current_state = current_state;
621 tony    1.1   
622               return (SetServiceStatus(g_service_status_handle, &current_status) == TRUE) ? true : false;
623             }
624             
625             /*-------------------------------------------------------------------------*
626              * Method: change_service_description                                      *
627              *                                                                         *
628              * Args:                                                                   *
629              *   service:                                                              *
630              *     Handle to the service                                               *
631              *                                                                         *
632              *   description:                                                          *
633              *     The service's description                                           *
634              *                                                                         *
635              * Description:                                                            *
636              *     This function sets the description for the service. The description *
637              *     text shows up in the Services mmc snapin. The description is added  *
638              *     as a benefit to users, but does not affect the service's operation. *
639              *     Therefore, if this function should fail for any reason, there is    *
640              *     no need to stop. That's why this function has no return value.      *
641              *                                                                         *
642 tony    1.1  * Returns:                                                                *
643              *     Nothing                                                             *
644              *                                                                         *
645              * Notes:                                                                  *
646              *     This function uses the ChangeServiceConfig2() API function which    *
647              *     first appeared in Windows2000. Therefore, this code checks the      *
648              *     OS version, before calling ChangeServiceConfig2().                  *
649              *-------------------------------------------------------------------------*/
650             void 
651             Service::change_service_description(SC_HANDLE service, char *description)
652             {
653               OSVERSIONINFO osvi;
654             
655               /* 
656                *  Test for Windows 2000 or greater
657                */ 
658               
659               osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
660             
661               if (GetVersionEx(&osvi) != 0                      && 
662                   osvi.dwPlatformId    == VER_PLATFORM_WIN32_NT && 
663 tony    1.1       osvi.dwMajorVersion  >= 5)
664                 {
665                   typedef BOOL (WINAPI *CHANGE_SERVICE_CONFIG2_T)(SC_HANDLE, DWORD, LPVOID);
666             
667                   HINSTANCE hdll = LoadLibrary("advapi32.dll");
668             
669                   if (hdll != NULL)
670                     {
671                       SERVICE_DESCRIPTION      sd;
672                       CHANGE_SERVICE_CONFIG2_T csc;
673             
674                       csc = (CHANGE_SERVICE_CONFIG2_T) GetProcAddress(hdll, "ChangeServiceConfig2A");
675             
676                       if (csc)
677                         {
678                           sd.lpDescription = description;
679                           csc(service, SERVICE_CONFIG_DESCRIPTION, &sd);
680                         }
681             
682                       FreeLibrary(hdll);
683                     }
684 tony    1.1     }
685             }
686             
687             /*-------------------------------------------------------------------------*
688              * Method: show_error                                                      *
689              *                                                                         *
690              * Args:                                                                   *
691              *   action:                                                               *
692              *     A single verb decribing the action going on when the error          *
693              *     occurred. For example, "opening", "creating", etc.                  *
694              *                                                                         *
695              *   object:                                                               *
696              *     Description of the object on which was action occurred. Examples    *
697              *     are "file", "service", etc.                                         *
698              *                                                                         *
699              *   hr:                                                                   *
700              *     The error status. Can be an hresult, or Win32 error status.         *
701              *                                                                         *
702              * Description:                                                            *
703              *     This function provides an even higher level of abstraction over     *
704              *     the Win32 event logging API's.                                      *
705 tony    1.1  *                                                                         *
706              * Returns:                                                                *
707              *     true  if event was successfully logged                              *
708              *     false if the event could not be logged                              *
709              *-------------------------------------------------------------------------*/
710             bool
711             Service::show_error(const char *action, const char *object, DWORD hr)
712             {
713               char console_title[_MAX_PATH] = {0};
714               char  txt[_MAX_PATH]          = "";
715               char  msg[_MAX_PATH]          = "";
716               DWORD nchars;
717             
718               nchars = FormatMessage(
719                 FORMAT_MESSAGE_FROM_SYSTEM,
720                 NULL,
721                 hr,
722                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
723                 msg,
724                 sizeof(msg),
725                 NULL);
726 tony    1.1 
727               if (nchars == 0) 
728                 sprintf(msg, "Unknown error code - %%X%x", hr);
729               else if (nchars > 1)
730                 {
731                   if (msg[nchars - 1] == '\n') msg[nchars - 1] = '\0';
732                   if (msg[nchars - 2] == '\r') msg[nchars - 2] = '\0';
733                 }
734             
735               sprintf(txt, "Failed to %s %s %s. Reason: %s", action, object, g_service_name, msg);
736             
737               // Running from a console window
738               // send courtesy message txt to stderr
739               if (GetConsoleTitle(console_title, _MAX_PATH) > 0)
740                 {
741 s.hills 1.3       PEGASUS_STD(cerr) << txt << PEGASUS_STD(endl);
742 tony    1.1     }
743             
744               return LogEvent(EVENTLOG_ERROR_TYPE, 1, txt);
745             }
746             
747             Service::State
748             Service::get_state(DWORD scm_state)
749             {
750               return (State)scm_state;
751             }
752             
753             Service::ReturnCode 
754             Service::get_error(DWORD error_status, const char *action)
755             {
756               switch (error_status)
757                 {
758                 /*
759                   // INFO: Could add cases to suppress error message.
760                   case ERROR_SERVICE_DOES_NOT_EXIST:
761                   case ERROR_SERVICE_CANNOT_ACCEPT_CTRL:
762                     break;
763 tony    1.1     */
764                   case SERVICE_RETURN_SUCCESS:
765                     break;
766             
767                   default:
768                     show_error(action, "service", error_status); 
769                     break;
770                 }
771               return (ReturnCode)error_status;
772             }
773             

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2