The Official Win32::Daemon Home Page
The Win32::Daemon extension gives Win32 Perl scripts the ability to function
as a true Win32 service without the need to use a service stub like srvany.exe.
Back to the top
The latest version
The latest version of Win32::Daemon is:
Back to the top
How do you get Win32::Daemon?
There are two ways to obtain Win32::Daemon. You can either download and install it
manually from our FTP site:
ftp://ftp.roth.net/pub/ntperl/Daemon/
If you have ActivePerl (aka Perl from ActiveState Tool Corp.
version 5.005 or higher) or if you have Core Perl 5.005 compiled with
the PERL_OBJECT macro defined
you can auto download and install the extension. You need
to run the Perl Package Manager script which comes with Perl in the
perl\bin directory:
perl ppm.pl install http://www.roth.net/perl/packages/win32-daemon.ppd
This will automatically download and install the latest version.
Back to the top
What Is A Win32 Service?
A Win32 service is quite similar to a Unix daemon. Basically it is a program that runs in
the background. When the computer boots up Windows all of the services are started. So unlike
normal applications, a user does not have to run it. As a matter in fact, the service runs even if
no user is logged on. This simply means that the service will run automatically at boot time.
All processes must run under a user account on Win32 machines. When you launch an application as a
user, the application runs under your user account. Therefore it only has access to files and system
resources that you, yourself, are allowed. Services are no different; they require a user account. When
you install a Win32 service you must specify an account. Most services use the LocalSystem account,
which is just another way of saying the operating system account. The LocalSystem account is
what operating system services (such as the logon, remote registry, file sharing, printer sharing,
event log, etc.) use. If a service is configured to use the LocalSystem, it does not need to specify any
password for the account. However, if you configure a service to run under a different account they you
must provide both the domain and user name along with the user account's password.
How is a Win32 Service Different From an Application?
All Win32 services must register with the Service Control Manager (SCM).
Need More Documentation?
In chapter 8 of our second book,
Win32 Perl Scripting: The Administrator's Handbook
we thoroughly explain how the Win32::Daemon extension works and provide several examples. We also compare it to
alternative solutions like SVRANY.EXE and explain why Win32::Daemon is far more useful.
For a good example on how the Win32::Daemon extension works check out the Win32 Service scripts in our
Perl Script Repository.
More of this is to come. If you found this page and are interested please drop us a line
and let us know.
Win32::Daemon - Extension enabling Win32 Perl scripts to run as a true
Win32 service.
use Win32::Daemon;
Win32::Daemon::StartService();
# ...process Perl code...
Win32::Daemon::StopService();
This extension enables a Win32 Perl script to act as a true Win32 service.
- AcceptedControls( [$NewControls] )
-
This function queries (and optionally sets) the current list of controls
that the service registers for. By registering for a control the script is
notifying the SCM that it is accepting the specified control messages. For
example, if you specify the SERVICE_ACCEPT_PAUSE_CONTINUE
control then the SCM knows that the script will accept and process any
attempt to pause and continue (resume from paused state) the service.
Recognized accepted controls:
SERVICE_ACCEPT_STOP...............The service accepts messages to stop.
SERVICE_ACCEPT_PAUSE_CONTINUE.....The service accepts messages to pause and continue.
SERVICE_ACCEPT_SHUTDOWN...........The service accepts messages to shutdown the system.
When the OS is shutting down the service will be notified
when it has accepted this control.
Following controls are only recognized on Windows 2000 and higher:
SERVICE_ACCEPT_PARAMCHANGE........The service accepts messages notifying it of any
parameter change made to the service.
SERVICE_ACCEPT_NETBINDCHANGE......The service accepts messages notifying it of any
network binding changes.
By default all of these controls are accepted. To change this pass in a
value consisting of any of these values OR'ed together.
NOTE that you can query and set these controls at any time. However it is only
supported to set them before you start the service (calling the StartService() function).
- CallbackTimer( [ $NewTimerValue ] )
-
This function returns the value of the callback timer. The value is in
milliseconds. This value indicates how often the ``Running'' callback
subroutine will be called. Note that the calling of this routine will be
blocked by any other callback.
If you pass in a value it will reset the timer to the specified frequency.
Passing in a 0 will disable all ``Running'' callbacks. Passing in -1 will
toggle the state between calling the ``Running'' callback subroutine and
not calling it.
- CreateService ( \%Hash )
-
This function creates a new service. The return is TRUE if the service was
created, and FALSE otherwise. If an error occurred, call GetLastError to
retrieve the actual error code.
The hash describes the service to be created. The keys are:
- name
-
The 'internal' service name; that is, the name of the registry key used to
store the information on this service.
- display
-
The 'display' service name; that is, the name displayed by the services
control panel or MMC plugin.
- path
-
The full path name to the executable. This should be the path to your Perl
executable, which will normally be the contents of $^X.
NOTE:If you are using a compiled perl script (such as one
generated with PerlApp) as opposed to a text based perl script file then this
value must point to the actual compiled script's executable (eg. MyCompiledPerlService.exe)
instead of ($^X which usually points to perl.exe). You can specify
any parameters to pass into the service using the "parameters" key.
- user
-
The username the service is to run under; this is optional.
- password
-
The password to be used to log in the service; this is technically
optional, but needs to be specified if {user} is.
- parameters
-
The parameters to be passed to Perl; in other words, the command line you
would execute interactively, but without the leading ``perl ''. The 'parameters' key
value is appended to the "path" key when starting the service.
Typically this will be something like:
MyPerlScript.pl /a /b /c
- machine
-
The name of the machine to create the service on. Omission or an empty
string specify the machine executing the call.
- service_type
-
An integer representing the type of the service; defaults to SERVICE_WIN32_OWN_PROCESS
.
- start_type
-
An integer specifying how (or whether) the service is to be started. The
default is SERVICE_AUTO_START
.
- error_control
-
An integer specifying how the Service Control Manager is to react if the
service fails to start. The default is
SERVICE_ERROR_IGNORE
, which in fact gets you an error log entry.
- load_order
-
The name of the load order group of which this service is a member. The
default is membership in no group. See value ServiceGroupOrder in registry
key HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control for the names.
- tag_id
-
An integer representing the startup order of the service within its load
ordering group.
- dependencies
-
A reference to the 'internal' names of services and/or load ordering groups
upon which this service depends. The default is no dependencies. Load order
group names are prefixed with a '+' to distinguish them from service names.
- description
-
A short text description of the service, displayed (at least) as flyover
help by the MMC ``services'' plugin.
- ConfigureService( \%Hash )
-
This function modifies the settings of an existing service. The return is TRUE if the service was
successfully modified and FALSE otherwise. If an error occurred, call GetLastError to
retrieve the actual error code.
The hash describes the settings of service that you wish to modify. The hash's keys and values are
the same used by the CreateService() method. When
calling ConfigureService() only specify hash keys that you want to modify. The only exception to this
is that you need to specify the name key (this can not be modified and must be present to
identify which service you are modifying) and machine key (only if you are configuring
a service on a remote machine).
- DeleteService ($Machine, $ServiceName )
-
This function deletes an existing service. The return is TRUE if the
service was deleted, and FALSE otherwise. If an error occurred, call
GetLastError to retrieve the actual error code.
The arguments are the name of the machine (an empty string specifies the
machine executing the call), and the 'internal' service name (i.e. the
string passed in the {name} element when the service was created).
A running service may not be deleted.
- GetSecurity( $Machine, $ServiceName )
-
This will return a binary Security Descriptor (SD) that is associated with
the specified service on the specified machine.
The SD is in self-relative format. It can be imported into a Win32::Perms
object using the Win32::Perms object's Import()
method.
- RegisterCallbacks( $CodeRef | \%Hash )
-
This will register specified code subroutines that will be called when
specified events take place. For example if you register a subroutine
called Pause()
with the pause event then this routine will be
called when there is an attempt to pause the service. Not all events must
have callbacks registered.
If only a reference to a subroutine is passed in then it will be called for
each and every event. You can pass in a hash containing particular key
names (listed below) with code references.
Possible hash key names:
Key Name Event
------------- --------------------------------------
start....................The service is starting.
pause....................The service is entering a paused state.
continue.................The service is resuming from a paused state.
stop.....................The service is stopping (see note below).
running..................The service is running (see note below).
interrogate..............The service is being queried for information.
shutdown.................The system is being shut down.
param_change.............There has been a parameter change to the system.
net_bind_add.............A new network binding has been made.
net_bind_remove..........A network binding has been removed.
net_bind_enable..........A network binding has been enabled.
net_bind_disable.........A network binding has been disabled.
device_event.............A device has generated some event.
hardware_profile_change..A change has been made to the system's hardware profile.
power_event..............A power event has occured (eg change to battery power).
session_change...........There has been a change in session.
user_defined.............A user defined event has been sent to the service.
NOTE: The 'Stop' state. When a service calls into the registered "stop" callback routine
the script should call the C<StopService()> function. This tells the service to terminate
and return back to the Perl script. This is the only way for the service to know that it
must stop.
Note: The 'Running' state. Periodically the extension will call into a
registered ``Running'' subroutine. This allows the script to process data.
This routine should be fast and return quickly otherwise it will block
other callback events from being run. The frequency of calling the
``Running'' subroutine is dictated by the callback timer value passed into StartService() and any changes made to this value by calling into
CallbackTimer().
- SetSecurity( $Machine, $ServiceName, $BinarySD | $Win32PermsObject )
-
This applies the specified Security Descriptor (SD) to the specified
service on the specified machine. You must have appropriate permissions to
call this function.
The specified SD can be either a binary SD (in self-relative or absolute
format) or it can be a Win32::Perms object.
This only sets the DACL and SACL. The owner and group are not set even if
they are specified in the SD.
- StartService( [ \%Context, $CallbackTimer ] )
-
This starts a new service thread. The script should call this as soon as
possible. When the service manager starts the service Perl is started and
the script is loaded.
This function returns the thread handle of the service thread. If you call
into this more than once it will only return the thread handle (it won't
create another new service thread).
- Callback Mode
-
If the script has already registered callback routines (using RegisterCallbacks()) then the call into StartService() will not return until the service has stopped. However callbacks will be
made for each state change and callback timer timeout (refer to RegisterCallbacks()).
- StopService()
-
This will instruct the service to terminate.
- QueryLastMessage( [$fResetMessage] )
-
This function returns the last message that the service manager has sent to
the service.
Pass in a non zero value to reset the pending message to SERVICE_CONTROL_NONE
. This way your script can tell when two of the same messages come in.
Occasionally the service manager will send messages to the service. These
messages typically request the service to change from one state to another.
It is important that the Perl script responds to each message otherwise the
service manager becomes confused about the current state of the service.
For example, if the service manager is submits a SERVICE_PAUSE_PENDING
then it expects the Perl script to recognize the change to a paused state
and submit the new state by calling State( SERVICE_PAUSED ).
You can update the service manager with the current status using the State() function.
Possible values returned are:
Valid Service Control Messages:
-------------------------------
SERVICE_CONTROL_NONE..............No message is pending.
SERVICE_CONTROL_STOP..............The SCM is requesting the service to stop.
This results in State() reporting SERVICE_STOP_PENDING.
SERVICE_CONTROL_PAUSE.............The SCM is requesting the service to pause.
This results in State() reporting SERVICE_PAUSE_PENDING.
SERVICE_CONTROL_CONTINUE..........The SCM is requesting the service to continue from a
paused state.
This results in State() reporting SERVICE_CONTINUE_PENDING.
SERVICE_CONTROL_INTERROGATE.......The service manager is querying the service's state
Windows 2000 specific messages:
SERVICE_CONTROL_SHUTDOWN..........The machine is shutting down. This indicates that
the service has roughly 20 seconds to clean up
and terminate. This time can be extended by
submitting SERVICE_STOP_PENDING via the State() function.
SERVICE_CONTROL_PARAMCHANGE.......Service parameters have been modified.
SERVICE_CONTROL_NETBINDADD........A network binding as been added.
SERVICE_CONTROL_NETBINDREMOVE.....A network binding has been removed.
SERVICE_CONTROL_NETBINDENABLE.....A network binding has been enabled.
SERVICE_CONTROL_NETBINDDISABLE....A network binding has been disabled.
SERVICE_CONTROL_DEVICEEVENT.......A device has generated some event.
SERVICE_CONTROL_HARDWAREPROFILECHANGE..A change has been made to the system's hardware profile.
SERVICE_CONTROL_POWEREVENT........A power event has occured (eg change to battery power).
SERVICE_CONTROL_SESSIONCHANGE.....There has been a change in session.
SERVICE_CONTROL_USER_DEFINED......This is a user defined control. There are 127 of these
beginning with SERVICE_CONTROL_USER_DEFINED as the base.
Note: When the system shuts down it will send a SERVICE_CONTROL_SHUTDOWN
message. The Perl script has approximately 20 seconds to perform any
shutdown activities before the Control Manger stops the service. If more
time is needed call the State() function passing in the SERVICE_STOP_PENDING
control message along with how many seconds it will take to shutdown the
service. This time value is only an estimate. When the service is finally
ready to stop it must submit the SERVICE_STOPPED
message as in:
if( SERVICE_CONTROL_SHUTDOWN == State() )
{
Win32::Daemon::State( SERVICE_STOP_PENDING, 30 );
#...process code...
Win32::Daemon::State( SERVICE_STOPPED );
}
- State([$NewState [, $Hint ] || \%Hash ] )
-
This function returns the current state of the service. It can optionally
update the status of the service as well. This is the last status reported
to the service manager.
Optionally you can pass in a value that will be sent to the service
manager. Optionally you can pass in a numeric value indicating the
``hint''. This is the number of milliseconds the SCM can expect to wait
before the service responds to the request. For example, if your service
script reports a hint of 30,000 milliseconds means that the SCM will have
to wait for 30 seconds for the script to change the service's state before
deciding that the script is non responsive.
If you are setting/updating the state instead of passing in the state and
wait hint you could pass in a hash reference. This allows you to specify
the state, wait hint and error state. You can use the following keys:
Hash Key
--------
state..........Valid service state (see table below).
waithint.......A wait hint explained above. This is in milliseconds.
error..........Any 32 bit error code. This is what will be reported if an application
queries the error state of the service. It is also what is reported if
a call to start the services fails.
To reset an error state pass in NO_ERROR.
The only invalid error value is 0xFFFFFFFF.
Example of passing in an error:
Win32::Daemon::State( { error => 0x12345678 } );
# Later to reset the error:
Win32::Daemon::State( { error => NO_ERROR } );
Possible values returned (or submitted):
Valid Service States:
---------------------
SERVICE_NOT_READY..........The SCM has not yet been initialized. If the SCM is slow or busy
then this value will result from a call to State().
If you get this value, just keep calling State() until you get
SERVICE_START_PENDING.
SERVICE_STOPPED............The service is stopped
SERVICE_RUNNING............The service is running
SERVICE_PAUSED.............The service is paused
SERVICE_START_PENDING......The service manager is attempting to start the service
SERVICE_STOP_PENDING.......The service manager is attempting to stop the service
SERVICE_CONTINUE_PENDING...The service manager is attempting to resume the service
SERVICE_PAUSE_PENDING......The service manager is attempting to pause the service
Callbacks were introduced in version v20030617.
The Win32::Daemon supports the concept of event callbacks. This allows a
script to register a particular subroutine with a particular event. When
the event occurs it will call the Perl subroutine registered with that
event. This can make it very simple to write scripts.
You register a callback subroutine by calling into the RegisterCallbacks() function. You can pass in a code reference or a hash. A code reference will
register the specified subroutine with all events. A hash allows you to
pick which events you want to register for which subroutines. You do not
have to register all events. If an event is not registered for a subroutine
then the script will not be notified when the event occurs.
At a minimum a script should register for the 'Start' and 'Running' states.
This enables the script to actually start and to periodically process data.
When an event callback occurs the subroutine should change the state
accordingly by passing in the new state into State(). For example the 'Start' callback would call
State( SERVICE_RUNNING ) to inform the service that it is officially running. Another example is the
'Pause' state should call State( SERVICE_PAUSED ) to inform the service that it is offically paused.
Once callback subroutines are registered the script enters the service mode
by calling
StartService(). This will being the process of calling the event callback routines. Note
that when callback routines are registered the StartService() function will not return until a callback routine calls StopService() (typically the 'Stop' event callback would call StopService().
When calling into StartService() you can pass in a hash reference. This reference is known as a ``context''
hash. For every callback the hash will be passed into the callback routine.
This enables a script to query and set data in the hash--essentially
letting you pass information across to different callback events. This
context hash is not required.
When a callback is made it always passes two parameters in: $State and $Context. $State is simply the state change that caused the
callback. This represents the event that took place (e.g. SERVICE_PAUSE_PENDING
,
SERVICE_START_PENDING
, etc). The $Context
is a reference to the context hash that
was passed into the StartService() function.
A typical callback routine should look similar to:
sub Callback_Start
{
my( $Event, $Context ) = @_;
$Context->{last_event} = $Event;
# ...do some work here...
# Tell the service manager that we have now
# entered the running state.
Win32::Daemon::State( SERVICE_RUNNING );
return();
}
Refer to Example 4: Using a single callback and Example 5: Using different callback routines for an example of using callbacks.
Compiled Perl Applications
Many users like to compile their perl scripts into executable programs. This way it is much easier to copy them around
from machine to machine since all necessary files, packages and binaries are compiled into one .exe file. These compiled
perl scripts are compatible with Win32::Deamon as long as you install it correctly.
If you are going to compile your Win32::Daemon based perl script into an .exe there is nothing unique you need to do
to your Win32::Daemon code with one single exception of the call into Win32::Daemon::CreateService(). When passing in
the 'path' and 'parameters' values into CreateService() observe the following simple rules:
1) If using a Perl script
path........The full path to the Perl interpeter (perl.exe).
This is typically:
c:\perl\bin\perl.exe
parameter...This value MUST start with the full path to the
perl script file and append any parameters
that you want passed into the service. For
example:
c:\scripts\myPerlService.pl -param1 -param2 "c:\\Param2Path"
2) If using a compiled Perl application
path........The full path to the compiled Perl application.
For example:
c:\compiledscripts\myPerlService.exe
parameter...This value is just the list of parameters
that you want passed into the service. For
example:
-param1 -param2 "c:\\Param2Path"
Refer to Example 3: Install the service for an example.
This example service will delete all .tmp files from the c:\temp directory
every time it starts. It will immediately terminate.
use Win32::Daemon;
# Tell the OS to start processing the service...
Win32::Daemon::StartService();
# Wait until the service manager is ready for us to continue...
while( SERVICE_START_PENDING != Win32::Daemon::State() )
{
sleep( 1 );
}
# Now let the service manager know that we are running...
Win32::Daemon::State( SERVICE_RUNNING );
# Okay, go ahead and process stuff...
unlink( glob( "c:\\temp\\*.tmp" ) );
# Tell the OS that the service is terminating...
Win32::Daemon::StopService();
This particular example does not really illustrate the capabilities of a
Perl based service.
# This style of Win32::Daemon use is obsolete. It still works but the
# callback model is more efficient and easier to use. Refer to examples 4 and 5.
use Win32;
use Win32::Daemon;
$SERVICE_SLEEP_TIME = 20; # 20 milliseconds
$PrevState = SERVICE_START_PENDING;
Win32::Daemon::StartService();
while( SERVICE_STOPPED != ( $State = Win32::Daemon::State() ) )
{
if( SERVICE_START_PENDING == $State )
{
# Initialization code
Win32::Daemon::State( SERVICE_RUNNING );
$PrevState = SERVICE_RUNNING;
}
elsif( SERVICE_STOP_PENDING == $State )
{
Win32::Daemon::State( SERVICE_STOPPED );
}
elsif( SERVICE_PAUSE_PENDING == $State )
{
# "Pausing...";
Win32::Daemon::State( SERVICE_PAUSED );
$PrevState = SERVICE_PAUSED;
next;
}
elsif( SERVICE_CONTINUE_PENDING == $State )
{
# "Resuming...";
Win32::Daemon::State( SERVICE_RUNNING );
$PrevState = SERVICE_RUNNING;
next;
}
elsif( SERVICE_STOP_PENDING == $State )
{
# "Stopping...";
Win32::Daemon::State( SERVICE_STOPPED );
$PrevState = SERVICE_STOPPED;
next;
}
elsif( SERVICE_RUNNING == $State )
{
# The service is running as normal...
# ...add the main code here...
}
else
{
# Got an unhandled control message. Set the state to
# whatever the previous state was.
Win32::Daemon::State( $PrevState );
}
# Check for any outstanding commands. Pass in a non zero value
# and it resets the Last Message to SERVICE_CONTROL_NONE.
if( SERVICE_CONTROL_NONE != ( my $Message = Win32::Daemon::QueryLastMessage( 1 ) ) )
{
if( SERVICE_CONTROL_INTERROGATE == $Message )
{
# Got here if the Service Control Manager is requesting
# the current state of the service. This can happen for
# a variety of reasons. Report the last state we set.
Win32::Daemon::State( $PrevState );
}
elsif( SERVICE_CONTROL_SHUTDOWN == $Message )
{
# Yikes! The system is shutting down. We had better clean up
# and stop.
# Tell the SCM that we are preparing to shutdown and that we expect
# it to take 25 seconds (so don't terminate us for at least 25 seconds)...
Win32::Daemon::State( SERVICE_STOP_PENDING, 25000 );
}
}
# Snooze for awhile so we don't suck up cpu time...
Win32::Sleep( $SERVICE_SLEEP_TIME );
}
# We are done so close down...
Win32::Daemon::StopService();
For the 'path' key the $^X equates to the full path of the perl executable.
Since no user is specified it defaults to the LocalSystem.
use Win32::Daemon;
# If using a compiled perl script (eg. myPerlService.exe) then
# $ServicePath must be the path to the .exe as in:
# $ServicePath = 'c:\CompiledPerlScripts\myPerlService.exe';
# Otherwise it must point to the Perl interpreter (perl.exe) which
# is conviently provided by the $^X variable...
my $ServicePath = $^X;
# If using a compiled perl script then $ServiceParams
# must be the parameters to pass into your Perl service as in:
# $ServiceParams = '-param1 -param2 "c:\\Param2Path"';
# OTHERWISE
# it MUST point to the perl script file that is the service such as:
my $ServiceParams = 'c:\perl\scripts\myPerlService.pl -param1 -param2 "c:\\Param2Path"';
%Hash = (
machine => '',
name => 'PerlTest',
display => 'Oh my GOD, Perl is a service!',
path => $ServicePath,
user => '',
pwd => '',
description => 'Some text description of this service',
parameters => $ServiceParams
);
if( Win32::Daemon::CreateService( \%Hash ) )
{
print "Successfully added.\n";
}
else
{
print "Failed to add service: " . Win32::FormatMessage( Win32::Daemon::GetLastError() ) . "\n";
}
NOTES: - ConfigureService: - If you specify a 'parameters' key you MUST
specify a 'path' key.
In this example only one subroutine is used for all callbacks. The
CallbackRoutine()
subroutine will receive all event callbacks.
Basically this callback routine will have to do essentially the same thing
that the main while loop in Example 2
does.
use Win32::Daemon;
Win32::Daemon::RegisterCallbacks( \&CallbackRoutine );
%Context = (
count => 0,
start_time => time(),
);
# Start the service passing in a context and
# indicating to callback using the "Running" event
# every 2000 milliseconds (2 seconds).
Win32::Daemon::StartService( \%Context, 2000 );
sub CallbackRoutine
{
my( $Event, $Context ) = @_;
$Context->{last_event} = $Event;
if( SERVICE_RUNNING == $Event )
{
# ... process your main stuff here...
# ... note that here there is no need to
# change the state
}
elsif( SERVICE_START_PENDING == $Event )
{
# Initialization code
# ...do whatever you need to do to start...
$Context->{last_state} = SERVICE_RUNNING;
Win32::Daemon::State( SERVICE_RUNNING );
}
elsif( SERVICE_PAUSE_PENDING == $Event )
{
$Context->{last_state} = SERVICE_PAUSED;
Win32::Daemon::State( SERVICE_PAUSED );
}
elsif( SERVICE_CONTINUE_PENDING == $Event )
{
$Context->{last_state} = SERVICE_RUNNING;
Win32::Daemon::State( SERVICE_RUNNING );
}
elsif( SERVICE_STOP_PENDING == $Event )
{
$Context->{last_state} = SERVICE_STOPPED;
Win32::Daemon::State( SERVICE_STOPPED );
# We need to notify the Daemon that we want to stop callbacks and the service.
Win32::Daemon::StopService();
}
else
{
# Take care of unhandled states by setting the State()
# to whatever the last state was we set...
Win32::Daemon::State( $Context->{last_state} );
}
return();
}
use Win32::Daemon;
Win32::Daemon::RegisterCallbacks( {
start => \&Callback_Start,
running => \&Callback_Running,
stop => \&Callback_Stop,
pause => \&Callback_Pause,
continue => \&Callback_Continue,
} );
%Context = (
last_state => SERVICE_STOPPED,
start_time => time(),
);
sub Callback_Running
{
my( $Event, $Context ) = @_;
# Note that here you want to check that the state
# is indeed SERVICE_RUNNING. Even though the Running
# callback is called it could have done so before
# calling the "Start" callback.
if( SERVICE_RUNNING == Win32::Daemon::State() )
{
# ... process your main stuff here...
# ... note that here there is no need to
# change the state
}
}
sub Callback_Start
{
my( $Event, $Context ) = @_;
# Initialization code
# ...do whatever you need to do to start...
$Context->{last_state} = SERVICE_RUNNING;
Win32::Daemon::State( SERVICE_RUNNING );
}
sub Callback_Pause
{
my( $Event, $Context ) = @_;
$Context->{last_state} = SERVICE_PAUSED;
Win32::Daemon::State( SERVICE_PAUSED );
}
sub Callback_Continue
{
my( $Event, $Context ) = @_;
$Context->{last_state} = SERVICE_RUNNING;
Win32::Daemon::State( SERVICE_RUNNING );
}
sub Callback_Stop
{
my( $Event, $Context ) = @_;
$Context->{last_state} = SERVICE_STOPPED;
Win32::Daemon::State( SERVICE_STOPPED );
# We need to notify the Daemon that we want to stop callbacks and the service.
Win32::Daemon::StopService();
}
- 20011205 rothd
-Fixed bug where "invalid service state 80" is reported in the Win32 event log.
-Added initial support for SCM request callbacks (this is not implemented fully and
is not supported yet).
-Added SERVICE_CONTROL_NONE constant
-Fixed State() so it only returns states, not commands.
-Modified QueryLastMessage(). It now allows you to reset the last message to SERVICE_CONTROL_NONE.
-Added SERVICE_NOT_READY state
-Cleaned up some states.
-Added AcceptedControls() function.
- 20011217 rothd
- Added support for .Net Server accept control contants:
SERVICE_ACCEPT_HARDWAREPROFILECHANGE
SERVICE_ACCEPT_POWEREVENT
SERVICE_ACCEPT_SESSIONCHANGE
- 20011221 rothd@roth.net
- Fixed bug where service doesn't work properly with Windows NT 4. We were
defaulting by acccepting the SERVICE_ACCEPT_PARAMCHANGE and
SERVICE_ACCEPT_NETBINDCHANGE controls. However, they were introduced in
Win2k so NT 4 coughed up blood with them.
- 20020108 rothd@roth.net
- Fixed another bug wwhere servie wouldn't work on Win2k machines. We
were treating Win2k (version 5.0) the same as WinXP (version 5.1) and
adding WinXP specific controls. This rendered the service unable to
start, pause or stop. Fix was only in the Daemon.pm file.
- 20020114 marc.pijnappels@nec-computers.com
- Fixed another bug where service wouldn't work on WinXP machines. Variable
recognized_controls was wrongly initialized for WinXP systems. This
rendered the service unable to start, pause or stop. Fix was only in
the Daemon.pm file.
- 20020605 rothd@roth.net
- Added support for reporting service errors. You can now pass in a
hash reference into State(). More details in the POD docs.
- 20030617 rothd@roth.net
- Added support for querying and setting service security. This includes
DACL and SACL support. Due to complexity and failures you can not set
owner or group. But in most cases (99%) this is not needed.
- GetSecurity()
- SetSecurity()
- Finished incorporating callback routines.
- Added a few more events.