summaryrefslogtreecommitdiff
path: root/ace/NT_Service.h
blob: d60d01559af79d11f5c17d63e2e3aa8ea2034427 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/* -*- C++ -*- */
// $Id$

// ============================================================================
//
// = LIBRARY
//    ace
// 
// = FILENAME
//    NT_Service.h
//
// = AUTHOR
//    Steve Huston
// 
// ============================================================================

#if !defined (ACE_NT_SERVICE_H)
#define ACE_NT_SERVICE_H

#include "ace/inc_user_config.h"

#if !defined (ACE_LACKS_PRAGMA_ONCE)
#pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */

#if defined (ACE_HAS_WINNT4) && ACE_HAS_WINNT4 != 0

#include "ace/Service_Object.h"
#include "ace/Synch.h"
#include "ace/Task.h"

// NT Services can be implemented using the framework defined by the
// ACE_NT_Service class, and the macros defined in this file.  Some quick
// refresher notes on NT Services:
//   - The main program defines an array of entries describing the services
//     offered.  The ACE_NT_SERVICE_ENTRY macro can help with this.
//   - For each service, a separate ServiceMain and Handler function need to
//     be defined.  These are taken care of by the ACE_NT_SERVICE_DEFINE
//     macro.
//   - When the main program/thread calls StartServiceCtrlDispatcher, NT
//     creates a thread for each service, and runs the ServiceMain function
//     for the service in that new thread.  When that thread exits, the service
//     is gone.
//
// To use this facility, you could derive a class from ACE_Service_Object (if
// you want to start via ACE's service configurator), or use any other class
// to run when the image starts (assuming that NT runs the image).  You must
// set up an NT SERVICE_TABLE_ENTRY array to define your service(s).  You
// can use the ACE_NT_SERVICE_... macros defined below for this.
// A SERVICE_TABLE might look like this:
//       ACE_NT_SERVICE_REFERENCE(Svc1);  // If service is in another file
//       SERVICE_TABLE_ENTRY myServices[] = {
//                    ACE_NT_SERVICE_ENTRY ("MyNeatService", Svc1),
//                    { 0, 0 } };
//
// In the file where your service(s) are implemented, use the
// ACE_NT_SERVICE_DEFINE macro to set up the following:
//    1. A pointer to the service's implementation object (must be derived
//       from ACE_NT_Service).
//    2. The service's Handler function (forwards all requests to the
//       ACE_NT_Service-derived object's handle_control function).
//    3. The service's ServiceMain function.  Creates a new instance of the
//       ACE_NT_Service-derived class SVCCLASS, unless one has been created
//       already.
//
// If you are using all the default constructor values, you
// can let the generated ServiceMain function create the object, else
// you need to create it by hand before calling StartServiceCtrlDispatcher.
// Set the pointer so ServiceMain won't create another one.
// Another reason you may want to do the object creation yourself is if you
// want to also implement suspend and resume functions (the ones inherited
// from ACE_Service_Object) to do something intelligent to the services which
// are running, like call their handle_control functions to request suspend
// and resume actions, similar to what NT would do if a Services control panel
// applet would do if the user clicks on Suspend.


// ACE_NT_SERVICE_START_TIMEOUT is an estimate of the number of milliseconds
// your service will take to start.  Default is 5 seconds; you can pass
// a different value (or set one) when you create the ACE_NT_Service object
// for your service.
#if !defined ACE_NT_SERVICE_START_TIMEOUT
#define ACE_NT_SERVICE_START_TIMEOUT  5000
#endif /* ACE_NT_SERVICE_TIMEOUT */

class ACE_Export ACE_NT_Service : public ACE_Task<ACE_MT_SYNCH>
{
  // = TITLE
  //     Provide the base class which defines the interface for controlling
  //     an NT service.
  //
  // = DESCRIPTION
public:
  // = Initialization and termination methods.
  ACE_NT_Service (DWORD start_timeout = ACE_NT_SERVICE_START_TIMEOUT,
                  DWORD service_type = SERVICE_WIN32_OWN_PROCESS,
                  DWORD controls_mask = SERVICE_ACCEPT_STOP);

  virtual ~ACE_NT_Service (void);

