[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