Changes to attempt to silence bcc64x
[ACE_TAO.git] / ACE / ace / NT_Service.h
blobf931d0fbd55d4ec611a88dab2f6de089e850a6a2
1 // -*- C++ -*-
3 //==========================================================================
4 /**
5 * @file NT_Service.h
7 * @author Steve Huston <shuston@riverace.com>
8 */
9 //==========================================================================
11 #ifndef ACE_NT_SERVICE_H
12 #define ACE_NT_SERVICE_H
14 #include /**/ "ace/pre.h"
16 #include /**/ "ace/config-all.h"
18 #if !defined (ACE_LACKS_PRAGMA_ONCE)
19 # pragma once
20 #endif /* ACE_LACKS_PRAGMA_ONCE */
22 #if defined (ACE_WIN32)
24 #include "ace/ACE.h"
25 #include "ace/OS_Log_Msg_Attributes.h"
26 #include "ace/Service_Object.h"
27 #include "ace/Task.h"
28 #include "ace/OS_NS_errno.h" // needed for those using our macros
30 // ACE_NT_SERVICE_START_TIMEOUT is an estimate of the number of
31 // milliseconds your service will take to start. Default is 5
32 // seconds; you can pass a different value (or set one) when you
33 // create the ACE_NT_Service object for your service.
34 #if !defined ACE_NT_SERVICE_START_TIMEOUT
35 #define ACE_NT_SERVICE_START_TIMEOUT 5000
36 #endif /* ACE_NT_SERVICE_TIMEOUT */
38 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
40 /**
41 * @class ACE_NT_Service
43 * @brief Provide the base class which defines the interface for controlling
44 * an NT service.
46 * NT Services can be implemented using the framework defined by
47 * the ACE_NT_Service class, and the macros defined in this file.
48 * Some quick refresher notes on NT Services:
50 * - The main program defines an array of entries describing the
51 * services offered. The ACE_NT_SERVICE_ENTRY macro can help with
52 * this.
53 * - For each service, a separate ServiceMain and Handler function
54 * need to be defined. These are taken care of by the
55 * ACE_NT_SERVICE_DEFINE macro.
56 * - When the main program/thread calls
57 * StartServiceCtrlDispatcher, NT creates a thread for each
58 * service, and runs the ServiceMain function for the service in
59 * that new thread. When that thread exits, the service is gone.
61 * To use this facility, you could derive a class from
62 * ACE_Service_Object (if you want to start via ACE's service
63 * configurator), or use any other class to run when the image
64 * starts (assuming that NT runs the image). You must set up an
65 * NT SERVICE_TABLE_ENTRY array to define your service(s). You
66 * can use the ACE_NT_SERVICE_... macros defined below for this.
68 * A SERVICE_TABLE might look like this:
69 * ACE_NT_SERVICE_REFERENCE(Svc1); // If service is in another file
70 * SERVICE_TABLE_ENTRY myServices[] = {
71 * ACE_NT_SERVICE_ENTRY ("MyNeatService", Svc1),
72 * { 0, 0 } };
74 * In the file where your service(s) are implemented, use the
75 * ACE_NT_SERVICE_DEFINE macro to set up the following:
76 * 1. A pointer to the service's implementation object (must be derived
77 * from ACE_NT_Service).
78 * 2. The service's Handler function (forwards all requests to the
79 * ACE_NT_Service-derived object's handle_control function).
80 * 3. The service's ServiceMain function. Creates a new instance
81 * of the ACE_NT_Service-derived class SVCCLASS, unless one has
82 * been created already.
84 * If you are using all the default constructor values, you can
85 * let the generated ServiceMain function create the object, else
86 * you need to create it by hand before calling
87 * StartServiceCtrlDispatcher. Set the pointer so ServiceMain
88 * won't create another one. Another reason you may want to do
89 * the object creation yourself is if you want to also implement
90 * suspend and resume functions (the ones inherited from
91 * ACE_Service_Object) to do something intelligent to the services
92 * which are running, like call their handle_control functions to
93 * request suspend and resume actions, similar to what NT would do
94 * if a Services control panel applet would do if the user clicks
95 * on Suspend.
97 class ACE_Export ACE_NT_Service : public ACE_Task<ACE_MT_SYNCH>
99 public:
100 /// Constructor primarily for use when running the service.
101 ACE_NT_Service (DWORD start_timeout = ACE_NT_SERVICE_START_TIMEOUT,
102 DWORD service_type = SERVICE_WIN32_OWN_PROCESS,
103 DWORD controls_mask = SERVICE_ACCEPT_STOP);
105 /// Constructor primarily for use when inserting/removing/controlling
106 /// the service.
107 ACE_NT_Service (const ACE_TCHAR *name,
108 const ACE_TCHAR *desc = 0,
109 DWORD start_timeout = ACE_NT_SERVICE_START_TIMEOUT,
110 DWORD service_type = SERVICE_WIN32_OWN_PROCESS,
111 DWORD controls_mask = SERVICE_ACCEPT_STOP);
113 virtual ~ACE_NT_Service ();
115 // = Functions to operate the service
118 * Hook called to open the service. By default, sets the service
119 * status to SERVICE_START_PENDING, calls the @c svc() method,
120 * interprets and sets the service status, and returns.
122 virtual int open (void *args = 0);
125 * Hook called when terminating the service. Inherited from
126 * ACE_Shared_Object. Default implementation sets the service status
127 * to SERVICE_STOPPED.
129 virtual int fini ();
132 * The actual service implementation. This function need not be overridden
133 * by applications that are just using SCM capabilities, but must be
134 * by subclasses when actually running the service. It is expected that
135 * this function will set the status to RUNNING.
137 virtual int svc ();
140 * This function is called in response to a request from the Service
141 * Dispatcher. It must interact with the <svc> function to effect the
142 * requested control operation. The default implementation handles
143 * all requests as follows:
144 * SERVICE_CONTROL_STOP: set stop pending, set cancel flag
145 * SERVICE_CONTROL_PAUSE: set pause pending, <suspend>, set paused
146 * SERVICE_CONTROL_CONTINUE: set continue pending, <resume>, set running
147 * SERVICE_CONTROL_INTERROGATE: reports current status
148 * SERVICE_CONTROL_SHUTDOWN: same as SERVICE_CONTROL_STOP.
150 virtual void handle_control (DWORD control_code);
152 /// Set the svc_handle_ member. This is only a public function because
153 /// the macro-generated service function calls it.
154 void svc_handle (const SERVICE_STATUS_HANDLE new_svc_handle);
157 // = Methods which can be used to do SCP-like functions. The first group
158 // are used to register/insert and remove the service's definition in the
159 // SCM registry.
161 /// Sets the name and description for the service.
162 /// If @a desc is 0, it takes the same value as name.
163 void name (const ACE_TCHAR *name, const ACE_TCHAR *desc = 0);
165 /// Get the service name.
166 const ACE_TCHAR *name () const;
168 /// Get the service description.
169 const ACE_TCHAR *desc () const;
171 /// Sets the host machine
172 void host (const ACE_TCHAR *host);
174 /// Get the host machine.
175 const ACE_TCHAR *host () const;
178 * Insert (create) the service in the NT Service Control Manager,
179 * with the given creation values. exe_path defaults to the path name
180 * of the program that calls the function. All other 0-defaulted arguments
181 * pass 0 into the service creation, taking NT_specified defaults.
182 * Returns -1 on error, 0 on success.
184 int insert (DWORD start_type = SERVICE_DEMAND_START,
185 DWORD error_control = SERVICE_ERROR_IGNORE,
186 const ACE_TCHAR *exe_path = 0,
187 const ACE_TCHAR *group_name = 0,
188 LPDWORD tag_id = 0,
189 const ACE_TCHAR *dependencies = 0,
190 const ACE_TCHAR *account_name = 0,
191 const ACE_TCHAR *password = 0,
192 DWORD desired_access = SERVICE_ALL_ACCESS);
195 * Remove the service from the NT Service Control Manager. Returns -1 on
196 * error, 0 on success. This just affects the SCM and registry - the
197 * can and will keep running fine if it is already running.
199 int remove ();
201 /// Sets the startup type for the service. Returns -1 on error, 0 on success.
202 int startup (DWORD startup);
204 /// Returns the current startup type.
205 DWORD startup ();
207 // = Methods to control ACE_Log_Msg behavior in the service.
210 * Set the ACE_Log_Msg attributes that the service thread will use to
211 * initialize its ACE_Log_Msg instance. This is how the initiating
212 * thread's logging ostream, etc. get into the service thread. The
213 * logging attributes in effect when this function is called are what
214 * the service thread will have at its disposal when it starts; therefore,
215 * the main thread should set up logging options for the process, and
216 * call this function just before calling the StartServiceCtrlDispatcher
217 * function.
219 void capture_log_msg_attributes ();
222 * Set the ACE_Log_Msg attributes in the current thread to those saved
223 * in the most recent call to @c capture_log_msg_attributes(). This function
224 * should be called from the service's service thread. Ideally, it is the
225 * first method called to be sure that any logging done is incorporated
226 * correctly into the process's established logging setup.
228 void inherit_log_msg_attributes ();
230 // = Methods which control the service's execution.
232 // These methods to start/pause/resume/stop/check the service all
233 // have the following common behavior with respect to @a wait_time
234 // and return value. @a wait_time is a pointer to an ACE_Time_Value
235 // object. If not supplied (a zero pointer) the function will wait
236 // indefinitely for the action to be finalized (service reach
237 // running state, completely shut down, etc.) or get "stuck" before
238 // returning. If the time is supplied, it specifies how long to
239 // wait for the service to reach a steady state, and on return, it
240 // is updated to the service's last reported wait hint. So, if you
241 // want to control the waiting yourself (for example, you want to
242 // react to UI events during the wait) specify a @a wait_time of (0,
243 // 0) and use the updated time to know when to check the service's
244 // state again. NOTE!!!! The wait_time things don't work yet. The
245 // calls always check status once, and do not wait for it to change.
247 // The return value from start_svc, stop_svc, pause_svc,
248 // continue_svc is 0 if the request to NT to effect the change was
249 // made successfully. The service may refuse to change, or not do
250 // what you wanted; so if you need to know, supply a <svc_state>
251 // pointer to receive the service's reported last state on return
252 // and check it to see if it's what you want. The functions only
253 // return -1 when the actual request to the service is refused -
254 // this would include privilege restrictions and if the service is
255 // not configured to receive the request (this is most likely to
256 // happen in the case of pause and continue).
259 * Start the service (must have been inserted before). wait_time is
260 * the time to wait for the service to reach a steady state before
261 * returning. If it is 0, the function waits as long as it takes
262 * for the service to reach the 'running' state, or gets stuck in
263 * some other state, or exits. If @a wait_time is supplied, it is
264 * updated on return to hold the service's last reported wait hint.
265 * svc_state can be used to receive the state which the service
266 * settled in. If the value is 0, the service never ran. argc/argv
267 * are passed to the service's ServiceMain function when it starts.
268 * Returns 0 for success, -1 for error.
270 int start_svc (ACE_Time_Value *wait_time = 0,
271 DWORD *svc_state = 0,
272 DWORD argc = 0, const ACE_TCHAR **argv = 0);
275 * Requests the service to stop. Will wait up to @a wait_time for
276 * the service to actually stop. If not specified, the function
277 * waits until the service either stops or gets stuck in some other
278 * state before it stops. If @a svc_state is specified, it receives
279 * the last reported state of the service. Returns 0 if the request
280 * was made successfully, -1 if not.
282 int stop_svc (ACE_Time_Value *wait_time = 0, DWORD *svc_state = 0);
284 /// Pause the service.
285 int pause_svc (ACE_Time_Value *wait_time = 0, DWORD *svc_state = 0);
287 /// Continue the service.
288 int continue_svc (ACE_Time_Value *wait_time = 0, DWORD *svc_state = 0);
291 * Get the current state for the service. If @a wait_hint is not 0,
292 * it receives the service's reported wait hint. Note that this
293 * function returns 0 on failure (not -1 as is usual in ACE). A
294 * zero return would (probably) only be returned if there is either
295 * no service with the given name in the SCM database, or the caller
296 * does not have sufficient rights to access the service state. The
297 * set of valid service state values are all greater than 0.
299 DWORD state (ACE_Time_Value *wait_hint = 0);
301 /// A version of <state> that returns -1 for failure, 0 for success.
302 /// The DWORD pointed to by @a pstate receives the state value.
303 int state (DWORD *pstate, ACE_Time_Value *wait_hint = 0);
306 * Test access to the object's service in the SCM. The service must
307 * already have been inserted in the SCM database. This function
308 * has no affect on the service itself. Returns 0 if the specified
309 * access is allowed, -1 otherwise (either the access is denied, or
310 * there is a problem with the service's definition - check
311 * ACE_OS::last_error to get the specific error indication.
313 int test_access (DWORD desired_access = SERVICE_ALL_ACCESS);
315 /// Declare the dynamic allocation hooks.
316 ACE_ALLOC_HOOK_DECLARE;
318 protected:
319 int report_status (DWORD new_status, DWORD time_hint = 0);
322 * Return the svc_sc_handle_ member. If the member is null, it
323 * retrieves the handle from the Service Control Manager and caches
324 * it.
326 SC_HANDLE svc_sc_handle ();
329 * Waits for the service to reach @a desired_state or get
330 * (apparently) stuck before it reaches that state. Will wait at
331 * most @a wait_time to get to the desired state. If @a wait_time is
332 * 0, then the function keeps waiting until the desired state is
333 * reached or the service doesn't update its state any further. The
334 * svc_status_ class member is updated upon return.
336 void wait_for_service_state (DWORD desired_state,
337 ACE_Time_Value *wait_time);
339 /// Called by <handle_control> when a stop/shutdown was requested.
340 virtual void stop_requested (DWORD control_code);
342 /// Called by <handle_control> when a pause was requested.
343 virtual void pause_requested (DWORD control_code);
345 /// Called by <handle_control> when a continue was requested.
346 virtual void continue_requested (DWORD control_code);
348 /// Called by <handle_control> when a interrogate was requested.
349 virtual void interrogate_requested (DWORD control_code);
351 protected:
352 /// Estimate of init time needed
353 DWORD start_time_;
354 /// Service handle - doesn't need close.
355 SERVICE_STATUS_HANDLE svc_handle_;
356 SERVICE_STATUS svc_status_;
358 /// Service's SCM handle
359 SC_HANDLE svc_sc_handle_;
360 ACE_TCHAR *name_;
361 ACE_TCHAR *desc_;
362 ACE_TCHAR *host_;
364 /// ACE_Log_Msg attributes to inherit from the starting thread.
365 ACE_OS_Log_Msg_Attributes log_msg_attributes_;
368 ACE_END_VERSIONED_NAMESPACE_DECL
370 // These macros help to get things set up correctly at compile time
371 // and to take most of the grudge work out of creating the proper
372 // functions and doing the registrations.
374 // ACE_NT_SERVICE_DEFINE - defines the 'ServiceMain' function which NT will
375 // call in its own thread when the service control
376 // dispatcher starts.
378 #define ACE_NT_SERVICE_DEFINE(SVCNAME, SVCCLASS, SVCDESC) \
379 ACE_NT_Service * _ace_nt_svc_obj_##SVCNAME = 0; \
380 VOID WINAPI ace_nt_svc_handler_##SVCNAME (DWORD fdwControl) { \
381 _ace_nt_svc_obj_##SVCNAME->handle_control(fdwControl); \
383 VOID WINAPI ace_nt_svc_main_##SVCNAME (DWORD dwArgc, \
384 ACE_TCHAR **lpszArgv) { \
385 bool delete_svc_obj = false; \
386 if (_ace_nt_svc_obj_##SVCNAME == 0) { \
387 ACE_NEW (_ace_nt_svc_obj_##SVCNAME, SVCCLASS); \
388 if (_ace_nt_svc_obj_##SVCNAME == 0) \
389 return; \
390 delete_svc_obj = true; \
392 else \
393 _ace_nt_svc_obj_##SVCNAME->inherit_log_msg_attributes (); \
394 _ace_nt_svc_obj_##SVCNAME->init(dwArgc, lpszArgv); \
395 _ace_nt_svc_obj_##SVCNAME->svc_handle( \
396 ACE_TEXT_RegisterServiceCtrlHandler(SVCDESC, \
397 &ace_nt_svc_handler_##SVCNAME)); \
398 _ace_nt_svc_obj_##SVCNAME->open(); \
399 _ace_nt_svc_obj_##SVCNAME->wait(); \
400 _ace_nt_svc_obj_##SVCNAME->fini(); \
401 if (delete_svc_obj) { \
402 delete _ace_nt_svc_obj_##SVCNAME; \
403 _ace_nt_svc_obj_##SVCNAME = 0; \
405 return; \
408 #define ACE_NT_SERVICE_REFERENCE(SVCNAME) \
409 extern ACE_NT_Service * _ace_nt_svc_obj_##SVCNAME; \
410 extern VOID WINAPI ace_nt_svc_main_##SVCNAME (DWORD dwArgc, \
411 ACE_TCHAR **lpszArgv);
413 #define ACE_NT_SERVICE_ENTRY(SVCDESC, SVCNAME) \
414 { const_cast<ACE_TCHAR*> (SVCDESC), \
415 &ace_nt_svc_main_##SVCNAME }
417 #define ACE_NT_SERVICE_RUN(SVCNAME, SVCINSTANCE, RET) \
418 ACE_TEXT_SERVICE_TABLE_ENTRY _ace_nt_svc_table[2] = \
420 ACE_NT_SERVICE_ENTRY(ACE_TEXT (#SVCNAME), SVCNAME), \
421 { 0, 0 } \
422 }; \
423 _ace_nt_svc_obj_##SVCNAME = SVCINSTANCE; \
424 _ace_nt_svc_obj_##SVCNAME->capture_log_msg_attributes (); \
425 ACE_OS::last_error (0); \
426 int RET = ACE_TEXT_StartServiceCtrlDispatcher(_ace_nt_svc_table);
428 #if defined (__ACE_INLINE__)
429 #include "ace/NT_Service.inl"
430 #endif /* __ACE_INLINE__ */
432 #endif /* ACE_WIN32 */
434 #include /**/ "ace/post.h"
436 #endif /* ACE_SERVICE_OBJECT_H */