win32-taskscheduler 0.1.0-x86-mswin32-60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGES 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
data/MANIFEST ADDED
@@ -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,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
+ }