|Bookmarks:||Page Index | Recent Changes | Recently Commented | Users | Registration|
Winserv is an utility that can create an NT service that runs any application. When the application exits, the service becomes stopped.
It 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 interact 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:
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 control requests to the application in different ways, 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 Tcl:tclsvc.
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.
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 <user-visible display name of the service>
-description <the description of the service, usually one or two sentences>
-binary <pathname of winserv.exe, defaults to the invoked instance's pathname>
-ipcmethod <must be blind, pipe, stdio or qstdio>
-start <auto, demand or disabled>
-errorcontrol <ignore, normal, severe or critical>
-user <logon as user>
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 %System Root?%\My App.exe? %Service Args?%
Note that you have to use -expand with %Service Args?% to pass the service's command-line parameters as extra arguments.
Winserv can communicate with the underlying application or script in three different ways:
It's the simpliest case, when the application is terminated with Terminate Process?
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.
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
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.
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.
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
'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
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.
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.
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:
on the remote machine.
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
Again, it applies only to the console applications and console interpreters.
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
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.
[Matthias Hoffmann]: Ok, I will try using wish. But this will blow up the application sizes, and services do not need any GUI... A new question: What does the following line mean:
file delete d:/winserv.log
[Anton Kovalenko]: Nothing useful. I've just overlooked a piece of old debugging stuff.
Again, you don't have to use [wish] 'now', with current version of Winserv. [Tclsh]
will work with any ipc method.