[Win32utils-devel] win32-daemon 0.6.1 problem

Park Heesob phasis at gmail.com
Wed Nov 5 10:55:59 EST 2008


----- Original Message ----- 
From: "Berger, Daniel" <Daniel.Berger at qwest.com>
To: "Development and ideas for win32utils projects" 
<win32utils-devel at rubyforge.org>
Sent: Tuesday, November 04, 2008 1:23 AM
Subject: Re: [Win32utils-devel] win32-daemon 0.6.1 problem
>
> PS - Maybe it's time to revisit
> http://rubyforge.org/tracker/index.php?func=detail&aid=16627&group_id=85
> &atid=413, too.
>
Here is the new version using TCP protocal.
======================= start daemon0.rb =======================
require 'windows/service'
require 'windows/thread'
require 'windows/synchronize'
require 'windows/handle'
require 'windows/error'
require 'windows/msvcrt/buffer'
require 'windows/msvcrt/string'
require 'win32/api'
require 'socket'

include Windows::Service
include Windows::Thread
include Windows::Synchronize
include Windows::Handle
include Windows::Error
include Windows::MSVCRT::Buffer
include Windows::MSVCRT::String


# Wraps SetServiceStatus.
def set_the_service_statue(curr_state, exit_code, check_point, wait_hint)
  service_status = 0.chr * 28 # sizeof(SERVICE_STATUS)

  # Disable control requests until the service is started.
  if curr_state == SERVICE_START_PENDING
     val = 0
  else
     val = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN |
           SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN
  end
  service_status[8,4] = [val].pack('L')


  # Initialize service_status struct
  service_status[0,4]  = [SERVICE_WIN32_OWN_PROCESS].pack('L')
  service_status[4,4]  = [curr_state].pack('L')
  service_status[12,4] = [exit_code].pack('L')
  service_status[20,4] = [check_point].pack('L')
  service_status[24,4] = [wait_hint].pack('L')

  service_state = curr_state

  # Send status of the service to the Service Controller.
  unless SetServiceStatus(@status_handle, service_status)
     SetEvent(@stop_event)
  end

end

begin
 @end_event = OpenEvent(EVENT_ALL_ACCESS, 0, "end_event_#{ARGV[0]}")
 if @end_event == 0
            raise Error, get_last_error
        end
 @stop_event = OpenEvent(EVENT_ALL_ACCESS, 0, "stop_event_#{ARGV[0]}")
 if @stop_event == 0
            raise Error, get_last_error
        end
 @pause_event = OpenEvent(EVENT_ALL_ACCESS, 0, "pause_event_#{ARGV[0]}")
 if @pause_event == 0
            raise Error, get_last_error
        end
 @resume_event = OpenEvent(EVENT_ALL_ACCESS, 0, "resume_event_#{ARGV[0]}")
 if @resume_event == 0
            raise Error, get_last_error
        end


 service_ctrl = Win32::API::Callback.new('L', 'V') do |ctrl_code|
   state = SERVICE_RUNNING

   case ctrl_code
      when SERVICE_CONTROL_STOP
         state = SERVICE_STOP_PENDING
      when SERVICE_CONTROL_PAUSE
         state = SERVICE_PAUSED
         SetEvent(@pause_event)
      when SERVICE_CONTROL_CONTINUE
         state = SERVICE_RUNNING
         SetEvent(@resume_event)
   end

   # Set the status of the service.
   set_the_service_statue(state, NO_ERROR, 0, 0)

   # Tell service_main thread to stop.
   if [SERVICE_CONTROL_STOP].include?(ctrl_code)
              wait_result = WaitForSingleObject(@end_event, INFINITE)
          if wait_result != WAIT_OBJECT_0
              set_the_service_statue(SERVICE_STOPPED,GetLastError(),0,0)
   else
       set_the_service_statue(SERVICE_STOPPED,NO_ERROR,0,0)
   end
           SetEvent(@stop_event)
           sleep 3
   end

 end

 svc_main = Win32::API::Callback.new('LL', 'I') do |argc, lpszargv|
   argv = []
   argc.times do |i|
     ptr = 0.chr * 4
     buf = 0.chr * 256
     memcpy(ptr,lpszargv+i*4,4)
     strcpy(buf,ptr.unpack('L').first)
     argv << buf.strip
   end
   service_name = argv[0]

   s = TCPSocket.open('127.0.0.1', ARGV[0])
   s.write(argv.join(';'))
   s.close

   # Register the service ctrl handler.
   @status_handle = RegisterServiceCtrlHandler(
      service_name,service_ctrl
   )
   # No service to stop, no service handle to notify, nothing to do
   # but exit at this point.
   return false if @status_handle == 0

   #The service has started.
   set_the_service_statue(SERVICE_RUNNING, NO_ERROR, 0, 0)

   true

 end


 dispatch_table = [""].pack('p') + [svc_main.address].pack('L') + "\0"*8

 if(!StartServiceCtrlDispatcher(dispatch_table))
  File.open("c:\\test.txt","a+") {|f|
    f.puts("StartServiceCtrlDispatcher Fail")
  }
 end

