/[LeafOK_CVS]/innwebd/NTService.cpp
ViewVC logotype

Contents of /innwebd/NTService.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (show annotations)
Fri May 20 14:33:29 2005 UTC (20 years, 10 months ago) by sysadm
Branch: MAIN
CVS Tags: innwebd_1-4-16-0_MIL, HEAD
Changes since 1.1: +3 -0 lines
Content type: text/x-c++src
Error occurred while calculating annotation data.
Add control for Service while shutdown

1 // NTService.cpp
2 //
3 // Implementation of CNTService
4
5 #include "stdafx.h"
6 #include ".\NTService.h"
7
8 // static variables
9 CNTService* CNTService::m_pThis = NULL;
10
11 CNTService::CNTService(const char* szServiceName)
12 {
13 // copy the address of the current object so we can access it from
14 // the static member callback functions.
15 // WARNING: This limits the application to only one CNTService object.
16 m_pThis = this;
17
18 // Set the default service name and version
19 strncpy(m_szServiceName, szServiceName, sizeof(m_szServiceName)-1);
20 m_iMajorVersion = 1;
21 m_iMinorVersion = 0;
22 m_hEventSource = NULL;
23
24 // set up the initial service status
25 m_hServiceStatus = NULL;
26 m_Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
27 m_Status.dwCurrentState = SERVICE_STOPPED;
28 m_Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
29 m_Status.dwWin32ExitCode = 0;
30 m_Status.dwServiceSpecificExitCode = 0;
31 m_Status.dwCheckPoint = 0;
32 m_Status.dwWaitHint = 0;
33 m_bIsRunning = FALSE;
34 }
35
36 CNTService::~CNTService()
37 {
38 DebugMsg("CNTService::~CNTService()");
39 if (m_hEventSource) {
40 ::DeregisterEventSource(m_hEventSource);
41 }
42 }
43
44 ////////////////////////////////////////////////////////////////////////////////////////
45 // Default command line argument parsing
46
47 // Returns TRUE if it found an arg it recognised, FALSE if not
48 // Note: processing some arguments causes output to stdout to be generated.
49 BOOL CNTService::ParseStandardArgs(int argc, char* argv[])
50 {
51 // See if we have any command line args we recognise
52 if (argc <= 1) return FALSE;
53
54 if (_stricmp(argv[1], "-v") == 0) {
55
56 // Spit out version info
57 printf("%s Version %d.%d\n",
58 m_szServiceName, m_iMajorVersion, m_iMinorVersion);
59 printf("The service is %s installed\n",
60 IsInstalled() ? "currently" : "not");
61 return TRUE; // say we processed the argument
62
63 } else if (_stricmp(argv[1], "-i") == 0) {
64
65 // Request to install.
66 if (IsInstalled()) {
67 printf("%s is already installed\n", m_szServiceName);
68 } else {
69 // Try and install the copy that's running
70 if (Install()) {
71 printf("%s installed\n", m_szServiceName);
72 } else {
73 printf("%s failed to install. Error %d\n", m_szServiceName, GetLastError());
74 }
75 }
76 return TRUE; // say we processed the argument
77
78 } else if (_stricmp(argv[1], "-u") == 0) {
79
80 // Request to uninstall.
81 if (!IsInstalled()) {
82 printf("%s is not installed\n", m_szServiceName);
83 } else {
84 // Try and remove the copy that's installed
85 if (Uninstall()) {
86 // Get the executable file path
87 char szFilePath[_MAX_PATH];
88 ::GetModuleFileName(NULL, szFilePath, sizeof(szFilePath));
89 printf("%s removed. (You must delete the file (%s) yourself.)\n",
90 m_szServiceName, szFilePath);
91 } else {
92 printf("Could not remove %s. Error %d\n", m_szServiceName, GetLastError());
93 }
94 }
95 return TRUE; // say we processed the argument
96
97 }
98
99 // Don't recognise the args
100 return FALSE;
101 }
102
103 ////////////////////////////////////////////////////////////////////////////////////////
104 // Install/uninstall routines
105
106 // Test if the service is currently installed
107 BOOL CNTService::IsInstalled()
108 {
109 BOOL bResult = FALSE;
110
111 // Open the Service Control Manager
112 SC_HANDLE hSCM = ::OpenSCManager(NULL, // local machine
113 NULL, // ServicesActive database
114 SC_MANAGER_ALL_ACCESS); // full access
115 if (hSCM) {
116
117 // Try to open the service
118 SC_HANDLE hService = ::OpenService(hSCM,
119 m_szServiceName,
120 SERVICE_QUERY_CONFIG);
121 if (hService) {
122 bResult = TRUE;
123 ::CloseServiceHandle(hService);
124 }
125
126 ::CloseServiceHandle(hSCM);
127 }
128
129 return bResult;
130 }
131
132 BOOL CNTService::Install()
133 {
134 // Open the Service Control Manager
135 SC_HANDLE hSCM = ::OpenSCManager(NULL, // local machine
136 NULL, // ServicesActive database
137 SC_MANAGER_ALL_ACCESS); // full access
138 if (!hSCM) return FALSE;
139
140 // Get the executable file path
141 char szFilePath[_MAX_PATH];
142 ::GetModuleFileName(NULL, szFilePath, sizeof(szFilePath));
143
144 // Create the service
145 SC_HANDLE hService = ::CreateService(hSCM,
146 m_szServiceName,
147 m_szServiceName,
148 SERVICE_ALL_ACCESS,
149 SERVICE_WIN32_OWN_PROCESS,
150 SERVICE_AUTO_START, // start condition
151 SERVICE_ERROR_NORMAL,
152 szFilePath,
153 NULL,
154 NULL,
155 NULL,
156 NULL,
157 NULL);
158 if (!hService) {
159 ::CloseServiceHandle(hSCM);
160 return FALSE;
161 }
162
163 // make registry entries to support logging messages
164 // Add the source name as a subkey under the Application
165 // key in the EventLog service portion of the registry.
166 char szKey[256];
167 HKEY hKey = NULL;
168 strcpy(szKey, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\");
169 strcat(szKey, m_szServiceName);
170 if (::RegCreateKey(HKEY_LOCAL_MACHINE, szKey, &hKey) != ERROR_SUCCESS) {
171 ::CloseServiceHandle(hService);
172 ::CloseServiceHandle(hSCM);
173 return FALSE;
174 }
175
176 // Add the Event ID message-file name to the 'EventMessageFile' subkey.
177 ::RegSetValueEx(hKey,
178 "EventMessageFile",
179 0,
180 REG_EXPAND_SZ,
181 (CONST BYTE*)szFilePath,
182 (DWORD)strlen(szFilePath) + 1);
183
184 // Set the supported types flags.
185 DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
186 ::RegSetValueEx(hKey,
187 "TypesSupported",
188 0,
189 REG_DWORD,
190 (CONST BYTE*)&dwData,
191 sizeof(DWORD));
192 ::RegCloseKey(hKey);
193
194 LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_INSTALLED, m_szServiceName);
195
196 // tidy up
197 ::CloseServiceHandle(hService);
198 ::CloseServiceHandle(hSCM);
199 return TRUE;
200 }
201
202 BOOL CNTService::Uninstall()
203 {
204 // Open the Service Control Manager
205 SC_HANDLE hSCM = ::OpenSCManager(NULL, // local machine
206 NULL, // ServicesActive database
207 SC_MANAGER_ALL_ACCESS); // full access
208 if (!hSCM) return FALSE;
209
210 BOOL bResult = FALSE;
211 SC_HANDLE hService = ::OpenService(hSCM,
212 m_szServiceName,
213 DELETE);
214 if (hService) {
215 if (::DeleteService(hService)) {
216 LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_REMOVED, m_szServiceName);
217 bResult = TRUE;
218 } else {
219 LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_NOTREMOVED, m_szServiceName);
220 }
221 ::CloseServiceHandle(hService);
222 }
223
224 ::CloseServiceHandle(hSCM);
225 return bResult;
226 }
227
228 ///////////////////////////////////////////////////////////////////////////////////////
229 // Logging functions
230
231 // This function makes an entry into the application event log
232 void CNTService::LogEvent(WORD wType, DWORD dwID,
233 const char* pszS1,
234 const char* pszS2,
235 const char* pszS3)
236 {
237 const char* ps[3];
238 ps[0] = pszS1;
239 ps[1] = pszS2;
240 ps[2] = pszS3;
241
242 int iStr = 0;
243 for (int i = 0; i < 3; i++) {
244 if (ps[i] != NULL) iStr++;
245 }
246
247 // Check the event source has been registered and if
248 // not then register it now
249 if (!m_hEventSource) {
250 m_hEventSource = ::RegisterEventSource(NULL, // local machine
251 m_szServiceName); // source name
252 }
253
254 if (m_hEventSource) {
255 ::ReportEvent(m_hEventSource,
256 wType,
257 0,
258 dwID,
259 NULL, // sid
260 iStr,
261 0,
262 ps,
263 NULL);
264 }
265 }
266
267 //////////////////////////////////////////////////////////////////////////////////////////////
268 // Service startup and registration
269
270 BOOL CNTService::StartService()
271 {
272 SERVICE_TABLE_ENTRY st[] = {
273 {m_szServiceName, ServiceMain},
274 {NULL, NULL}
275 };
276
277 DebugMsg("Calling StartServiceCtrlDispatcher()");
278 BOOL b = ::StartServiceCtrlDispatcher(st);
279 DebugMsg("Returned from StartServiceCtrlDispatcher()");
280 return b;
281 }
282
283 // static member function (callback)
284 void CNTService::ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
285 {
286 // Get a pointer to the C++ object
287 CNTService* pService = m_pThis;
288
289 pService->DebugMsg("Entering CNTService::ServiceMain()");
290 // Register the control request handler
291 pService->m_Status.dwCurrentState = SERVICE_START_PENDING;
292 pService->m_hServiceStatus = RegisterServiceCtrlHandler(pService->m_szServiceName,
293 Handler);
294 if (pService->m_hServiceStatus == NULL) {
295 pService->LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_CTRLHANDLERNOTINSTALLED);
296 return;
297 }
298
299 // Start the initialisation
300 if (pService->Initialize()) {
301
302 // Do the real work.
303 // When the Run function returns, the service has stopped.
304 pService->m_bIsRunning = TRUE;
305 pService->m_Status.dwWin32ExitCode = 0;
306 pService->m_Status.dwCheckPoint = 0;
307 pService->m_Status.dwWaitHint = 0;
308 pService->Run();
309 }
310
311 // Tell the service manager we are stopped
312 pService->SetStatus(SERVICE_STOPPED);
313
314 pService->DebugMsg("Leaving CNTService::ServiceMain()");
315 }
316
317 ///////////////////////////////////////////////////////////////////////////////////////////
318 // status functions
319
320 void CNTService::SetStatus(DWORD dwState)
321 {
322 DebugMsg("CNTService::SetStatus(%lu, %lu)", m_hServiceStatus, dwState);
323 m_Status.dwCurrentState = dwState;
324 ::SetServiceStatus(m_hServiceStatus, &m_Status);
325 }
326
327 ///////////////////////////////////////////////////////////////////////////////////////////
328 // Service initialization
329
330 BOOL CNTService::Initialize()
331 {
332 DebugMsg("Entering CNTService::Initialize()");
333
334 // Start the initialization
335 SetStatus(SERVICE_START_PENDING);
336
337 // Perform the actual initialization
338 BOOL bResult = OnInit();
339
340 // Set final state
341 m_Status.dwWin32ExitCode = GetLastError();
342 m_Status.dwCheckPoint = 0;
343 m_Status.dwWaitHint = 0;
344 if (!bResult) {
345 LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_FAILEDINIT);
346 SetStatus(SERVICE_STOPPED);
347 return FALSE;
348 }
349
350 LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_STARTED);
351 SetStatus(SERVICE_RUNNING);
352
353 DebugMsg("Leaving CNTService::Initialize()");
354 return TRUE;
355 }
356
357 ///////////////////////////////////////////////////////////////////////////////////////////////
358 // main function to do the real work of the service
359
360 // This function performs the main work of the service.
361 // When this function returns the service has stopped.
362 void CNTService::Run()
363 {
364 DebugMsg("Entering CNTService::Run()");
365
366 while (m_bIsRunning) {
367 DebugMsg("Sleeping...");
368 Sleep(5000);
369 }
370
371 // nothing more to do
372 DebugMsg("Leaving CNTService::Run()");
373 }
374
375 //////////////////////////////////////////////////////////////////////////////////////
376 // Control request handlers
377
378 // static member function (callback) to handle commands from the
379 // service control manager
380 void CNTService::Handler(DWORD dwOpcode)
381 {
382 // Get a pointer to the object
383 CNTService* pService = m_pThis;
384
385 pService->DebugMsg("CNTService::Handler(%lu)", dwOpcode);
386 switch (dwOpcode) {
387 case SERVICE_CONTROL_STOP: // 1
388 pService->SetStatus(SERVICE_STOP_PENDING);
389 pService->OnStop();
390 pService->m_bIsRunning = FALSE;
391 pService->LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_STOPPED);
392 break;
393
394 case SERVICE_CONTROL_PAUSE: // 2
395 pService->OnPause();
396 break;
397
398 case SERVICE_CONTROL_CONTINUE: // 3
399 pService->OnContinue();
400 break;
401
402 case SERVICE_CONTROL_INTERROGATE: // 4
403 pService->OnInterrogate();
404 break;
405
406 case SERVICE_CONTROL_SHUTDOWN: // 5
407 pService->SetStatus(SERVICE_STOP_PENDING);
408 pService->OnShutdown();
409 pService->m_bIsRunning = FALSE;
410 pService->LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_STOPPED);
411 break;
412
413 default:
414 if (dwOpcode >= SERVICE_CONTROL_USER) {
415 if (!pService->OnUserControl(dwOpcode)) {
416 pService->LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_BADREQUEST);
417 }
418 } else {
419 pService->LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_BADREQUEST);
420 }
421 break;
422 }
423
424 // Report current status
425 pService->DebugMsg("Updating status (%lu, %lu)",
426 pService->m_hServiceStatus,
427 pService->m_Status.dwCurrentState);
428 ::SetServiceStatus(pService->m_hServiceStatus, &pService->m_Status);
429 }
430
431 // Called when the service is first initialized
432 BOOL CNTService::OnInit()
433 {
434 DebugMsg("CNTService::OnInit()");
435 return TRUE;
436 }
437
438 // Called when the service control manager wants to stop the service
439 void CNTService::OnStop()
440 {
441 DebugMsg("CNTService::OnStop()");
442 }
443
444 // called when the service is interrogated
445 void CNTService::OnInterrogate()
446 {
447 DebugMsg("CNTService::OnInterrogate()");
448 }
449
450 // called when the service is paused
451 void CNTService::OnPause()
452 {
453 DebugMsg("CNTService::OnPause()");
454 }
455
456 // called when the service is continued
457 void CNTService::OnContinue()
458 {
459 DebugMsg("CNTService::OnContinue()");
460 }
461
462 // called when the service is shut down
463 void CNTService::OnShutdown()
464 {
465 DebugMsg("CNTService::OnShutdown()");
466 }
467
468 // called when the service gets a user control message
469 BOOL CNTService::OnUserControl(DWORD dwOpcode)
470 {
471 DebugMsg("CNTService::OnUserControl(%8.8lXH)", dwOpcode);
472 return FALSE; // say not handled
473 }
474
475
476 ////////////////////////////////////////////////////////////////////////////////////////////
477 // Debugging support
478
479 void CNTService::DebugMsg(const char* pszFormat, ...)
480 {
481 char buf[1024];
482 sprintf(buf, "[%s](%lu): ", m_szServiceName, GetCurrentThreadId());
483 va_list arglist;
484 va_start(arglist, pszFormat);
485 vsprintf(&buf[strlen(buf)], pszFormat, arglist);
486 va_end(arglist);
487 strcat(buf, "\n");
488 OutputDebugString(buf);
489 }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1