Winserv [http://www.sw4me.com/winserv] is an utility that can create an NT service running any application. When the application exits, the service becomes stopped. Download winserv at http://www.sw4me.com/winserv.zip [[36k]] Winserv can be used as a command-line utility to configure, control, view status of any NT service, whether it is winserv-based or not. Winserv can operate with a remote machine's service control manager. When you use winserv from a command prompt, just prepend '''\\Machine\''' to the service name if you want to operate with remote service: winserv status \\MyServer\alerter The service name that winserv requires is not the display name of the service, but rather the internal unique name. Winserv is designed with scripting languages in mind, TCL in particular. It can forward SCM signals to the application in different ways, thus enabling you to do any cleanup on stop and to implement "paused" service state. Winserv contains a little TCL package that lets you use it as a drop-in replacement for [tclsvc]. ---- '''Getting started''' The basic syntax for winserv invocation is the following: winserv subcommand service-name options [ args ... ] The only exception to this rule is the ''help'' subcommand that doesn't need any arguments (and ignores them, if any). winserv install service-name service-options command args ... creates a service that runs ''command'' (any executable) when started and stops when the command completes. Command-line parameters for the command may also be specified. winserv configure service-name service-options [ command args ... ] modifies various parameters for the service in SCM and registry databases. If the command is specified, it is stored in registry as a new command for the winserv-based service. winserv uninstall service-name marks a service for deletion. When it is stopped and all handles to it are closed, the service is removed from the SCM database. winserv showconfig service-name show the current service's parameters that may be modified with ''configure'' subcommand. Some parameters make sense only for winserv-based services, and they will not be shown for other services (read further for parameters description). winserv stop service-name [ -nowait ] winserv pause service-name [ -nowait ] winserv continue service-name [ -nowait ] winserv usercontrol service-name [ -code <128-255> ] winserv paramchange service-name These subcommands send control signals to the running service. Option ''-nowait'' means that the utility shouldn't wait until the service will report an appropriate status for the request (stopped for ''stop'', paused for ''pause'', running for ''continue''). winserv start service-name [ args ... ] Starts the service with the given command-line arguments. winserv restart service-name [ args ... ] Restarts the service, i.e. stops it, waits for it to be stopped, and then starts it with the arguments given. winserv status service-name Prints out the current status of the service, one of: RUNNING, STOPPED, PAUSED, START_PENDING, PAUSE_PENDING, CONTINUE_PENDING, STOP_PENDING. '''Service options''' Using ''install'' and ''configure'' subcommands, you can specify parameters for the newly-created or configured service. Some of the service options require an argument. Here is the list of supported service options: -displayname -description -binary -ipcmethod -start -errorcontrol -[no]expand -[non]interactive -loadordergroup -depends service1,service2... -user -password Winserv will refuse to set binary pathname and some winserv-specific options for non-winserv based services. Use '''-forceforeign''' option to suppress this behavior. Use '''-expand''' to store the application's command-line in registry as a REG_EXPAND_SZ type of value. In this case, all references to environment variables will be auto-expanded before starting the application: winserv install myappsrv -expand %SystemRoot%\MyApp.exe %ServiceArgs% Note that you have to use -expand with %ServiceArgs% to pass the service's command-line parameters as extra arguments. '''IPC methods''' Winserv can communicate with the underlying application or script in three different ways: * -ipcmethod blind It's the simpliest case, when the application is terminated with TerminateProcess if the service is stopped. There is no way for the application to do any cleanup, and it can't write to the event log or accept pause/continue and other signals. This method must be used only for 3rd-party closed-source applications that don't have any data in memory that must be written on exit. * -ipcmethod stdio Winserv forwards the SCM signals in the textual form to the applications's stdin, and the application reports its state on stdout. The application can use special escape sequences to write to the eventlog with specific level (error, information, success, etc.), to signal its current status (paused, running), to declare what SCM control codes it accepts. Any plain-text (escapeless) line from stdout is just written to the event log at the "information" level, and any line from stderr is written at the "error" level. This IPC method may be used for closed-source application that doesn't know anything about winserv. In this case you won't be able to terminate the application with SCM control code (winserv stop); it must terminate by itself. * -ipcmethod qstdio This method is similar to stdio, except that unescaped plain-text strings aren't forwarded to the event log. It may be useful if the application is too chatty. * -ipcmethod pipe This method was designed especially for non-console [tclkit]s, where we don't have access to normal stdin or stdout, but only to their emulation. The application must open two named pipes on startup: open \\\\.\\pipe\\winserv.scm.out.$service_name w+ open \\\\.\\pipe\\winserv.scm.in.$service_name w+ and use the first one instead of stdout, and the second one instead of stdin. In all other aspects this method is equivalent to -ipcmethod stdio. Don't change the order in which the pipes are opened! If you do it, the communication between winserv and the application can't be established any more! If the named pipes are not opened after 30 seconds, winserv will terminate the application. ---- '''Porting tclsvc-based applications to winserv''' is easy. You should install a winserv support package to a place where your interpreter can find it, and then add two lines of code at the beginning of your script: package require winserv winserv::startup Notice that it won't prevent your script from being run by [tclsvc]: winserv support package checks tcl_service global varible and doesn't try to connect winserv if the variable already exists. When running under winserv, winserv::startup sets the tcl_service and tcl_service_winserv global variables to 1. It imports ''eventlog'' command into the global namespace. This command is a mostly-compatible (though less powerful) replacement for the tclsvc's eventlog. It doesn't open the eventlog directly; instead, it uses the active IPC method to pass messages to winserv. A lot of winserv-specific facilities become available after winserv::startup. winserv::accept ?[-]pause? ?[-]paramchange? ?[-]shutdown? ... This command lets the application accept certain SCM control code groups. If the dash precedes the group name, it means that this group is not accepted any more. winserv::accept reset Use it to accept only the STOP code, as winserv does by default. winserv::handle code script This command defines a script to handle particular SCM control code (STOP, PAUSE, CONTINUE, PARAMCHANGE, NETBINDADD, NETBINDREMOVE, NETBINDDISABLE, NETBINDENABLE, as well as user-defined codes CODE128..CODE255). For PAUSE and CONTINUE control codes the script can [break] or throw an error to indicate that the service status wasn't really changed (so it must leave running or paused, respectively). Use empty script to remove the handler. ---- '''Internals''' You know enough to use winserv with TCL. As of another scripting languages, you may want to implement helper modules, similar to TCL winserv support package. To do it, you have to know what escape sequences winserv interprets when the application writes it to stdout or named pipe. Each string that winserv will parse must be terminated by a newline. If you use escape sequences, you must put each sequence on a line by itself. \033 a accept/deny control codes: \033 a p accept pause/continue control codes. \033 a c accept PARAMCHANGE \033 a s accept SHUTDOWN \033 a n accept NETBIND... codes \033 a r reset; accept STOP and nothing more. \033 a P don't accept pause/continue \033 a C don't accept PARAMCHANGE \033 a S don't accept SHUTDOWN \033 a N don't accept NETBIND... \033 s set service status: \033 s p the service is now paused \033 s P the service is going to pause (PAUSE_PENDING) \033 s C the service is going to continue (CONTINUE_PENDING) \033 s r the service is running \033 s S the service is going to stop (STOP_PENDING) \033 e add message to the event log: \033 e i at the information level \033 e e at the error level \033 e s at the success level \033 e w at the warning level \033 e a at the audit/success level \033 e A at the audit/failure level. For eventlog escapes, the message that will be added must follow the escape sequence on the same line. If the message contains embedded newlines, they must be replaced with \014 (form feed) control character. ---- '''Remote installation issues''' Winserv can manage the services remotely. You can even install a service over the network, but there is something to remember: * Use remote registry access to get remote SystemRoot and Program Files paths. * Use administrative shared folders (C$, D$...) to copy all necessary files to the remote machine * Use the -binary option for winserv to specify the location of winserv.exe on the remote machine. ---- '''Console applications''' Unfortunately, applications for the console subsystem will almost always require some modification to survive logoff. It's only 7 lines of C code or so, and you can see src/tcl-nologoff.c for an example. A lot of scripting language interpreters have a special variant of executable in their Windows versions: the executable is linked for the windows subsystem, not the console one, though it doesn't provide GUI per se. I recommend to use this kind of interpreters for your service, together with -ipcmethod pipe. As of TCL (tclsh*.exe console interpreter), the nologoff.dll included in the winserv support package takes care of making the interpreter ready to survive logoff. Winserv::startup will load this dll. If you use [freewrap] to create a stand-alone executable, you should copy this dll to the real filesystem and let winserv know where it is: package require winserv set winserv::nologoff_dll c:/Unwrapped/nologoff.dll winserv::startup Again, it applies only to the console applications and console interpreters. ---- '''Licensing''' Winserv is free software. It comes with a one-line license: Do what you want with this software, but don't blame me The reason for such a license is that winserv is created to be shipped with other applications, and I don't want a developer to ''bother'' with any licensing issues. It doesn't mean that I'm not going to get money for this software. Voluntary donations are gladly accepted. Go http://secure.emetrix.com/order/product.asp?PID=46366953 to support development of winserv with a donation of $20. You will get a registration code that is unnecessary for winserv itself, as it doesn't have any limitations and doesn't require registration. But you'd better remember the code: it can become useful to get a discount for my other products. ---- [Matthias Hoffmann]: Just tried to run [tclhttpd] with '''winserv'''; only a few modifications are needed. Principally, it works great, but then noticed, as with '''tclsvc''', that is doesn't work as expected, because logging off the user closes the tclsh84.exe-process. When logging off, win32 informs all running processes (windows) about the shutdown to give them the chance to gracefully shutdown which, in this case, is wrong! Perhaps hiding the tclsh84.exe process helps (e.g., with '''hidewndw.exe'''), just haven't tried this..... Also, another aspect: It would be nice if one could turn off the behaviour that '''winserv''' redirects '''stdout''' and '''stderr''' to the eventlog, because some applications are relatively chatty... ---- [Anton Kovalenko]: 30-Oct-2004. The logoff problem doesn't exist any more for TCL. Winserv support package loads a small dll that does the right thing. This problem affects console applications only. If you were trying [wish] with -ipcmethod pipe, the service wouldn't stop when a user is logging off. As of your last suggestion: new ipc method '''qstdio''' was introduced, that is slightly different from '''stdio''': all unescaped text strings are ignored, so it's unlikely that any application can pollute the event log unintentionally.