win32-service 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +7 -0
- data/doc/daemon.txt +1 -1
- data/doc/service.txt +1 -3
- data/ext/win32/daemon.c +25 -21
- data/lib/win32/service.rb +87 -47
- data/test/tc_daemon.rb +1 -1
- data/test/tc_service.rb +1 -1
- metadata +6 -6
data/CHANGES
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 0.6.1 - 1-Jan-2008
|
2
|
+
* The Service.services method now handles the scenario where a particular
|
3
|
+
service may still exist, but its underlying registry entry has been deleted.
|
4
|
+
In this case, most ServiceInfo struct members are set to nil and a warning
|
5
|
+
is issued.
|
6
|
+
* RDoc updates.
|
7
|
+
|
1
8
|
== 0.6.0 - 25-Nov-2007
|
2
9
|
* The Service control class is now pure Ruby. The Daemon class is still C,
|
3
10
|
however. That may change in the future. This means the windows-pr
|
data/doc/daemon.txt
CHANGED
data/doc/service.txt
CHANGED
@@ -16,8 +16,6 @@
|
|
16
16
|
require "win32/service"
|
17
17
|
include Win32
|
18
18
|
|
19
|
-
s = Service.new("some_machine")
|
20
|
-
|
21
19
|
# Create a new service
|
22
20
|
Service.create('some_service', nil,
|
23
21
|
:service_type => Service::WIN32_OWN_PROCESS,
|
@@ -352,7 +350,7 @@ Service::ERROR_CRITICAL
|
|
352
350
|
Use RegisterServiceCtrlHandlerEx().
|
353
351
|
|
354
352
|
= Copyright
|
355
|
-
(C) 2003-
|
353
|
+
(C) 2003-2008, Daniel J. Berger, All Rights Reserved
|
356
354
|
|
357
355
|
= License
|
358
356
|
Ruby's
|
data/ext/win32/daemon.c
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
#include <malloc.h>
|
6
6
|
#include <tchar.h>
|
7
7
|
|
8
|
-
#define WIN32_SERVICE_VERSION "0.6.
|
8
|
+
#define WIN32_SERVICE_VERSION "0.6.1"
|
9
9
|
|
10
10
|
static VALUE cDaemonError;
|
11
11
|
|
@@ -482,15 +482,15 @@ static VALUE daemon_mainloop(VALUE self)
|
|
482
482
|
* of the service status constants, e.g. RUNNING, PAUSED, etc.
|
483
483
|
*
|
484
484
|
* This method is typically used within your service_main method to setup the
|
485
|
-
* loop.
|
485
|
+
* loop. For example:
|
486
486
|
*
|
487
|
-
*
|
488
|
-
*
|
489
|
-
*
|
490
|
-
*
|
491
|
-
*
|
492
|
-
*
|
493
|
-
*
|
487
|
+
* class MyDaemon < Daemon
|
488
|
+
* def service_main
|
489
|
+
* while state == RUNNING || state == PAUSED || state == IDLE
|
490
|
+
* # Your main loop here
|
491
|
+
* end
|
492
|
+
* end
|
493
|
+
* end
|
494
494
|
*
|
495
495
|
* See the Daemon#running? method for an abstraction of the above code.
|
496
496
|
*/
|
@@ -503,15 +503,15 @@ static VALUE daemon_state(VALUE self){
|
|
503
503
|
* status is either RUNNING, PAUSED or IDLE.
|
504
504
|
*
|
505
505
|
* This is typically used within your service_main method to setup the main
|
506
|
-
* loop.
|
506
|
+
* loop. For example:
|
507
507
|
*
|
508
|
-
*
|
509
|
-
*
|
510
|
-
*
|
511
|
-
*
|
508
|
+
* class MyDaemon < Daemon
|
509
|
+
* def service_main
|
510
|
+
* while running?
|
511
|
+
* # Your main loop here
|
512
|
+
* end
|
512
513
|
* end
|
513
514
|
* end
|
514
|
-
* end
|
515
515
|
*/
|
516
516
|
static VALUE daemon_is_running(VALUE self){
|
517
517
|
VALUE v_bool = Qfalse;
|
@@ -527,7 +527,7 @@ static VALUE daemon_is_running(VALUE self){
|
|
527
527
|
}
|
528
528
|
|
529
529
|
/*
|
530
|
-
* This is a shortcut for Daemon
|
530
|
+
* This is a shortcut for Daemon.new + Daemon#mainloop.
|
531
531
|
*/
|
532
532
|
static VALUE daemon_c_mainloop(VALUE klass){
|
533
533
|
VALUE v_args[1];
|
@@ -537,11 +537,15 @@ static VALUE daemon_c_mainloop(VALUE klass){
|
|
537
537
|
|
538
538
|
void Init_daemon()
|
539
539
|
{
|
540
|
-
|
540
|
+
/* The Win32 module serves as a namespace only. */
|
541
|
+
VALUE mWin32 = rb_define_module("Win32");
|
542
|
+
|
543
|
+
/* The Daemon class encapsulates a Windows service through the use
|
544
|
+
* of callback methods and a main loop.
|
545
|
+
*/
|
546
|
+
VALUE cDaemon = rb_define_class_under(mWin32, "Daemon", rb_cObject);
|
541
547
|
|
542
|
-
|
543
|
-
mWin32 = rb_define_module("Win32");
|
544
|
-
cDaemon = rb_define_class_under(mWin32, "Daemon", rb_cObject);
|
548
|
+
/* Error typically raised if something goes wrong with your daemon. */
|
545
549
|
cDaemonError = rb_define_class_under(cDaemon, "Error", rb_eStandardError);
|
546
550
|
|
547
551
|
rb_define_alloc_func(cDaemon, daemon_allocate);
|
@@ -556,7 +560,7 @@ void Init_daemon()
|
|
556
560
|
|
557
561
|
// Constants
|
558
562
|
|
559
|
-
/* 0.6.
|
563
|
+
/* 0.6.1: The version of this library */
|
560
564
|
rb_define_const(cDaemon, "VERSION", rb_str_new2(WIN32_SERVICE_VERSION));
|
561
565
|
|
562
566
|
/* Service has received a signal to resume but is not yet running */
|
data/lib/win32/service.rb
CHANGED
@@ -6,8 +6,15 @@ require 'windows/security'
|
|
6
6
|
require 'windows/msvcrt/string'
|
7
7
|
require 'windows/msvcrt/buffer'
|
8
8
|
|
9
|
+
# The Win32 module serves as a namespace only.
|
9
10
|
module Win32
|
11
|
+
|
12
|
+
# The Service class encapsulates services controller actions, such as
|
13
|
+
# creating, starting, configuring or deleting services.
|
10
14
|
class Service
|
15
|
+
|
16
|
+
# This is the error typically raised if one of the Service methods
|
17
|
+
# should fail for any reason.
|
11
18
|
class Error < StandardError; end
|
12
19
|
|
13
20
|
include Windows::Error
|
@@ -25,7 +32,7 @@ module Win32
|
|
25
32
|
extend Windows::MSVCRT::String
|
26
33
|
extend Windows::MSVCRT::Buffer
|
27
34
|
|
28
|
-
VERSION = '0.6.
|
35
|
+
VERSION = '0.6.1'
|
29
36
|
|
30
37
|
# SCM security and access rights
|
31
38
|
|
@@ -197,6 +204,7 @@ module Win32
|
|
197
204
|
# Run a command
|
198
205
|
ACTION_RUN_COMMAND = SC_ACTION_RUN_COMMAND
|
199
206
|
|
207
|
+
# :stopdoc: #
|
200
208
|
StatusStruct = Struct.new('ServiceStatus', :service_type,
|
201
209
|
:current_state, :controls_accepted, :win32_exit_code,
|
202
210
|
:service_specific_exit_code, :check_point, :wait_hint, :interactive,
|
@@ -216,6 +224,8 @@ module Win32
|
|
216
224
|
:description, :interactive, :pid, :service_flags, :reset_period,
|
217
225
|
:reboot_message, :command, :num_actions, :actions
|
218
226
|
)
|
227
|
+
|
228
|
+
# :startdoc: #
|
219
229
|
|
220
230
|
# Creates a new service with +service_name+ on +host+, or the local host
|
221
231
|
# if no host is specified. The +options+ parameter is a hash that can
|
@@ -242,7 +252,7 @@ module Win32
|
|
242
252
|
# Example:
|
243
253
|
#
|
244
254
|
# # Configure everything
|
245
|
-
# Service.
|
255
|
+
# Service.new('some_service', nil,
|
246
256
|
# :service_type => Service::WIN32_OWN_PROCESS,
|
247
257
|
# :description => 'A custom service I wrote just for fun',
|
248
258
|
# :start_type => Service::AUTO_START,
|
@@ -1084,59 +1094,81 @@ module Win32
|
|
1084
1094
|
|
1085
1095
|
config_buf = get_config_info(handle_scs)
|
1086
1096
|
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1097
|
+
if config_buf != ERROR_FILE_NOT_FOUND
|
1098
|
+
binary_path = 0.chr * 260
|
1099
|
+
strcpy(binary_path, config_buf[12,4].unpack('L').first)
|
1100
|
+
binary_path = binary_path.unpack('Z*')[0]
|
1090
1101
|
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1102
|
+
load_order = 0.chr * 260
|
1103
|
+
strcpy(load_order, config_buf[16,4].unpack('L').first)
|
1104
|
+
load_order = load_order.unpack('Z*')[0]
|
1094
1105
|
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1106
|
+
start_name = 0.chr * 260
|
1107
|
+
strcpy(start_name, config_buf[28,4].unpack('L').first)
|
1108
|
+
start_name = start_name.unpack('Z*')[0]
|
1098
1109
|
|
1099
|
-
|
1100
|
-
|
1110
|
+
start_type = get_start_type(config_buf[4,4].unpack('L').first)
|
1111
|
+
error_ctrl = get_error_control(config_buf[8,4].unpack('L').first)
|
1101
1112
|
|
1102
|
-
|
1113
|
+
tag_id = config_buf[20,4].unpack('L').first
|
1103
1114
|
|
1104
|
-
|
1115
|
+
deps = get_dependencies(config_buf[24,4].unpack('L').first)
|
1105
1116
|
|
1106
|
-
|
1107
|
-
|
1117
|
+
description = 0.chr * 1024
|
1118
|
+
buf = get_config2_info(handle_scs, SERVICE_CONFIG_DESCRIPTION)
|
1108
1119
|
|
1109
|
-
|
1110
|
-
|
1120
|
+
strcpy(description, buf[0,4].unpack('L').first)
|
1121
|
+
description = description.unpack('Z*')[0]
|
1122
|
+
else
|
1123
|
+
msg = "WARNING: The registry entry for the #{service_name} "
|
1124
|
+
msg += "service could not be found."
|
1125
|
+
warn msg
|
1126
|
+
|
1127
|
+
binary_path = nil
|
1128
|
+
load_order = nil
|
1129
|
+
start_name = nil
|
1130
|
+
start_type = nil
|
1131
|
+
error_ctrl = nil
|
1132
|
+
tag_id = nil
|
1133
|
+
deps = nil
|
1134
|
+
description = nil
|
1135
|
+
end
|
1111
1136
|
|
1112
1137
|
buf2 = get_config2_info(handle_scs, SERVICE_CONFIG_FAILURE_ACTIONS)
|
1113
1138
|
|
1114
|
-
|
1139
|
+
if buf2 != ERROR_FILE_NOT_FOUND
|
1140
|
+
reset_period = buf2[0,4].unpack('L').first
|
1115
1141
|
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1142
|
+
reboot_msg = 0.chr * 260
|
1143
|
+
strcpy(reboot_msg, buf2[4,4].unpack('L').first)
|
1144
|
+
reboot_msg = reboot_msg.unpack('Z*')[0]
|
1119
1145
|
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1146
|
+
command = 0.chr * 260
|
1147
|
+
strcpy(command, buf2[8,4].unpack('L').first)
|
1148
|
+
command = command.unpack('Z*')[0]
|
1123
1149
|
|
1124
|
-
|
1125
|
-
|
1150
|
+
num_actions = buf2[12,4].unpack('L').first
|
1151
|
+
actions = nil
|
1126
1152
|
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1153
|
+
if num_actions > 0
|
1154
|
+
action_ptr = buf2[16,4].unpack('L').first
|
1155
|
+
action_buf = [0,0].pack('LL') * num_actions
|
1156
|
+
memcpy(action_buf, action_ptr, action_buf.size)
|
1131
1157
|
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1158
|
+
i = 0
|
1159
|
+
actions = {}
|
1160
|
+
num_actions.times{ |n|
|
1161
|
+
action_type, delay = action_buf[i, 8].unpack('LL')
|
1162
|
+
action_type = get_action_type(action_type)
|
1163
|
+
actions[n+1] = {:action_type => action_type, :delay => delay}
|
1164
|
+
i += 8
|
1165
|
+
}
|
1166
|
+
end
|
1167
|
+
else
|
1168
|
+
reset_period = nil
|
1169
|
+
reboot_message = nil
|
1170
|
+
command = nil
|
1171
|
+
actions = nil
|
1140
1172
|
end
|
1141
1173
|
|
1142
1174
|
CloseServiceHandle(handle_scs)
|
@@ -1153,11 +1185,11 @@ module Win32
|
|
1153
1185
|
wait_hint,
|
1154
1186
|
binary_path,
|
1155
1187
|
start_type,
|
1156
|
-
|
1188
|
+
error_ctrl,
|
1157
1189
|
load_order,
|
1158
1190
|
tag_id,
|
1159
1191
|
start_name,
|
1160
|
-
|
1192
|
+
deps,
|
1161
1193
|
description,
|
1162
1194
|
interactive,
|
1163
1195
|
pid,
|
@@ -1316,7 +1348,10 @@ module Win32
|
|
1316
1348
|
end
|
1317
1349
|
end
|
1318
1350
|
|
1319
|
-
# Shortcut for QueryServiceConfig. Returns the buffer.
|
1351
|
+
# Shortcut for QueryServiceConfig. Returns the buffer. In rare cases
|
1352
|
+
# the underlying registry entry may have been deleted, but the service
|
1353
|
+
# still exists. In that case, the ERROR_FILE_NOT_FOUND value is returned
|
1354
|
+
# instead.
|
1320
1355
|
#
|
1321
1356
|
def self.get_config_info(handle)
|
1322
1357
|
bytes_needed = [0].pack('L')
|
@@ -1328,6 +1363,8 @@ module Win32
|
|
1328
1363
|
|
1329
1364
|
if !bool && err_num == ERROR_INSUFFICIENT_BUFFER
|
1330
1365
|
config_buf = 0.chr * bytes_needed.unpack('L').first
|
1366
|
+
elsif err_num == ERROR_FILE_NOT_FOUND
|
1367
|
+
return err_num
|
1331
1368
|
else
|
1332
1369
|
error = get_last_error(err_num)
|
1333
1370
|
CloseServiceHandle(handle)
|
@@ -1361,13 +1398,15 @@ module Win32
|
|
1361
1398
|
# First attempt at QueryServiceConfig2 is to get size needed
|
1362
1399
|
bool = QueryServiceConfig2(handle, info_level, 0, 0, bytes_needed)
|
1363
1400
|
|
1364
|
-
|
1401
|
+
err_num = GetLastError()
|
1365
1402
|
|
1366
|
-
if !bool &&
|
1403
|
+
if !bool && err_num == ERROR_INSUFFICIENT_BUFFER
|
1367
1404
|
config2_buf = 0.chr * bytes_needed.unpack('L').first
|
1405
|
+
elsif err_num == ERROR_FILE_NOT_FOUND
|
1406
|
+
return err_num
|
1368
1407
|
else
|
1369
1408
|
CloseServiceHandle(handle)
|
1370
|
-
raise Error,
|
1409
|
+
raise Error, get_last_error(err_num)
|
1371
1410
|
end
|
1372
1411
|
|
1373
1412
|
bytes_needed = [0].pack('L')
|
@@ -1382,8 +1421,9 @@ module Win32
|
|
1382
1421
|
)
|
1383
1422
|
|
1384
1423
|
unless bool
|
1424
|
+
error = GetLastError()
|
1385
1425
|
CloseServiceHandle(handle)
|
1386
|
-
raise Error, get_last_error
|
1426
|
+
raise Error, get_last_error(error)
|
1387
1427
|
end
|
1388
1428
|
|
1389
1429
|
config2_buf
|
data/test/tc_daemon.rb
CHANGED
data/test/tc_service.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: win32-service
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel J. Berger
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2008-01-01 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -35,18 +35,18 @@ extra_rdoc_files:
|
|
35
35
|
- doc/service.txt
|
36
36
|
- doc/daemon.txt
|
37
37
|
files:
|
38
|
+
- doc/daemon.txt
|
39
|
+
- doc/service.txt
|
38
40
|
- test/tc_daemon.rb
|
39
41
|
- test/tc_service.rb
|
40
42
|
- test/tc_service_create.rb
|
41
43
|
- test/tc_service_info.rb
|
42
44
|
- test/tc_service_status.rb
|
43
45
|
- lib/win32/service.rb
|
46
|
+
- ext/win32/daemon.c
|
44
47
|
- CHANGES
|
45
48
|
- README
|
46
49
|
- MANIFEST
|
47
|
-
- ext/win32/daemon.c
|
48
|
-
- doc/service.txt
|
49
|
-
- doc/daemon.txt
|
50
50
|
has_rdoc: true
|
51
51
|
homepage: http://www.rubyforge.org/projects/win32utils
|
52
52
|
post_install_message:
|
@@ -69,7 +69,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
69
69
|
requirements: []
|
70
70
|
|
71
71
|
rubyforge_project: win32utils
|
72
|
-
rubygems_version: 0.
|
72
|
+
rubygems_version: 1.0.1
|
73
73
|
signing_key:
|
74
74
|
specification_version: 2
|
75
75
|
summary: An library for controlling and creating MS Windows services
|