in reply to Perl script as windows service

I do not think you need to remove the DOS box. This is not the issue. You use your script to install the service, I understand. You start the service within the win32 SERVICES dialog. I think.

Problem is, that your script actually has neither a start hook nor a run hook!

Initialize the daemon with something like

Win32::Daemon::RegisterCallbacks( { start => \&startService, stop => \&stopService, pause => \&pauseService, continue => \&continueService, running => \&runService, } );

Next, define some callbacks.

sub startService { # start the win32 service daemon # ------------------------------ my ($event, $context) = @_; $context -> { last_state } = SERVICE_RUNNING; Win32::Daemon::State( SERVICE_START_PENDING, 30000 ); # do what need to be done # exit Win32::Daemon::State( SERVICE_RUNNING ); } # ==================================================================== +========== sub stopService { # stop the win32 service daemon # ----------------------------- my ($event, $context) = @_; $context -> { last_state } = SERVICE_STOPPED; Win32::Daemon::State( SERVICE_STOP_PENDING, 30000 ); # do what needs to be done # exit Win32::Daemon::State( SERVICE_STOPPED ); Win32::Daemon::StopService(); } # ==================================================================== +========== sub pauseService { # let the win32 service daemon make a pause # ----------------------------------------- my ($event, $context) = @_; $context -> { last_state } = SERVICE_PAUSED; # do what needs to be done # exit Win32::Daemon::State( SERVICE_PAUSED ); } # ==================================================================== +========== sub continueService { # let the win32 service daemon exit a pause # ----------------------------------------- my ($event, $context) = @_; $context -> { last_state } = SERVICE_RUNNING; # do what needs to be done # exit Win32::Daemon::State( SERVICE_RUNNING ); } # ==================================================================== +========== sub runService { # this is the callback of by the win32 service daemon # --------------------------------------------------- my ($event, $context) = @_; if ( Win32::Daemon::State() == SERVICE_RUNNING ) { # count the number of calls (I do not know why) $context -> { count }++; } }

Regarding your error message I add the following comment. Your service did not respond to the start method, because there is none. If there is a start method, you need to be careful to inform the win32 service manager, how long your startup will take. See this Win32::Daemon::State( SERVICE_STOP_PENDING, 30000 ); statement.

Replies are listed 'Best First'.
Re^2: Perl script as windows service
by holli (Abbot) on Mar 02, 2005 at 08:54 UTC
    I did not really dig into the code, but isnīt
    while(1) { # delete all *.tmp files at c:\temp unlink( glob( "c:\\temp1\\*.txt" ) ); #keep_alive(); sleep(5); # and wait #last unless keep_alive(); Log("PRINTING"); }
    the main processing loop of the service?


    holli, /regexed monk/

      Yes. Looks like. But I think he did not catch the Win32::Daemon idea. For this reason, I paste the following snippet. I tested it. It works fine on a win32 even though it does nothing!. Here, the runService method is the processor, called every five seconds.

      #!/usr/bin/perl $| = 1; use strict; use Getopt::Long; use Win32; use Win32::Daemon; my %opt; GetOptions ( \%opt, "run", "install", "remove", "start", "stop", "restart", "pause", "resume|continue", ); my @currDir = split /\//, $0; my $script = $0; my $scriptPath = "."; if (scalar @currDir > 1) { $script = pop @currDir; $scriptPath = join "/", @currDir; chdir( $scriptPath ); } my %serviceConfig = ( name => 'mytest', display => 'mytest', description => 'this is my test description', machine => '', path => $^X, parameters => ( sprintf '"e:/dia/temp/service.pl" --run', $scriptPath, $script ), start_type => SERVICE_AUTO_START, ); Win32::Daemon::RegisterCallbacks( { start => \&startService, stop => \&stopService, pause => \&pauseService, continue => \&continueService, running => \&runService, } ); # ==================================================================== +========== # main # ==================================================================== +========== if( $opt { install } ) { &installService(); exit(); } elsif( $opt { remove } ) { &removeService(); exit(); } elsif( $opt { status } ) { &serviceStatus(); exit(); } elsif( $opt { run } ) { my %context = { last_state => SERVICE_STOPPED, count => 0, start_time => time(), }; Win32::Daemon::StartService( \%context, 5000 ); } elsif( $opt { start } ) { my $cmd = sprintf 'net start %s', $serviceConfig { name }; system( $cmd ); exit(); } elsif( $opt { stop } ) { my $cmd = sprintf 'net stop %s', $serviceConfig { name }; system( $cmd ); exit(); } elsif( $opt { pause } ) { my $cmd = sprintf 'net pause %s', $serviceConfig { name }; system( $cmd ); exit(); } elsif( $opt { resume } ) { my $cmd = sprintf 'net continue %s', $serviceConfig { name }; system( $cmd ); exit(); } elsif( $opt { restart } ) { my $cmd = sprintf 'net stop %s', $serviceConfig { name }; system( $cmd ); $cmd = sprintf 'net start %s', $serviceConfig { name }; system( $cmd ); exit(); } else { die "Nothing to do\n"; } # ==================================================================== +========== # SERVICE SETUP # ==================================================================== +========== sub installService { # installs the win32 service daemon # --------------------------------- if( Win32::Daemon::CreateService( \%serviceConfig ) ) { &debug( 'The service [%s] was successfully installed', $servic +eConfig { display } ); } else { &debug( 'Failed to install the service [%s]: %s', $serviceConfig { display }, GetError() ); } } # ==================================================================== +========== sub removeService { # removes the win32 service daemon # -------------------------------- if( Win32::Daemon::DeleteService( $serviceConfig { name } ) ) { &debug( 'The service [%s] was successfully removed', $serviceC +onfig { display } ); } else { &debug( 'Failed to remove the service [%s]: %s', $serviceConfig { display }, GetError() ); } } # ==================================================================== +========== # CALLBACK ROUTINES # ==================================================================== +========== sub startService { # start the win32 service daemon # ------------------------------ my ($event, $context) = @_; $context -> { last_state } = SERVICE_RUNNING; Win32::Daemon::State( SERVICE_START_PENDING, 30000 ); &debug( 'Starting the service' ); # let's go Win32::Daemon::State( SERVICE_RUNNING ); } # ==================================================================== +========== sub stopService { # stop the win32 service daemon # ----------------------------- my ($event, $context) = @_; $context -> { last_state } = SERVICE_STOPPED; Win32::Daemon::State( SERVICE_STOP_PENDING, 30000 ); &debug( 'Stopping the service' ); Win32::Daemon::State( SERVICE_STOPPED ); Win32::Daemon::StopService(); } # ==================================================================== +========== sub pauseService { # let the win32 service daemon make a pause # ----------------------------------------- my ($event, $context) = @_; &debug( 'Pausing the service' ); $context -> { last_state } = SERVICE_PAUSED; Win32::Daemon::State( SERVICE_PAUSED ); } # ==================================================================== +========== sub continueService { # let the win32 service daemon exit a pause # ----------------------------------------- my ($event, $context) = @_; &debug( 'Resuming the service' ); $context -> { last_state } = SERVICE_RUNNING; Win32::Daemon::State( SERVICE_RUNNING ); } # ==================================================================== +========== sub runService { # this is the callback of by the win32 service daemon # --------------------------------------------------- my ($event, $context) = @_; if ( Win32::Daemon::State() == SERVICE_RUNNING ) { # count the number of calls (I do not know why) $context -> { count }++; } } sub debug { my ($fmt, @data) = @_; my $message = sprintf $fmt, @data; open( FILE, ">>e:/dia/temp/service.log" ); print FILE "$message\n"; close( FILE ); if (-t STDOUT && -t STDIN) { print "$message\n"; } } # ==================================================================== +========== sub GetError { # returns win32 daemon errors # --------------------------- return( Win32::FormatMessage( Win32::Daemon::GetLastError() ) ); } # ==================================================================== +========== __END__
        Please excuse me as I am new to perl and still struggling to grasp some ideas and need your help. I tried running the above example it doesn't give any error and ran fine but everytime I try to run it from the commandline it executes the following:
        else { die "Nothing to do\n"; }
        and no service is created. Is there any parameter needs to pass while running the script. And what exactly is the following for:
        my %opt; GetOptions ( \%opt, "run", "install", "remove", "start", "stop", "restart", "pause", "resume|continue", );
        What exactly is GetOptions for. I tried to modify thie above scripty and put the following code in the else part:
        else { #die "Nothing to do\n"; &removeService(); &installService(); my $cmd = 'net start $serviceConfig{name}'; my $results = `$cmd`; if($!) { &debug("Net Start returned error: $@\n" . $results); die "ERROR"; } #don't know what is this for my %context = { last_state => SERVICE_STOPPED, count => 0, start_time => time(), }; Win32::Daemon::StartService( \%context, 3000 ); exit(); }
        now I run the script and service gets created and can start,stop,resume etc.. the service under services. I don't if it's the right way. Any comments will be really appeciated. Thanks
        Thank you for the example. I would propose a little modification.

        The code to make the call directory-independent could be improved using modules File::Basename and Cwd:

        use Cwd; use File::Basename; my $scriptPath = File::Basename::dirname($0); chdir($scriptPath) if $scriptPath; $scriptPath = Cwd::getcwd(); my $script = File::Basename::basename($0); my %serviceConfig = ( name => 'mytest', display => 'mytest', description => 'this is my test description', machine => '', path => $^X, parameters => qq{"$scriptPath/$script" --run}, start_type => SERVICE_AUTO_START, );
        The old code with sprintf did not work because you forgot to put the placeholders :)

        Thank you again,

        Flavio
        perl -ple'$_=reverse' <<<ti.xittelop@oivalf

        Don't fool yourself.
        can someone explain the purpose of the following and how is it being utilized in the code:
        parameters => ( sprintf '"e:/dia/temp/service.pl" --run', $scriptPath, $script ),
        start_type => SERVICE_AUTO_START,