win32-service 0.7.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
metadata CHANGED
@@ -1,78 +1,75 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: win32-service
3
- version: !ruby/object:Gem::Version
4
- hash: 7
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.0
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 7
9
- - 2
10
- version: 0.7.2
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Daniel J. Berger
14
9
  - Park Heesob
15
10
  autorequire:
16
11
  bindir: bin
17
12
  cert_chain: []
18
-
19
- date: 2011-09-07 00:00:00 Z
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
22
- name: windows-pr
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
13
+ date: 2013-06-20 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ffi
17
+ requirement: !ruby/object:Gem::Requirement
25
18
  none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 7
30
- segments:
31
- - 1
32
- - 0
33
- - 8
34
- version: 1.0.8
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
35
23
  type: :runtime
36
- version_requirements: *id001
37
- - !ruby/object:Gem::Dependency
38
- name: test-unit
39
24
  prerelease: false
40
- requirement: &id002 !ruby/object:Gem::Requirement
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: test-unit
33
+ requirement: !ruby/object:Gem::Requirement
41
34
  none: false
42
- requirements:
43
- - - ">="
44
- - !ruby/object:Gem::Version
45
- hash: 11
46
- segments:
47
- - 2
48
- - 1
49
- - 0
50
- version: 2.1.0
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: 2.4.0
51
39
  type: :development
52
- version_requirements: *id002
53
- description: " The win32-service library provides a Ruby interface to services on\n MS Windows. You can create new services, or control, configure and\n inspect existing services.\n\n In addition, you can create a pure Ruby service by using the Daemon\n class that is included as part of the library.\n"
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: 2.4.0
47
+ description: ! " The win32-service library provides a Ruby interface to services
48
+ on\n MS Windows. You can create new services, or control, configure and\n inspect
49
+ existing services.\n\n In addition, you can create a pure Ruby service by using
50
+ the Daemon\n class that is included as part of the library.\n"
54
51
  email: djberg96@gmail.com
55
52
  executables: []
56
-
57
- extensions:
58
- - ext/extconf.rb
59
- extra_rdoc_files:
53
+ extensions: []
54
+ extra_rdoc_files:
60
55
  - CHANGES
61
56
  - README
62
57
  - MANIFEST
63
58
  - doc/service.txt
64
59
  - doc/daemon.txt
65
- - ext/win32/daemon.c
66
- files:
60
+ files:
67
61
  - CHANGES
68
62
  - doc/daemon.txt
69
63
  - doc/service.txt
70
64
  - examples/demo_daemon.rb
71
65
  - examples/demo_daemon_ctl.rb
72
66
  - examples/demo_services.rb
73
- - ext/extconf.rb
74
- - ext/win32/daemon.c
67
+ - lib/win32/daemon.rb
75
68
  - lib/win32/service.rb
69
+ - lib/win32/windows/constants.rb
70
+ - lib/win32/windows/functions.rb
71
+ - lib/win32/windows/helper.rb
72
+ - lib/win32/windows/structs.rb
76
73
  - MANIFEST
77
74
  - Rakefile
78
75
  - README
@@ -83,42 +80,32 @@ files:
83
80
  - test/test_win32_service_info.rb
84
81
  - test/test_win32_service_status.rb
85
82
  - win32-service.gemspec
86
- homepage: http://www.rubyforge.org/projects/win32utils
87
- licenses:
83
+ homepage: http://github.com/djberg96/win32-service
84
+ licenses:
88
85
  - Artistic 2.0
89
86
  post_install_message:
90
87
  rdoc_options: []
91
-
92
- require_paths:
88
+ require_paths:
93
89
  - lib
94
- required_ruby_version: !ruby/object:Gem::Requirement
90
+ required_ruby_version: !ruby/object:Gem::Requirement
95
91
  none: false
96
- requirements:
97
- - - ">="
98
- - !ruby/object:Gem::Version
99
- hash: 51
100
- segments:
101
- - 1
102
- - 8
103
- - 2
104
- version: 1.8.2
105
- required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
97
  none: false
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- hash: 3
111
- segments:
112
- - 0
113
- version: "0"
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
114
102
  requirements: []
115
-
116
- rubyforge_project: win32utils
117
- rubygems_version: 1.8.10
103
+ rubyforge_project:
104
+ rubygems_version: 1.8.24
118
105
  signing_key:
