Windows NT provides support for special programs called services . NT services run in the background, usually without direct user interaction, often started automatically at some point in the boot process. They typically run under a special "system" account which means that they do not need to be associated with a username and password. (This also places some security restrictions on what services can do by default.)
Services are analogous to Unix "daemons," but formalised into the operating system. This formal role of NT services brings some advantages to the system administrator. For example, they can be configured to start automatically at various points in the boot process, or can be controlled - locally or remotely - using NET START, Control Panel Services or programs such as SrvPanel.
The downside of this is that ordinary programs will not run as NT services. A service program needs to establish and maintain contact with the NT Service Control Manager (SCM). This requires special coding endemic to the program: if a service does not maintain contact with the SCM, NT assumes it has failed and shuts it down.
As an alternative to writing special code, the Windows NT Resource Kit provides a utility called SRVANY.EXE . SRVANY.EXE will start an ordinary program in the context of an NT service. However it is pretty limited and does not address some of the constraints of NT Services:
Because of these limitations I wrote two utilities, SVC and SRVSTART. SVC allows you to install, modify or remove Windows NT services. SRVSTART allows you to run executable programs as if they were services.
Between them they give you far greater management and flexibility than is provided by the Windows NT and the NT Resource Kit.
Copyright and Distribution
This article is Copyright (C) 2000 Nick Rozanski (Nick@Rozanski.com).
SVC and SRVSTART are distributed under the terms of the
GNU General Public License
as published by the Free Software Foundation (675 Mass Ave, Cambridge, MA 02139, USA)
They are distributed in the hope that they will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
Effectivity
This article applies to the following versions of software:
| Software | Version |
|---|---|
| SVC | 1.x |
| SRVSTART | 2.x |
SRVSTART is a rewrite (in C++) of an earlier version of the program called SYBSTART .
The new version contains a number of enhancements and extra features.
SVC.EXE - Windows NT Service Management
SVC is a simple command-line utility which allows you to install, modify or remove Windows NT Services
Pre-Requisites
SVC runs on Windows NT (not 95 or 98).
To run it you require the following files somewhere in your PATH.
SVC will prompt you for all responses. At any point you can type ? (question mark) for a short explanatory help message.
If you are having trouble running SVC, you can try running svc.exe -d . This prints out internal SVC debug messages as it runs.
If you don't like SVC's command-line interface, I recommend SrvPanel from Ballard Software.
This is an easy-to-use GUI utility which allows you to install and modify services,
although it doesn't have all the install functionality of SVC.
It also has a very nice interface for starting and stopping services individually or in groups.
Restrictions
Because modifying services is a potentially destructive activity,
SVC is deliberately restricted in what it can do.
A service to be installed, modified or removed must have the following characteristics:
Making incorrect changes can render Windows NT unuseable.
If you don't know what you are doing, don't mess about with services!
SRVSTART.EXE - Windows NT Service Execution
SRVSTART is a Win32 executable and DLL which allows you to run commands as if they were Windows NT services.
It also has some features to enhance the running of ordinary console commands (prompting for parameters etc).
Pre-Requisites
SRVSTART runs on Windows NT (not 95 or 98).
To run it you require the following files somewhere in your PATH.
srvstart cmd window_title [ options ... ] program [ program_parameters ... ]
srvstart svc service_name [ options ... ] program [ program_parameters ... ]
For testing, you can supply the keyword any instead of cmd or svc.
This will attempt to run the program as a service (keyword svc)
and if this fails run it as a console command (keyword cmd).
Operation
SRVSTART does the following.
The following SRVSTART options apply to command mode only.
The following SRVSTART options apply to service mode only.
If no -p option is given, a default path of the form:
%SYBASE%\install;SYBASE%\bin;%SYBASE%\dll;%SystemRoot%;%SystemRoot%\system32is used. (%SystemRoot% is the Windows NT root directory, eg C:\WINNT.)
The -q option assigns a path as above, but using the value supplied to -q , instead of %SYBASE%. For example, -q C:\NEWSYB would assign a path of the form C:\NEWSYB\install;C:\NEWSYB\bin;... etc.
Environment values which contain embedded environment variables will have these substituted, but only if they are already defined. For example:
... -l myvar1=myvalue1 -l myvar2=my_%myvar1%_val ...will set myvar1 to myvalue1 and myvar2 to my_myvalue1_val. However
... -l myvar2=my_%myvar1%_val -l myvar1=myvalue1 ...will set myvar2 to my_%myvar1%_val (since myvar1 is not defined at this point).
-o target causes debug messages to be sent to target.
-h displays help information and exits.
(The other srvstart parameters need not be supplied in this case.)
Startup Options
-x specifies the priority at which the program should run.
In command mode, -w opens a new console window to run the program,
and -m opens this window minimised.
These options are ignored in service mode.
Service Management Options
If the -y seconds option is specified,
SRVSTART waits this number of seconds before reporting to the Windows NT Service Control Manager that the service has started.
Use this option if the command takes a long time to initialise (default zero).
In service mode, SRVSTART regularly checks the process it has started to see if it is still running.
If it has finished, then SRVSTART reports a "service stopped" status to the Service Control Manager and then exits.
The -t seconds option defines how often this check is done (default every second).
Control File
-c controlfile specifies that SRVSTART should get its options from controlfile.
This is a text file with one option per line. Options are grouped in sections, with the section name (which is the window or service name) in square brackets. Options before any section apply to all commands.
All section lines are of the form [service_or_window_name]. All option lines are of the form keyword=value. Blank lines, and comments lines (starting #) are ignored.
For example:
# commentSRVSTART reads the control file, applying all keywords before the first section. It then finds the section whose name matches the supplied window or service name, and applies all keywords in that section.
keyword=value
...
[service_or_window_name_1]
keyword=value
keyword=value
...
[service_or_window_name_2]
keyword=value
...
When a control file is used,
the program and program_parameters
can be omitted from the command line.
Control File Keywords
The following keywords replace the SRVSTART command-line options.
The following keywords are used to define SRVSTART commands. Apart from startup they have no command-line equivalents.
This should wait for the service program to enter a "running" state (eg wait for a database server to complete recovery). It should exit with a status of 0 once the service program is up and running. It should exit with a non-zero status if the service program has failed or is never going to enter a running status. Once this command has exited with a status of 0, SRVSTART considers that the service program is running.
Note that if the shutdown option is not defined, then SRVSTART will shut down the service program using the Win32 TerminateProcess() API. This is apparently equivalent to a Unix kill -9 and leaves DLLs in an undefined state. I have not to date observed any problems with this.
auto_restart does not, of course, restart the service program if it is stopped by request (eg NET STOP or Control Panel|Services).
program and program_parameters may refer to environment variables using the %var% syntax. These will be substituted (not recursively) where encountered, for example %HOME%\bin\mycommand.exe %SYSTEMROOT% .
For command mode, if the -w flag is not supplied, the command can also be a DOS command (eg dir).
Parameters
For command mode, parameters may include substitution text of the form:
{prompt}Here, SRVSTART displays the prompt on stdout and reads from stdin , substituting the entered text for everything between { and }.
{prompt:default}
If the user just presses return, then default will be used (if supplied). Either default or prompt can be empty strings.
If prompt or default include a space or other symbol meaningful to the NT "shell", surround them in double-quotes.
If prompt begins with a - (hyphen) then the text entered by the user will not be echoed back to the terminal (for passwords etc).
For example:
send_server.exe -s{server:MYSERV} -u{user name} -p{-password}This will result in the following interaction:
server [MYSERV]: enter server name here or press return for MYSERV
user name: no default
password: response will not be echoed to screen
SRVSTART does not extensively validate things supplied to it on the command line or in the control file. A bad invocation can sometimes cause it to core dump.
SRVSTART is pretty relaxed in its error-checking of things like new . Failure here should become obvious pretty quickly.
In command mode when the -w flag is not supplied,
it would be very useful if SRVSTART changed the window title (so you could see it in the taskbar).
I can't work out how to do this.
SRVSTART.DLL - Windows NT Service Support Library
The SRVSTART DLL on its own provides all of the service management features of SRVSTART to programs written in C++.
This allows you to write your own NT services, making just a few simple calls to manage the service's interactions with the SCM.
Pre-Requisites
The SRVSTART library runs on Windows NT (not 95 or 98).
To run it you require the following files somewhere in your PATH at runtime.
Further information on building programs to use the DLL is given below.
Synopsis
The SRVSTART library exports the following classes.
The following examples show how to use CmdRunner to run a command in the same or another process.
#include <CmdRunner.h>It is invalid to create more than one CmdRunner object.
// typedef enum START_MODES { COMMAND_MODE, SERVICE_MODE, ANY_MODE };
// CmdRunner(START_MODES mode = COMMAND_MODE,char *nm = NULL) throw (SrvStartException) ;
cmdRunner = new CmdRunner(CmdRunner::COMMAND_MODE,"MY_COMMAND");
#include <CmdRunner.h>
// void setStartupCommand(const char *sc);
// void addStartupCommandArgument(const char *arg);
cmdRunner->setStartupCommand("D:\bin\mycommand.exe");
cmdRunner->addStartupCommandArgument("arg1");
// etc.
#include <CmdRunner.h>
// void addEnv(const char *nm,const char *val) throw (SrvStartException);
cmdRunner->addEnv("MYVAR","MYVALUE");
// etc.
#include <CmdRunner.h>
// void setStartInNewWindow(bool nw);
// etc.
cmdRunner->setStartInNewWindow(true);
// etc.
#include <CmdRunner.h>
// void start() throw (SrvStartException);
cmdRunner->start();
start() blocks until the command has completed.
The following examples show how to use ScmConnector in a service program.
#include <ScmConnector.h>It is invalid to create more than one ScmConnector object.
// ScmConnector(char *svcName,bool allowConnectErrors = false) throw (SrvStartException) ;
scmConnector = new ScmConnector("MY_SERVICE");
#include <ScmConnector.h>
// void notifyScmStatus(SCM_STATUSES scmStatus,bool ignoreErrors = false) throw (SrvStartException);
scmConnector->notifyScmStatus(ScmConnector::STATUS_RUNNING);
#include <ScmConnector.h>
scmConnector->notifyScmStatus(ScmConnector::STATUS_STOPPING);
scmConnector->notifyScmStatus(ScmConnector::STATUS_STOPPED);
ExitProcess(...)
There are three ways to do this.
#include <ScmConnector.h>
// void installStopCallback(bool *stopRequestedVar) throw (SrvStartException);
bool stopRequested;
scmConnector->installStopCallback(&stopRequested);
// later ...
if (stopRequested) ...
If you select this method, then you will typically poll the variable regularly to see if it has been set to true, and if it has, shut down.
#include <ScmConnector.h>
// void installStopCallback(HANDLE *stopRequestedEvent) throw (SrvStartException);
HANDLE stopEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
scmConnector->installStopCallback(&stopEvent);
// later ...
WaitForSingleObject(stopEvent,...
If you select this method, you will typically poll the event regularly (or maybe wait on it) to see if it has been signalled, and if it has, shut down.
#include <ScmConnector.h>
// typedef void STOP_HANDLER_FUNCTION(void*);
// void installStopCallback(STOP_HANDLER_FUNCTION *stopRequestedFunction, void *genericPointer) throw (SrvStartException);
// define the function
void stopCallbackFunction(void *genericPointer) { ... }
scmConnector->installStopCallback(&stopCallbackFunction, static_cast<void*>(this));
If you select this method, your passed function must shut down the service itself.
Whichever method you choose, you must ensure that if the callback is activated, your service program will shut itself down.
Timing
Timing is crucial with service programs.
In particular, the program must connect to the SCM within one second of startup,
or Windows NT assumes it is invalid.
To ensure this, you should make sure that you create the ScmConnector object early in your program (preferably right at the start). Once you do this, ScmConnector will make the appropriate status notifications to the Service Control Manager for you.
Furthermore, a service program must respond promptly to requests from the Service Control Manager (specifically, "interrogate" and "stop" requests). ScmConnector handles this for you automatically once it has been instantiated. It runs in its own thread (two threads, actually) and you do not need to take any special actions other than to notify it when your status changes (when you are shutting down).
These constraints aside, there are no restrictions on the time that a service can take to start or stop.
However ScmConnector will log an informational message if startup takes more than a minute.
Exception Handling
In general, methods respond to errors by raising a C++ exception.
All methods which can throw an exception are defined using the following syntax:
class::method(parameters...) throw (SrvStarterException);This syntax is not supported by Microsoft C++ (they claim it is non-standard) but I have included it to denote the methods which can throw exceptions. Note that most constructors fall into this category.
All exceptions are of class SrvStart::SrvStarterException, defined in SrvStart.h. (SrvStart is the namespace here.) Some of the key public data members of this class include:
SRVSTART_EXCEPTION exceptionId;Your calling program should catch these exceptions and interrogate the thrown object for further information.
char className[SRVSTART_EXCEPTION_STRING_SIZE];
char methodName[SRVSTART_EXCEPTION_STRING_SIZE];
char errorMessage[SRVSTART_EXCEPTION_STRING_SIZE];
char sourceFile[SRVSTART_EXCEPTION_STRING_SIZE];
int lineNumber;
When creating your ScmConnector object, set the paramter allowConnectErrors to true. Then check the status of the service.
#include <ScmConnector.h>If status is STATUS_MUST_START_AS_CONSOLE then the ScmConnector failed to connect to the Service Control Manager. No exception will be raised in this case.
// typedef enum SCM_STATUSES { STATUS_INITIALISING,STATUS_STARTING,
// STATUS_RUNNING,STATUS_STOPPING,STATUS_STOPPED,
// STATUS_MUST_START_AS_CONSOLE,STATUS_FAILED };
// SCM_STATUSES getScmStatus();
ScmConnector::SCM_STATUSES status = scmConnector->getScmStatus();
using namespace SrvStart;
SVC and SRVSTART are built using Microsoft Visual C++. I have not used any non-standard features (as far as I am aware) so the source should compile under any C++ compiler for Windows NT. (I haven't tried this.)
Full source code for the executables and DLL is included.
Support
I welcome feedback and comments on these programs.
You can email me (mailto:Nick@Rozanski.com) for support, although I can't guarantee to give any.
Please note that the Sybase features in SVC and SRVSTART are only included for backwards compatibility and may not be maintained in the future. (I have now left Sybase.)
| URL: http://www.Nick.Rozanski.com/services.htm (last updated 2000-04-12_13:09:50) | produced on Cygwin32 using mkhtml |