1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2008 Index Data
3 * See the file LICENSE for details.
8 * \brief Implements NT service handling for GFS.
20 static AppService *pService = NULL;
21 static BOOL bRunAsService = TRUE;
22 static void *pAppHandle = NULL;
24 /* Private functions to this module */
25 void Service_Create(LPTSTR pAppName, LPTSTR pServiceName, LPTSTR pServiceDisplayName, LPTSTR pDependancies, int argc, char **argv);
26 void Service_Delete();
27 void Service_Initialize();
28 BOOL NotifyServiceController();
29 BOOL UpdateServiceStatus(DWORD Status);
30 void FailServiceStart(DWORD Win32Code, DWORD PrivateCode);
31 void CmdInstallService(int argc, char *argv[], BOOL bAutoStart);
32 void CmdRemoveService();
33 LPTSTR GetLastErrorText(LPTSTR lpszBuf, DWORD dwSize);
34 BOOL CheckServiceArguments(int argc, char *argv[]);
36 /* Callback functions for thee service manager */
37 void WINAPI ServiceMain(DWORD argc, LPTSTR argv[]);
38 void WINAPI ServiceControlHandler(DWORD fdwControl);
40 /* Function to handle Ctrl + C etc... */
41 BOOL EventHandlerRoutine(DWORD dwCtrlType);
43 void Service_Create(LPTSTR pAppName, LPTSTR pServiceName, LPTSTR pServiceDisplayName, LPTSTR pDependancies, int argc, char **argv)
45 pService = malloc(sizeof(AppService));
46 pService->pAppName = pAppName;
47 pService->pServiceName = pServiceName;
48 pService->pServiceDisplayName = pServiceDisplayName;
49 pService->pDependancies = pDependancies;
50 pService->hService = 0;
51 pService->ServiceTable[0].lpServiceName = pServiceName;
52 pService->ServiceTable[0].lpServiceProc = ServiceMain;
53 pService->ServiceTable[1].lpServiceName = NULL;
54 pService->ServiceTable[1].lpServiceProc = NULL;
55 pService->argc = argc;
56 pService->argv = argv;
63 /* Mark the service as stopping */
64 UpdateServiceStatus(SERVICE_STOP_PENDING);
66 /* Stop the service */
67 StopAppService(pAppHandle);
69 /* Service has now stopped */
70 UpdateServiceStatus(SERVICE_STOPPED);
78 void Service_Initialize()
82 /* Register ourselves with the control dispatcher */
83 StartServiceCtrlDispatcher(pService->ServiceTable);
87 void WINAPI ServiceMain(DWORD argc, LPTSTR argv[])
91 if (NotifyServiceController())
93 /* Set the status to pending */
94 UpdateServiceStatus(SERVICE_START_PENDING);
96 /* Lets attempt to start the service */
97 if (StartAppService(pAppHandle, pService->argc, pService->argv))
99 /* Service is now up and running */
100 UpdateServiceStatus(SERVICE_RUNNING);
102 /* Lets wait for our clients */
103 RunAppService(pAppHandle);
107 FailServiceStart(GetLastError(), 0);
114 BOOL NotifyServiceController()
116 if (pService == NULL)
124 pService->ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
125 pService->ServiceStatus.dwCurrentState = SERVICE_STOPPED;
126 pService->ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
127 pService->ServiceStatus.dwWin32ExitCode = 0;
128 pService->ServiceStatus.dwServiceSpecificExitCode = 0;
129 pService->ServiceStatus.dwCheckPoint = 0;
130 pService->ServiceStatus.dwWaitHint = 0;
131 pService->hService = RegisterServiceCtrlHandler(pService->pServiceName, ServiceControlHandler);
133 if (pService->hService)
134 UpdateServiceStatus(SERVICE_START_PENDING);
142 void WINAPI ServiceControlHandler(DWORD fdwControl)
144 if (pService != NULL)
148 case SERVICE_CONTROL_STOP:
149 /* Update the service status to be pending */
153 case SERVICE_CONTROL_INTERROGATE:
154 UpdateServiceStatus(pService->ServiceStatus.dwCurrentState);
163 BOOL UpdateServiceStatus(DWORD Status)
165 if (pService != NULL)
167 if (pService->hService)
169 pService->ServiceStatus.dwCurrentState = Status;
170 if ((Status == SERVICE_START_PENDING) || (Status == SERVICE_STOP_PENDING))
172 pService->ServiceStatus.dwCheckPoint ++;
173 pService->ServiceStatus.dwWaitHint = 5000; /* 5 sec.*/
177 pService->ServiceStatus.dwCheckPoint = 0;
178 pService->ServiceStatus.dwWaitHint = 0;
181 return(SetServiceStatus(pService->hService, &pService->ServiceStatus));
188 void FailServiceStart(DWORD Win32Code, DWORD PrivateCode)
190 if (pService != NULL)
192 pService->ServiceStatus.dwWin32ExitCode = Win32Code;
193 pService->ServiceStatus.dwServiceSpecificExitCode = PrivateCode;
194 UpdateServiceStatus(SERVICE_STOPPED);
198 void CmdInstallService(int argc, char *argv[], BOOL bAutoStart)
200 if (pService != NULL)
202 SC_HANDLE schService;
203 SC_HANDLE schSCManager;
207 if (GetModuleFileName(NULL, szPath, 512) == 0)
209 _tprintf(TEXT("Unable to install %s - %s\n"), TEXT(pService->pServiceDisplayName), GetLastErrorText(pService->szErr, 256));
214 char cwdstr[_MAX_PATH];
216 if (!_getcwd(cwdstr, sizeof(cwdstr)))
217 strcpy (cwdstr, ".");
219 strcat (szPath, TEXT(" -runservice \""));
220 strcat (szPath, cwdstr);
221 strcat (szPath, "\"");
223 for (i = 1; i < argc; i++)
225 /* We will add the given command line arguments to the command */
226 /* We are not interested in the install and remove options */
227 if ((strcmp("-install", argv[i]) != 0) &&
228 (strcmp("-installa", argv[i]) != 0) &&
229 (strcmp("-remove", argv[i]) != 0))
231 strcat(szPath, TEXT(" "));
232 strcat(szPath, argv[i]);
236 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
237 NULL, /* database (NULL == default) */
238 SC_MANAGER_ALL_ACCESS); /* access required */
241 schService = CreateService(schSCManager, /* SCManager database */
242 TEXT(pService->pServiceName), /* name of service */
243 TEXT(pService->pServiceDisplayName), /* name to display */
244 SERVICE_ALL_ACCESS, /* desired access */
245 SERVICE_WIN32_OWN_PROCESS, /* service type */
246 bAutoStart ? SERVICE_AUTO_START :
247 SERVICE_DEMAND_START, /* start type */
248 SERVICE_ERROR_NORMAL, /* error control type */
249 szPath, /* service's binary */
250 NULL, /* no load ordering group */
251 NULL, /* no tag identifier */
252 TEXT(pService->pDependancies), /* dependencies */
253 NULL, /* LocalSystem account */
254 NULL); /* no password */
258 _tprintf(TEXT("%s installed.\n"), TEXT(pService->pServiceDisplayName));
259 CloseServiceHandle(schService);
263 _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(pService->szErr, 256));
266 CloseServiceHandle(schSCManager);
269 _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(pService->szErr,256));
274 void CmdRemoveService()
276 if (pService != NULL)
278 SC_HANDLE schService;
279 SC_HANDLE schSCManager;
281 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
282 NULL, /* database (NULL == default) */
283 SC_MANAGER_ALL_ACCESS); /* access required */
286 schService = OpenService(schSCManager, TEXT(pService->pServiceName), SERVICE_ALL_ACCESS);
290 /* try to stop the service */
291 if (ControlService(schService, SERVICE_CONTROL_STOP, &pService->ServiceStatus))
293 _tprintf(TEXT("Stopping %s."), TEXT(pService->pServiceDisplayName));
296 while (QueryServiceStatus(schService, &pService->ServiceStatus))
298 if (pService->ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING)
307 if (pService->ServiceStatus.dwCurrentState == SERVICE_STOPPED)
308 _tprintf(TEXT("\n%s stopped.\n"), TEXT(pService->pServiceDisplayName));
310 _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(pService->pServiceDisplayName));
314 /* now remove the service */
315 if(DeleteService(schService))
316 _tprintf(TEXT("%s removed.\n"), TEXT(pService->pServiceDisplayName));
318 _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(pService->szErr,256));
320 CloseServiceHandle(schService);
323 _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(pService->szErr,256));
325 CloseServiceHandle(schSCManager);
328 _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(pService->szErr,256));
332 LPTSTR GetLastErrorText(LPTSTR lpszBuf, DWORD dwSize)
335 LPTSTR lpszTemp = NULL;
337 dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
345 /* supplied buffer is not long enough */
346 if (!dwRet || ((long)dwSize < (long)dwRet + 14))
347 lpszBuf[0] = TEXT('\0');
350 lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0'); /* remove cr and newline character */
351 _stprintf(lpszBuf, TEXT("%s (0x%x)"), lpszTemp, GetLastError());
355 LocalFree((HLOCAL)lpszTemp);
360 BOOL CheckServiceArguments(int argc, char *argv[])
364 /* Lets process the arguments */
365 for (i = 1; i < argc; i++)
367 if (stricmp("-install", argv[i]) == 0)
369 /* They want to install the service */
370 CmdInstallService(argc, argv, FALSE);
372 /* We don't carry on, after we have installed the service */
375 else if (stricmp("-installa", argv[i]) == 0)
377 /* They want to install the service */
378 CmdInstallService(argc, argv, TRUE);
380 /* We don't carry on, after we have installed the service */
383 else if (stricmp("-remove", argv[i]) == 0)
385 /* Here they want to remove it */
388 /* We don't carry on, after we have removed the service */
391 else if (stricmp ("-runservice", argv[i]) == 0)
393 /* We can carry on, if we reached here */
400 bRunAsService = FALSE;
404 BOOL SetupService(int argc, char *argv[], void *pHandle, LPTSTR pAppName, LPTSTR pServiceName, LPTSTR pServiceDisplayName, LPTSTR pDependancies)
406 BOOL bDeleteService = TRUE;
407 BOOL bResult = FALSE;
409 /* Save the handle for later use */
410 pAppHandle = pHandle;
412 /* Create our service class */
413 Service_Create(pAppName, pServiceName, pServiceDisplayName, pDependancies, argc, argv);
415 if (CheckServiceArguments(argc, argv))
419 /* No need to set the console control handler, as the service manager handles all this for us */
420 Service_Initialize();
421 bDeleteService = FALSE;
425 /* Set the console control handler for exiting the program */
426 SetConsoleCtrlHandler((PHANDLER_ROUTINE)EventHandlerRoutine, TRUE);
428 /* Now do the main work */
429 ServiceMain(argc, argv);
432 /* We have been successful initializing, so let the caller know */
438 /* Finished with the service now */
444 BOOL EventHandlerRoutine(DWORD dwCtrlType)
446 /* This routine dosn't seem to get called all the time, Why ??? */
449 case CTRL_C_EVENT: /* A CTRL+C signal was received, either from keyboard input or from a signal generated by the GenerateConsoleCtrlEvent function.*/
450 case CTRL_BREAK_EVENT: /* A CTRL+BREAK signal was received, either from keyboard input or from a signal generated by GenerateConsoleCtrlEvent.*/
451 case CTRL_CLOSE_EVENT: /* A signal that the system sends to all processes attached to a console when the user closes the console (either by choosing the Close command from the console window's System menu, or by choosing the End Task command from the Task List).*/
452 case CTRL_LOGOFF_EVENT: /* A signal that the system sends to all console processes when a user is logging off. This signal does not indicate which user is logging off, so no assumptions can be made.*/
453 case CTRL_SHUTDOWN_EVENT: /* A signal that the system sends to all console processes when the system */
454 /* We are basically shutting down, so call Service_Delete */
460 /* we are not handling this one, so return FALSE */
468 * indent-tabs-mode: nil
470 * vim: shiftwidth=4 tabstop=8 expandtab