119
106
  specification_version: 3
120
107
  summary: An interface for MS Windows services
121
- test_files:
108
+ test_files:
122
109
  - test/test_win32_daemon.rb
123
110
  - test/test_win32_service.rb
124
111
  - test/test_win32_service_configure.rb
data/ext/extconf.rb DELETED
@@ -1,9 +0,0 @@
1
- require 'mkmf'
2
-
3
- dir_config('win32-daemon')
4
- dir_config('seh')
5
-
6
- have_func('RegisterServiceCtrlHandlerEx')
7
- have_header('seh.h')
8
-
9
- create_makefile('win32/daemon', 'win32')
data/ext/win32/daemon.c DELETED
@@ -1,612 +0,0 @@
1
- #include "ruby.h"
2
- #include <windows.h>
3
- #include <string.h>
4
- #include <stdlib.h>
5
- #include <malloc.h>
6
- #include <tchar.h>
7
-
8
- #ifdef HAVE_SEH_H
9
- #include <seh.h>
10
- #endif
11
-
12
- #define WIN32_SERVICE_VERSION "0.7.2"
13
-
14
- // Ruby 1.9.x
15
- #ifndef RSTRING_PTR
16
- #define RSTRING_PTR(s) (RSTRING(s)->ptr)
17
- #endif
18
- #ifndef RSTRING_LEN
19
- #define RSTRING_LEN(s) (RSTRING(s)->len)
20
- #endif
21
-
22
- #ifndef RARRAY_PTR
23
- #define RARRAY_PTR(a) (RARRAY(a)->ptr)
24
- #endif
25
- #ifndef RARRAY_LEN
26
- #define RARRAY_LEN(a) (RARRAY(a)->len)
27
- #endif
28
-
29
- static VALUE cDaemonError;
30
-
31
- static HANDLE hThread;
32
- static HANDLE hStartEvent;
33
- static HANDLE hStopEvent;
34
- static HANDLE hStopCompletedEvent;
35
- static SERVICE_STATUS_HANDLE ssh;
36
- static DWORD dwServiceState;
37
- static TCHAR error[1024];
38
- static int Argc;
39
- static VALUE* Argv;
40
-
41
- CRITICAL_SECTION csControlCode;
42
- // I happen to know from looking in the header file
43
- // that 0 is not a valid service control code
44
- // so we will use it, the value does not matter
45
- // as long as it will never show up in ServiceCtrl
46
- // - Patrick Hurley
47
- #define IDLE_CONTROL_CODE 0
48
- static int waiting_control_code = IDLE_CONTROL_CODE;
49
-
50
- static VALUE service_close(VALUE);
51
- void WINAPI Service_Main(DWORD dwArgc, LPTSTR *lpszArgv);
52
- void WINAPI Service_Ctrl(DWORD dwCtrlCode);
53
- void SetTheServiceStatus(DWORD dwCurrentState,DWORD dwWin32ExitCode,
54
- DWORD dwCheckPoint, DWORD dwWaitHint);
55
-
56
- // Return an error code as a string
57
- LPTSTR ErrorDescription(DWORD p_dwError)
58
- {
59
- HLOCAL hLocal = NULL;
60
- static TCHAR ErrStr[1024];
61
- int len;
62
-
63
- if (!(len=FormatMessage(
64
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
65
- FORMAT_MESSAGE_FROM_SYSTEM |
66
- FORMAT_MESSAGE_IGNORE_INSERTS,
67
- NULL,
68
- p_dwError,
69
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
70
- (LPTSTR)&hLocal,
71
- 0,
72
- NULL)))
73
- {
74
- rb_raise(rb_eStandardError, "unable to format error message");
75
- }
76
- memset(ErrStr, 0, sizeof(ErrStr));
77
- strncpy(ErrStr, (LPTSTR)hLocal, len-2); // remove \r\n
78
- LocalFree(hLocal);
79
- return ErrStr;
80
- }
81
-
82
- // Called by the service control manager after the call to
83
- // StartServiceCtrlDispatcher.
84
- void WINAPI Service_Main(DWORD dwArgc, LPTSTR *lpszArgv)
85
- {
86
- // Obtain the name of the service.
87
- LPTSTR lpszServiceName = lpszArgv[0];
88
-
89
- // Args passed to Service.start
90
- if(dwArgc > 1){
91
- unsigned int i;
92
- Argc = dwArgc - 1;
93
- Argv = malloc(sizeof(VALUE)*Argc);
94
-
95
- for(i=1; i < dwArgc; i++)
96
- Argv[i-1] = rb_str_new2(lpszArgv[i]);
97
- }
98
-
99
- // Register the service ctrl handler.
100
- ssh = RegisterServiceCtrlHandler(
101
- lpszServiceName,
102
- (LPHANDLER_FUNCTION)Service_Ctrl
103
- );
104
-
105
- // no service to stop, no service handle to notify, nothing to do but exit
106
- if(ssh == (SERVICE_STATUS_HANDLE)0)
107
- return;
108
-
109
- // The service has started.
110
- SetTheServiceStatus(SERVICE_RUNNING, NO_ERROR, 0, 0);
111
-
112
- SetEvent(hStartEvent);
113
-
114
- // Main loop for the service.
115
- while(WaitForSingleObject(hStopEvent, 1000) != WAIT_OBJECT_0)
116
- {
117
- }
118
-
119
- // Main loop for the service.
120
- while(WaitForSingleObject(hStopCompletedEvent, 1000) != WAIT_OBJECT_0)
121
- {
122
- }
123
-
124
- // Stop the service.
125
- SetTheServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0);
126
- }
127
-
128
- VALUE Service_Event_Dispatch(VALUE val)
129
- {
130
- VALUE func,self;
131
- VALUE result = Qnil;
132
-
133
- if(val!=Qnil) {
134
- self = RARRAY_PTR(val)[0];
135
- func = NUM2INT(RARRAY_PTR(val)[1]);
136
-
137
- result = rb_funcall(self,func,0);
138
- }
139
-
140
- return result;
141
- }
142
-
143
- VALUE Ruby_Service_Ctrl(VALUE self){
144
- while(WaitForSingleObject(hStopEvent,0) == WAIT_TIMEOUT){
145
- #if !defined(__GNUC__) || defined(HAVE_SEH_H)
146
- __try{
147
- #endif
148
- EnterCriticalSection(&csControlCode);
149
-
150
- // Check to see if anything interesting has been signaled
151
- if(waiting_control_code != IDLE_CONTROL_CODE){
152
- if(waiting_control_code != SERVICE_CONTROL_STOP){
153
- // If there is a code, create a ruby thread to deal with it
154
- // this might be over engineering the solution, but I don't
155
- // want to block Service_Ctrl longer than necessary and the
156
- // critical section will block it.
157
- VALUE EventHookHash = rb_ivar_get(self, rb_intern("@event_hooks"));
158
-
159
- if(EventHookHash != Qnil){
160
- VALUE val = rb_hash_aref(
161
- EventHookHash,
162
- INT2NUM(waiting_control_code)
163
- );
164
-
165
- if(val != Qnil)
166
- rb_thread_create(Service_Event_Dispatch, (void*) val);
167
- }
168
- }
169
- else{
170
- break;
171
- }
172
-
173
- waiting_control_code = IDLE_CONTROL_CODE;
174
- }
175
- #if !defined(__GNUC__) || defined(HAVE_SEH_H)
176
- }
177
- __finally {
178
- #endif
179
- LeaveCriticalSection(&csControlCode);
180
- #if !defined(__GNUC__) || defined(HAVE_SEH_H)
181
- }
182
- #endif
183
- // This is an ugly polling loop, be as polite as possible
184
- rb_thread_polling();
185
- }
186
-
187
- // Force service_stop call
188
- {
189
- VALUE EventHookHash = rb_ivar_get(self, rb_intern("@event_hooks"));
190
-
191
- if(EventHookHash != Qnil){
192
- VALUE val = rb_hash_aref(EventHookHash, INT2NUM(SERVICE_CONTROL_STOP));
193
-
194
- if(val!=Qnil)
195
- rb_thread_create(Service_Event_Dispatch, (void*) val);
196
- }
197
- }
198
-
199
- return Qnil;
200
- }
201
-
202
- // Handles control signals from the service control manager.
203
- void WINAPI Service_Ctrl(DWORD dwCtrlCode)
204
- {
205
- DWORD dwState = SERVICE_RUNNING;
206
-
207
- #if !defined(__GNUC__) || defined(HAVE_SEH_H)
208
- __try{
209
- #endif
210
- EnterCriticalSection(&csControlCode);
211
- waiting_control_code = dwCtrlCode;
212
- #if !defined(__GNUC__) || defined(HAVE_SEH_H)
213
- }
214
- __finally{
215
- #endif
216
- LeaveCriticalSection(&csControlCode);
217
- #if !defined(__GNUC__) || defined(HAVE_SEH_H)
218
- }
219
- #endif
220
-
221
- switch(dwCtrlCode)
222
- {
223
- case SERVICE_CONTROL_STOP:
224
- dwState = SERVICE_STOP_PENDING;
225
- break;
226
- case SERVICE_CONTROL_SHUTDOWN:
227
- dwState = SERVICE_STOP_PENDING;
228
- break;
229
- case SERVICE_CONTROL_PAUSE:
230
- dwState = SERVICE_PAUSED;
231
- break;
232
- case SERVICE_CONTROL_CONTINUE:
233
- dwState = SERVICE_RUNNING;
234
- break;
235
- case SERVICE_CONTROL_INTERROGATE:
236
- break;
237
- default:
238
- break;
239
- }
240
-
241
- // Set the status of the service.
242
- SetTheServiceStatus(dwState, NO_ERROR, 0, 0);
243
-
244
- // Tell service_main thread to stop.
245
- if ((dwCtrlCode == SERVICE_CONTROL_STOP) ||
246
- (dwCtrlCode == SERVICE_CONTROL_SHUTDOWN))
247
- {
248
- if(!SetEvent(hStopEvent))
249
- SetTheServiceStatus(SERVICE_STOPPED, GetLastError(), 0, 0);
250
- }
251
- }
252
-
253
- // Wraps SetServiceStatus.
254
- void SetTheServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
255
- DWORD dwCheckPoint, DWORD dwWaitHint)
256
- {
257
- SERVICE_STATUS ss; // Current status of the service.
258
-
259
- // Disable control requests until the service is started.
260
- if(dwCurrentState == SERVICE_START_PENDING){
261
- ss.dwControlsAccepted = 0;
262
- }
263
- else{
264
- ss.dwControlsAccepted =
265
- SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN|
266
- SERVICE_ACCEPT_PAUSE_CONTINUE|SERVICE_ACCEPT_SHUTDOWN;
267
- }
268
-
269
- // Initialize ss structure.
270
- ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
271
- ss.dwServiceSpecificExitCode = 0;
272
- ss.dwCurrentState = dwCurrentState;
273
- ss.dwWin32ExitCode = dwWin32ExitCode;
274
- ss.dwCheckPoint = dwCheckPoint;
275
- ss.dwWaitHint = dwWaitHint;
276
-
277
- dwServiceState = dwCurrentState;
278
-
279
- // Send status of the service to the Service Controller.
280
- if(!SetServiceStatus(ssh, &ss))
281
- SetEvent(hStopEvent);
282
- }
283
-
284
- DWORD WINAPI ThreadProc(LPVOID lpParameter){
285
- SERVICE_TABLE_ENTRY ste[] =
286
- {{TEXT(""),(LPSERVICE_MAIN_FUNCTION)Service_Main}, {NULL, NULL}};
287
-
288
- // No service to step, no service handle, no ruby exceptions, just
289
- // terminate the thread.
290
- if(!StartServiceCtrlDispatcher(ste))
291
- return 1;
292
-
293
- return 0;
294
- }
295
-
296
- static VALUE daemon_allocate(VALUE klass){
297
- return Data_Wrap_Struct(klass, 0, 0, 0);
298
- }
299
-
300
- // Call service_main method
301
- static VALUE daemon_mainloop_protect(VALUE self)
302
- {
303
- if(rb_respond_to(self,rb_intern("service_main"))){
304
- if(Argc == 0)
305
- rb_funcall(self, rb_intern("service_main"), 0);
306
- else
307
- rb_funcall2(self, rb_intern("service_main"), Argc, Argv);
308
- }
309
-
310
- return self;
311
- }
312
-
313
- static VALUE daemon_mainloop_ensure(VALUE self)
314
- {
315
- int i;
316
-
317
- // Signal both the ruby thread and service_main thread to terminate
318
- SetEvent(hStopEvent);
319
-
320
- // Wait for ALL ruby threads to exit
321
- for(i=1; TRUE; i++)
322
- {
323
- VALUE list = rb_funcall(rb_cThread, rb_intern("list"), 0);
324
-
325
- if(RARRAY_LEN(list) <= 1)
326
- break;
327
-
328
- // This is another ugly polling loop, be as polite as possible
329
- rb_thread_polling();
330
-
331
- SetTheServiceStatus(SERVICE_STOP_PENDING, 0, i, 1000);
332
- }
333
-
334
- // Only one ruby thread
335
- SetEvent(hStopCompletedEvent);
336
-
337
- // Wait for the thread to stop BEFORE we close the hStopEvent handle
338
- WaitForSingleObject(hThread, INFINITE);
339
-
340
- // Close the event handle, ignoring failures. We may be cleaning up
341
- // after an exception, so let that exception fall through.
342
- CloseHandle(hStopEvent);
343
-
344
- return self;
345
- }
346
-
347
- /*
348
- * This is the method that actually puts your code into a loop and allows it
349
- * to run as a service. The code that is actually run while in the mainloop
350
- * is what you defined in your own Daemon#service_main method.
351
- */
352
- static VALUE daemon_mainloop(VALUE self)
353
- {
354
- DWORD ThreadId;
355
- HANDLE events[2];
356
- DWORD index;
357
- VALUE result, EventHookHash;
358
- int status = 0;
359
-
360
- dwServiceState = 0;
361
-
362
- // Redirect STDIN, STDOUT and STDERR to the NUL device if they're still
363
- // associated with a tty. This helps newbs avoid Errno::EBADF errors.
364
- if(rb_funcall(rb_stdin, rb_intern("isatty"), 0) == Qtrue)
365
- rb_funcall(rb_stdin, rb_intern("reopen"), 1, rb_str_new2("NUL"));
366
-
367
- if(rb_funcall(rb_stdout, rb_intern("isatty"), 0) == Qtrue)
368
- rb_funcall(rb_stdout, rb_intern("reopen"), 1, rb_str_new2("NUL"));
369
-
370
- if(rb_funcall(rb_stderr, rb_intern("isatty"), 0) == Qtrue)
371
- rb_funcall(rb_stderr, rb_intern("reopen"), 1, rb_str_new2("NUL"));
372
-
373
- // Use a markable instance variable to prevent the garbage collector
374
- // from freeing the hash before Ruby_Service_Ctrl exits, or just
375
- // at any ole time while running the service
376
- EventHookHash = rb_hash_new();
377
- rb_ivar_set(self, rb_intern("@event_hooks"), EventHookHash);
378
-
379
- // Event hooks
380
- if(rb_respond_to(self, rb_intern("service_stop"))){
381
- rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_STOP),
382
- rb_ary_new3(2, self, INT2NUM(rb_intern("service_stop"))));
383
- }
384
-
385
- if(rb_respond_to(self, rb_intern("service_pause"))){
386
- rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_PAUSE),
387
- rb_ary_new3(2, self, INT2NUM(rb_intern("service_pause"))));
388
- }
389
-
390
- if(rb_respond_to(self, rb_intern("service_resume"))){
391
- rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_CONTINUE),
392
- rb_ary_new3(2, self, INT2NUM(rb_intern("service_resume"))));
393
- }
394
-
395
- if(rb_respond_to(self, rb_intern("service_interrogate"))){
396
- rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_INTERROGATE),
397
- rb_ary_new3(2, self, INT2NUM(rb_intern("service_interrogate"))));
398
- }
399
-
400
- if(rb_respond_to(self, rb_intern("service_shutdown"))){
401
- rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_SHUTDOWN),
402
- rb_ary_new3(2, self, INT2NUM(rb_intern("service_shutdown"))));
403
- }
404
-
405
- #ifdef SERVICE_CONTROL_PARAMCHANGE
406
- if(rb_respond_to(self, rb_intern("service_paramchange"))){
407
- rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_PARAMCHANGE),
408
- rb_ary_new3(2, self, INT2NUM(rb_intern("service_paramchange"))));
409
- }
410
- #endif
411
-
412
- #ifdef SERVICE_CONTROL_NETBINDADD
413
- if(rb_respond_to(self, rb_intern("service_netbindadd"))){
414
- rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_NETBINDADD),
415
- rb_ary_new3(2, self, INT2NUM(rb_intern("service_netbindadd"))));
416
- }
417
- #endif
418
-
419
- #ifdef SERVICE_CONTROL_NETBINDREMOVE
420
- if(rb_respond_to(self, rb_intern("service_netbindremove"))){
421
- rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_NETBINDREMOVE),
422
- rb_ary_new3(2, self, INT2NUM(rb_intern("service_netbindremove"))));
423
- }
424
- #endif
425
-
426
- #ifdef SERVICE_CONTROL_NETBINDENABLE
427
- if(rb_respond_to(self, rb_intern("service_netbindenable"))){
428
- rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_NETBINDENABLE),
429
- rb_ary_new3(2, self, INT2NUM(rb_intern("service_netbindenable"))));
430
- }
431
- #endif
432
-
433
- #ifdef SERVICE_CONTROL_NETBINDDISABLE
434
- if(rb_respond_to(self, rb_intern("service_netbinddisable"))){
435
- rb_hash_aset(EventHookHash, INT2NUM(SERVICE_CONTROL_NETBINDDISABLE),
436
- rb_ary_new3(2, self, INT2NUM(rb_intern("service_netbinddisable"))));
437
- }
438
- #endif
439
-
440
- // Calling init here so that init failures never even tries to
441
- // start the service... of course that means that init methods
442
- // must be very quick, because the SCM will be receiving no
443
- // START_PENDING messages while init's running - I may fix this
444
- // later
445
- if(rb_respond_to(self, rb_intern("service_init")))
446
- rb_funcall(self, rb_intern("service_init"),0);
447
-
448
- // Create the event to signal the service to start.
449
- hStartEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
450
-
451
- if(hStartEvent == NULL)
452
- rb_raise(cDaemonError, ErrorDescription(GetLastError()));
453
-
454
- // Create the event to signal the service to stop.
455
- hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
456
-
457
- if(hStopEvent == NULL)
458
- rb_raise(cDaemonError, ErrorDescription(GetLastError()));
459
-
460
- // Create the event to signal the service that stop has completed
461
- hStopCompletedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
462
-
463
- if(hStopCompletedEvent == NULL)
464
- rb_raise(cDaemonError, ErrorDescription(GetLastError()));
465
-
466
- // Create Thread for service main
467
- hThread = CreateThread(NULL, 0, ThreadProc, 0, 0, &ThreadId);
468
-
469
- if(hThread == INVALID_HANDLE_VALUE)
470
- rb_raise(cDaemonError, ErrorDescription(GetLastError()));
471
-
472
- events[0] = hThread;
473
- events[1] = hStartEvent;
474
-
475
- // wait for Service_Main function to either start the service OR terminate
476
- while((index = WaitForMultipleObjects(2,events,FALSE,1000)) == WAIT_TIMEOUT)
477
- {
478
- }
479
-
480
- // thread exited, so the show is off
481
- if(index == WAIT_OBJECT_0)
482
- rb_raise(cDaemonError, "Service_Main thread exited abnormally");
483
-
484
- // from this point onward, stopevent must be triggered!
485
-
486
- // Create the green thread to poll for Service_Ctrl events
487
- rb_thread_create(Ruby_Service_Ctrl, (void *)self);
488
-
489
- result = rb_protect(daemon_mainloop_protect, self, &status);
490
-
491
- // service_main raised an exception
492
- if(status){
493
- daemon_mainloop_ensure(self);
494
- rb_jump_tag(status);
495
- }
496
-
497
- // service_main exited cleanly
498
- return daemon_mainloop_ensure(self);
499
- }
500
-
501
- /*
502
- * Returns the state of the service (as an constant integer) which can be any
503
- * of the service status constants, e.g. RUNNING, PAUSED, etc.
504
- *
505
- * This method is typically used within your service_main method to setup the
506
- * loop. For example:
507
- *
508
- * class MyDaemon < Daemon
509
- * def service_main
510
- * while state == RUNNING || state == PAUSED || state == IDLE
511
- * # Your main loop here
512
- * end
513
- * end
514
- * end
515
- *
516
- * See the Daemon#running? method for an abstraction of the above code.
517
- */
518
- static VALUE daemon_state(VALUE self){
519
- return UINT2NUM(dwServiceState);
520
- }
521
-
522
- /*
523
- * Returns whether or not the service is in a running state, i.e. the service
524
- * status is either RUNNING, PAUSED or IDLE.
525
- *
526
- * This is typically used within your service_main method to setup the main
527
- * loop. For example:
528
- *
529
- * class MyDaemon < Daemon
530
- * def service_main
531
- * while running?
532
- * # Your main loop here
533
- * end
534
- * end
535
- * end
536
- */
537
- static VALUE daemon_is_running(VALUE self){
538
- VALUE v_bool = Qfalse;
539
-
540
- if(
541
- (dwServiceState == SERVICE_RUNNING) ||
542
- (dwServiceState == SERVICE_PAUSED) ||
543
- (dwServiceState == 0)
544
- ){
545
- v_bool = Qtrue;
546
- }
547
-
548
- return v_bool;
549
- }
550
-
551
- /*
552
- * This is a shortcut for Daemon.new + Daemon#mainloop.
553
- */
554
- static VALUE daemon_c_mainloop(VALUE klass){
555
- VALUE v_args[1];
556
- VALUE v_daemon = rb_class_new_instance(0, v_args, klass);
557
- return rb_funcall(v_daemon, rb_intern("mainloop"), 0, 0);
558
- }
559
-
560
- void Init_daemon()
561
- {
562
- /* The Win32 module serves as a namespace only. */
563
- VALUE mWin32 = rb_define_module("Win32");
564
-
565
- /* The Daemon class encapsulates a Windows service through the use
566
- * of callback methods and a main loop.
567
- */
568
- VALUE cDaemon = rb_define_class_under(mWin32, "Daemon", rb_cObject);
569
-
570
- /* Error typically raised if something goes wrong with your daemon. */
571
- cDaemonError = rb_define_class_under(cDaemon, "Error", rb_eStandardError);
572
-
573
- rb_define_alloc_func(cDaemon, daemon_allocate);
574
- rb_define_method(cDaemon, "mainloop", daemon_mainloop, 0);
575
- rb_define_method(cDaemon, "state", daemon_state, 0);
576
- rb_define_method(cDaemon, "running?", daemon_is_running, 0);
577
-
578
- rb_define_singleton_method(cDaemon, "mainloop", daemon_c_mainloop, 0);
579
-
580
- // Intialize critical section used by green polling thread
581
- InitializeCriticalSection(&csControlCode);
582
-
583
- // Constants
584
-
585
- /* 0.7.2: The version of this library */
586
- rb_define_const(cDaemon, "VERSION", rb_str_new2(WIN32_SERVICE_VERSION));
587
-
588
- /* Service has received a signal to resume but is not yet running */
589
- rb_define_const(cDaemon, "CONTINUE_PENDING",
590
- INT2NUM(SERVICE_CONTINUE_PENDING));
591
-
592
- /* Service has received a signal to pause but is not yet paused */
593
- rb_define_const(cDaemon, "PAUSE_PENDING", INT2NUM(SERVICE_PAUSE_PENDING));
594
-
595
- /* Service is in a paused state */
596
- rb_define_const(cDaemon, "PAUSED", INT2NUM(SERVICE_PAUSED));
597
-
598
- /* Service is running */
599
- rb_define_const(cDaemon, "RUNNING", INT2NUM(SERVICE_RUNNING));
600
-
601
- /* Service has received a signal to start but is not yet running */
602
- rb_define_const(cDaemon, "START_PENDING", INT2NUM(SERVICE_START_PENDING));
603
-
604
- /* Service has received a signal to stop but has not yet stopped */
605
- rb_define_const(cDaemon, "STOP_PENDING", INT2NUM(SERVICE_STOP_PENDING));
606
-
607
- /* Service is stopped. */
608
- rb_define_const(cDaemon, "STOPPED", INT2NUM(SERVICE_STOPPED));
609
-
610
- /* Service is in an idle state */
611
- rb_define_const(cDaemon, "IDLE", INT2NUM(0));
612
- }