win32-taskscheduler 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES ADDED
@@ -0,0 +1,39 @@
1
+ == 0.1.0 - 11-May-2008
2
+ * The TaskScheduler#save instance method now accepts an optional file name.
3
+ * Most of the TaskScheduler setter methods now return the value specified
4
+ instead of true.
5
+ * Removed the RUN_ONLY_IF_DOCKED and RUN_IF_CONNECTED_TO_INTERNET constants.
6
+ The MSDN docs say that they are unused.
7
+ * Added more documentation. Much more rdoc friendly now.
8
+ * Added many more tests.
9
+ * Better type handling for bad arguments.
10
+ * Added a Rakefile with tasks for building, installation and testing.
11
+ * Added a gemspec.
12
+ * Inlined the rdoc documentation.
13
+ * Internal project reorganization and code cleanup.
14
+
15
+ == 0.0.3 - 1-Mar-2005
16
+ * Bug fix for the bitFieldToHumanDays() internal function.
17
+ * Moved the 'examples' directory to the toplevel directory.
18
+ * Made the CHANGES and README files rdoc friendly.
19
+ * Minor updates to taskscheduler.h.
20
+
21
+ == 0.0.2 - 04-Aug-2004
22
+ * Now uses the newer allocation framework and replaced all instances of the
23
+ deprecated STR2CSTR() function with StringValuePtr(). This means that, as
24
+ of this release, Ruby 1.8.0 or later is required.
25
+ * Modified the constructor to accept arguments. This is just some sugar for
26
+ creating a new task item in one call instead of two.
27
+ * The argument to trigger= now must be a hash. The same goes for the 'type'
28
+ sub-hash.
29
+ * Added the add_trigger() method. Actually, the C code for this method was
30
+ already in place, I simply forgot to create a corresponding Ruby method
31
+ for it.
32
+ * Removed the create_trigger() method. This was really nothing more than an
33
+ alias for trigger=(). I got confused somehow.
34
+ * Test suite modified and many more tests added.
35
+ * Documentation updates, including docs for a couple of methods that I had
36
+ accidentally omitted previously.
37
+
38
+ == 0.0.1 - 24-Apr-2004
39
+ * Initial release
@@ -0,0 +1,11 @@
1
+ * CHANGES
2
+ * MANIFEST
3
+ * README
4
+ * Rakefile
5
+ * win32-taskscheduler.gemspec
6
+ * ext/extconf.rb
7
+ * ext/win32/taskscheduler.c
8
+ * ext/win32/taskscheduler.h
9
+ * doc/taskscheduler.txt
10
+ * examples/taskscheduler_test.rb
11
+ * test/tc_taskscheduler.rb
data/README ADDED
@@ -0,0 +1,62 @@
1
+ = Description
2
+ The win32-taskscheduler library is a Ruby interface to the MS Windows Task
3
+ Scheduler. It is analogous to the Unix cron daemon.
4
+
5
+ = Synopsis
6
+ require 'win32/taskscheduler'
7
+ include Win32
8
+
9
+ t = TaskScheduler.new
10
+
11
+ trigger = {
12
+ :start_year => 2014,
13
+ :start_month => 4,
14
+ :start_day => 25,
15
+ :start_hour => 23,
16
+ :start_minute => 5,
17
+ :trigger_type => TaskScheduler::MONTHLY_DOW,
18
+ :type => {
19
+ :weeks => TaskScheduler::FIRST | TaskScheduler::LAST,
20
+ :days_of_week => TaskScheduler::MONDAY | TaskScheduler::FRIDAY,
21
+ :months => TaskScheduler::APRIL | TaskScheduler::MAY
22
+ }
23
+ }
24
+
25
+ t.new_work_item('foo', trigger)
26
+ t.application_name = 'notepad.exe'
27
+ t.save
28
+
29
+ = Prerequisites
30
+ Ruby 1.8.2 or later. Building from source requires VC++ 6.0 or later.
31
+
32
+ = Installation
33
+ rake install (non-gem) OR rake install_gem (gem)
34
+
35
+ For most of you 'gem install win32-taskscheduler' will work.
36
+
37
+ = Documentation
38
+ If you installed this library as a gem then the documentation was built for
39
+ you and can be viewed if your gem server is running.
40
+
41
+ Otherwise, you can look at the doc/taskscheduler.txt file which should have
42
+ everything you need.
43
+
44
+ = Acknowledgements
45
+ This library was modeled to some degree on the Win32::TaskScheduler Perl
46
+ module by Umberto Nicoletti. However, there are some differences. Please see
47
+ the documentation for details.
48
+
49
+ = On using OLE + WMI + Win32_ScheduledJob
50
+ I will probably include a pure Ruby version of this library at some point,
51
+ and you can find what I have so far in CVS under lib/win32. Note, however,
52
+ that there are some significant differences in behavior between the C
53
+ library and WMI, along with limitations regarding modification to existing
54
+ tasks.
55
+
56
+ You can find a list of differences here: http://tinyurl.com/2l3yau
57
+
58
+ = Developer's Notes
59
+ The CoInitialize() function is used internally instead of CoInitializeEx()
60
+ function intentionally. The CoInitialize() function merely calls the
61
+ CoInitializeEx() function with NULL and COINIT_APARTMENTTHREADED arguments,
62
+ which is what we would do in any case.
@@ -0,0 +1,14 @@
1
+ require 'mkmf'
2
+ require 'rbconfig'
3
+ include Config
4
+
5
+ CONFIG['COMPILE_C'].sub!(/-Tc/, '-Tp') # -Tp tells cl to compile as c++
6
+ $LIBS += ' ole32.lib comsupp.lib '
7
+
8
+ build_num = CONFIG['build'].split('_').last.to_i
9
+
10
+ if build_num > 60
11
+ $LIBS += 'comsuppwd.lib '
12
+ end
13
+
14
+ create_makefile('win32/taskscheduler', 'win32')
@@ -0,0 +1,2036 @@
1
+ /* taskscheduler.c */
2
+ #include "ruby.h"
3
+ #include <windows.h>
4
+ #include <initguid.h>
5
+ #include <ole2.h>
6
+ #include <mstask.h>
7
+ #include <msterr.h>
8
+ #include <objidl.h>
9
+ #include <wchar.h>
10
+ #include <stdio.h>
11
+ #include <tchar.h>
12
+ #include <comutil.h>
13
+ #include "taskscheduler.h"
14
+
15
+ static TCHAR error[ERROR_BUFFER];
16
+
17
+ static VALUE ts_allocate(VALUE klass){
18
+ TSStruct* ptr = (TSStruct*)malloc(sizeof(TSStruct));
19
+ return Data_Wrap_Struct(klass, 0, ts_free, ptr);
20
+ }
21
+
22
+ /*
23
+ * call-seq: TaskScheduler.new(work_item, host=nil)
24
+ *
25
+ * Returns a new TaskScheduler object. If a work_item (and possibly
26
+ * the trigger) are passed as arguments then a new work item is created and
27
+ * associated with that trigger, although you can still activate other tasks
28
+ * with the same handle.
29
+ *
30
+ * This is really just a bit of convenience. Passing arguments to the
31
+ * constructor is the same as calling new + new_work_item.
32
+ */
33
+ static VALUE ts_init(int argc, VALUE *argv, VALUE self)
34
+ {
35
+ ITaskScheduler *pITS;
36
+ HRESULT hr = S_OK;
37
+ TSStruct* ptr;
38
+ VALUE v_taskname, v_trigger;
39
+
40
+ Data_Get_Struct(self,TSStruct,ptr);
41
+ ptr->pITS = NULL;
42
+ ptr->pITask = NULL;
43
+
44
+ rb_scan_args(argc, argv, "02", &v_taskname, &v_trigger);
45
+
46
+ hr = CoInitialize(NULL);
47
+
48
+ if(SUCCEEDED(hr)){
49
+ hr = CoCreateInstance(
50
+ CLSID_CTaskScheduler,
51
+ NULL,
52
+ CLSCTX_INPROC_SERVER,
53
+ IID_ITaskScheduler,
54
+ (void **) &pITS
55
+ );
56
+
57
+ if(FAILED(hr))
58
+ rb_raise(cTSError, ErrorString(GetLastError()));
59
+ }
60
+ else{
61
+ rb_raise(cTSError, ErrorString(GetLastError()));
62
+ }
63
+
64
+ ptr->pITS = pITS;
65
+ ptr->pITask = NULL;
66
+
67
+ if(Qnil != v_taskname){
68
+ if(Qnil != v_trigger){
69
+ Check_Type(v_trigger,T_HASH);
70
+ ts_new_work_item(self,v_taskname,v_trigger);
71
+ }
72
+ else{
73
+ ts_new_work_item(self,v_taskname,Qnil);
74
+ }
75
+ }
76
+
77
+ return self;
78
+ }
79
+
80
+ /*
81
+ * Returns an array of scheduled tasks.
82
+ */
83
+ static VALUE ts_enum(VALUE self)
84
+ {
85
+ TSStruct* ptr;
86
+ HRESULT hr;
87
+ IEnumWorkItems *pIEnum;
88
+ LPWSTR *lpwszNames;
89
+ VALUE v_enum;
90
+ TCHAR dest[NAME_MAX];
91
+ DWORD dwFetchedTasks = 0;
92
+
93
+ Data_Get_Struct(self,TSStruct,ptr);
94
+
95
+ if(ptr->pITS == NULL)
96
+ rb_raise(cTSError, "fatal error: null pointer(ts_enum)");
97
+
98
+ hr = ptr->pITS->Enum(&pIEnum);
99
+
100
+ if(FAILED(hr))
101
+ rb_raise(cTSError, ErrorString(GetLastError()));
102
+
103
+ v_enum = rb_ary_new();
104
+
105
+ while(SUCCEEDED(pIEnum->Next(TASKS_TO_RETRIEVE,
106
+ &lpwszNames,
107
+ &dwFetchedTasks))
108
+ && (dwFetchedTasks != 0)
109
+ )
110
+ {
111
+ while(dwFetchedTasks){
112
+ WideCharToMultiByte(
113
+ CP_ACP,
114
+ 0,
115
+ lpwszNames[--dwFetchedTasks],
116
+ -1,
117
+ dest,
118
+ NAME_MAX,
119
+ NULL,
120
+ NULL
121
+ );
122
+
123
+ rb_ary_push(v_enum, rb_str_new2(dest));
124
+ CoTaskMemFree(lpwszNames[dwFetchedTasks]);
125
+ }
126
+ CoTaskMemFree(lpwszNames);
127
+ }
128
+
129
+ pIEnum->Release();
130
+
131
+ return v_enum;
132
+ }
133
+
134
+ /*
135
+ * call-seq:
136
+ * TaskScheduler#activate(task)
137
+ *
138
+ * Activates the given +task+.
139
+ */
140
+ static VALUE ts_activate(VALUE self, VALUE v_task){
141
+ TSStruct* ptr;
142
+ HRESULT hr;
143
+ wchar_t cwszTaskName[NAME_MAX];
144
+
145
+ Data_Get_Struct(self, TSStruct, ptr);
146
+
147
+ if(ptr->pITS == NULL)
148
+ rb_raise(cTSError, "fatal error: null pointer (ts_activate)");
149
+
150
+ StringValue(v_task);
151
+
152
+ MultiByteToWideChar(
153
+ CP_ACP,
154
+ 0,
155
+ StringValuePtr(v_task),
156
+ RSTRING(v_task)->len+1,
157
+ cwszTaskName,
158
+ NAME_MAX
159
+ );
160
+
161
+ hr = ptr->pITS->Activate(cwszTaskName,IID_ITask,
162
+ (IUnknown**) &(ptr->pITask));
163
+
164
+ if(FAILED(hr))
165
+ rb_raise(cTSError, ErrorString(GetLastError()));
166
+
167
+ return self;
168
+ }
169
+
170
+ /*
171
+ * Deletes the specified +task+.
172
+ */
173
+ static VALUE ts_delete(VALUE self, VALUE v_task)
174
+ {
175
+ TSStruct* ptr;
176
+ HRESULT hr;
177
+ wchar_t cwszTaskName[NAME_MAX];
178
+
179
+ Data_Get_Struct(self, TSStruct, ptr);
180
+ StringValue(v_task);
181
+
182
+ if(ptr->pITS == NULL)
183
+ rb_raise(cTSError, "fatal error: null pointer (ts_delete)");
184
+
185
+ MultiByteToWideChar(
186
+ CP_ACP,
187
+ 0,
188
+ StringValuePtr(v_task),
189
+ RSTRING(v_task)->len + 1,
190
+ cwszTaskName,
191
+ NAME_MAX
192
+ );
193
+
194
+ hr = ptr->pITS->Delete(cwszTaskName);
195
+
196
+ if(FAILED(hr))
197
+ rb_raise(cTSError, ErrorString(GetLastError()));
198
+
199
+ return self;
200
+ }
201
+
202
+ /*
203
+ * Executes the current task.
204
+ */
205
+ static VALUE ts_run(VALUE self)
206
+ {
207
+ TSStruct* ptr;
208
+ HRESULT hr;
209
+
210
+ Data_Get_Struct(self, TSStruct, ptr);
211
+
212
+ if(ptr->pITask == NULL)
213
+ rb_raise(cTSError, "fatal error: null pointer (ts_run)");
214
+
215
+ hr = ptr->pITask->Run();
216
+
217
+ if(FAILED(hr))
218
+ rb_raise(cTSError, ErrorString(GetLastError()));
219
+
220
+ return self;
221
+ }
222
+
223
+ /*
224
+ * call-seq:
225
+ * TaskScheduler#save(file=nil)
226
+ *
227
+ * Saves the current task. Tasks must be saved before they can be activated.
228
+ * The .job file itself is typically stored in the C:\WINDOWS\Tasks folder.
229
+ *
230
+ * If +file+ (an absolute path) is specified then the job is saved to that
231
+ * file instead. A '.job' extension is recommended but not enforced.
232
+ *
233
+ * Note that calling TaskScheduler#save also resets the TaskScheduler object
234
+ * so that there is no currently active task.
235
+ */
236
+ static VALUE ts_save(int argc, VALUE* argv, VALUE self)
237
+ {
238
+ TSStruct* ptr;
239
+ HRESULT hr;
240
+ IPersistFile *pIPersistFile;
241
+ LPOLESTR ppszFileName = NULL;
242
+ VALUE v_bool = Qfalse;
243
+ VALUE v_file = Qnil;
244
+
245
+ rb_scan_args(argc, argv, "01", &v_file);
246
+
247
+ if(!NIL_P(v_file))
248
+ ppszFileName = _bstr_t(StringValuePtr(v_file));
249
+
250
+ Data_Get_Struct(self, TSStruct, ptr);
251
+
252
+ if(ptr->pITask == NULL)
253
+ rb_raise(cTSError, "fatal error: null pointer (ts_save)");
254
+
255
+ hr = ptr->pITask->QueryInterface(IID_IPersistFile,
256
+ (void **)&pIPersistFile);
257
+
258
+ if(FAILED(hr))
259
+ rb_raise(cTSError, ErrorString(GetLastError()));
260
+
261
+ hr = pIPersistFile->Save(ppszFileName, TRUE);
262
+
263
+ if(FAILED(hr)){
264
+ strcpy(error, ErrorString(GetLastError()));
265
+ pIPersistFile->Release();
266
+ rb_raise(cTSError, error);
267
+ }
268
+
269
+ pIPersistFile->Release();
270
+
271
+ // Call CoInitialize to initialize the COM library and then
272
+ // CoCreateInstance to get the Task Scheduler object.
273
+ // - Added by phasis68
274
+ CoUninitialize();
275
+ hr = CoInitialize(NULL);
276
+
277
+ if(SUCCEEDED(hr)){
278
+ hr = CoCreateInstance(
279
+ CLSID_CTaskScheduler,
280
+ NULL,
281
+ CLSCTX_INPROC_SERVER,
282
+ IID_ITaskScheduler,
283
+ (void **) &(ptr->pITS)
284
+ );
285
+
286
+ if(FAILED(hr)){
287
+ CoUninitialize();
288
+ rb_raise(cTSError, ErrorString(GetLastError()));
289
+ }
290
+ }
291
+ else{
292
+ rb_raise(cTSError, ErrorString(GetLastError()));
293
+ }
294
+
295
+ ptr->pITask->Release();
296
+ ptr->pITask = NULL;
297
+
298
+ return self;
299
+ }
300
+
301
+ /*
302
+ * Terminate the current task.
303
+ */
304
+ static VALUE ts_terminate(VALUE self, VALUE v_task)
305
+ {
306
+ TSStruct* ptr;
307
+ HRESULT hr;
308
+
309
+ Data_Get_Struct(self, TSStruct, ptr);
310
+
311
+ if(ptr->pITask == NULL)
312
+ rb_raise(cTSError, "fatal error: null pointer (ts_terminate)");
313
+
314
+ hr = ptr->pITask->Terminate();
315
+
316
+ if(FAILED(hr))
317
+ rb_raise(cTSError, ErrorString(GetLastError()));
318
+
319
+ return self;
320
+ }
321
+
322
+ /*
323
+ * Sets the host on which the various task methods will execute.
324
+ */
325
+ static VALUE ts_set_target_computer(VALUE self, VALUE v_host)
326
+ {
327
+ TSStruct* ptr;
328
+ HRESULT hr;
329
+ wchar_t cwszHostName[NAME_MAX];
330
+
331
+ Data_Get_Struct(self, TSStruct, ptr);
332
+ StringValue(v_host);
333
+
334
+ if(ptr->pITS == NULL)
335
+ rb_raise(cTSError, "fatal error: null pointer (ts_set_target_computer");
336
+
337
+ MultiByteToWideChar(
338
+ CP_ACP,
339
+ 0,
340
+ StringValuePtr(v_host),
341
+ RSTRING(v_host)->len + 1,
342
+ cwszHostName,
343
+ NAME_MAX
344
+ );
345
+
346
+ hr = ptr->pITS->SetTargetComputer(cwszHostName);
347
+
348
+ if(FAILED(hr))
349
+ rb_raise(cTSError, ErrorString(GetLastError()));
350
+
351
+ return v_host;
352
+ }
353
+
354
+ /*
355
+ * call-seq:
356
+ * TaskScheduler#set_account_information(user, password)
357
+ *
358
+ * Sets the +user+ and +password+ for the given task. If the user and
359
+ * password are set properly true is returned. In some cases the job may
360
+ * be created, but the account information was bad. In this case the
361
+ * task is created but a warning is generated and false is returned.
362
+ */
363
+ static VALUE ts_set_account_information(VALUE self, VALUE v_usr, VALUE v_pwd)
364
+ {
365
+ TSStruct* ptr;
366
+ HRESULT hr;
367
+ wchar_t cwszUsername[NAME_MAX];
368
+ wchar_t cwszPassword[NAME_MAX];
369
+ VALUE v_bool = Qtrue;
370
+
371
+ StringValue(v_usr);
372
+ StringValue(v_pwd);
373
+
374
+ Data_Get_Struct(self, TSStruct, ptr);
375
+ check_ts_ptr(ptr, "ts_set_account_information");
376
+
377
+ if((NIL_P(v_usr) || RSTRING(v_usr)->len == 0)
378
+ && (NIL_P(v_pwd) || RSTRING(v_pwd)->len == 0))
379
+ {
380
+ hr = ptr->pITask->SetAccountInformation(L"", NULL);
381
+ }
382
+ else{
383
+
384
+ MultiByteToWideChar(CP_ACP, 0, StringValuePtr(v_usr),
385
+ RSTRING(v_usr)->len+1, cwszUsername, NAME_MAX);
386
+
387
+ MultiByteToWideChar(CP_ACP, 0, StringValuePtr(v_pwd),
388
+ RSTRING(v_pwd)->len+1, cwszPassword, NAME_MAX);
389
+
390
+ hr = ptr->pITask->SetAccountInformation(cwszUsername, cwszPassword);
391
+ }
392
+
393
+ switch(hr){
394
+ case S_OK:
395
+ return Qtrue;
396
+ case E_ACCESSDENIED:
397
+ rb_raise(cTSError, "access denied");
398
+ break;
399
+ case E_INVALIDARG:
400
+ rb_raise(cTSError, "invalid argument");
401
+ break;
402
+ case E_OUTOFMEMORY:
403
+ rb_raise(cTSError, "out of memory");
404
+ break;
405
+ case SCHED_E_NO_SECURITY_SERVICES:
406
+ rb_raise(cTSError, "no security services on this platform");
407
+ break;
408
+ #ifdef SCHED_E_UNSUPPORTED_ACCOUNT_OPTION
409
+ case SCHED_E_UNSUPPORTED_ACCOUNT_OPTION:
410
+ rb_raise(cTSError, "unsupported account option");
411
+ break;
412
+ #endif
413
+ #ifdef SCHED_E_ACCOUNT_INFORMATION_NOT_SET
414
+ // Oddly, even if this error occurs, the job is still created, so
415
+ // we generate a warning instead of an error, but return false.
416
+ case SCHED_E_ACCOUNT_INFORMATION_NOT_SET:
417
+ rb_warn("job created, but password was invalid");
418
+ v_bool = Qfalse;
419
+ break;
420
+ #endif
421
+ default:
422
+ rb_raise(cTSError, "unknown error");
423
+ }
424
+
425
+ return v_bool;
426
+ }
427
+
428
+ /*
429
+ * Returns the user associated with the task or nil if no user has yet
430
+ * been associated with the task.
431
+ */
432
+ static VALUE ts_get_account_information(VALUE self)
433
+ {
434
+ TSStruct* ptr;
435
+ HRESULT hr;
436
+ LPWSTR lpcwszUsername;
437
+ TCHAR user[NAME_MAX];
438
+ VALUE v_user;
439
+
440
+ Data_Get_Struct(self, TSStruct, ptr);
441
+ check_ts_ptr(ptr, "ts_get_account_information");
442
+
443
+ hr = ptr->pITask->GetAccountInformation(&lpcwszUsername);
444
+
445
+ if((SUCCEEDED(hr)) && (hr != SCHED_E_NO_SECURITY_SERVICES)){
446
+ WideCharToMultiByte(
447
+ CP_ACP,
448
+ 0,
449
+ lpcwszUsername,
450
+ -1,
451
+ user,
452
+ NAME_MAX,
453
+ NULL,
454
+ NULL
455
+ );
456
+ CoTaskMemFree(lpcwszUsername);
457
+ v_user = rb_str_new2(user);
458
+ }
459
+ else if(hr == SCHED_E_ACCOUNT_INFORMATION_NOT_SET){
460
+ v_user = Qnil;
461
+ }
462
+ else{
463
+ CoTaskMemFree(lpcwszUsername);
464
+ rb_raise(cTSError, ErrorString(hr));
465
+ }
466
+
467
+ return v_user;
468
+ }
469
+
470
+ /*
471
+ * Sets the application associated with the task.
472
+ */
473
+ static VALUE ts_set_application_name(VALUE self, VALUE v_app)
474
+ {
475
+ TSStruct* ptr;
476
+ HRESULT hr;
477
+ wchar_t cwszAppname[NAME_MAX];
478
+
479
+ Data_Get_Struct(self, TSStruct, ptr);
480
+ check_ts_ptr(ptr, "ts_set_application");
481
+ StringValue(v_app);
482
+
483
+ MultiByteToWideChar(
484
+ CP_ACP,
485
+ 0,
486
+ StringValuePtr(v_app),
487
+ RSTRING(v_app)->len+1,
488
+ cwszAppname,
489
+ NAME_MAX
490
+ );
491
+
492
+ hr = ptr->pITask->SetApplicationName(cwszAppname);
493
+
494
+ if(FAILED(hr))
495
+ rb_raise(cTSError, ErrorString(GetLastError()));
496
+
497
+ return v_app;
498
+ }
499
+
500
+ /*
501
+ * Returns the application name associated with the task.
502
+ */
503
+ static VALUE ts_get_application_name(VALUE self)
504
+ {
505
+ TSStruct* ptr;
506
+ HRESULT hr;
507
+ LPWSTR lpcwszAppname;
508
+ TCHAR app[NAME_MAX];
509
+
510
+ Data_Get_Struct(self,TSStruct,ptr);
511
+ check_ts_ptr(ptr, "ts_get_application_name");
512
+
513
+ hr = ptr->pITask->GetApplicationName(&lpcwszAppname);
514
+
515
+ if(SUCCEEDED(hr)){
516
+ WideCharToMultiByte(CP_ACP, 0, lpcwszAppname, -1, app, NAME_MAX, NULL, NULL );
517
+ CoTaskMemFree(lpcwszAppname);
518
+ }
519
+ else{
520
+ rb_raise(cTSError, ErrorString(GetLastError()));
521
+ }
522
+
523
+ return rb_str_new2(app);
524
+ }
525
+
526
+ /*
527
+ * Sets the parameters for the task. These parameters are passed as command
528
+ * line arguments to the application the task will run. To clear the command
529
+ * line parameters set it to an empty string.
530
+ */
531
+ static VALUE ts_set_parameters(VALUE self, VALUE v_param)
532
+ {
533
+ TSStruct* ptr;
534
+ HRESULT hr;
535
+ wchar_t cwszParameters[NAME_MAX];
536
+
537
+ Data_Get_Struct(self,TSStruct,ptr);
538
+ check_ts_ptr(ptr, "ts_set_parameters");
539
+ StringValue(v_param);
540
+
541
+ MultiByteToWideChar(
542
+ CP_ACP,
543
+ 0,
544
+ StringValuePtr(v_param),
545
+ RSTRING(v_param)->len+1,
546
+ cwszParameters,
547
+ NAME_MAX
548
+ );
549
+
550
+ hr = ptr->pITask->SetParameters(cwszParameters);
551
+
552
+ if(FAILED(hr))
553
+ rb_raise(cTSError, ErrorString(GetLastError()));
554
+
555
+ return v_param;
556
+ }
557
+
558
+ /*
559
+ * Returns the parameters for the task.
560
+ */
561
+ static VALUE ts_get_parameters(VALUE self)
562
+ {
563
+ TSStruct* ptr;
564
+ HRESULT hr;
565
+ LPWSTR lpcwszParameters;
566
+ TCHAR param[NAME_MAX];
567
+
568
+ Data_Get_Struct(self, TSStruct, ptr);
569
+ check_ts_ptr(ptr, "ts_get_parameters");
570
+
571
+ hr = ptr->pITask->GetParameters(&lpcwszParameters);
572
+
573
+ if(SUCCEEDED(hr)){
574
+ WideCharToMultiByte(
575
+ CP_ACP,
576
+ 0,
577
+ lpcwszParameters,
578
+ -1,
579
+ param,
580
+ NAME_MAX,
581
+ NULL,
582
+ NULL
583
+ );
584
+ CoTaskMemFree(lpcwszParameters);
585
+ }
586
+ else{
587
+ rb_raise(cTSError, ErrorString(GetLastError()));
588
+ }
589
+
590
+ return rb_str_new2(param);
591
+ }
592
+
593
+ /*
594
+ * Sets the working directory for the task.
595
+ */
596
+ static VALUE ts_set_working_directory(VALUE self, VALUE v_dir)
597
+ {
598
+ TSStruct* ptr;
599
+ HRESULT hr;
600
+ wchar_t cwszDirectory[NAME_MAX];
601
+
602
+ Data_Get_Struct(self, TSStruct, ptr);
603
+ check_ts_ptr(ptr, "ts_set_working_directory");
604
+ StringValue(v_dir);
605
+
606
+ MultiByteToWideChar(
607
+ CP_ACP,
608
+ 0,
609
+ StringValuePtr(v_dir),
610
+ RSTRING(v_dir)->len+1,
611
+ cwszDirectory,
612
+ NAME_MAX
613
+ );
614
+
615
+ hr = ptr->pITask->SetWorkingDirectory(cwszDirectory);
616
+
617
+ if(FAILED(hr))
618
+ rb_raise(cTSError, ErrorString(GetLastError()));
619
+
620
+ return v_dir;
621
+ }
622
+
623
+ /*
624
+ * Returns the working directory for the task.
625
+ */
626
+ static VALUE ts_get_working_directory(VALUE self)
627
+ {
628
+ TSStruct* ptr;
629
+ HRESULT hr;
630
+ LPWSTR lpcwszDirectory;
631
+ TCHAR dir[NAME_MAX];
632
+
633
+ Data_Get_Struct(self, TSStruct, ptr);
634
+ check_ts_ptr(ptr, "ts_get_working_directory");
635
+
636
+ hr = ptr->pITask->GetWorkingDirectory(&lpcwszDirectory);
637
+
638
+ if(SUCCEEDED(hr)){
639
+ WideCharToMultiByte(
640
+ CP_ACP,
641
+ 0,
642
+ lpcwszDirectory,
643
+ -1,
644
+ dir,
645
+ NAME_MAX,
646
+ NULL,
647
+ NULL
648
+ );
649
+ CoTaskMemFree(lpcwszDirectory);
650
+ }
651
+ else{
652
+ rb_raise(cTSError, ErrorString(GetLastError()));
653
+ }
654
+
655
+ return rb_str_new2(dir);
656
+ }
657
+
658
+ /*
659
+ * Sets the priority for the task. This can be any one of REALTIME, HIGH,
660
+ * NORMAL, IDLE, ABOVE_NORMAL or BELOW_NORMAL.
661
+ */
662
+ static VALUE ts_set_priority(VALUE self, VALUE v_priority)
663
+ {
664
+ TSStruct* ptr;
665
+ HRESULT hr;
666
+ DWORD dwPriority;
667
+
668
+ Data_Get_Struct(self, TSStruct, ptr);
669
+ check_ts_ptr(ptr, "ts_set_priority");
670
+
671
+ dwPriority = NUM2UINT(v_priority);
672
+
673
+ hr = ptr->pITask->SetPriority(dwPriority);
674
+
675
+ if(FAILED(hr))
676
+ rb_raise(cTSError, ErrorString(GetLastError()));
677
+
678
+ return v_priority;
679
+ }
680
+
681
+ /*
682
+ * Returns the priority for the class. The possibilities are 'realtime',
683
+ * 'high', 'normal', 'idle', 'above_normal', 'below_normal' and 'unknown'.
684
+ */
685
+ static VALUE ts_get_priority(VALUE self)
686
+ {
687
+ TSStruct* ptr;
688
+ HRESULT hr;
689
+ DWORD dwPriority;
690
+ VALUE v_priority;
691
+
692
+ Data_Get_Struct(self, TSStruct, ptr);
693
+ check_ts_ptr(ptr, "ts_get_priority");
694
+
695
+ hr = ptr->pITask->GetPriority(&dwPriority);
696
+
697
+ if(SUCCEEDED(hr)){
698
+ if(dwPriority & IDLE_PRIORITY_CLASS)
699
+ v_priority = rb_str_new2("idle");
700
+
701
+ if(dwPriority & NORMAL_PRIORITY_CLASS)
702
+ v_priority = rb_str_new2("normal");
703
+
704
+ if(dwPriority & HIGH_PRIORITY_CLASS)
705
+ v_priority = rb_str_new2("high");
706
+
707
+ if(dwPriority & REALTIME_PRIORITY_CLASS)
708
+ v_priority = rb_str_new2("realtime");
709
+
710
+ if(dwPriority & BELOW_NORMAL_PRIORITY_CLASS)
711
+ v_priority = rb_str_new2("below_normal");
712
+
713
+ if(dwPriority & ABOVE_NORMAL_PRIORITY_CLASS)
714
+ v_priority = rb_str_new2("above_normal");
715
+
716
+ v_priority = rb_str_new2("unknown");
717
+ }
718
+ else{
719
+ rb_raise(cTSError, ErrorString(GetLastError()));
720
+ }
721
+
722
+ return v_priority;
723
+ }
724
+
725
+ /*
726
+ * Creates a new +work_item+ for the given +task+.
727
+ */
728
+ static VALUE ts_new_work_item(VALUE self, VALUE v_task, VALUE v_trigger)
729
+ {
730
+ TSStruct* ptr;
731
+ HRESULT hr;
732
+ wchar_t cwszTaskName[NAME_MAX];
733
+ ITaskTrigger *pITaskTrigger;
734
+ WORD piNewTrigger;
735
+ TASK_TRIGGER pTrigger;
736
+ VALUE i, htmp;
737
+
738
+ Data_Get_Struct(self, TSStruct, ptr);
739
+ Check_Type(v_trigger, T_HASH);
740
+
741
+ if(ptr->pITS == NULL)
742
+ rb_raise(cTSError, "null pointer error (ts_new_work_item)");
743
+
744
+ if(ptr->pITask != NULL){
745
+ ptr->pITask->Release();
746
+ ptr->pITask = NULL;
747
+ }
748
+
749
+ MultiByteToWideChar(
750
+ CP_ACP,
751
+ 0,
752
+ StringValuePtr(v_task),
753
+ RSTRING(v_task)->len+1,
754
+ cwszTaskName,
755
+ NAME_MAX
756
+ );
757
+
758
+ hr = ptr->pITS->NewWorkItem(
759
+ cwszTaskName, // Name of task
760
+ CLSID_CTask, // Class identifier
761
+ IID_ITask, // Interface identifier
762
+ (IUnknown**)&(ptr->pITask) // Address of task interface
763
+ );
764
+
765
+ if(FAILED(hr)){
766
+ ptr->pITask = NULL; // added by phasis68 for ts_free prevent
767
+ rb_raise(cTSError, "NewWorkItem() function failed");
768
+ }
769
+
770
+ hr = ptr->pITask->CreateTrigger(&piNewTrigger, &pITaskTrigger);
771
+
772
+ if(FAILED(hr))
773
+ rb_raise(cTSError, "CreateTrigger() failed");
774
+
775
+ /*
776
+ * Define TASK_TRIGGER structure. Note that wBeginDay, wBeginMonth and
777
+ * wBeginYear must be set to a valid day, month, and year respectively.
778
+ */
779
+ ZeroMemory(&pTrigger, sizeof(TASK_TRIGGER));
780
+ pTrigger.cbTriggerSize = sizeof(TASK_TRIGGER);
781
+
782
+ if((i = rb_hash_aref(v_trigger, rb_str_new2("start_year"))) != Qnil)
783
+ pTrigger.wBeginYear = NUM2INT(i);
784
+
785
+ if((i = rb_hash_aref(v_trigger, rb_str_new2("start_month"))) != Qnil)
786
+ pTrigger.wBeginMonth = NUM2INT(i);
787
+
788
+ if((i = rb_hash_aref(v_trigger, rb_str_new2("start_day")))!=Qnil)
789
+ pTrigger.wBeginDay = NUM2INT(i);
790
+
791
+ if((i = rb_hash_aref(v_trigger, rb_str_new2("end_year"))) != Qnil)
792
+ pTrigger.wEndYear = NUM2INT(i);
793
+
794
+ if((i = rb_hash_aref(v_trigger, rb_str_new2("end_month"))) != Qnil)
795
+ pTrigger.wEndMonth = NUM2INT(i);
796
+
797
+ if((i = rb_hash_aref(v_trigger, rb_str_new2("end_day"))) != Qnil)
798
+ pTrigger.wEndDay = NUM2INT(i);
799
+
800
+ if((i = rb_hash_aref(v_trigger, rb_str_new2("start_hour"))) != Qnil)
801
+ pTrigger.wStartHour = NUM2INT(i);
802
+
803
+ if((i = rb_hash_aref(v_trigger, rb_str_new2("start_minute"))) != Qnil)
804
+ pTrigger.wStartMinute = NUM2INT(i);
805
+
806
+ if((i = rb_hash_aref(v_trigger, rb_str_new2("minutes_duration"))) != Qnil)
807
+ pTrigger.MinutesDuration = NUM2INT(i);
808
+
809
+ if((i = rb_hash_aref(v_trigger, rb_str_new2("minutes_interval"))) != Qnil)
810
+ pTrigger.MinutesInterval = NUM2INT(i);
811
+
812
+ if((i = rb_hash_aref(v_trigger, rb_str_new2("random_minutes_interval"))) != Qnil)
813
+ pTrigger.wRandomMinutesInterval = NUM2INT(i);
814
+
815
+ if((i = rb_hash_aref(v_trigger, rb_str_new2("flags"))) != Qnil)
816
+ pTrigger.rgFlags = NUM2INT(i);
817
+
818
+ if((i = rb_hash_aref(v_trigger, rb_str_new2("trigger_type"))) != Qnil)
819
+ pTrigger.TriggerType = (TASK_TRIGGER_TYPE)NUM2INT(i);
820
+
821
+ htmp =rb_hash_aref(v_trigger, rb_str_new2("type"));
822
+
823
+ if(TYPE(htmp)!=T_HASH)
824
+ htmp = Qnil;
825
+
826
+ switch(pTrigger.TriggerType){
827
+ case TASK_TIME_TRIGGER_DAILY:
828
+ if(htmp != Qnil){
829
+ if((i = rb_hash_aref(htmp, rb_str_new2("days_interval"))) != Qnil)
830
+ pTrigger.Type.Daily.DaysInterval = NUM2INT(i);
831
+ }
832
+ break;
833
+ case TASK_TIME_TRIGGER_WEEKLY:
834
+ if(htmp != Qnil){
835
+ if((i = rb_hash_aref(htmp, rb_str_new2("weeks_interval"))) != Qnil)
836
+ pTrigger.Type.Weekly.WeeksInterval = NUM2INT(i);
837
+
838
+ if((i=rb_hash_aref(htmp, rb_str_new2("days_of_week")))!=Qnil)
839
+ pTrigger.Type.Weekly.rgfDaysOfTheWeek = NUM2INT(i);
840
+ }
841
+ break;
842
+ case TASK_TIME_TRIGGER_MONTHLYDATE:
843
+ if(htmp != Qnil){
844
+ if((i = rb_hash_aref(htmp, rb_str_new2("months"))) != Qnil)
845
+ pTrigger.Type.MonthlyDate.rgfMonths = NUM2INT(i);
846
+
847
+ if((i = rb_hash_aref(htmp, rb_str_new2("days"))) != Qnil)
848
+ pTrigger.Type.MonthlyDate.rgfDays = humanDaysToBitField(NUM2INT(i));
849
+ }
850
+ break;
851
+ case TASK_TIME_TRIGGER_MONTHLYDOW:
852
+ if(htmp != Qnil){
853
+ if((i = rb_hash_aref(htmp, rb_str_new2("weeks"))) != Qnil)
854
+ pTrigger.Type.MonthlyDOW.wWhichWeek = NUM2INT(i);
855
+
856
+ if((i = rb_hash_aref(htmp, rb_str_new2("days_of_week"))) != Qnil)
857
+ pTrigger.Type.MonthlyDOW.rgfDaysOfTheWeek = NUM2INT(i);
858
+
859
+ if((i = rb_hash_aref(htmp, rb_str_new2("months"))) != Qnil)
860
+ pTrigger.Type.MonthlyDOW.rgfMonths = NUM2INT(i);
861
+ }
862
+ break;
863
+ default:
864
+ rb_raise(cTSError, "Unknown trigger type");
865
+ }
866
+
867
+ hr = pITaskTrigger->SetTrigger (&pTrigger);
868
+
869
+ if(FAILED(hr))
870
+ rb_raise(cTSError, "SetTrigger() failed");
871
+
872
+ pITaskTrigger->Release();
873
+
874
+ return self;
875
+ }
876
+
877
+ /*
878
+ * Returns the number of triggers associated with the active task.
879
+ */
880
+ static VALUE ts_get_trigger_count(VALUE self)
881
+ {
882
+ TSStruct* ptr;
883
+ HRESULT hr;
884
+ WORD TriggerCount;
885
+ VALUE v_count;
886
+
887
+ Data_Get_Struct(self, TSStruct, ptr);
888
+ check_ts_ptr(ptr, "ts_get_trigger_count");
889
+
890
+ hr = ptr->pITask->GetTriggerCount(&TriggerCount);
891
+
892
+ if(SUCCEEDED(hr))
893
+ v_count = UINT2NUM(TriggerCount);
894
+ else
895
+ rb_raise(cTSError, ErrorString(GetLastError()));
896
+
897
+ return v_count;
898
+ }
899
+
900
+ /*
901
+ * call-seq:
902
+ * TaskScheduler#trigger_string(index)
903
+ *
904
+ * Returns a string that describes the current trigger at the specified
905
+ * index for the active task.
906
+ *
907
+ * Example: "At 7:14 AM every day, starting 4/11/2009"
908
+ *
909
+ */
910
+ static VALUE ts_get_trigger_string(VALUE self, VALUE v_index)
911
+ {
912
+ TSStruct* ptr;
913
+ HRESULT hr;
914
+ WORD TriggerIndex;
915
+ LPWSTR ppwszTrigger;
916
+ TCHAR buf[NAME_MAX];
917
+
918
+ Data_Get_Struct(self,TSStruct, ptr);
919
+ check_ts_ptr(ptr, "ts_get_trigger_string");
920
+
921
+ TriggerIndex = NUM2INT(v_index);
922
+
923
+ hr = ptr->pITask->GetTriggerString(TriggerIndex,&ppwszTrigger);
924
+
925
+ if(SUCCEEDED(hr)){
926
+ WideCharToMultiByte(
927
+ CP_ACP,
928
+ 0,
929
+ ppwszTrigger,
930
+ -1,
931
+ buf,
932
+ NAME_MAX,
933
+ NULL,
934
+ NULL
935
+ );
936
+ CoTaskMemFree(ppwszTrigger);
937
+ }
938
+ else{
939
+ rb_raise(cTSError, ErrorString(GetLastError()));
940
+ }
941
+
942
+ return rb_str_new2(buf);
943
+ }
944
+
945
+ /*
946
+ * call-seq:
947
+ * TaskScheduler#delete_trigger(index)
948
+ *
949
+ * Deletes the trigger at the specified +index+. Returns the index of the
950
+ * trigger that was deleted.
951
+ */
952
+ static VALUE ts_delete_trigger(VALUE self, VALUE v_index)
953
+ {
954
+ TSStruct* ptr;
955
+ HRESULT hr;
956
+ WORD TriggerIndex;
957
+
958
+ Data_Get_Struct(self, TSStruct, ptr);
959
+ check_ts_ptr(ptr, "ts_delete_trigger");
960
+
961
+ TriggerIndex = NUM2INT(v_index);
962
+
963
+ hr = ptr->pITask->DeleteTrigger(TriggerIndex);
964
+
965
+ if(FAILED(hr))
966
+ rb_raise(cTSError, ErrorString(GetLastError()));
967
+
968
+ return v_index;
969
+ }
970
+
971
+ /*
972
+ * call-seq:
973
+ * TaskScheduler#trigger(index)
974
+ *
975
+ * Returns a hash that describes the trigger for the active task at the
976
+ * given +index+.
977
+ */
978
+ static VALUE ts_get_trigger(VALUE self, VALUE index)
979
+ {
980
+ TSStruct* ptr;
981
+ HRESULT hr;
982
+ WORD TriggerIndex;
983
+ VALUE trigger,htmp;
984
+ ITaskTrigger *pITaskTrigger;
985
+ TASK_TRIGGER pTrigger;
986
+
987
+ Data_Get_Struct(self, TSStruct, ptr);
988
+ check_ts_ptr(ptr, "ts_get_trigger");
989
+
990
+ TriggerIndex = NUM2INT(index);
991
+
992
+ hr = ptr->pITask->GetTrigger(TriggerIndex,&pITaskTrigger);
993
+
994
+ if(FAILED(hr))
995
+ rb_raise(cTSError, ErrorString(GetLastError()));
996
+
997
+ ZeroMemory(&pTrigger, sizeof(TASK_TRIGGER));
998
+ pTrigger.cbTriggerSize = sizeof(TASK_TRIGGER);
999
+
1000
+ hr = pITaskTrigger->GetTrigger(&pTrigger);
1001
+
1002
+ if(FAILED(hr)){
1003
+ strcpy(error, ErrorString(GetLastError()));
1004
+ pITaskTrigger->Release();
1005
+ rb_raise(cTSError, error);
1006
+ }
1007
+
1008
+ trigger = rb_hash_new();
1009
+
1010
+ rb_hash_aset(trigger, rb_str_new2("start_year"),
1011
+ INT2NUM(pTrigger.wBeginYear));
1012
+
1013
+ rb_hash_aset(trigger, rb_str_new2("start_month"),
1014
+ INT2NUM(pTrigger.wBeginMonth));
1015
+
1016
+ rb_hash_aset(trigger, rb_str_new2("start_day"),
1017
+ INT2NUM(pTrigger.wBeginDay));
1018
+
1019
+ rb_hash_aset(trigger, rb_str_new2("end_year"),
1020
+ INT2NUM(pTrigger.wEndYear));
1021
+
1022
+ rb_hash_aset(trigger, rb_str_new2("end_month"),
1023
+ INT2NUM(pTrigger.wEndMonth));
1024
+
1025
+ rb_hash_aset(trigger, rb_str_new2("end_day"),
1026
+ INT2NUM(pTrigger.wEndDay));
1027
+
1028
+ rb_hash_aset(trigger, rb_str_new2("start_hour"),
1029
+ INT2NUM(pTrigger.wStartHour));
1030
+
1031
+ rb_hash_aset(trigger, rb_str_new2("start_minute"),
1032
+ INT2NUM(pTrigger.wStartMinute));
1033
+
1034
+ rb_hash_aset(trigger, rb_str_new2("minutes_duration"),
1035
+ INT2NUM(pTrigger.MinutesDuration));
1036
+
1037
+ rb_hash_aset(trigger, rb_str_new2("minutes_interval"),
1038
+ INT2NUM(pTrigger.MinutesInterval));
1039
+
1040
+ rb_hash_aset(trigger, rb_str_new2("trigger_type"),
1041
+ INT2NUM(pTrigger.TriggerType));
1042
+
1043
+ rb_hash_aset(trigger, rb_str_new2("random_minutes_interval"),
1044
+ INT2NUM(pTrigger.wRandomMinutesInterval));
1045
+
1046
+ rb_hash_aset(trigger, rb_str_new2("flags"),
1047
+ INT2NUM(pTrigger.rgFlags));
1048
+
1049
+ switch(pTrigger.TriggerType){
1050
+ case TASK_TIME_TRIGGER_DAILY:
1051
+ htmp = rb_hash_new();
1052
+ rb_hash_aset(htmp, rb_str_new2("days_interval"),
1053
+ INT2NUM(pTrigger.Type.Daily.DaysInterval));
1054
+ rb_hash_aset(trigger, rb_str_new2("type"), htmp);
1055
+ break;
1056
+ case TASK_TIME_TRIGGER_WEEKLY:
1057
+ htmp = rb_hash_new();
1058
+ rb_hash_aset(htmp, rb_str_new2("weeks_interval"),
1059
+ INT2NUM(pTrigger.Type.Weekly.WeeksInterval));
1060
+ rb_hash_aset(htmp, rb_str_new2("days_of_week"),
1061
+ INT2NUM(pTrigger.Type.Weekly.rgfDaysOfTheWeek));
1062
+ rb_hash_aset(trigger, rb_str_new2("type"), htmp);
1063
+ break;
1064
+ case TASK_TIME_TRIGGER_MONTHLYDATE:
1065
+ htmp = rb_hash_new();
1066
+ rb_hash_aset(htmp, rb_str_new2("days"),
1067
+ INT2NUM(bitFieldToHumanDays(pTrigger.Type.MonthlyDate.rgfDays)));
1068
+ rb_hash_aset(htmp, rb_str_new2("months"),
1069
+ INT2NUM(pTrigger.Type.MonthlyDate.rgfMonths));
1070
+ rb_hash_aset(trigger, rb_str_new2("type"), htmp);
1071
+ break;
1072
+ case TASK_TIME_TRIGGER_MONTHLYDOW:
1073
+ htmp = rb_hash_new();
1074
+ rb_hash_aset(htmp, rb_str_new2("weeks"),
1075
+ INT2NUM(bitFieldToHumanDays(pTrigger.Type.MonthlyDOW.wWhichWeek)));
1076
+ rb_hash_aset(htmp, rb_str_new2("days_of_week"),
1077
+ INT2NUM(pTrigger.Type.MonthlyDOW.rgfDaysOfTheWeek));
1078
+ rb_hash_aset(htmp, rb_str_new2("months"), INT2NUM(pTrigger.Type.MonthlyDOW.rgfMonths));
1079
+ rb_hash_aset(trigger, rb_str_new2("type"), htmp);
1080
+ break;
1081
+ default:
1082
+ rb_raise(cTSError, "Unknown trigger type");
1083
+ }
1084
+
1085
+ pITaskTrigger->Release();
1086
+ return trigger;
1087
+ }
1088
+
1089
+ /*
1090
+ * call-seq:
1091
+ * TaskScheduler#add_trigger(index, options)
1092
+ *
1093
+ * Adds the given trigger of hash +options+ at the specified +index+.
1094
+ */
1095
+ static VALUE ts_add_trigger(VALUE self, VALUE index, VALUE trigger)
1096
+ {
1097
+ TSStruct* ptr;
1098
+ HRESULT hr;
1099
+ WORD TriggerIndex;
1100
+ ITaskTrigger *pITaskTrigger;
1101
+ TASK_TRIGGER pTrigger;
1102
+ VALUE i, htmp;
1103
+
1104
+ Data_Get_Struct(self, TSStruct, ptr);
1105
+ Check_Type(trigger, T_HASH);
1106
+ check_ts_ptr(ptr, "ts_add_trigger");
1107
+
1108
+ TriggerIndex = NUM2INT(index);
1109
+
1110
+ hr = ptr->pITask->GetTrigger(TriggerIndex,&pITaskTrigger);
1111
+
1112
+ if(FAILED(hr))
1113
+ rb_raise(cTSError, ErrorString(GetLastError()));
1114
+
1115
+ ZeroMemory(&pTrigger, sizeof(TASK_TRIGGER));
1116
+
1117
+ // Define TASK_TRIGGER structure. Note that wBeginDay, wBeginMonth and
1118
+ // wBeginYear must be set to a valid day, month, and year respectively.
1119
+ pTrigger.cbTriggerSize = sizeof(TASK_TRIGGER);
1120
+
1121
+ if((i = rb_hash_aref(trigger, rb_str_new2("start_year"))) != Qnil)
1122
+ pTrigger.wBeginYear = NUM2INT(i);
1123
+
1124
+ if((i = rb_hash_aref(trigger, rb_str_new2("start_month"))) != Qnil)
1125
+ pTrigger.wBeginMonth = NUM2INT(i);
1126
+
1127
+ if((i = rb_hash_aref(trigger, rb_str_new2("start_day"))) != Qnil)
1128
+ pTrigger.wBeginDay = NUM2INT(i);
1129
+
1130
+ if((i = rb_hash_aref(trigger, rb_str_new2("end_year"))) != Qnil)
1131
+ pTrigger.wEndYear = NUM2INT(i);
1132
+
1133
+ if((i = rb_hash_aref(trigger, rb_str_new2("end_month"))) != Qnil)
1134
+ pTrigger.wEndMonth = NUM2INT(i);
1135
+
1136
+ if((i = rb_hash_aref(trigger, rb_str_new2("end_day"))) != Qnil)
1137
+ pTrigger.wEndDay = NUM2INT(i);
1138
+
1139
+ if((i = rb_hash_aref(trigger, rb_str_new2("start_hour"))) != Qnil)
1140
+ pTrigger.wStartHour = NUM2INT(i);
1141
+
1142
+ if((i = rb_hash_aref(trigger, rb_str_new2("start_minute"))) != Qnil)
1143
+ pTrigger.wStartMinute = NUM2INT(i);
1144
+
1145
+ if((i = rb_hash_aref(trigger, rb_str_new2("minutes_duration"))) != Qnil)
1146
+ pTrigger.MinutesDuration = NUM2INT(i);
1147
+
1148
+ if((i = rb_hash_aref(trigger, rb_str_new2("minutes_interval"))) != Qnil)
1149
+ pTrigger.MinutesInterval = NUM2INT(i);
1150
+
1151
+ if((i = rb_hash_aref(trigger, rb_str_new2("random_minutes_interval"))) != Qnil)
1152
+ pTrigger.wRandomMinutesInterval = NUM2INT(i);
1153
+
1154
+ if((i = rb_hash_aref(trigger, rb_str_new2("flags"))) != Qnil)
1155
+ pTrigger.rgFlags = NUM2INT(i);
1156
+
1157
+ if((i = rb_hash_aref(trigger, rb_str_new2("trigger_type"))) != Qnil)
1158
+ pTrigger.TriggerType = (TASK_TRIGGER_TYPE)NUM2INT(i);
1159
+
1160
+ htmp = rb_hash_aref(trigger, rb_str_new2("type"));
1161
+ Check_Type(htmp, T_HASH);
1162
+
1163
+ switch(pTrigger.TriggerType){
1164
+ case TASK_TIME_TRIGGER_DAILY:
1165
+ if((i = rb_hash_aref(htmp, rb_str_new2("days_interval"))) != Qnil)
1166
+ pTrigger.Type.Daily.DaysInterval = NUM2INT(i);
1167
+ break;
1168
+ case TASK_TIME_TRIGGER_WEEKLY:
1169
+ if((i = rb_hash_aref(htmp, rb_str_new2("weeks_interval"))) != Qnil)
1170
+ pTrigger.Type.Weekly.WeeksInterval = NUM2INT(i);
1171
+ if((i = rb_hash_aref(htmp, rb_str_new2("days_of_week"))) != Qnil)
1172
+ pTrigger.Type.Weekly.rgfDaysOfTheWeek = NUM2INT(i);
1173
+ break;
1174
+ case TASK_TIME_TRIGGER_MONTHLYDATE:
1175
+ if((i = rb_hash_aref(htmp, rb_str_new2("months"))) != Qnil)
1176
+ pTrigger.Type.MonthlyDate.rgfMonths = NUM2INT(i);
1177
+ if((i = rb_hash_aref(htmp, rb_str_new2("days"))) != Qnil)
1178
+ pTrigger.Type.MonthlyDate.rgfDays = humanDaysToBitField(NUM2INT(i));
1179
+ break;
1180
+ case TASK_TIME_TRIGGER_MONTHLYDOW:
1181
+ if((i = rb_hash_aref(htmp, rb_str_new2("weeks"))) != Qnil)
1182
+ pTrigger.Type.MonthlyDOW.wWhichWeek = NUM2INT(i);
1183
+ if((i = rb_hash_aref(htmp, rb_str_new2("days_of_week"))) != Qnil)
1184
+ pTrigger.Type.MonthlyDOW.rgfDaysOfTheWeek = NUM2INT(i);
1185
+ if((i = rb_hash_aref(htmp, rb_str_new2("months"))) != Qnil)
1186
+ pTrigger.Type.MonthlyDOW.rgfMonths = NUM2INT(i);
1187
+ break;
1188
+ default:
1189
+ rb_raise(cTSError, "Unknown trigger type");
1190
+ }
1191
+
1192
+ hr = pITaskTrigger->SetTrigger(&pTrigger);
1193
+
1194
+ if(FAILED(hr))
1195
+ rb_raise(cTSError, ErrorString(GetLastError()));
1196
+
1197
+ pITaskTrigger->Release();
1198
+
1199
+ return Qtrue;
1200
+ }
1201
+
1202
+ /*
1203
+ * call-seq:
1204
+ * TaskScheduler#trigger=(options)
1205
+ *
1206
+ * Takes a hash of +options+ that set the various trigger values, i.e. when
1207
+ * and how often the task will run. Valid keys are:
1208
+ *
1209
+ * * start_year # Must be greater than or equal to current year
1210
+ * * start_month # 1-12
1211
+ * * start_day # 1-31
1212
+ * * start_hour # 0-23
1213
+ * * start_minute # 0-59
1214
+ * * end_year
1215
+ * * end_month
1216
+ * * end_day
1217
+ * * minutes_duration
1218
+ * * minutes_interval
1219
+ * * random_minutes_interval
1220
+ * * flags
1221
+ * * trigger_type
1222
+ * * type # A sub-hash
1223
+ *
1224
+ * The 'trigger_type' determines what values are valid for the 'type'
1225
+ * key. They are as follows:
1226
+ *
1227
+ * Trigger Type Valid 'type' keys
1228
+ * ------------ ---------------------
1229
+ * DAILY days_interval
1230
+ * WEEKLY weeks_interval, days_of_week
1231
+ * MONTHLY_DATE months, days
1232
+ * MONTHLY_DOW weeks, days_of_week, months
1233
+ *--
1234
+ * TODO: Allow symbols or strings.
1235
+ */
1236
+ static VALUE ts_set_trigger(VALUE self, VALUE v_opts)
1237
+ {
1238
+ TSStruct* ptr;
1239
+ HRESULT hr;
1240
+ WORD TriggerIndex;
1241
+ ITaskTrigger *pITaskTrigger;
1242
+ TASK_TRIGGER pTrigger;
1243
+ VALUE i, htmp;
1244
+
1245
+ Data_Get_Struct(self, TSStruct, ptr);
1246
+ Check_Type(v_opts, T_HASH);
1247
+ check_ts_ptr(ptr, "ts_set_trigger");
1248
+
1249
+ hr = ptr->pITask->CreateTrigger(&TriggerIndex, &pITaskTrigger);
1250
+
1251
+ if(FAILED(hr))
1252
+ rb_raise(cTSError, ErrorString(GetLastError()));
1253
+
1254
+ ZeroMemory(&pTrigger, sizeof(TASK_TRIGGER));
1255
+
1256
+ // Define TASK_TRIGGER structure. Note that wBeginDay, wBeginMonth, and
1257
+ // wBeginYear must be set to a valid day, month, and year respectively.
1258
+ pTrigger.cbTriggerSize = sizeof(TASK_TRIGGER);
1259
+
1260
+ if((i = rb_hash_aref(v_opts, rb_str_new2("start_year"))) != Qnil)
1261
+ pTrigger.wBeginYear = NUM2INT(i);
1262
+
1263
+ if((i = rb_hash_aref(v_opts, rb_str_new2("start_month"))) != Qnil)
1264
+ pTrigger.wBeginMonth = NUM2INT(i);
1265
+
1266
+ if((i = rb_hash_aref(v_opts, rb_str_new2("start_day"))) != Qnil)
1267
+ pTrigger.wBeginDay = NUM2INT(i);
1268
+
1269
+ if((i = rb_hash_aref(v_opts, rb_str_new2("end_year"))) != Qnil)
1270
+ pTrigger.wEndYear = NUM2INT(i);
1271
+
1272
+ if((i = rb_hash_aref(v_opts, rb_str_new2("end_month"))) != Qnil)
1273
+ pTrigger.wEndMonth = NUM2INT(i);
1274
+
1275
+ if((i = rb_hash_aref(v_opts, rb_str_new2("end_day"))) != Qnil)
1276
+ pTrigger.wEndDay = NUM2INT(i);
1277
+
1278
+ if((i = rb_hash_aref(v_opts, rb_str_new2("start_hour"))) != Qnil)
1279
+ pTrigger.wStartHour = NUM2INT(i);
1280
+
1281
+ if((i = rb_hash_aref(v_opts, rb_str_new2("start_minute"))) != Qnil)
1282
+ pTrigger.wStartMinute = NUM2INT(i);
1283
+
1284
+ if((i = rb_hash_aref(v_opts, rb_str_new2("minutes_duration"))) != Qnil)
1285
+ pTrigger.MinutesDuration = NUM2INT(i);
1286
+
1287
+ if((i = rb_hash_aref(v_opts, rb_str_new2("minutes_interval"))) != Qnil)
1288
+ pTrigger.MinutesInterval = NUM2INT(i);
1289
+
1290
+ if((i = rb_hash_aref(v_opts, rb_str_new2("random_minutes_interval"))) != Qnil)
1291
+ pTrigger.wRandomMinutesInterval = NUM2INT(i);
1292
+
1293
+ if((i = rb_hash_aref(v_opts, rb_str_new2("flags"))) != Qnil)
1294
+ pTrigger.rgFlags = NUM2INT(i);
1295
+
1296
+ if((i = rb_hash_aref(v_opts, rb_str_new2("trigger_type")))!=Qnil)
1297
+ pTrigger.TriggerType = (TASK_TRIGGER_TYPE)NUM2INT(i);
1298
+
1299
+ htmp = rb_hash_aref(v_opts, rb_str_new2("type"));
1300
+
1301
+ if(htmp != Qnil)
1302
+ Check_Type(htmp, T_HASH);
1303
+
1304
+ switch(pTrigger.TriggerType) {
1305
+ case TASK_TIME_TRIGGER_DAILY:
1306
+ if((i = rb_hash_aref(htmp, rb_str_new2("days_interval"))) != Qnil)
1307
+ pTrigger.Type.Daily.DaysInterval = NUM2INT(i);
1308
+
1309
+ break;
1310
+ case TASK_TIME_TRIGGER_WEEKLY:
1311
+ if((i = rb_hash_aref(htmp, rb_str_new2("weeks_interval"))) != Qnil)
1312
+ pTrigger.Type.Weekly.WeeksInterval = NUM2INT(i);
1313
+
1314
+ if((i = rb_hash_aref(htmp, rb_str_new2("days_of_week"))) != Qnil)
1315
+ pTrigger.Type.Weekly.rgfDaysOfTheWeek = NUM2INT(i);
1316
+
1317
+ break;
1318
+ case TASK_TIME_TRIGGER_MONTHLYDATE:
1319
+ if((i = rb_hash_aref(htmp, rb_str_new2("months"))) != Qnil)
1320
+ pTrigger.Type.MonthlyDate.rgfMonths = NUM2INT(i);
1321
+
1322
+ if((i = rb_hash_aref(htmp, rb_str_new2("days"))) != Qnil)
1323
+ pTrigger.Type.MonthlyDate.rgfDays = humanDaysToBitField(NUM2INT(i));
1324
+
1325
+ break;
1326
+ case TASK_TIME_TRIGGER_MONTHLYDOW:
1327
+ if((i = rb_hash_aref(htmp, rb_str_new2("weeks"))) != Qnil)
1328
+ pTrigger.Type.MonthlyDOW.wWhichWeek = NUM2INT(i);
1329
+
1330
+ if((i = rb_hash_aref(htmp, rb_str_new2("days_of_week"))) != Qnil)
1331
+ pTrigger.Type.MonthlyDOW.rgfDaysOfTheWeek = NUM2INT(i);
1332
+
1333
+ if((i = rb_hash_aref(htmp, rb_str_new2("months"))) != Qnil)
1334
+ pTrigger.Type.MonthlyDOW.rgfMonths = NUM2INT(i);
1335
+ break;
1336
+ default:
1337
+ rb_raise(cTSError, "Unknown trigger type");
1338
+ }
1339
+
1340
+ hr = pITaskTrigger->SetTrigger(&pTrigger);
1341
+
1342
+ if(FAILED(hr))
1343
+ rb_raise(cTSError, ErrorString(GetLastError()));
1344
+
1345
+ pITaskTrigger->Release();
1346
+
1347
+ return v_opts;
1348
+ }
1349
+
1350
+ /*
1351
+ * Sets an OR'd value of flags that modify the behavior of the work item.
1352
+ */
1353
+ static VALUE ts_set_flags(VALUE self, VALUE v_flags)
1354
+ {
1355
+ TSStruct* ptr;
1356
+ HRESULT hr;
1357
+ DWORD dwFlags;
1358
+
1359
+ Data_Get_Struct(self, TSStruct, ptr);
1360
+
1361
+ check_ts_ptr(ptr, "ts_set_flags");
1362
+
1363
+ dwFlags = NUM2UINT(v_flags);
1364
+
1365
+ hr = ptr->pITask->SetFlags(dwFlags);
1366
+
1367
+ if(FAILED(hr))
1368
+ rb_raise(cTSError, ErrorString(GetLastError()));
1369
+
1370
+ return v_flags;
1371
+ }
1372
+
1373
+ /*
1374
+ * Returns the flags (integer) that modify the behavior of the work item. You
1375
+ * must OR the return value to determine the flags yourself.
1376
+ *--
1377
+ * TODO: Change this to an array of strings. There aren't that many.
1378
+ */
1379
+ static VALUE ts_get_flags(VALUE self)
1380
+ {
1381
+ TSStruct* ptr;
1382
+ HRESULT hr;
1383
+ DWORD dwFlags;
1384
+ VALUE v_flags;
1385
+
1386
+ Data_Get_Struct(self, TSStruct, ptr);
1387
+
1388
+ check_ts_ptr(ptr, "ts_get_flags");
1389
+
1390
+ hr = ptr->pITask->GetFlags(&dwFlags);
1391
+
1392
+ if(SUCCEEDED(hr))
1393
+ v_flags = UINT2NUM(dwFlags);
1394
+ else
1395
+ rb_raise(cTSError, ErrorString(GetLastError()));
1396
+
1397
+ return v_flags;
1398
+ }
1399
+
1400
+ /*
1401
+ * Returns the status of the current task. The possible return values are
1402
+ * "ready", "running", "not scheduled" or "unknown", though the latter should
1403
+ * never occur.
1404
+ *
1405
+ * In the case of "not scheduled", it means that one or more of the properties
1406
+ * that are needed to run the work item on a schedule have not been set.
1407
+ */
1408
+ static VALUE ts_get_status(VALUE self)
1409
+ {
1410
+ TSStruct* ptr;
1411
+ HRESULT hr;
1412
+ HRESULT st;
1413
+ VALUE v_status;
1414
+
1415
+ Data_Get_Struct(self, TSStruct, ptr);
1416
+
1417
+ check_ts_ptr(ptr, "ts_get_status");
1418
+
1419
+ hr = ptr->pITask->GetStatus(&st);
1420
+
1421
+ if(SUCCEEDED(hr)){
1422
+ switch((DWORD)st){
1423
+ case SCHED_S_TASK_READY:
1424
+ v_status = rb_str_new2("ready");
1425
+ break;
1426
+ case SCHED_S_TASK_RUNNING:
1427
+ v_status = rb_str_new2("running");
1428
+ break;
1429
+ case SCHED_S_TASK_NOT_SCHEDULED:
1430
+ v_status = rb_str_new2("not scheduled");
1431
+ break;
1432
+ default:
1433
+ v_status = rb_str_new2("unknown");
1434
+ };
1435
+ }
1436
+ else{
1437
+ rb_raise(cTSError, ErrorString(GetLastError()));
1438
+ }
1439
+
1440
+ return v_status;
1441
+ }
1442
+
1443
+ /*
1444
+ * Returns the exit code from when it last attempted to run the task.
1445
+ */
1446
+ static VALUE ts_get_exit_code(VALUE self)
1447
+ {
1448
+ TSStruct* ptr;
1449
+ HRESULT hr;
1450
+ DWORD dwCode;
1451
+ VALUE v_exit_code;
1452
+
1453
+ Data_Get_Struct(self, TSStruct, ptr);
1454
+
1455
+ check_ts_ptr(ptr, "ts_get_exit_code");
1456
+
1457
+ hr = ptr->pITask->GetExitCode(&dwCode);
1458
+
1459
+ if(SUCCEEDED(hr))
1460
+ v_exit_code = UINT2NUM(dwCode);
1461
+ else
1462
+ rb_raise(cTSError, ErrorString(GetLastError()));
1463
+
1464
+ return v_exit_code;
1465
+ }
1466
+
1467
+ /*
1468
+ * Sets the comment associated with the task.
1469
+ */
1470
+ static VALUE ts_set_comment(VALUE self, VALUE v_comment)
1471
+ {
1472
+ TSStruct* ptr;
1473
+ HRESULT hr;
1474
+ wchar_t buf[NAME_MAX];
1475
+
1476
+ Data_Get_Struct(self, TSStruct, ptr);
1477
+ check_ts_ptr(ptr, "ts_set_comment");
1478
+ StringValue(v_comment);
1479
+
1480
+ MultiByteToWideChar(
1481
+ CP_ACP,
1482
+ 0,
1483
+ StringValuePtr(v_comment),
1484
+ RSTRING(v_comment)->len + 1,
1485
+ buf,
1486
+ NAME_MAX
1487
+ );
1488
+
1489
+ hr = ptr->pITask->SetComment(buf);
1490
+
1491
+ if(FAILED(hr))
1492
+ rb_raise(cTSError, ErrorString(GetLastError()));
1493
+
1494
+ return v_comment;
1495
+ }
1496
+
1497
+ /*
1498
+ * Returns the comment associated with the task.
1499
+ */
1500
+ static VALUE ts_get_comment(VALUE self)
1501
+ {
1502
+ TSStruct* ptr;
1503
+ HRESULT hr;
1504
+ LPWSTR lpComment;
1505
+ TCHAR buf[NAME_MAX];
1506
+ VALUE v_comment;
1507
+
1508
+ Data_Get_Struct(self, TSStruct, ptr);
1509
+
1510
+ check_ts_ptr(ptr, "ts_get_comment");
1511
+
1512
+ hr = ptr->pITask->GetComment(&lpComment);
1513
+
1514
+ if(SUCCEEDED(hr))
1515
+ {
1516
+ WideCharToMultiByte(CP_ACP, 0, lpComment, -1, buf, NAME_MAX, NULL, NULL);
1517
+ CoTaskMemFree(lpComment);
1518
+ v_comment = rb_str_new2(buf);
1519
+ }
1520
+ else{
1521
+ rb_raise(cTSError, ErrorString(GetLastError()));
1522
+ }
1523
+
1524
+ return v_comment;
1525
+ }
1526
+
1527
+ /*
1528
+ * Sets the name of the user who created the task.
1529
+ */
1530
+ static VALUE ts_set_creator(VALUE self, VALUE v_creator){
1531
+ TSStruct* ptr;
1532
+ HRESULT hr;
1533
+ wchar_t cwszCreator[NAME_MAX];
1534
+
1535
+ Data_Get_Struct(self, TSStruct, ptr);
1536
+ check_ts_ptr(ptr, "ts_set_creator");
1537
+ StringValue(v_creator);
1538
+
1539
+ MultiByteToWideChar(
1540
+ CP_ACP,
1541
+ 0,
1542
+ StringValuePtr(v_creator),
1543
+ RSTRING(v_creator)->len + 1,
1544
+ cwszCreator,
1545
+ NAME_MAX
1546
+ );
1547
+
1548
+ hr = ptr->pITask->SetCreator(cwszCreator);
1549
+
1550
+ if(FAILED(hr))
1551
+ rb_raise(cTSError,ErrorString(GetLastError()));
1552
+
1553
+ return v_creator;
1554
+ }
1555
+
1556
+ /*
1557
+ * Returns the name of the user who created the task.
1558
+ */
1559
+ static VALUE ts_get_creator(VALUE self){
1560
+ TSStruct* ptr;
1561
+ HRESULT hr;
1562
+ LPWSTR lpCreator;
1563
+ TCHAR crt[NAME_MAX];
1564
+ VALUE v_creator;
1565
+
1566
+ Data_Get_Struct(self, TSStruct, ptr);
1567
+
1568
+ check_ts_ptr(ptr, "ts_get_creator");
1569
+
1570
+ hr = ptr->pITask->GetCreator(&lpCreator);
1571
+
1572
+ if(SUCCEEDED(hr)){
1573
+ WideCharToMultiByte(CP_ACP, 0, lpCreator, -1, crt, NAME_MAX, NULL, NULL);
1574
+ CoTaskMemFree(lpCreator);
1575
+ v_creator = rb_str_new2(crt);
1576
+ }
1577
+ else{
1578
+ rb_raise(cTSError, ErrorString(GetLastError()));
1579
+ }
1580
+
1581
+ return v_creator;
1582
+ }
1583
+
1584
+ /*
1585
+ * Returns a Time object that indicates the next time the scheduled task
1586
+ * will run.
1587
+ */
1588
+ static VALUE ts_get_next_run_time(VALUE self)
1589
+ {
1590
+ TSStruct* ptr;
1591
+ HRESULT hr;
1592
+ SYSTEMTIME nextRun;
1593
+ VALUE argv[7];
1594
+ VALUE v_time;
1595
+
1596
+ Data_Get_Struct(self, TSStruct, ptr);
1597
+
1598
+ check_ts_ptr(ptr, "ts_get_next_run_time");
1599
+
1600
+ hr = ptr->pITask->GetNextRunTime(&nextRun);
1601
+
1602
+ if(SUCCEEDED(hr)){
1603
+ argv[0] = INT2NUM(nextRun.wYear);
1604
+ argv[1] = INT2NUM(nextRun.wMonth);
1605
+ argv[2] = INT2NUM(nextRun.wDay);
1606
+ argv[3] = INT2NUM(nextRun.wHour);
1607
+ argv[4] = INT2NUM(nextRun.wMinute);
1608
+ argv[5] = INT2NUM(nextRun.wSecond);
1609
+ argv[6] = INT2NUM(nextRun.wMilliseconds * 1000);
1610
+ v_time = rb_funcall2(rb_cTime, rb_intern("local"), 7, argv);
1611
+ }
1612
+ else{
1613
+ rb_raise(cTSError,ErrorString(GetLastError()));
1614
+ }
1615
+
1616
+ return v_time;
1617
+ }
1618
+
1619
+ /*
1620
+ * Returns a Time object indicating the most recent time the task ran or
1621
+ * nil if the task has never run.
1622
+ */
1623
+ static VALUE ts_get_most_recent_run_time(VALUE self)
1624
+ {
1625
+ TSStruct* ptr;
1626
+ HRESULT hr;
1627
+ SYSTEMTIME lastRun;
1628
+ VALUE argv[7];
1629
+ VALUE v_time;
1630
+
1631
+ Data_Get_Struct(self, TSStruct, ptr);
1632
+
1633
+ check_ts_ptr(ptr, "ts_get_most_recent_run_time");
1634
+
1635
+ hr = ptr->pITask->GetMostRecentRunTime(&lastRun);
1636
+
1637
+ if(SCHED_S_TASK_HAS_NOT_RUN == hr){
1638
+ v_time = Qnil;
1639
+ }
1640
+ else if(SUCCEEDED(hr)){
1641
+ argv[0] = INT2NUM(lastRun.wYear);
1642
+ argv[1] = INT2NUM(lastRun.wMonth);
1643
+ argv[2] = INT2NUM(lastRun.wDay);
1644
+ argv[3] = INT2NUM(lastRun.wHour);
1645
+ argv[4] = INT2NUM(lastRun.wMinute);
1646
+ argv[5] = INT2NUM(lastRun.wSecond);
1647
+ argv[6] = INT2NUM(lastRun.wMilliseconds * 1000);
1648
+ v_time = rb_funcall2(rb_cTime, rb_intern("local"), 7, argv);
1649
+ }
1650
+ else{
1651
+ rb_raise(cTSError, ErrorString(GetLastError()));
1652
+ }
1653
+
1654
+ return v_time;
1655
+ }
1656
+
1657
+ /*
1658
+ * Sets the maximum length of time, in milliseconds, that the task can run
1659
+ * before terminating. Returns the value you specified if successful.
1660
+ */
1661
+ static VALUE ts_set_max_run_time(VALUE self, VALUE v_max_run_time)
1662
+ {
1663
+ TSStruct* ptr;
1664
+ HRESULT hr;
1665
+ DWORD maxRunTimeMilliSeconds;
1666
+
1667
+ Data_Get_Struct(self, TSStruct, ptr);
1668
+
1669
+ check_ts_ptr(ptr, "ts_set_max_run_time");
1670
+
1671
+ maxRunTimeMilliSeconds = NUM2UINT(v_max_run_time);
1672
+
1673
+ hr = ptr->pITask->SetMaxRunTime(maxRunTimeMilliSeconds);
1674
+
1675
+ if(FAILED(hr))
1676
+ rb_raise(cTSError, ErrorString(GetLastError()));
1677
+
1678
+ return v_max_run_time;
1679
+ }
1680
+
1681
+ /*
1682
+ * Returns the maximum length of time, in milliseconds, the task can run
1683
+ * before terminating.
1684
+ */
1685
+ static VALUE ts_get_max_run_time(VALUE self)
1686
+ {
1687
+ TSStruct* ptr;
1688
+ HRESULT hr;
1689
+ DWORD maxRunTimeMilliSeconds;
1690
+ VALUE v_max_run_time;
1691
+
1692
+ Data_Get_Struct(self, TSStruct, ptr);
1693
+
1694
+ check_ts_ptr(ptr, "ts_get_max_run_time");
1695
+
1696
+ hr = ptr->pITask->GetMaxRunTime(&maxRunTimeMilliSeconds);
1697
+
1698
+ if(SUCCEEDED(hr))
1699
+ v_max_run_time = UINT2NUM(maxRunTimeMilliSeconds);
1700
+ else
1701
+ rb_raise(cTSError, ErrorString(GetLastError()));
1702
+
1703
+ return v_max_run_time;
1704
+ }
1705
+
1706
+ /*
1707
+ * The TaskScheduler class encapsulates the MS Windows task scheduler,
1708
+ * with which you can create, modify and delete new tasks.
1709
+ */
1710
+ void Init_taskscheduler()
1711
+ {
1712
+ VALUE mWin32, cTaskScheduler;;
1713
+
1714
+ // The C++ code requires explicit function casting via 'VALUEFUNC'
1715
+
1716
+ // Modules and classes
1717
+
1718
+ /* The Win32 module serves as a toplevel namespace only */
1719
+ mWin32 = rb_define_module("Win32");
1720
+
1721
+ /* The TaskScheduler class encapsulates tasks related to the
1722
+ * Windows task scheduler */
1723
+ cTaskScheduler = rb_define_class_under(mWin32, "TaskScheduler", rb_cObject);
1724
+
1725
+ /* The TaskScheduler::Error class is raised whenever an operation related
1726
+ * the task scheduler fails.
1727
+ */
1728
+ cTSError = rb_define_class_under(cTaskScheduler, "Error", rb_eStandardError);
1729
+
1730
+ // Taskscheduler class and instance methods
1731
+
1732
+ rb_define_alloc_func(cTaskScheduler, ts_allocate);
1733
+ rb_define_method(cTaskScheduler, "initialize", VALUEFUNC(ts_init), -1);
1734
+ rb_define_method(cTaskScheduler, "enum", VALUEFUNC(ts_enum), 0);
1735
+ rb_define_method(cTaskScheduler, "activate", VALUEFUNC(ts_activate), 1);
1736
+ rb_define_method(cTaskScheduler, "delete", VALUEFUNC(ts_delete), 1);
1737
+ rb_define_method(cTaskScheduler, "run", VALUEFUNC(ts_run), 0);
1738
+ rb_define_method(cTaskScheduler, "save", VALUEFUNC(ts_save), -1);
1739
+ rb_define_method(cTaskScheduler, "terminate", VALUEFUNC(ts_terminate), 0);
1740
+
1741
+ rb_define_method(cTaskScheduler, "machine=",
1742
+ VALUEFUNC(ts_set_target_computer), 1);
1743
+
1744
+ rb_define_method(cTaskScheduler, "set_account_information",
1745
+ VALUEFUNC(ts_set_account_information), 2);
1746
+
1747
+ rb_define_method(cTaskScheduler, "account_information",
1748
+ VALUEFUNC(ts_get_account_information), 0);
1749
+
1750
+ rb_define_method(cTaskScheduler, "application_name",
1751
+ VALUEFUNC(ts_get_application_name), 0);
1752
+
1753
+ rb_define_method(cTaskScheduler, "application_name=",
1754
+ VALUEFUNC(ts_set_application_name), 1);
1755
+
1756
+ rb_define_method(cTaskScheduler, "parameters",
1757
+ VALUEFUNC(ts_get_parameters), 0);
1758
+
1759
+ rb_define_method(cTaskScheduler, "parameters=",
1760
+ VALUEFUNC(ts_set_parameters), 1);
1761
+
1762
+ rb_define_method(cTaskScheduler, "working_directory",
1763
+ VALUEFUNC(ts_get_working_directory), 0);
1764
+
1765
+ rb_define_method(cTaskScheduler, "working_directory=",
1766
+ VALUEFUNC(ts_set_working_directory), 1);
1767
+
1768
+ rb_define_method(cTaskScheduler, "priority",
1769
+ VALUEFUNC(ts_get_priority), 0);
1770
+
1771
+ rb_define_method(cTaskScheduler, "priority=",
1772
+ VALUEFUNC(ts_set_priority), 1);
1773
+
1774
+ rb_define_method(cTaskScheduler, "new_work_item",
1775
+ VALUEFUNC(ts_new_work_item), 2);
1776
+
1777
+ rb_define_alias(cTaskScheduler, "new_task", "new_work_item");
1778
+
1779
+ // Trigger related methods
1780
+
1781
+ rb_define_method(cTaskScheduler, "trigger_count",
1782
+ VALUEFUNC(ts_get_trigger_count), 0);
1783
+
1784
+ rb_define_method(cTaskScheduler, "trigger_string",
1785
+ VALUEFUNC(ts_get_trigger_string), 1);
1786
+
1787
+ rb_define_method(cTaskScheduler, "delete_trigger",
1788
+ VALUEFUNC(ts_delete_trigger), 1);
1789
+
1790
+ rb_define_method(cTaskScheduler, "trigger",
1791
+ VALUEFUNC(ts_get_trigger), 1);
1792
+
1793
+ rb_define_method(cTaskScheduler, "trigger=",
1794
+ VALUEFUNC(ts_set_trigger), 1);
1795
+
1796
+ rb_define_method(cTaskScheduler, "add_trigger",
1797
+ VALUEFUNC(ts_add_trigger), 2);
1798
+
1799
+ rb_define_method(cTaskScheduler, "flags",
1800
+ VALUEFUNC(ts_get_flags), 0);
1801
+
1802
+ rb_define_method(cTaskScheduler, "flags=",
1803
+ VALUEFUNC(ts_set_flags), 1);
1804
+
1805
+ rb_define_method(cTaskScheduler, "status",
1806
+ VALUEFUNC(ts_get_status), 0);
1807
+
1808
+ rb_define_method(cTaskScheduler, "exit_code",
1809
+ VALUEFUNC(ts_get_exit_code), 0);
1810
+
1811
+ rb_define_method(cTaskScheduler, "comment",
1812
+ VALUEFUNC(ts_get_comment), 0);
1813
+
1814
+ rb_define_method(cTaskScheduler, "comment=",
1815
+ VALUEFUNC(ts_set_comment), 1);
1816
+
1817
+ rb_define_method(cTaskScheduler, "creator",
1818
+ VALUEFUNC(ts_get_creator), 0);
1819
+
1820
+ rb_define_method(cTaskScheduler, "creator=",
1821
+ VALUEFUNC(ts_set_creator), 1);
1822
+
1823
+ rb_define_method(cTaskScheduler, "next_run_time",
1824
+ VALUEFUNC(ts_get_next_run_time), 0);
1825
+
1826
+ rb_define_method(cTaskScheduler, "most_recent_run_time",
1827
+ VALUEFUNC(ts_get_most_recent_run_time), 0);
1828
+
1829
+ rb_define_method(cTaskScheduler, "max_run_time",
1830
+ VALUEFUNC(ts_get_max_run_time), 0);
1831
+
1832
+ rb_define_method(cTaskScheduler, "max_run_time=",
1833
+ VALUEFUNC(ts_set_max_run_time), 1);
1834
+
1835
+ rb_define_alias(cTaskScheduler, "host=", "machine=");
1836
+
1837
+ /* 0.1.0: The version of this library, returned as a String */
1838
+ rb_define_const(cTaskScheduler, "VERSION",
1839
+ rb_str_new2(WIN32_TASKSCHEDULER_VERSION));
1840
+
1841
+ /* 4: Typically used for system monitoring applications */
1842
+ rb_define_const(cTaskScheduler, "IDLE", INT2FIX(IDLE_PRIORITY_CLASS));
1843
+
1844
+ /* 8: The default priority class. Recommended for most applications */
1845
+ rb_define_const(cTaskScheduler, "NORMAL", INT2FIX(NORMAL_PRIORITY_CLASS));
1846
+
1847
+ /* 13: High priority. Use only for applications that need regular focus */
1848
+ rb_define_const(cTaskScheduler, "HIGH", INT2FIX(HIGH_PRIORITY_CLASS));
1849
+
1850
+ /* 24: Extremely high priority. May affect other applications. Not recommended. */
1851
+ rb_define_const(cTaskScheduler, "REALTIME", INT2FIX(REALTIME_PRIORITY_CLASS));
1852
+
1853
+ /* 6: Between the IDLE and NORMAL priority class */
1854
+ rb_define_const(cTaskScheduler, "BELOW_NORMAL", INT2FIX(BELOW_NORMAL_PRIORITY_CLASS));
1855
+
1856
+ /* 10: Between the NORMAL and HIGH priority class */
1857
+ rb_define_const(cTaskScheduler, "ABOVE_NORMAL", INT2FIX(ABOVE_NORMAL_PRIORITY_CLASS));
1858
+
1859
+ /* 0: Trigger is set to run the task a single time */
1860
+ rb_define_const(cTaskScheduler, "ONCE", INT2FIX(TASK_TIME_TRIGGER_ONCE));
1861
+
1862
+ /* 1: Trigger is set to run the task on a daily interval */
1863
+ rb_define_const(cTaskScheduler, "DAILY", INT2FIX(TASK_TIME_TRIGGER_DAILY));
1864
+
1865
+ /* 2: Trigger is set to run the work item on specific days of a specific
1866
+ * week of a specific month
1867
+ */
1868
+ rb_define_const(cTaskScheduler, "WEEKLY", INT2FIX(TASK_TIME_TRIGGER_WEEKLY));
1869
+
1870
+ /* 3: Trigger is set to run the task on a specific day(s) of the month */
1871
+ rb_define_const(cTaskScheduler, "MONTHLYDATE",
1872
+ INT2FIX(TASK_TIME_TRIGGER_MONTHLYDATE)
1873
+ );
1874
+
1875
+ /* 4: Trigger is set to run the task on specific days, weeks and months */
1876
+ rb_define_const(cTaskScheduler, "MONTHLYDOW",
1877
+ INT2FIX(TASK_TIME_TRIGGER_MONTHLYDOW)
1878
+ );
1879
+
1880
+ /* 5: Trigger is set to run the task if the system remains idle for the amount
1881
+ * of time specified.
1882
+ */
1883
+ rb_define_const(cTaskScheduler, "ON_IDLE",
1884
+ INT2FIX(TASK_EVENT_TRIGGER_ON_IDLE));
1885
+
1886
+ /* 6: Trigger is set to run the task at system startup */
1887
+ rb_define_const(cTaskScheduler, "AT_SYSTEMSTART",
1888
+ INT2FIX(TASK_EVENT_TRIGGER_AT_SYSTEMSTART));
1889
+
1890
+ /* 7: Trigger is set to run the task when a user logs on */
1891
+ rb_define_const(cTaskScheduler, "AT_LOGON",
1892
+ INT2FIX(TASK_EVENT_TRIGGER_AT_LOGON));
1893
+
1894
+ /* The task will run between the 1st and 7th day of the month */
1895
+ rb_define_const(cTaskScheduler, "FIRST_WEEK", INT2FIX(TASK_FIRST_WEEK));
1896
+
1897
+ /* The task will run between the 8th and 14th day of the month */
1898
+ rb_define_const(cTaskScheduler, "SECOND_WEEK", INT2FIX(TASK_SECOND_WEEK));
1899
+
1900
+ /* The task will run between the 15th and 21st day of the month */
1901
+ rb_define_const(cTaskScheduler, "THIRD_WEEK", INT2FIX(TASK_THIRD_WEEK));
1902
+
1903
+ /* The task will run between the 22nd and 28th day of the month */
1904
+ rb_define_const(cTaskScheduler, "FOURTH_WEEK", INT2FIX(TASK_FOURTH_WEEK));
1905
+
1906
+ /* The task will run between the last seven days of the month */
1907
+ rb_define_const(cTaskScheduler, "LAST_WEEK", INT2FIX(TASK_LAST_WEEK));
1908
+
1909
+ /* The task will run on Sunday */
1910
+ rb_define_const(cTaskScheduler, "SUNDAY", INT2FIX(TASK_SUNDAY));
1911
+
1912
+ /* The task will run on Monday */
1913
+ rb_define_const(cTaskScheduler, "MONDAY", INT2FIX(TASK_MONDAY));
1914
+
1915
+ /* The task will run on Tuesday */
1916
+ rb_define_const(cTaskScheduler, "TUESDAY", INT2FIX(TASK_TUESDAY));
1917
+
1918
+ /* The task will run on Wednesday */
1919
+ rb_define_const(cTaskScheduler, "WEDNESDAY", INT2FIX(TASK_WEDNESDAY));
1920
+
1921
+ /* The task will run on Thursday */
1922
+ rb_define_const(cTaskScheduler, "THURSDAY", INT2FIX(TASK_THURSDAY));
1923
+
1924
+ /* The task will run on Friday */
1925
+ rb_define_const(cTaskScheduler, "FRIDAY", INT2FIX(TASK_FRIDAY));
1926
+
1927
+ /* The task will run on Saturday */
1928
+ rb_define_const(cTaskScheduler, "SATURDAY", INT2FIX(TASK_SATURDAY));
1929
+
1930
+ /* The task will run in January */
1931
+ rb_define_const(cTaskScheduler, "JANUARY", INT2FIX(TASK_JANUARY));
1932
+
1933
+ /* The task will run in Februrary */
1934
+ rb_define_const(cTaskScheduler, "FEBRUARY", INT2FIX(TASK_FEBRUARY));
1935
+
1936
+ /* The task will run in March */
1937
+ rb_define_const(cTaskScheduler, "MARCH", INT2FIX(TASK_MARCH));
1938
+
1939
+ /* The task will run in April */
1940
+ rb_define_const(cTaskScheduler, "APRIL", INT2FIX(TASK_APRIL));
1941
+
1942
+ /* The task will run in May */
1943
+ rb_define_const(cTaskScheduler, "MAY", INT2FIX(TASK_MAY));
1944
+
1945
+ /* The task will run in June */
1946
+ rb_define_const(cTaskScheduler, "JUNE", INT2FIX(TASK_JUNE));
1947
+
1948
+ /* The task will run in July */
1949
+ rb_define_const(cTaskScheduler, "JULY", INT2FIX(TASK_JULY));
1950
+
1951
+ /* The task will run in August */
1952
+ rb_define_const(cTaskScheduler, "AUGUST", INT2FIX(TASK_AUGUST));
1953
+
1954
+ /* The task will run in September */
1955
+ rb_define_const(cTaskScheduler, "SEPTEMBER", INT2FIX(TASK_SEPTEMBER));
1956
+
1957
+ /* The task will run in October */
1958
+ rb_define_const(cTaskScheduler, "OCTOBER", INT2FIX(TASK_OCTOBER));
1959
+
1960
+ /* The task will run in November */
1961
+ rb_define_const(cTaskScheduler, "NOVEMBER", INT2FIX(TASK_NOVEMBER));
1962
+
1963
+ /* The task will run in December */
1964
+ rb_define_const(cTaskScheduler, "DECEMBER", INT2FIX(TASK_DECEMBER));
1965
+
1966
+ /* The task must be allowed to interact with the logged-on user */
1967
+ rb_define_const(cTaskScheduler, "INTERACTIVE", INT2FIX(TASK_FLAG_INTERACTIVE));
1968
+
1969
+ /* The task must be deleted when there are no more scheduled run times */
1970
+ rb_define_const(cTaskScheduler, "DELETE_WHEN_DONE",
1971
+ INT2FIX(TASK_FLAG_DELETE_WHEN_DONE));
1972
+
1973
+ /* The task must be disabled */
1974
+ rb_define_const(cTaskScheduler, "DISABLED", INT2FIX(TASK_FLAG_DISABLED));
1975
+
1976
+ /* The task must only begin if the computer is not in use at the scheduled
1977
+ * start time.
1978
+ */
1979
+ rb_define_const(cTaskScheduler, "START_ONLY_IF_IDLE",
1980
+ INT2FIX(TASK_FLAG_START_ONLY_IF_IDLE));
1981
+
1982
+ /* The task must be terminated if the computer makes an idle to non-idle
1983
+ * transition while the task is running.
1984
+ */
1985
+ rb_define_const(cTaskScheduler, "KILL_ON_IDLE_END",
1986
+ INT2FIX(TASK_FLAG_KILL_ON_IDLE_END));
1987
+
1988
+ /* The task must not start if the computer is running on battery power */
1989
+ rb_define_const(cTaskScheduler, "DONT_START_IF_ON_BATTERIES",
1990
+ INT2FIX(TASK_FLAG_DONT_START_IF_ON_BATTERIES));
1991
+
1992
+ /* The task must end, and the associated application must quit, if the
1993
+ * computer switches to batter power.
1994
+ */
1995
+ rb_define_const(cTaskScheduler, "KILL_IF_GOING_ON_BATTERIES",
1996
+ INT2FIX(TASK_FLAG_KILL_IF_GOING_ON_BATTERIES));
1997
+
1998
+ /* The task must be hidden */
1999
+ rb_define_const(cTaskScheduler, "HIDDEN", INT2FIX(TASK_FLAG_HIDDEN));
2000
+
2001
+ /* The task must start again if the computer makes a non-idel to idle
2002
+ * transition before all the task's triggers elapse.
2003
+ */
2004
+ rb_define_const(cTaskScheduler, "RESTART_ON_IDLE_RESUME",
2005
+ INT2FIX(TASK_FLAG_RESTART_ON_IDLE_RESUME));
2006
+
2007
+ /* The task must cause the system to resume or awaken if the system is
2008
+ * sleeping.
2009
+ */
2010
+ rb_define_const(cTaskScheduler, "SYSTEM_REQUIRED",
2011
+ INT2FIX(TASK_FLAG_SYSTEM_REQUIRED));
2012
+
2013
+ /* Trigger structure's end date is valid. If this flag is not set the end
2014
+ * date data is ignored and the trigger will be valid indefinitely.
2015
+ */
2016
+ rb_define_const(cTaskScheduler, "FLAG_HAS_END_DATE",
2017
+ INT2FIX(TASK_TRIGGER_FLAG_HAS_END_DATE));
2018
+
2019
+ /* Task will be terminated at the end of the active trigger's lifetime. */
2020
+ rb_define_const(cTaskScheduler, "FLAG_KILL_AT_DURATION_END",
2021
+ INT2FIX(TASK_TRIGGER_FLAG_KILL_AT_DURATION_END));
2022
+
2023
+ /* Task trigger is inactive */
2024
+ rb_define_const(cTaskScheduler, "FLAG_DISABLED",
2025
+ INT2FIX(TASK_TRIGGER_FLAG_DISABLED));
2026
+
2027
+ /* The task must run only if the user specified in the task is logged
2028
+ * on interactively.
2029
+ */
2030
+ rb_define_const(cTaskScheduler, "RUN_ONLY_IF_LOGGED_ON",
2031
+ INT2FIX(TASK_FLAG_RUN_ONLY_IF_LOGGED_ON));
2032
+
2033
+ /* 1440: The maximum number of times a scheduled task can be run per day. */
2034
+ rb_define_const(cTaskScheduler, "MAX_RUN_TIMES",
2035
+ INT2FIX(TASK_MAX_RUN_TIMES));
2036
+ }