rescue Exception => err
         File.open("c:\\test.txt","a+") {|f|
     f.puts(err.inspect)
  }
end
======================= end daemon0.rb =======================


======================= start daemon.rb =======================
require 'windows/service'
require 'windows/thread'
require 'windows/synchronize'
require 'windows/handle'
require 'windows/error'
require 'windows/msvcrt/buffer'
require 'windows/msvcrt/string'
require 'win32/api'
require 'win32/process'
require 'win32/service'
require 'socket'

module Win32
   class Daemon
      class Error < StandardError; end

      include Windows::Service
      include Windows::Thread
      include Windows::Synchronize
      include Windows::Handle
      include Windows::Error
      include Windows::MSVCRT::Buffer
      include Windows::MSVCRT::String

      VERSION = '0.6.1'

      # The Daemon has received a resume signal, but is not yet running
      CONTINUE_PENDING = 0x00000005

      # The Daemon is in an idle state
      IDLE = 0

      # The Daemon is stopped, i.e. not running
      STOPPED = 0x00000001

      # The Daemon has received a start signal, but is not yet running
      START_PENDING = 0x00000002

      # The Daemon has received a sto signal but is not yet stopped.
      STOP_PENDING = 0x00000003

      # The Daemon is running normally
      RUNNING = 0x00000004

      # The Daemon has received a pause signal, but is not yet paused
      PAUSE_PENDING = 0x00000006

      # The Daemon is in a paused state
      PAUSED = 0x00000007

      # The current state of the service, e.g. RUNNING, PAUSED, etc.
      attr_reader :state

      def mainloop
        gs = TCPserver.open(0)
       @end_event = CreateEvent(0, 0, 0, "end_event_#{gs.addr[1]}")
 if @end_event == 0
            raise Error, get_last_error
        end
       @stop_event = CreateEvent(0, 0, 0, "stop_event_#{gs.addr[1]}")
 if @stop_event == 0
            raise Error, get_last_error
        end
       @pause_event = CreateEvent(0, 0, 0, "pause_event_#{gs.addr[1]}")
 if @pause_event == 0
            raise Error, get_last_error
        end
       @resume_event = CreateEvent(0, 0, 0, "resume_event_#{gs.addr[1]}")
 if @resume_event == 0
            raise Error, get_last_error
        end

        service_init() if defined?(service_init)

        ruby = File.join(CONFIG['bindir'], 'ruby ').tr('/', '\\')
        path = File.dirname(__FILE__) + "//daemon0.rb #{gs.addr[1]}"

        Process.create(
    :app_name         => ruby + path,
       :creation_flags   => Process::CREATE_NO_WINDOW
        )

 nsock = select([gs])
 s = gs.accept
 data = s.gets
 s.close

        data = data || ''
 argv = data.split(';')
 @service_name = argv[0]

 handles = [@stop_event, at pause_event, at resume_event]

 t = Thread.new {
  while(true) do
   wait = WaitForMultipleObjects(
           handles.size,
           handles.pack('L*'),
           0,
           10
         )
   if wait >= WAIT_OBJECT_0 && wait <= WAIT_OBJECT_0 + handles.size - 1
    index = wait - WAIT_OBJECT_0
    case handles[index]
    when @stop_event
     service_stop() if defined?(service_stop)
     return
    when @pause_event
     service_pause() if defined?(service_pause)
    when @resume_event
     service_resume() if defined?(service_resume)
    end
   end
  end
 }

        service_main(argv) if defined?(service_main)
 SetEvent(@end_event)
 t.join
      end

      def running?
        true if [RUNNING,START_PENDING].include?(state)
      end

      def state
         case Win32::Service.status(@service_name).current_state
    when 'running'
     return RUNNING
    when 'start pending'
         return START_PENDING
    when 'stopped'
         return STOPPED
    when 'paused'
         return PAUSED
  end
  return 0
      end

      # Shortcut for Daemon.new#mainloop
      def self.mainloop
         new.mainloop
      end

   end
end
======================= end daemon.rb =======================

Regards,

Park Heesob 




More information about the win32utils-devel mailing list