Services under Microsoft Windows NT

Services under Microsoft Windows NT

See Also

TWAPI
contains a full set of commands for configuration and management of Windows services. As of V2.0.9, TWAPI also supports writing Windows services in Tcl.
Tcl as an NT Service
tclsvc
tclsvc - Tcl as an NT Service
Tclhttpd as a Windows Service
How To Create a User-Defined Service
COSH
information about integrating Tcl with the NT Shell.
Tcl Dev Kit, by ActiveState
includes a Service Manager application that turns Tcl scripts into Windows NT, 2000, 2003, XP services. WJR: We've used it in production quite a bit, and it's proven to be reliable.
Winserv
A/AK: like srvany or ServiceInstaller, but with some TCL-specific useful features.
Windows Services chapter
from BOOK Tcl Programming for Windows

Non-Tcl Programs

ServiceInstaller for Windows NT
a no-charge product that that makes any executable into a service.

as of today, 2002/11/13, the download link on the home page above is broken. EF

but you can download this at sourceforge [L1 ]. I use this to great effect with Starpacks AF


Firedaemon [L2 ] is utility that allows you to install and run virtually any native Win32 application or script as a Windows NT/2K/XP service. FireDaemon is easy to configure through a GUI and also has a console interface. The GUI is really a bridge into the console interface.

Firedaemon comes in two flavors: a free Lite version (with limited functionality for non-commercial use) and a fully functional Pro version.

I had great success with the lite version, it contains a myriad of options and installing my script as a service was a matter of minutes. I can start and stop the service both from the FireDaemon GUI interface and from the standard Windows interface without any problems. EF

Description

A service is roughtly the Windows equivalent of Unix/Linux daemon.

Tcl As A Win95/98/ME Service

Windows 95/98/ME can provide a simple sort of service - that is a program operating in the background independant of user logins - by creating a registry key that is read during system startup.

To create a Win98 service you should create a string value under the key HKEY_LOCAL_MACHINE\Software\Microsoft\CurrentVersion\RunServices such as "MyService" = "...\wish.exe ...\script.tcl"

The RunServices key is read during system startup and all the service programs are started before the user logs in. Unfortunately when the user logs out, the service will be stopped unless a call is made to the SCM (Service Configuration Manager) to register the process as a service at run time. The call to be made is found in kernel32.dll and is RegisterServiceProcess(DWORD processID, DWORD boolRegister) Once a process is registered it will not be terminated on user logout and will remain until system shutdown.

PT: I've written a simple single file package to provide a Tcl interface to this call [L3 ]

registerservice ?-processid PID? true|false

will let you register your script with the SCM so that it carries on running after the user logs out.

This is not the same as the NT service stuff. NT services are much better supported by the operating system and are to be reccommended over the Win98 style of pseudo-service. That said - this is a solution for this platform.

SRVANY

How To Create a User-Defined Service under NT , and the companion How to Create User-Defined Service under 2000 . The SRVANY described there does not have the intelligence to realize that a service has crashed, and is no longer in the process table. Despite this, srvany is apparently widely used as a utility which allows any .exe to serve as a service.


TP: I too have used SRVANY with some luck (for various reasons I did not use any of the more native Tcl alternatives listed on this page.) I used this code in one of my TclKit applications to install as a service. Note that I bundled the srvany.exe and helper .EXE's in my TclKit toplevel to ensure they would be available at runtime.

proc install {srvName {appArgs {}}} {

    set installDir [file dirname [info nameofexecutable]]

    package require registry
    set myKey [join [list HKEY_LOCAL_MACHINE SYSTEM CurrentControlSet \
        Services $srvName] \\]
    set myParm $myKey\\Parameters

    # check if already installed
    set key ""
    catch {set key [registry get $myParm Application]}
    if {[string length $key]} {
        showMsg "$srvName is already installed as a service" info
        exit
    }

    # copy out helper exe's from the TclKit's top level 
    if {[info exists ::starkit::topdir]} {
        foreach exe [list sc.exe instsrv.exe srvany.exe] {
            set target [file join $installDir $exe]
            catch {file copy -force [file join $::starkit::topdir $exe] $target}
        }
    }

    # install as service
    catch {exec [file join $installDir instsrv.exe] $srvName  \ 
        [file nativename [file join $installDir srvany.exe]]} x

    # now fix up registry to run this program
    registry set $myParm
    registry set $myParm Application [file nativename [info nameofexecutable]]

    # if application args are defined, add to registry key
    if {[string length $appArgs]} {
        registry set $myParm AppParameters $appArgs
    }

    showMsg " $srvName has now been installed as a service.\n\
        Start the $srvName service with the Service manager." info

    exit
}

proc remove {srvName} {
    set installDir [file dirname [info nameofexecutable]]

    package require registry
    set myKey [join [list HKEY_LOCAL_MACHINE SYSTEM CurrentControlSet \
        Services $SrvName \\]
    set myParm $myKey\\Parameters

    # check if already installed
    set key ""
    catch {set key [registry get $myParm Application]}
    if {[string length $key] == 0} {
        showMsg "$srvName is not installed as a service."
        exit
    }

    # copy out sc.exe
    if {[info exists ::starkit::topdir]} {
        foreach exe [list sc.exe] {
            set target [file join $installDir $exe]
            catch {file copy -force [file join $::starkit::topdir $exe] $target}
        }
    }

    # stop service and remove as service
    catch {exec [file join $installDir sc.exe] stop $srvName }
    catch {exec [file join $installDir sc.exe] delete $srvName }

    # clean up any left over registry keys
    catch {registry delete $myKey}

    showMsg " $srvName has been removed as a service." info

    exit

}

proc showMsg {msg {icon error}} {
    if {[lsearch [package names] Tk] >= 0} {
        tk_messageBox -type ok -icon $icon -message $msg \
            -title [wm title .]
    } else {
        puts stderr $msg
    }
}

A few notes:

There seem to be several versions of srvany.exe, sc.exe, and instsrv.exe more or less available. These programs were apparently at one time part of the NT Developers Resource Kit, but have been dropped in recent NT Resource Kits from Microsoft. There are still several versions floating around the net. Try Googling for srvany. The ones that work for me have file sizes:

instsrv.exe   18432
sc.exe   54032
srvany.exe   15360

Starting the service for the first time with the sc.exe seems to have problems with my technique; you should instead start the service with Win NT's Service Manager program.


ZLM - Before TWAPI I used to exec the NET command to interact with Windows services from tcl. To check if a service is running:

set my_service "some service name"
set x [exec net start]
foreach y [split $x \n] {  
    set this_service [string trim $y]  
    if {$this_service  == $my_service} { set serv_status 1 }
}
if { $serv_status == 0 } { pleaseStart $my_service }

To start a service:

proc pleaseStart {my_service} {
    set status [catch {exec net start $my_service} result]
    if {$status == 0}  { 
        #success. Now do something
    } else { 
        #Uh oh. Now do something else
    }
}