  virtual int open (void *args = 0);
  // Hook called to open the service.  By default, will set the status to
  // START_PENDING, svc(), wait(), then set the status to STOPPED.

  virtual int svc (void) = 0;
  // The actual service implementation.  This function must be implemented
  // by subclasses.  It is expected that this function will set the status
  // to RUNNING.

  virtual void  handle_control (DWORD control_code);
  // This function is called in response to a request from the Service
  // Dispatcher.  It must interact with the svc() function to effect the
  // requested control operation.  The default implementation handles
  // all requests as follows:
  //    SERVICE_CONTROL_STOP: set stop pending, set cancel flag
  //    SERVICE_CONTROL_PAUSE: set pause pending, suspend(), set paused
  //    SERVICE_CONTROL_CONTINUE: set continue pending, resume(), set running
  //    SERVICE_CONTROL_INTERROGATE: reports current status
  //    SERVICE_CONTROL_SHUTDOWN: same as SERVICE_CONTROL_STOP.

  void svc_handle (const SERVICE_STATUS_HANDLE new_svc_handle);
  // Set the svc_handle_ member.

  ACE_ALLOC_HOOK_DECLARE;
  // Declare the dynamic allocation hooks.

protected:
  int report_status (DWORD new_status, DWORD time_hint = 0);

protected:
  DWORD                  start_time_;   // Estimate of init time needed
  SERVICE_STATUS_HANDLE  svc_handle_;   // Service handle - doesn't need close.
  SERVICE_STATUS         svc_status_;
};

// These macros help to get things set up correctly at compile time
// and to take most of the grudge work out of creating the proper
// functions and doing the registrations.
//
// ACE_NT_SERVICE_DEFINE - defines the 'ServiceMain' function which NT will
//                         call in its own thread when the service control
//                         dispatcher starts.

#define ACE_NT_SERVICE_DEFINE(SVCNAME, SVCCLASS, SVCDESC)                   \
  ACE_NT_Service * _ace_nt_svc_obj_##SVCNAME = 0;                           \
  VOID WINAPI ace_nt_svc_handler_##SVCNAME (DWORD fdwControl) {             \
    _ace_nt_svc_obj_##SVCNAME->handle_control(fdwControl);                  \
  }                                                                         \
  VOID WINAPI ace_nt_svc_main_##SVCNAME (DWORD dwArgc, LPTSTR *lpszArgv) {  \
    int delete_svc_obj = 0;                                                 \
    if (_ace_nt_svc_obj_##SVCNAME == 0) {                                   \
      ACE_NEW (_ace_nt_svc_obj_##SVCNAME, SVCCLASS);                        \
      if (_ace_nt_svc_obj_##SVCNAME == 0)                                   \
        return;                                                             \
      delete_svc_obj = 1;                                                   \
    }                                                                       \
    _ace_nt_svc_obj_##SVCNAME->init(dwArgc, lpszArgv);                      \
    _ace_nt_svc_obj_##SVCNAME->svc_handle(                                  \
                  RegisterServiceCtrlHandler(SVCDESC,                       \
                                          &ace_nt_svc_handler_##SVCNAME));  \
    _ace_nt_svc_obj_##SVCNAME->open();                                      \
    _ace_nt_svc_obj_##SVCNAME->wait();                                      \
    _ace_nt_svc_obj_##SVCNAME->fini();                                      \
    if (delete_svc_obj) {                                                   \
      delete _ace_nt_svc_obj_##SVCNAME;                                     \
      _ace_nt_svc_obj_##SVCNAME = 0;                                        \
    }                                                                       \
    return;                                                                 \
  }

#define ACE_NT_SERVICE_REFERENCE(SVCNAME)                                  \
extern VOID WINAPI ace_nt_svc_main_##SVCNAME (DWORD dwArgc, LPTSTR *lpszArgv);

#define ACE_NT_SERVICE_ENTRY(SVCDESC, SVCNAME)                             \
                      { SVCDESC, &ace_nt_svc_main_##SVCNAME }

#if defined (__ACE_INLINE__)
#include "ace/NT_Service.i"
#endif /* __ACE_INLINE__ */

#endif /* ACE_HAS_WINNT4 */
#endif /* ACE_SERVICE_OBJECT_H */