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

Annotation of /innwebd/NTService.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (hide annotations) (vendor branch)
Fri Jun 25 07:01:51 2004 UTC (21 years, 8 months ago) by sysadm
Branch: GNU
CVS Tags: V101
Changes since 1.1: +0 -0 lines
Content type: text/x-c++src
no message

1 sysadm 1.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->OnShutdown();
408     break;
409    
410     default:
411     if (dwOpcode >= SERVICE_CONTROL_USER) {
412     if (!pService->OnUserControl(dwOpcode)) {
413     pService->LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_BADREQUEST);
414     }
415     } else {
416     pService->LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_BADREQUEST);
417     }
418     break;
419     }
420    
421     // Report current status
422     pService->DebugMsg("Updating status (%lu, %lu)",
423     pService->m_hServiceStatus,
424     pService->m_Status.dwCurrentState);
425     ::SetServiceStatus(pService->m_hServiceStatus, &pService->m_Status);
426     }
427    
428     // Called when the service is first initialized
429     BOOL CNTService::OnInit()
430     {
431     DebugMsg("CNTService::OnInit()");
432     return TRUE;
433     }
434    
435     // Called when the service control manager wants to stop the service
436     void CNTService::OnStop()
437     {
438     DebugMsg("CNTService::OnStop()");
439     }
440    
441     // called when the service is interrogated
442     void CNTService::OnInterrogate()
443     {
444     DebugMsg("CNTService::OnInterrogate()");
445     }
446    
447     // called when the service is paused
448     void CNTService::OnPause()
449     {
450     DebugMsg("CNTService::OnPause()");
451     }
452    
453     // called when the service is continued
454     void CNTService::OnContinue()
455     {
456     DebugMsg("CNTService::OnContinue()");
457     }
458    
459     // called when the service is shut down
460     void CNTService::OnShutdown()
461     {
462     DebugMsg("CNTService::OnShutdown()");
463     }
464    
465     // called when the service gets a user control message
466     BOOL CNTService::OnUserControl(DWORD dwOpcode)
467     {
468     DebugMsg("CNTService::OnUserControl(%8.8lXH)", dwOpcode);
469     return FALSE; // say not handled
470     }
471    
472    
473     ////////////////////////////////////////////////////////////////////////////////////////////
474     // Debugging support
475    
476     void CNTService::DebugMsg(const char* pszFormat, ...)
477     {
478     char buf[1024];
479     sprintf(buf, "[%s](%lu): ", m_szServiceName, GetCurrentThreadId());
480     va_list arglist;
481     va_start(arglist, pszFormat);
482     vsprintf(&buf[strlen(buf)], pszFormat, arglist);
483     va_end(arglist);
484     strcat(buf, "\n");
485     OutputDebugString(buf);
486     }

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