Hi, Here is a patch against the SVN head.
Changes: - fixes incompatibility with fork() : END {} block executed only in the main thread. - fixes white spaces in POD - changes to go towards 'strict' mode Olivier Mengué dol...@cpan.org Index: Daemon.pm =================================================================== --- Daemon.pm (revision 485) +++ Daemon.pm (working copy) @@ -3,12 +3,14 @@ #// Daemon.pm #// Win32::Daemon Perl extension package file #// -#// Copyright (c) 1998-2002 Dave Roth +#// Copyright (c) 1998-2008 Dave Roth #// Courtesy of Roth Consulting #// http://www.roth.net/ #// -#// This file may be copied or modified only under the terms of either -#// the Artistic License or the GNU General Public License, which may +#// Copyright (c) 2009 Olivier Mengue +#// +#// This file may be copied or modified only under the terms of either +#// the Artistic License or the GNU General Public License, which may #// be found in the Perl 5.0 source kit. #// #// 2008.03.24 :Date @@ -17,21 +19,25 @@ package Win32::Daemon; -$PACKAGE = $Package = "Win32::Daemon"; -$VERSION = 20080324; +#use strict; +#use warnings; +our $PACKAGE = $Package = "Win32::Daemon"; + +our $VERSION = 20080324; require Exporter; require DynaLoader; +use vars qw( $AUTOLOAD ); my @OSVerInfo = Win32::GetOSVersion(); my $OSVersion = "$OSVerInfo[1].$OSVerInfo[2]"; my $RECOGNIZED_CONTROLS; -...@isa= qw( Exporter DynaLoader ); +our @ISA= qw( Exporter DynaLoader ); # Items to export into callers namespace by default. Note: do not export # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. -...@export = qw( +our @EXPORT = qw( SERVICE_CONTROL_USER_DEFINED SERVICE_NOT_READY @@ -60,7 +66,7 @@ SERVICE_CONTROL_SESSIONCHANGE SERVICE_CONTROL_USER_DEFINED SERVICE_CONTROL_RUNNING - SERVICE_CONTROL_PRESHUTDOWN + SERVICE_CONTROL_PRESHUTDOWN SERVICE_CONTROL_TIMER SERVICE_CONTROL_START @@ -82,8 +88,8 @@ SERVICE_ACCEPT_STOP SERVICE_ACCEPT_PAUSE_CONTINUE - SERVICE_ACCEPT_SHUTDOWN - SERVICE_ACCEPT_PARAMCHANGE + SERVICE_ACCEPT_SHUTDOWN + SERVICE_ACCEPT_PARAMCHANGE SERVICE_ACCEPT_NETBINDCHANGE SERVICE_WIN32_OWN_PROCESS @@ -109,12 +115,11 @@ ); -...@export_ok = qw( -); +our @EXPORT_OK = (); -bootstrap $Package; +bootstrap(__PACKAGE__); -sub AUTOLOAD +sub AUTOLOAD { # This AUTOLOAD is used to 'autoload' constants from the constant() # XS function. If a constant is not found then control is passed @@ -138,9 +143,8 @@ # $Result == 1 if the constant is valid but not defined # that is, the extension knows that the constant exists but for # some wild reason it was not compiled with it. - $pack = 0; - ($pack,$file,$line) = caller; - print "Your vendor has not defined $Package macro $constname, used in $file at line $line."; + my ($pack,$file,$line) = caller; + print "Your vendor has not defined ".__PACKAGE__." macro $Constant, used in $file at line $line."; } elsif( 2 == $Result ) { @@ -160,7 +164,8 @@ END { - Win32::Daemon::StopService(); + # Stop the service only if we are in the main thread (not in a forked process) + Win32::Daemon::StopService() if $$ > 0; } __END__ @@ -237,7 +242,7 @@ 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 C<SERVICE_ACCEPT_PAUSE_CONTINUE> control then -the SCM knows that the script will accept and process any attempt to pause and continue (resume +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: @@ -250,13 +255,13 @@ Following controls are only recognized on Windows 2000 and higher: - SERVICE_ACCEPT_PARAMCHANGE........The service accepts messages notifying it of any + 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 + 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. +any of these values OR'ed together. B<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 C<StartService()> function). @@ -268,8 +273,8 @@ 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. +a 0 will disable all "Running" callbacks. Passing in -1 will toggle the state between +calling the "Running" callback subroutine and not calling it. =item CreateService ( \%Hash ) @@ -291,12 +296,12 @@ The 'display' service name; that is, the name displayed by the services control panel or MMC plugin. -=item path +=item 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. -B<NOTE:> If you are using a compiled perl script (such as one +B<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 @@ -386,7 +391,7 @@ =item GetSecurity( $Machine, $ServiceName ) This will return a binary Security Descriptor (SD) that is associated with the -specified service on the specified machine. +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. @@ -399,7 +404,7 @@ 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 +event. You can pass in a hash containing particular key names (listed below) with code references. Possible hash key names: @@ -424,7 +429,7 @@ 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 @@ -433,7 +438,7 @@ 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 +frequency of calling the "Running" subroutine is dictated by the callback timer value passed into C<StartService()> and any changes made to this value by calling into C<CallbackTimer()>. @@ -463,7 +468,7 @@ =item Callback Mode If the script has already registered callback routines (using C<RegisterCallbacks()>) then -the call into C<StartService()> will not return until the service has stopped. However +the call into C<StartService()> will not return until the service has stopped. However callbacks will be made for each state change and callback timer timeout (refer to C<RegisterCallbacks()>). =back @@ -484,7 +489,7 @@ Pass in a non zero value to reset the pending message to C<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 +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 @@ -502,11 +507,11 @@ 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 + 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 - + SERVICE_CONTROL_USER_DEFINED......This is a user defined control. There are 127 of these beginning with SERVICE_CONTROL_USER_DEFINED as the base. Windows 2000 specific messages: @@ -524,7 +529,7 @@ 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. - + Windows Vista + specific messages: SERVICE_CONTROL_PRESHUTDOWN ......The machine is about to shut down. This provides the service much more time to shutdown than SERVICE_CONTROL_SHUTDOWN. @@ -534,8 +539,8 @@ B<Note:> When the system shuts down it will send a C<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 C<State()> function -passing in the C<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 +passing in the C<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 C<SERVICE_STOPPED> message as in: if( SERVICE_CONTROL_SHUTDOWN == State() ) @@ -558,7 +563,7 @@ 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 +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: @@ -566,7 +571,7 @@ -------- 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 + 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. @@ -585,7 +590,7 @@ --------------------- 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 + 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 @@ -601,15 +606,15 @@ Callbacks were introduced in version v20030617. -The Win32::Daemon supports the concept of event callbacks. This allows a script to +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 C<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 +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. @@ -623,14 +628,14 @@ that it is offically paused. Once callback subroutines are registered the script enters the service mode by calling -C<StartService()>. This will being the process of calling the event callback routines. -Note that when callback routines are registered the C<StartService()> function will not +C<StartService()>. This will being the process of calling the event callback routines. +Note that when callback routines are registered the C<StartService()> function will not return until a callback routine calls C<StopService()> (typically the 'Stop' event callback would call C<StopService()>. When calling into C<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 +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 @@ -644,9 +649,9 @@ { 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 ); @@ -659,31 +664,31 @@ =head1 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 +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 +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::C<CreateService()>. When passing in the 'path' and 'parameters' values into C<CreateService()> observe the following simple rules: =over 4 1) If using a Perl script - path........The full path to the Perl interpeter (perl.exe). + 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 + + 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. + 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: @@ -768,7 +773,7 @@ { # The service is running as normal... # ...add the main code here... - + } else { @@ -806,17 +811,17 @@ =head2 Example 3: Install the service -For the 'path' key the $^X equates to the full path of the +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 + 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; + my $ServicePath = $^X; # If using a compiled perl script then $ServiceParams # must be the parameters to pass into your Perl service as in: @@ -878,7 +883,7 @@ # ... note that here there is no need to # change the state - } + } elsif( SERVICE_START_PENDING == $Event ) { # Initialization code @@ -951,7 +956,7 @@ # ... note that here there is no need to # change the state } - } + } sub Callback_Start { @@ -1020,6 +1025,13 @@ =head1 HISTORY: + - 20091028 Olivier Mengue + -Disabled END {} in non-main threads to fix bug RT#50020 + -Changes to go to 'strict' mode. + -Fixed white spaces in POD. + + - 20080321 rothd + - 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 @@ -1038,11 +1050,11 @@ SERVICE_ACCEPT_SESSIONCHANGE - 20011221 ro...@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 + - 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 ro...@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 @@ -1050,15 +1062,15 @@ start, pause or stop. Fix was only in the Daemon.pm file. - 20020114 marc.pijnapp...@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 + - 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 ro...@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 ro...@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 @@ -1067,7 +1079,7 @@ - SetSecurity() - Finished incorporating callback routines. - Added a few more events. - + - 20080321 ro...@roth.net -Callbacks can now return a state value. This is the functional equivilent of calling Win32::Daemon::State( $NewState ) before returning: @@ -1089,11 +1101,8 @@ -Callback timer works correctly! -CALLBACK_RUNNING has been depreciated and replaced with CALLBACK_TIMER. It is only called when the timer (set by CallbackTimer()) has expired. Use this as a heartbeat. You only need - to set it once either with CallbackTimer() or passing in the timer value when calling into + to set it once either with CallbackTimer() or passing in the timer value when calling into StartService(). Set the callback using "timer" as the callback name. Using "running" will also work but it is mapped to "timer". If you specify both, only "timer" will be registered. - - - \ No newline at end of file ===================================================================