win32-taskscheduler 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +17 -0
- data/README +61 -53
- data/Rakefile +19 -39
- data/lib/win32/taskscheduler.rb +1442 -1430
- data/test/test_taskscheduler.rb +522 -508
- data/win32-taskscheduler.gemspec +23 -30
- metadata +19 -9
data/CHANGES
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
== 0.2.1 - 8-Oct-2011
|
2
|
+
* Fixed a bug that would not allow task to run as SYSTEM. Thanks go to
|
3
|
+
Josh cooper for the spot and patch.
|
4
|
+
* Fixed a bug in new_work_item that would cause it to crash if you tried
|
5
|
+
to create a work item that already existed. An error is now raised instead.
|
6
|
+
Thanks go to Pete Higgins for the spot.
|
7
|
+
* The set_trigger and trigger= methods now internally transform and validate
|
8
|
+
the trigger hash in the same manner as new_work_item. Thanks again go to
|
9
|
+
Pete Higgins.
|
10
|
+
* Cleaned up the repo. The C source files have been removed from the main
|
11
|
+
repository (and this gem). They are in a separate branch on github for
|
12
|
+
anyone who misses them.
|
13
|
+
* Refactored the Rakefile, removing tasks related to the old C source files,
|
14
|
+
and added tasks for cleaning, building and installing a gem.
|
15
|
+
* Updated the README file, eliminating references to anything that was only
|
16
|
+
related to the older C version.
|
17
|
+
|
1
18
|
== 0.2.0 - 19-Jun-2009
|
2
19
|
* Rewritten in pure Ruby!
|
3
20
|
* The TaskScheduler::ONCE constant is now a valid trigger type. Thanks go to
|
data/README
CHANGED
@@ -1,68 +1,76 @@
|
|
1
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.
|
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
4
|
|
5
|
-
=
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
ts = TaskScheduler.new
|
5
|
+
= Prerequisites
|
6
|
+
* win32-api
|
7
|
+
* windows-pr
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
# in the months of April and May.
|
14
|
-
#
|
15
|
-
trigger = {
|
16
|
-
:start_year => 2014,
|
17
|
-
:start_month => 4,
|
18
|
-
:start_day => 25,
|
19
|
-
:start_hour => 23,
|
20
|
-
:start_minute => 5,
|
21
|
-
:trigger_type => TaskScheduler::MONTHLYDOW,
|
22
|
-
:type => {
|
23
|
-
:weeks => TaskScheduler::FIRST_WEEK | TaskScheduler::LAST_WEEK,
|
24
|
-
:days_of_week => TaskScheduler::MONDAY | TaskScheduler::FRIDAY,
|
25
|
-
:months => TaskScheduler::APRIL | TaskScheduler::MAY
|
26
|
-
}
|
27
|
-
}
|
9
|
+
= Installation
|
10
|
+
gem install win32-taskscheduler
|
28
11
|
|
29
|
-
|
30
|
-
|
31
|
-
|
12
|
+
= Synopsis
|
13
|
+
require 'win32/taskscheduler'
|
14
|
+
include Win32
|
32
15
|
|
33
|
-
=
|
34
|
-
Ruby 1.8.2 or later.
|
35
|
-
Building from source requires VC++ 6.0 or later.
|
36
|
-
Windows XP or earlier. Vista and later not currently supported.
|
16
|
+
ts = TaskScheduler.new
|
37
17
|
|
38
|
-
|
39
|
-
|
18
|
+
# Create a trigger that starts on April 25, 2014 at 11:05 pm. The trigger
|
19
|
+
# will run on the first and last week of the month, on Monday and Friday,
|
20
|
+
# in the months of April and May.
|
21
|
+
#
|
22
|
+
trigger = {
|
23
|
+
:start_year => 2014,
|
24
|
+
:start_month => 4,
|
25
|
+
:start_day => 25,
|
26
|
+
:start_hour => 23,
|
27
|
+
:start_minute => 5,
|
28
|
+
:trigger_type => TaskScheduler::MONTHLYDOW,
|
29
|
+
:type => {
|
30
|
+
:weeks => TaskScheduler::FIRST_WEEK | TaskScheduler::LAST_WEEK,
|
31
|
+
:days_of_week => TaskScheduler::MONDAY | TaskScheduler::FRIDAY,
|
32
|
+
:months => TaskScheduler::APRIL | TaskScheduler::MAY
|
33
|
+
}
|
34
|
+
}
|
40
35
|
|
41
|
-
|
36
|
+
ts.new_work_item('my_notepad', trigger)
|
37
|
+
ts.application_name = 'notepad.exe'
|
38
|
+
ts.save
|
42
39
|
|
43
40
|
= Documentation
|
44
|
-
If you installed this library as a gem then the documentation was built for
|
45
|
-
you and can be viewed if your gem server is running.
|
41
|
+
If you installed this library as a gem then the documentation was built for
|
42
|
+
you and can be viewed if your gem server is running. There is also some
|
43
|
+
documentation on the github wiki page.
|
46
44
|
|
47
|
-
Otherwise, you can look at the doc/taskscheduler.txt file which should have
|
48
|
-
everything you need.
|
45
|
+
Otherwise, you can look at the doc/taskscheduler.txt file which should have
|
46
|
+
everything you need.
|
49
47
|
|
50
48
|
= Acknowledgements
|
51
|
-
This library was modeled to some degree on the Win32::TaskScheduler Perl
|
52
|
-
module by Umberto Nicoletti. However, there are some differences. Please see
|
53
|
-
the documentation for details.
|
49
|
+
This library was modeled to some degree on the Win32::TaskScheduler Perl
|
50
|
+
module by Umberto Nicoletti. However, there are some differences. Please see
|
51
|
+
the documentation for details.
|
52
|
+
|
53
|
+
= Using OLE
|
54
|
+
There's an OLE version in the works. Please see the 'ole' branch on github.
|
55
|
+
|
56
|
+
= Warranty
|
57
|
+
This package is provided "as is" and without any express or
|
58
|
+
implied warranties, including, without limitation, the implied
|
59
|
+
warranties of merchantability and fitness for a particular purpose.
|
60
|
+
|
61
|
+
= Known Issues
|
62
|
+
None known.
|
63
|
+
|
64
|
+
Please submit any bug reports to the project page at
|
65
|
+
http://www.rubyforge.org/projects/win32utils.
|
54
66
|
|
55
|
-
=
|
56
|
-
|
57
|
-
|
58
|
-
that there are some significant differences in behavior between the C
|
59
|
-
library and WMI, along with limitations regarding modification to existing
|
60
|
-
tasks.
|
67
|
+
= Copyright
|
68
|
+
(C) 2003-2011 Daniel J. Berger
|
69
|
+
All Rights Reserved
|
61
70
|
|
62
|
-
|
71
|
+
= License
|
72
|
+
Artistic 2.0
|
63
73
|
|
64
|
-
=
|
65
|
-
|
66
|
-
|
67
|
-
CoInitializeEx() function with NULL and COINIT_APARTMENTTHREADED arguments,
|
68
|
-
which is what we would do in any case.
|
74
|
+
= Authors
|
75
|
+
Park Heesob
|
76
|
+
Daniel Berger
|
data/Rakefile
CHANGED
@@ -1,54 +1,34 @@
|
|
1
1
|
require 'rake'
|
2
|
-
require 'rake/clean'
|
3
2
|
require 'rake/testtask'
|
3
|
+
require 'rake/clean'
|
4
4
|
require 'rbconfig'
|
5
5
|
include Config
|
6
6
|
|
7
|
-
|
8
|
-
desc "Cleans up the C related files created during the build"
|
9
|
-
task :clean do
|
10
|
-
Dir.chdir('ext') do
|
11
|
-
if File.exists?('taskscheduler.o') || File.exists?('taskscheduler.so')
|
12
|
-
sh 'nmake distclean'
|
13
|
-
end
|
14
|
-
|
15
|
-
if File.exists?('win32/taskscheduler.so')
|
16
|
-
File.delete('win32/taskscheduler.so')
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
desc "Builds, but does not install, the win32-taskscheduler library"
|
22
|
-
task :build => [:clean] do
|
23
|
-
Dir.chdir('ext') do
|
24
|
-
ruby 'extconf.rb'
|
25
|
-
sh 'nmake'
|
26
|
-
FileUtils.cp('taskscheduler.so', 'win32/taskscheduler.so')
|
27
|
-
end
|
28
|
-
end
|
29
|
-
=end
|
7
|
+
CLEAN.include("**/*.gem", "**/*.rbc", ".rbx")
|
30
8
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
9
|
+
namespace 'gem' do
|
10
|
+
desc 'Create the win32-taskscheduler gem'
|
11
|
+
task :create => [:clean] do
|
12
|
+
spec = eval(IO.read('win32-taskscheduler.gemspec'))
|
13
|
+
Gem::Builder.new(spec).build
|
14
|
+
end
|
37
15
|
|
38
|
-
desc 'Install the win32-taskscheduler library as a gem'
|
39
|
-
task :
|
40
|
-
|
41
|
-
|
42
|
-
|
16
|
+
desc 'Install the win32-taskscheduler library as a gem'
|
17
|
+
task :install => [:create] do
|
18
|
+
file = Dir['win32-taskscheduler*.gem'].first
|
19
|
+
sh "gem install #{file}"
|
20
|
+
end
|
43
21
|
end
|
44
22
|
|
45
23
|
desc 'Run the example code'
|
46
24
|
task :example do
|
47
|
-
|
25
|
+
ruby '-Iib examples/taskscheduler_example.rb'
|
48
26
|
end
|
49
27
|
|
50
|
-
desc
|
28
|
+
desc 'Run the test suite for the win32-taskscheduler library'
|
51
29
|
Rake::TestTask.new do |t|
|
52
|
-
|
53
|
-
|
30
|
+
t.verbose = true
|
31
|
+
t.warning = true
|
54
32
|
end
|
33
|
+
|
34
|
+
task :default => :test
|
data/lib/win32/taskscheduler.rb
CHANGED
@@ -9,1669 +9,1681 @@ include Windows::Process
|
|
9
9
|
include Windows::Error
|
10
10
|
include Windows::MSVCRT::Buffer
|
11
11
|
|
12
|
+
# The Win32 module serves as a namespace only
|
12
13
|
module Win32
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
end
|
190
|
-
|
191
|
-
self
|
14
|
+
# The TaskScheduler class encapsulates taskscheduler settings and behavior
|
15
|
+
class TaskScheduler
|
16
|
+
|
17
|
+
# The version of the win32-taskscheduler library
|
18
|
+
VERSION = '0.2.1'
|
19
|
+
|
20
|
+
# The error class raised if any task scheduler specific calls fail.
|
21
|
+
class Error < StandardError; end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# :stopdoc:
|
26
|
+
|
27
|
+
TASK_TIME_TRIGGER_ONCE = 0
|
28
|
+
TASK_TIME_TRIGGER_DAILY = 1
|
29
|
+
TASK_TIME_TRIGGER_WEEKLY = 2
|
30
|
+
TASK_TIME_TRIGGER_MONTHLYDATE = 3
|
31
|
+
TASK_TIME_TRIGGER_MONTHLYDOW = 4
|
32
|
+
TASK_EVENT_TRIGGER_ON_IDLE = 5
|
33
|
+
TASK_EVENT_TRIGGER_AT_SYSTEMSTART = 6
|
34
|
+
TASK_EVENT_TRIGGER_AT_LOGON = 7
|
35
|
+
|
36
|
+
TASK_SUNDAY = 0x1
|
37
|
+
TASK_MONDAY = 0x2
|
38
|
+
TASK_TUESDAY = 0x4
|
39
|
+
TASK_WEDNESDAY = 0x8
|
40
|
+
TASK_THURSDAY = 0x10
|
41
|
+
TASK_FRIDAY = 0x20
|
42
|
+
TASK_SATURDAY = 0x40
|
43
|
+
TASK_FIRST_WEEK = 1
|
44
|
+
TASK_SECOND_WEEK = 2
|
45
|
+
TASK_THIRD_WEEK = 3
|
46
|
+
TASK_FOURTH_WEEK = 4
|
47
|
+
TASK_LAST_WEEK = 5
|
48
|
+
TASK_JANUARY = 0x1
|
49
|
+
TASK_FEBRUARY = 0x2
|
50
|
+
TASK_MARCH = 0x4
|
51
|
+
TASK_APRIL = 0x8
|
52
|
+
TASK_MAY = 0x10
|
53
|
+
TASK_JUNE = 0x20
|
54
|
+
TASK_JULY = 0x40
|
55
|
+
TASK_AUGUST = 0x80
|
56
|
+
TASK_SEPTEMBER = 0x100
|
57
|
+
TASK_OCTOBER = 0x200
|
58
|
+
TASK_NOVEMBER = 0x400
|
59
|
+
TASK_DECEMBER = 0x800
|
60
|
+
|
61
|
+
TASK_FLAG_INTERACTIVE = 0x1
|
62
|
+
TASK_FLAG_DELETE_WHEN_DONE = 0x2
|
63
|
+
TASK_FLAG_DISABLED = 0x4
|
64
|
+
TASK_FLAG_START_ONLY_IF_IDLE = 0x10
|
65
|
+
TASK_FLAG_KILL_ON_IDLE_END = 0x20
|
66
|
+
TASK_FLAG_DONT_START_IF_ON_BATTERIES = 0x40
|
67
|
+
TASK_FLAG_KILL_IF_GOING_ON_BATTERIES = 0x80
|
68
|
+
TASK_FLAG_RUN_ONLY_IF_DOCKED = 0x100
|
69
|
+
TASK_FLAG_HIDDEN = 0x200
|
70
|
+
TASK_FLAG_RUN_IF_CONNECTED_TO_INTERNET = 0x400
|
71
|
+
TASK_FLAG_RESTART_ON_IDLE_RESUME = 0x800
|
72
|
+
TASK_FLAG_SYSTEM_REQUIRED = 0x1000
|
73
|
+
TASK_FLAG_RUN_ONLY_IF_LOGGED_ON = 0x2000
|
74
|
+
TASK_TRIGGER_FLAG_HAS_END_DATE = 0x1
|
75
|
+
TASK_TRIGGER_FLAG_KILL_AT_DURATION_END = 0x2
|
76
|
+
TASK_TRIGGER_FLAG_DISABLED = 0x4
|
77
|
+
|
78
|
+
TASK_MAX_RUN_TIMES = 1440
|
79
|
+
TASKS_TO_RETRIEVE = 5
|
80
|
+
|
81
|
+
# COM
|
82
|
+
|
83
|
+
CLSCTX_INPROC_SERVER = 0x1
|
84
|
+
CLSID_CTask = [0x148BD520,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
|
85
|
+
CLSID_CTaskScheduler = [0x148BD52A,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
|
86
|
+
IID_ITaskScheduler = [0x148BD527,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
|
87
|
+
IID_ITask = [0x148BD524,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
|
88
|
+
IID_IPersistFile = [0x0000010b,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46].pack('LSSC8')
|
89
|
+
|
90
|
+
public
|
91
|
+
|
92
|
+
# :startdoc:
|
93
|
+
|
94
|
+
# Shorthand constants
|
95
|
+
|
96
|
+
IDLE = IDLE_PRIORITY_CLASS
|
97
|
+
NORMAL = NORMAL_PRIORITY_CLASS
|
98
|
+
HIGH = HIGH_PRIORITY_CLASS
|
99
|
+
REALTIME = REALTIME_PRIORITY_CLASS
|
100
|
+
BELOW_NORMAL = BELOW_NORMAL_PRIORITY_CLASS
|
101
|
+
ABOVE_NORMAL = ABOVE_NORMAL_PRIORITY_CLASS
|
102
|
+
|
103
|
+
ONCE = TASK_TIME_TRIGGER_ONCE
|
104
|
+
DAILY = TASK_TIME_TRIGGER_DAILY
|
105
|
+
WEEKLY = TASK_TIME_TRIGGER_WEEKLY
|
106
|
+
MONTHLYDATE = TASK_TIME_TRIGGER_MONTHLYDATE
|
107
|
+
MONTHLYDOW = TASK_TIME_TRIGGER_MONTHLYDOW
|
108
|
+
|
109
|
+
ON_IDLE = TASK_EVENT_TRIGGER_ON_IDLE
|
110
|
+
AT_SYSTEMSTART = TASK_EVENT_TRIGGER_AT_SYSTEMSTART
|
111
|
+
AT_LOGON = TASK_EVENT_TRIGGER_AT_LOGON
|
112
|
+
FIRST_WEEK = TASK_FIRST_WEEK
|
113
|
+
SECOND_WEEK = TASK_SECOND_WEEK
|
114
|
+
THIRD_WEEK = TASK_THIRD_WEEK
|
115
|
+
FOURTH_WEEK = TASK_FOURTH_WEEK
|
116
|
+
LAST_WEEK = TASK_LAST_WEEK
|
117
|
+
SUNDAY = TASK_SUNDAY
|
118
|
+
MONDAY = TASK_MONDAY
|
119
|
+
TUESDAY = TASK_TUESDAY
|
120
|
+
WEDNESDAY = TASK_WEDNESDAY
|
121
|
+
THURSDAY = TASK_THURSDAY
|
122
|
+
FRIDAY = TASK_FRIDAY
|
123
|
+
SATURDAY = TASK_SATURDAY
|
124
|
+
JANUARY = TASK_JANUARY
|
125
|
+
FEBRUARY = TASK_FEBRUARY
|
126
|
+
MARCH = TASK_MARCH
|
127
|
+
APRIL = TASK_APRIL
|
128
|
+
MAY = TASK_MAY
|
129
|
+
JUNE = TASK_JUNE
|
130
|
+
JULY = TASK_JULY
|
131
|
+
AUGUST = TASK_AUGUST
|
132
|
+
SEPTEMBER = TASK_SEPTEMBER
|
133
|
+
OCTOBER = TASK_OCTOBER
|
134
|
+
NOVEMBER = TASK_NOVEMBER
|
135
|
+
DECEMBER = TASK_DECEMBER
|
136
|
+
|
137
|
+
INTERACTIVE = TASK_FLAG_INTERACTIVE
|
138
|
+
DELETE_WHEN_DONE = TASK_FLAG_DELETE_WHEN_DONE
|
139
|
+
DISABLED = TASK_FLAG_DISABLED
|
140
|
+
START_ONLY_IF_IDLE = TASK_FLAG_START_ONLY_IF_IDLE
|
141
|
+
KILL_ON_IDLE_END = TASK_FLAG_KILL_ON_IDLE_END
|
142
|
+
DONT_START_IF_ON_BATTERIES = TASK_FLAG_DONT_START_IF_ON_BATTERIES
|
143
|
+
KILL_IF_GOING_ON_BATTERIES = TASK_FLAG_KILL_IF_GOING_ON_BATTERIES
|
144
|
+
RUN_ONLY_IF_DOCKED = TASK_FLAG_RUN_ONLY_IF_DOCKED
|
145
|
+
HIDDEN = TASK_FLAG_HIDDEN
|
146
|
+
RUN_IF_CONNECTED_TO_INTERNET = TASK_FLAG_RUN_IF_CONNECTED_TO_INTERNET
|
147
|
+
RESTART_ON_IDLE_RESUME = TASK_FLAG_RESTART_ON_IDLE_RESUME
|
148
|
+
SYSTEM_REQUIRED = TASK_FLAG_SYSTEM_REQUIRED
|
149
|
+
RUN_ONLY_IF_LOGGED_ON = TASK_FLAG_RUN_ONLY_IF_LOGGED_ON
|
150
|
+
|
151
|
+
FLAG_HAS_END_DATE = TASK_TRIGGER_FLAG_HAS_END_DATE
|
152
|
+
FLAG_KILL_AT_DURATION_END = TASK_TRIGGER_FLAG_KILL_AT_DURATION_END
|
153
|
+
FLAG_DISABLED = TASK_TRIGGER_FLAG_DISABLED
|
154
|
+
|
155
|
+
MAX_RUN_TIMES = TASK_MAX_RUN_TIMES
|
156
|
+
|
157
|
+
# Returns a new TaskScheduler object. If a work_item (and possibly the
|
158
|
+
# the trigger) are passed as arguments then a new work item is created and
|
159
|
+
# associated with that trigger, although you can still activate other tasks
|
160
|
+
# with the same handle.
|
161
|
+
#
|
162
|
+
# This is really just a bit of convenience. Passing arguments to the
|
163
|
+
# constructor is the same as calling TaskScheduler.new plus
|
164
|
+
# TaskScheduler#new_work_item.
|
165
|
+
#
|
166
|
+
def initialize(work_item=nil, trigger=nil)
|
167
|
+
@pITS = nil
|
168
|
+
@pITask = nil
|
169
|
+
|
170
|
+
hr = CoInitialize(0)
|
171
|
+
|
172
|
+
if SUCCEEDED(hr)
|
173
|
+
ptr = 0.chr * 4
|
174
|
+
|
175
|
+
hr = CoCreateInstance(
|
176
|
+
CLSID_CTaskScheduler,
|
177
|
+
nil,
|
178
|
+
CLSCTX_INPROC_SERVER,
|
179
|
+
IID_ITaskScheduler,
|
180
|
+
ptr
|
181
|
+
)
|
182
|
+
|
183
|
+
if FAILED(hr)
|
184
|
+
raise Error, get_last_error
|
185
|
+
end
|
186
|
+
|
187
|
+
@pITS = ptr.unpack('L').first
|
188
|
+
else
|
189
|
+
raise Error, get_last_error
|
192
190
|
end
|
193
191
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
192
|
+
if work_item
|
193
|
+
if trigger
|
194
|
+
raise TypeError unless trigger.is_a?(Hash)
|
195
|
+
new_work_item(work_item, trigger)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
201
199
|
|
202
|
-
|
203
|
-
|
204
|
-
|
200
|
+
# Returns an array of scheduled task names.
|
201
|
+
#
|
202
|
+
def enum
|
203
|
+
raise Error, 'null pointer' if @pITS.nil?
|
205
204
|
|
206
|
-
|
205
|
+
lpVtbl = 0.chr * 4
|
206
|
+
table = 0.chr * 24
|
207
207
|
|
208
|
-
|
209
|
-
|
208
|
+
memcpy(lpVtbl, @pITS, 4)
|
209
|
+
memcpy(table, lpVtbl.unpack('L').first, 24)
|
210
|
+
table = table.unpack('L*')
|
210
211
|
|
211
|
-
|
212
|
+
enum = Win32::API::Function.new(table[5], 'PP', 'L')
|
212
213
|
|
213
|
-
|
214
|
-
|
215
|
-
table = 0.chr * 16
|
214
|
+
ptr = 0.chr * 4
|
215
|
+
hr = enum.call(@pITS, ptr)
|
216
216
|
|
217
|
-
|
218
|
-
memcpy(table, lpVtbl.unpack('L').first, 16)
|
219
|
-
table = table.unpack('L*')
|
217
|
+
raise Error, get_last_error if hr != S_OK
|
220
218
|
|
221
|
-
|
222
|
-
|
219
|
+
pIEnum = ptr.unpack('L').first
|
220
|
+
lpVtbl = 0.chr * 4
|
221
|
+
table = 0.chr * 16
|
223
222
|
|
224
|
-
|
225
|
-
|
226
|
-
|
223
|
+
memcpy(lpVtbl, pIEnum, 4)
|
224
|
+
memcpy(table, lpVtbl.unpack('L').first, 16)
|
225
|
+
table = table.unpack('L*')
|
227
226
|
|
228
|
-
|
229
|
-
|
227
|
+
_next = Win32::API::Function.new(table[3], 'PLPP', 'L')
|
228
|
+
release = Win32::API::Function.new(table[2], 'P', 'L')
|
230
229
|
|
231
|
-
|
232
|
-
|
233
|
-
|
230
|
+
array = []
|
231
|
+
fetched_tasks = 0.chr * 4
|
232
|
+
pnames = 0.chr * 4
|
234
233
|
|
235
|
-
|
236
|
-
|
237
|
-
wcscpy(str, names[i*4, 4].unpack('L').first)
|
238
|
-
array.push(wide_to_multi(str))
|
239
|
-
CoTaskMemFree(names[i*4, 4].unpack('L').first)
|
240
|
-
end
|
234
|
+
while (_next.call(pIEnum, TASKS_TO_RETRIEVE, pnames, fetched_tasks) >= S_OK) &&
|
235
|
+
(fetched_tasks.unpack('L').first != 0)
|
241
236
|
|
242
|
-
|
243
|
-
|
237
|
+
tasks = fetched_tasks.unpack('L').first
|
238
|
+
names = 0.chr * 4 * tasks
|
239
|
+
memcpy(names, pnames.unpack('L').first, 4 * tasks)
|
244
240
|
|
245
|
-
|
241
|
+
for i in 0 ... tasks
|
242
|
+
str = 0.chr * 256
|
243
|
+
wcscpy(str, names[i*4, 4].unpack('L').first)
|
244
|
+
array.push(wide_to_multi(str))
|
245
|
+
CoTaskMemFree(names[i*4, 4].unpack('L').first)
|
246
|
+
end
|
246
247
|
|
247
|
-
|
248
|
+
CoTaskMemFree(pnames.unpack('L').first)
|
248
249
|
end
|
249
|
-
|
250
|
-
alias :tasks :enum
|
251
250
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
raise TypeError unless task.is_a?(String)
|
251
|
+
release.call(pIEnum)
|
252
|
+
|
253
|
+
array
|
254
|
+
end
|
257
255
|
|
258
|
-
|
256
|
+
alias :tasks :enum
|
259
257
|
|
260
|
-
|
261
|
-
|
258
|
+
# Activate the specified task.
|
259
|
+
#
|
260
|
+
def activate(task)
|
261
|
+
raise Error, 'null pointer' if @pITS.nil?
|
262
|
+
raise TypeError unless task.is_a?(String)
|
262
263
|
|
263
|
-
|
264
|
-
memcpy(table, lpVtbl.unpack('L').first, 28)
|
265
|
-
table = table.unpack('L*')
|
264
|
+
task = multi_to_wide(task)
|
266
265
|
|
267
|
-
|
266
|
+
lpVtbl = 0.chr * 4
|
267
|
+
table = 0.chr * 28
|
268
268
|
|
269
|
-
|
270
|
-
|
269
|
+
memcpy(lpVtbl, @pITS, 4)
|
270
|
+
memcpy(table, lpVtbl.unpack('L').first, 28)
|
271
|
+
table = table.unpack('L*')
|
271
272
|
|
272
|
-
|
273
|
-
raise Error, get_last_error
|
274
|
-
end
|
273
|
+
activate = Win32::API::Function.new(table[6], 'PPPP', 'L')
|
275
274
|
|
276
|
-
|
275
|
+
ptr = 0.chr * 4
|
276
|
+
hr = activate.call(@pITS, task, IID_ITask, ptr)
|
277
277
|
|
278
|
-
|
278
|
+
if hr != S_OK
|
279
|
+
raise Error, get_last_error
|
279
280
|
end
|
280
281
|
|
281
|
-
|
282
|
-
|
283
|
-
def delete(task)
|
284
|
-
raise Error, 'null pointer' if @pITS.nil?
|
285
|
-
raise TypeError unless task.is_a?(String)
|
282
|
+
@pITask = ptr.unpack('L').first
|
283
|
+
end
|
286
284
|
|
287
|
-
|
285
|
+
# Delete the specified task name.
|
286
|
+
#
|
287
|
+
def delete(task)
|
288
|
+
raise Error, 'null pointer' if @pITS.nil?
|
289
|
+
raise TypeError unless task.is_a?(String)
|
288
290
|
|
289
|
-
|
290
|
-
table = 0.chr * 32
|
291
|
+
task = multi_to_wide(task)
|
291
292
|
|
292
|
-
|
293
|
-
|
294
|
-
table = table.unpack('L*')
|
293
|
+
lpVtbl = 0.chr * 4
|
294
|
+
table = 0.chr * 32
|
295
295
|
|
296
|
-
|
296
|
+
memcpy(lpVtbl, @pITS, 4)
|
297
|
+
memcpy(table, lpVtbl.unpack('L').first, 32)
|
298
|
+
table = table.unpack('L*')
|
297
299
|
|
298
|
-
|
300
|
+
delete = Win32::API::Function.new(table[7], 'PP', 'L')
|
299
301
|
|
300
|
-
|
301
|
-
raise Error, get_last_error
|
302
|
-
end
|
302
|
+
hr = delete.call(@pITS,task)
|
303
303
|
|
304
|
-
|
304
|
+
if hr != S_OK
|
305
|
+
raise Error, get_last_error
|
305
306
|
end
|
307
|
+
end
|
306
308
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
309
|
+
# Execute the current task.
|
310
|
+
#
|
311
|
+
def run
|
312
|
+
raise Error, 'null pointer' if @pITask.nil?
|
311
313
|
|
312
|
-
|
313
|
-
|
314
|
+
lpVtbl = 0.chr * 4
|
315
|
+
table = 0.chr * 52
|
314
316
|
|
315
|
-
|
316
|
-
|
317
|
-
|
317
|
+
memcpy(lpVtbl, @pITask, 4)
|
318
|
+
memcpy(table, lpVtbl.unpack('L').first, 52)
|
319
|
+
table = table.unpack('L*')
|
318
320
|
|
319
|
-
|
321
|
+
run = Win32::API::Function.new(table[12], 'P', 'L')
|
320
322
|
|
321
|
-
|
323
|
+
hr = run.call(@pITask)
|
322
324
|
|
323
|
-
|
324
|
-
|
325
|
-
end
|
326
|
-
|
327
|
-
self
|
325
|
+
if hr != S_OK
|
326
|
+
raise Error,get_last_error
|
328
327
|
end
|
328
|
+
end
|
329
|
+
|
330
|
+
# Saves the current task. Tasks must be saved before they can be activated.
|
331
|
+
# The .job file itself is typically stored in the C:\WINDOWS\Tasks folder.
|
332
|
+
#
|
333
|
+
# If +file+ (an absolute path) is specified then the job is saved to that
|
334
|
+
# file instead. A '.job' extension is recommended but not enforced.
|
335
|
+
#
|
336
|
+
# Note that calling TaskScheduler#save also resets the TaskScheduler object
|
337
|
+
# so that there is no currently active task.
|
338
|
+
#
|
339
|
+
def save(file = nil)
|
340
|
+
raise Error, 'null pointer' if @pITask.nil?
|
341
|
+
file = multi_to_wide(file) if file
|
342
|
+
|
343
|
+
lpVtbl = 0.chr * 4
|
344
|
+
table = 0.chr * 12
|
329
345
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
# If +file+ (an absolute path) is specified then the job is saved to that
|
334
|
-
# file instead. A '.job' extension is recommended but not enforced.
|
335
|
-
#
|
336
|
-
# Note that calling TaskScheduler#save also resets the TaskScheduler object
|
337
|
-
# so that there is no currently active task.
|
338
|
-
#
|
339
|
-
def save(file = nil)
|
340
|
-
raise Error, 'null pointer' if @pITask.nil?
|
341
|
-
file = multi_to_wide(file) if file
|
346
|
+
memcpy(lpVtbl, @pITask, 4)
|
347
|
+
memcpy(table, lpVtbl.unpack('L').first, 12)
|
348
|
+
table = table.unpack('L*')
|
342
349
|
|
343
|
-
|
344
|
-
|
350
|
+
queryinterface = Win32::API::Function.new(table[0],'PPP','L')
|
351
|
+
release = Win32::API::Function.new(table[2],'P','L')
|
345
352
|
|
346
|
-
|
347
|
-
memcpy(table, lpVtbl.unpack('L').first, 12)
|
348
|
-
table = table.unpack('L*')
|
353
|
+
ptr = 0.chr * 4
|
349
354
|
|
350
|
-
|
351
|
-
release = Win32::API::Function.new(table[2],'P','L')
|
355
|
+
hr = queryinterface.call(@pITask, IID_IPersistFile, ptr)
|
352
356
|
|
353
|
-
|
357
|
+
if hr != S_OK
|
358
|
+
raise Error, get_last_error
|
359
|
+
end
|
360
|
+
|
361
|
+
pIPersistFile = ptr.unpack('L').first
|
362
|
+
|
363
|
+
lpVtbl = 0.chr * 4
|
364
|
+
table = 0.chr * 28
|
354
365
|
|
355
|
-
|
366
|
+
memcpy(lpVtbl, pIPersistFile,4)
|
367
|
+
memcpy(table, lpVtbl.unpack('L').first, 28)
|
368
|
+
table = table.unpack('L*')
|
356
369
|
|
357
|
-
|
358
|
-
|
359
|
-
end
|
370
|
+
save = Win32::API::Function.new(table[6],'PPL','L')
|
371
|
+
release = Win32::API::Function.new(table[2],'P','L')
|
360
372
|
|
361
|
-
|
373
|
+
hr = save.call(pIPersistFile,file,1)
|
362
374
|
|
363
|
-
|
364
|
-
|
375
|
+
if hr != S_OK
|
376
|
+
raise Error,get_last_error
|
377
|
+
end
|
365
378
|
|
366
|
-
|
367
|
-
memcpy(table, lpVtbl.unpack('L').first, 28)
|
368
|
-
table = table.unpack('L*')
|
379
|
+
release.call(pIPersistFile)
|
369
380
|
|
370
|
-
|
371
|
-
|
381
|
+
CoUninitialize()
|
382
|
+
hr = CoInitialize(nil)
|
372
383
|
|
373
|
-
|
384
|
+
if hr >= 0
|
385
|
+
ptr = 0.chr * 4
|
374
386
|
|
375
|
-
|
376
|
-
|
377
|
-
|
387
|
+
hr = CoCreateInstance(
|
388
|
+
CLSID_CTaskScheduler,
|
389
|
+
nil,
|
390
|
+
CLSCTX_INPROC_SERVER,
|
391
|
+
IID_ITaskScheduler,
|
392
|
+
ptr
|
393
|
+
)
|
378
394
|
|
379
|
-
|
395
|
+
if hr != S_OK
|
396
|
+
CoUninitialize()
|
397
|
+
raise Error, get_last_error
|
398
|
+
end
|
380
399
|
|
381
|
-
|
382
|
-
|
400
|
+
@pITS = ptr.unpack('L').first
|
401
|
+
else
|
402
|
+
raise Error,get_last_error
|
403
|
+
end
|
383
404
|
|
384
|
-
|
385
|
-
|
405
|
+
release.call(@pITask)
|
406
|
+
@pITask = nil
|
407
|
+
end
|
386
408
|
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
IID_ITaskScheduler,
|
392
|
-
ptr
|
393
|
-
)
|
409
|
+
# Terminate the current task.
|
410
|
+
#
|
411
|
+
def terminate
|
412
|
+
raise Error, 'null pointer' if @pITask.nil?
|
394
413
|
|
395
|
-
|
396
|
-
|
397
|
-
raise Error, get_last_error
|
398
|
-
end
|
414
|
+
lpVtbl = 0.chr * 4
|
415
|
+
table = 0.chr * 56
|
399
416
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
end
|
417
|
+
memcpy(lpVtbl,@pITask,4)
|
418
|
+
memcpy(table,lpVtbl.unpack('L').first,56)
|
419
|
+
table = table.unpack('L*')
|
404
420
|
|
405
|
-
|
406
|
-
|
421
|
+
teriminate = Win32::API::Function.new(table[13],'P','L')
|
422
|
+
hr = teriminate.call(@pITask)
|
407
423
|
|
408
|
-
|
424
|
+
if hr != S_OK
|
425
|
+
raise Error,get_last_error
|
409
426
|
end
|
427
|
+
end
|
410
428
|
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
429
|
+
# Set the host on which the various TaskScheduler methods will execute.
|
430
|
+
#
|
431
|
+
def machine=(host)
|
432
|
+
raise Error, 'null pointer' if @pITS.nil?
|
433
|
+
raise TypeError unless host.is_a?(String)
|
415
434
|
|
416
|
-
|
417
|
-
table = 0.chr * 56
|
435
|
+
host_w = multi_to_wide(host)
|
418
436
|
|
419
|
-
|
420
|
-
|
421
|
-
table = table.unpack('L*')
|
437
|
+
lpVtbl = 0.chr * 4
|
438
|
+
table = 0.chr * 16
|
422
439
|
|
423
|
-
|
424
|
-
|
440
|
+
memcpy(lpVtbl, @pITS, 4)
|
441
|
+
memcpy(table, lpVtbl.unpack('L').first, 16)
|
442
|
+
table = table.unpack('L*')
|
425
443
|
|
426
|
-
|
427
|
-
raise Error,get_last_error
|
428
|
-
end
|
444
|
+
setTargetComputer = Win32::API::Function.new(table[3], 'PP', 'L')
|
429
445
|
|
430
|
-
|
446
|
+
hr = setTargetComputer.call(@pITS, host_w)
|
447
|
+
|
448
|
+
if hr != S_OK
|
449
|
+
raise Error, get_last_error
|
450
|
+
end
|
451
|
+
|
452
|
+
host
|
453
|
+
end
|
454
|
+
|
455
|
+
alias :host= :machine=
|
456
|
+
|
457
|
+
# Sets the +user+ and +password+ for the given task. If the user and
|
458
|
+
# password are set properly then true is returned.
|
459
|
+
#
|
460
|
+
# In some cases the job may be created, but the account information was
|
461
|
+
# bad. In this case the task is created but a warning is generated and
|
462
|
+
# false is returned.
|
463
|
+
#
|
464
|
+
def set_account_information(user, password)
|
465
|
+
raise Error, 'null pointer' if @pITS.nil?
|
466
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
467
|
+
|
468
|
+
lpVtbl = 0.chr * 4
|
469
|
+
table = 0.chr * 124
|
470
|
+
|
471
|
+
memcpy(lpVtbl, @pITask, 4)
|
472
|
+
memcpy(table, lpVtbl.unpack('L').first, 124)
|
473
|
+
table = table.unpack('L*')
|
474
|
+
|
475
|
+
setAccountInformation = Win32::API::Function.new(table[30],'PPP','L')
|
476
|
+
|
477
|
+
if (user.nil? || user=="") && (password.nil? || password=="")
|
478
|
+
hr = setAccountInformation.call(@pITask, multi_to_wide(""), nil)
|
479
|
+
else
|
480
|
+
user = multi_to_wide(user)
|
481
|
+
password = multi_to_wide(password)
|
482
|
+
hr = setAccountInformation.call(@pITask, user, password)
|
431
483
|
end
|
432
484
|
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
485
|
+
bool = true
|
486
|
+
|
487
|
+
case hr
|
488
|
+
when S_OK
|
489
|
+
return true
|
490
|
+
when 0x80070005 # E_ACCESSDENIED
|
491
|
+
raise Error, 'access denied'
|
492
|
+
when 0x80070057 # E_INVALIDARG
|
493
|
+
raise Error, 'invalid argument'
|
494
|
+
when 0x8007000E # E_OUTOFMEMORY
|
495
|
+
raise Error, 'out of memory'
|
496
|
+
when 0x80041312 # SCHED_E_NO_SECURITY_SERVICES
|
497
|
+
raise Error, 'no security services on this platform'
|
498
|
+
when 0x80041314 # SCHED_E_UNSUPPORTED_ACCOUNT_OPTION
|
499
|
+
raise Error, 'unsupported account option'
|
500
|
+
when 0x8004130F # SCHED_E_ACCOUNT_INFORMATION_NOT_SET
|
501
|
+
warn 'job created, but password was invalid'
|
502
|
+
bool = false
|
503
|
+
else
|
504
|
+
raise Error, 'unknown error'
|
505
|
+
end
|
506
|
+
bool
|
507
|
+
end
|
508
|
+
|
509
|
+
# Returns the user associated with the task or nil if no user has yet
|
510
|
+
# been associated with the task.
|
511
|
+
#
|
512
|
+
def account_information
|
513
|
+
raise Error, 'null pointer' if @pITS.nil?
|
514
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
515
|
+
|
516
|
+
lpVtbl = 0.chr * 4
|
517
|
+
table = 0.chr * 128
|
518
|
+
|
519
|
+
memcpy(lpVtbl, @pITask, 4)
|
520
|
+
memcpy(table,lpVtbl.unpack('L').first, 128)
|
521
|
+
table = table.unpack('L*')
|
522
|
+
|
523
|
+
getAccountInformation = Win32::API::Function.new(table[31], 'PP', 'L')
|
524
|
+
|
525
|
+
ptr = 0.chr * 4
|
526
|
+
hr = getAccountInformation.call(@pITask, ptr)
|
527
|
+
|
528
|
+
if hr == 0x8004130F # SCHED_E_ACCOUNT_INFORMATION_NOT_SET
|
529
|
+
user = nil
|
530
|
+
elsif hr >= 0 && hr != 0x80041312 # SCHED_E_NO_SECURITY_SERVICES
|
531
|
+
str = 0.chr * 256
|
532
|
+
wcscpy(str, ptr.unpack('L').first)
|
533
|
+
CoTaskMemFree(ptr.unpack('L').first)
|
534
|
+
user = wide_to_multi(str)
|
535
|
+
else
|
536
|
+
CoTaskMemFree(p.unpack('L').first)
|
537
|
+
raise Error,get_last_error(hr)
|
538
|
+
end
|
438
539
|
|
439
|
-
|
540
|
+
user
|
541
|
+
end
|
440
542
|
|
441
|
-
|
442
|
-
|
543
|
+
# Returns the name of the application associated with the task.
|
544
|
+
#
|
545
|
+
def application_name
|
546
|
+
raise Error, 'null pointer' if @pITS.nil?
|
547
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
443
548
|
|
444
|
-
|
445
|
-
|
446
|
-
table = table.unpack('L*')
|
549
|
+
lpVtbl = 0.chr * 4
|
550
|
+
table = 0.chr * 136
|
447
551
|
|
448
|
-
|
552
|
+
memcpy(lpVtbl, @pITask,4)
|
553
|
+
memcpy(table, lpVtbl.unpack('L').first, 136)
|
554
|
+
table = table.unpack('L*')
|
449
555
|
|
450
|
-
|
556
|
+
getApplicationName = Win32::API::Function.new(table[33],'PP','L')
|
451
557
|
|
452
|
-
|
453
|
-
|
454
|
-
end
|
558
|
+
ptr = 0.chr * 4
|
559
|
+
hr = getApplicationName.call(@pITask, ptr)
|
455
560
|
|
456
|
-
|
561
|
+
if hr >= S_OK
|
562
|
+
str = 0.chr * 256
|
563
|
+
wcscpy(str, ptr.unpack('L').first)
|
564
|
+
app = wide_to_multi(str)
|
565
|
+
CoTaskMemFree(ptr.unpack('L').first)
|
566
|
+
else
|
567
|
+
raise Error, get_last_error
|
457
568
|
end
|
458
569
|
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
hr = setAccountInformation.call(@pITask, "", nil)
|
483
|
-
else
|
484
|
-
user = multi_to_wide(user)
|
485
|
-
password = multi_to_wide(password)
|
486
|
-
hr = setAccountInformation.call(@pITask, user, password)
|
487
|
-
end
|
488
|
-
|
489
|
-
bool = true
|
490
|
-
|
491
|
-
case hr
|
492
|
-
when S_OK
|
493
|
-
return true
|
494
|
-
when 0x80070005 # E_ACCESSDENIED
|
495
|
-
raise Error, 'access denied'
|
496
|
-
when 0x80070057 # E_INVALIDARG
|
497
|
-
raise Error, 'invalid argument'
|
498
|
-
when 0x8007000E # E_OUTOFMEMORY
|
499
|
-
raise Error, 'out of memory'
|
500
|
-
when 0x80041312 # SCHED_E_NO_SECURITY_SERVICES
|
501
|
-
raise Error, 'no security services on this platform'
|
502
|
-
when 0x80041314 # SCHED_E_UNSUPPORTED_ACCOUNT_OPTION
|
503
|
-
raise Error, 'unsupported account option'
|
504
|
-
when 0x8004130F # SCHED_E_ACCOUNT_INFORMATION_NOT_SET
|
505
|
-
warn 'job created, but password was invalid'
|
506
|
-
bool = false
|
507
|
-
else
|
508
|
-
raise Error, 'unknown error'
|
509
|
-
end
|
510
|
-
bool
|
570
|
+
app
|
571
|
+
end
|
572
|
+
|
573
|
+
# Sets the application name associated with the task.
|
574
|
+
#
|
575
|
+
def application_name=(app)
|
576
|
+
raise Error, 'null pointer' if @pITS.nil?
|
577
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
578
|
+
raise TypeError unless app.is_a?(String)
|
579
|
+
|
580
|
+
app_w = multi_to_wide(app)
|
581
|
+
|
582
|
+
lpVtbl = 0.chr * 4
|
583
|
+
table = 0.chr * 132
|
584
|
+
memcpy(lpVtbl,@pITask,4)
|
585
|
+
memcpy(table,lpVtbl.unpack('L').first,132)
|
586
|
+
table = table.unpack('L*')
|
587
|
+
setApplicationName = Win32::API::Function.new(table[32],'PP','L')
|
588
|
+
|
589
|
+
hr = setApplicationName.call(@pITask,app_w)
|
590
|
+
|
591
|
+
if hr != S_OK
|
592
|
+
raise Error,get_last_error(hr)
|
511
593
|
end
|
512
594
|
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
CoTaskMemFree(p.unpack('L').first)
|
541
|
-
raise Error,get_last_error(hr)
|
542
|
-
end
|
543
|
-
|
544
|
-
user
|
595
|
+
app
|
596
|
+
end
|
597
|
+
|
598
|
+
# Returns the command line parameters for the task.
|
599
|
+
#
|
600
|
+
def parameters
|
601
|
+
raise Error, 'null pointer' if @pITS.nil?
|
602
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
603
|
+
|
604
|
+
lpVtbl = 0.chr * 4
|
605
|
+
table = 0.chr * 144
|
606
|
+
|
607
|
+
memcpy(lpVtbl, @pITask, 4)
|
608
|
+
memcpy(table, lpVtbl.unpack('L').first, 144)
|
609
|
+
table = table.unpack('L*')
|
610
|
+
|
611
|
+
getParameters = Win32::API::Function.new(table[35], 'PP', 'L')
|
612
|
+
ptr = 0.chr * 4
|
613
|
+
hr = getParameters.call(@pITask, ptr)
|
614
|
+
|
615
|
+
if hr >= S_OK
|
616
|
+
str = 0.chr * 256
|
617
|
+
wcscpy(str, ptr.unpack('L').first)
|
618
|
+
param = wide_to_multi(str)
|
619
|
+
CoTaskMemFree(ptr.unpack('L').first)
|
620
|
+
else
|
621
|
+
raise Error, get_last_error
|
545
622
|
end
|
546
623
|
|
547
|
-
|
548
|
-
|
549
|
-
def application_name
|
550
|
-
raise Error, 'null pointer' if @pITS.nil?
|
551
|
-
raise Error, 'No currently active task' if @pITask.nil?
|
624
|
+
param
|
625
|
+
end
|
552
626
|
|
553
|
-
|
554
|
-
|
627
|
+
# Sets the parameters for the task. These parameters are passed as command
|
628
|
+
# line arguments to the application the task will run. To clear the command
|
629
|
+
# line parameters set it to an empty string.
|
630
|
+
#
|
631
|
+
def parameters=(param)
|
632
|
+
raise Error, 'null pointer(ts_set_parameters)' if @pITS.nil?
|
633
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
634
|
+
raise TypeError unless param.is_a?(String)
|
555
635
|
|
556
|
-
|
557
|
-
memcpy(table, lpVtbl.unpack('L').first, 136)
|
558
|
-
table = table.unpack('L*')
|
636
|
+
param_w = multi_to_wide(param)
|
559
637
|
|
560
|
-
|
638
|
+
lpVtbl = 0.chr * 4
|
639
|
+
table = 0.chr * 140
|
561
640
|
|
562
|
-
|
563
|
-
|
641
|
+
memcpy(lpVtbl,@pITask,4)
|
642
|
+
memcpy(table,lpVtbl.unpack('L').first,140)
|
643
|
+
table = table.unpack('L*')
|
564
644
|
|
565
|
-
|
566
|
-
|
567
|
-
wcscpy(str, ptr.unpack('L').first)
|
568
|
-
app = wide_to_multi(str)
|
569
|
-
CoTaskMemFree(ptr.unpack('L').first)
|
570
|
-
else
|
571
|
-
raise Error, get_last_error
|
572
|
-
end
|
645
|
+
setParameters = Win32::API::Function.new(table[34],'PP','L')
|
646
|
+
hr = setParameters.call(@pITask,param_w)
|
573
647
|
|
574
|
-
|
648
|
+
if hr != S_OK
|
649
|
+
raise Error, get_last_error(hr)
|
575
650
|
end
|
576
651
|
|
577
|
-
|
578
|
-
|
579
|
-
def application_name=(app)
|
580
|
-
raise Error, 'null pointer' if @pITS.nil?
|
581
|
-
raise Error, 'No currently active task' if @pITask.nil?
|
582
|
-
raise TypeError unless app.is_a?(String)
|
652
|
+
param
|
653
|
+
end
|
583
654
|
|
584
|
-
|
655
|
+
# Returns the working directory for the task.
|
656
|
+
#
|
657
|
+
def working_directory
|
658
|
+
raise Error,"fatal error: null pointer(ts_get_parameters)" if @pITS.nil?
|
659
|
+
raise Error,"No currently active task" if @pITask.nil?
|
585
660
|
|
586
|
-
|
587
|
-
|
588
|
-
memcpy(lpVtbl,@pITask,4)
|
589
|
-
memcpy(table,lpVtbl.unpack('L').first,132)
|
590
|
-
table = table.unpack('L*')
|
591
|
-
setApplicationName = Win32::API::Function.new(table[32],'PP','L')
|
661
|
+
lpVtbl = 0.chr * 4
|
662
|
+
table = 0.chr * 152
|
592
663
|
|
593
|
-
|
664
|
+
memcpy(lpVtbl, @pITask,4)
|
665
|
+
memcpy(table, lpVtbl.unpack('L').first,152)
|
666
|
+
table = table.unpack('L*')
|
594
667
|
|
595
|
-
|
596
|
-
raise Error,get_last_error(hr)
|
597
|
-
end
|
598
|
-
app
|
599
|
-
end
|
668
|
+
getWorkingDirectory = Win32::API::Function.new(table[37],'PP','L')
|
600
669
|
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
memcpy(table, lpVtbl.unpack('L').first, 144)
|
612
|
-
table = table.unpack('L*')
|
613
|
-
|
614
|
-
getParameters = Win32::API::Function.new(table[35], 'PP', 'L')
|
615
|
-
ptr = 0.chr * 4
|
616
|
-
hr = getParameters.call(@pITask, ptr)
|
617
|
-
|
618
|
-
if hr >= S_OK
|
619
|
-
str = 0.chr * 256
|
620
|
-
wcscpy(str, ptr.unpack('L').first)
|
621
|
-
param = wide_to_multi(str)
|
622
|
-
CoTaskMemFree(ptr.unpack('L').first)
|
623
|
-
else
|
624
|
-
raise Error, get_last_error
|
625
|
-
end
|
626
|
-
|
627
|
-
param
|
670
|
+
ptr = 0.chr * 4
|
671
|
+
hr = getWorkingDirectory.call(@pITask, ptr)
|
672
|
+
|
673
|
+
if hr >= S_OK
|
674
|
+
str = 0.chr * 256
|
675
|
+
wcscpy(str, ptr.unpack('L').first)
|
676
|
+
dir = wide_to_multi(str)
|
677
|
+
CoTaskMemFree(ptr.unpack('L').first)
|
678
|
+
else
|
679
|
+
raise Error, get_last_error
|
628
680
|
end
|
629
681
|
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
682
|
+
dir
|
683
|
+
end
|
684
|
+
|
685
|
+
# Sets the working directory for the task.
|
686
|
+
#
|
687
|
+
def working_directory=(dir)
|
688
|
+
raise Error, 'null pointer' if @pITS.nil?
|
689
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
690
|
+
raise TypeError unless dir.is_a?(String)
|
638
691
|
|
639
|
-
|
692
|
+
dir_w = multi_to_wide(dir)
|
640
693
|
|
641
|
-
|
642
|
-
|
694
|
+
lpVtbl = 0.chr * 4
|
695
|
+
table = 0.chr * 148
|
643
696
|
|
644
|
-
|
645
|
-
|
646
|
-
|
697
|
+
memcpy(lpVtbl, @pITask,4)
|
698
|
+
memcpy(table, lpVtbl.unpack('L').first, 148)
|
699
|
+
table = table.unpack('L*')
|
647
700
|
|
648
|
-
|
649
|
-
|
701
|
+
setWorkingDirectory = Win32::API::Function.new(table[36], 'PP', 'L')
|
702
|
+
hr = setWorkingDirectory.call(@pITask, dir_w)
|
650
703
|
|
651
|
-
|
652
|
-
|
653
|
-
end
|
654
|
-
param
|
704
|
+
if hr != S_OK
|
705
|
+
raise Error, get_last_error(hr)
|
655
706
|
end
|
656
707
|
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
708
|
+
dir
|
709
|
+
end
|
710
|
+
|
711
|
+
# Returns the task's priority level. Possible values are 'idle',
|
712
|
+
# 'normal', 'high', 'realtime', 'below_normal', 'above_normal',
|
713
|
+
# and 'unknown'.
|
714
|
+
#
|
715
|
+
def priority
|
716
|
+
raise Error, 'null pointer(ts_get_priority)' if @pITS.nil?
|
717
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
718
|
+
|
719
|
+
lpVtbl = 0.chr * 4
|
720
|
+
table = 0.chr * 160
|
721
|
+
|
722
|
+
memcpy(lpVtbl, @pITask, 4)
|
723
|
+
memcpy(table, lpVtbl.unpack('L').first, 160)
|
724
|
+
table = table.unpack('L*')
|
725
|
+
|
726
|
+
getPriority = Win32::API::Function.new(table[39], 'PP', 'L')
|
727
|
+
|
728
|
+
ptr = 0.chr * 4
|
729
|
+
hr = getPriority.call(@pITask, ptr)
|
730
|
+
|
731
|
+
if hr >= S_OK
|
732
|
+
pri = ptr.unpack('L').first
|
733
|
+
if (pri & IDLE_PRIORITY_CLASS) != 0
|
734
|
+
priority = 'idle'
|
735
|
+
elsif (pri & NORMAL_PRIORITY_CLASS) != 0
|
736
|
+
priority = 'normal'
|
737
|
+
elsif (pri & HIGH_PRIORITY_CLASS) != 0
|
738
|
+
priority = 'high'
|
739
|
+
elsif (pri & REALTIME_PRIORITY_CLASS) != 0
|
740
|
+
priority = 'realtime'
|
741
|
+
elsif (pri & BELOW_NORMAL_PRIORITY_CLASS) != 0
|
742
|
+
priority = 'below_normal'
|
743
|
+
elsif (pri & ABOVE_NORMAL_PRIORITY_CLASS) != 0
|
744
|
+
priority = 'above_normal'
|
745
|
+
else
|
746
|
+
priority = 'unknown'
|
747
|
+
end
|
748
|
+
else
|
749
|
+
raise Error, get_last_error
|
750
|
+
end
|
662
751
|
|
663
|
-
|
664
|
-
|
752
|
+
priority
|
753
|
+
end
|
665
754
|
|
666
|
-
|
667
|
-
|
668
|
-
|
755
|
+
# Sets the priority of the task. The +priority+ should be a numeric
|
756
|
+
# priority constant value.
|
757
|
+
#
|
758
|
+
def priority=(priority)
|
759
|
+
raise Error, 'null pointer' if @pITS.nil?
|
760
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
761
|
+
raise TypeError unless priority.is_a?(Numeric)
|
669
762
|
|
670
|
-
|
763
|
+
lpVtbl = 0.chr * 4
|
764
|
+
table = 0.chr * 156
|
671
765
|
|
672
|
-
|
673
|
-
|
766
|
+
memcpy(lpVtbl, @pITask, 4)
|
767
|
+
memcpy(table, lpVtbl.unpack('L').first, 156)
|
768
|
+
table = table.unpack('L*')
|
674
769
|
|
675
|
-
|
676
|
-
|
677
|
-
wcscpy(str, ptr.unpack('L').first)
|
678
|
-
dir = wide_to_multi(str)
|
679
|
-
CoTaskMemFree(ptr.unpack('L').first)
|
680
|
-
else
|
681
|
-
raise Error, get_last_error
|
682
|
-
end
|
770
|
+
setPriority = Win32::API::Function.new(table[38], 'PL', 'L')
|
771
|
+
hr = setPriority.call(@pITask, priority)
|
683
772
|
|
684
|
-
|
773
|
+
if hr != S_OK
|
774
|
+
raise Error, get_last_error(hr)
|
685
775
|
end
|
686
776
|
|
687
|
-
|
688
|
-
|
689
|
-
def working_directory=(dir)
|
690
|
-
raise Error, 'null pointer' if @pITS.nil?
|
691
|
-
raise Error, 'No currently active task' if @pITask.nil?
|
692
|
-
raise TypeError unless dir.is_a?(String)
|
777
|
+
priority
|
778
|
+
end
|
693
779
|
|
694
|
-
|
780
|
+
# Creates a new work item (scheduled job) with the given +trigger+. The
|
781
|
+
# trigger variable is a hash of options that define when the scheduled
|
782
|
+
# job should run.
|
783
|
+
#
|
784
|
+
def new_work_item(task, trigger)
|
785
|
+
raise TypeError unless trigger.is_a?(Hash)
|
786
|
+
raise Error, 'null pointer' if @pITS.nil?
|
695
787
|
|
696
|
-
|
697
|
-
|
788
|
+
# I'm working around github issue #1 here.
|
789
|
+
enum.each{ |name|
|
790
|
+
if name.downcase == task.downcase + '.job'
|
791
|
+
raise Error, "task '#{task}' already exists"
|
792
|
+
end
|
793
|
+
}
|
698
794
|
|
699
|
-
|
700
|
-
memcpy(table, lpVtbl.unpack('L').first, 148)
|
701
|
-
table = table.unpack('L*')
|
795
|
+
trigger = transform_and_validate(trigger)
|
702
796
|
|
703
|
-
|
704
|
-
|
797
|
+
if @pITask
|
798
|
+
lpVtbl = 0.chr * 4
|
799
|
+
table = 0.chr * 12
|
705
800
|
|
706
|
-
|
707
|
-
|
708
|
-
|
801
|
+
memcpy(lpVtbl, @pITask, 4)
|
802
|
+
memcpy(table, lpVtbl.unpack('L').first, 12)
|
803
|
+
table = table.unpack('L*')
|
709
804
|
|
710
|
-
|
805
|
+
release = Win32::API::Function.new(table[2], 'P', 'L')
|
806
|
+
release.call(@pITask)
|
807
|
+
|
808
|
+
@pITask = nil
|
711
809
|
end
|
712
810
|
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
#
|
717
|
-
def priority
|
718
|
-
raise Error, 'null pointer(ts_get_priority)' if @pITS.nil?
|
719
|
-
raise Error, 'No currently active task' if @pITask.nil?
|
720
|
-
|
721
|
-
lpVtbl = 0.chr * 4
|
722
|
-
table = 0.chr * 160
|
723
|
-
|
724
|
-
memcpy(lpVtbl, @pITask, 4)
|
725
|
-
memcpy(table, lpVtbl.unpack('L').first, 160)
|
726
|
-
table = table.unpack('L*')
|
727
|
-
|
728
|
-
getPriority = Win32::API::Function.new(table[39], 'PP', 'L')
|
729
|
-
|
730
|
-
ptr = 0.chr * 4
|
731
|
-
hr = getPriority.call(@pITask, ptr)
|
732
|
-
|
733
|
-
if hr >= S_OK
|
734
|
-
pri = ptr.unpack('L').first
|
735
|
-
if (pri & IDLE_PRIORITY_CLASS) != 0
|
736
|
-
priority = 'idle'
|
737
|
-
elsif (pri & NORMAL_PRIORITY_CLASS) != 0
|
738
|
-
priority = 'normal'
|
739
|
-
elsif (pri & HIGH_PRIORITY_CLASS) != 0
|
740
|
-
priority = 'high'
|
741
|
-
elsif (pri & REALTIME_PRIORITY_CLASS) != 0
|
742
|
-
priority = 'realtime'
|
743
|
-
elsif (pri & BELOW_NORMAL_PRIORITY_CLASS) != 0
|
744
|
-
priority = 'below_normal'
|
745
|
-
elsif (pri & ABOVE_NORMAL_PRIORITY_CLASS) != 0
|
746
|
-
priority = 'above_normal'
|
747
|
-
else
|
748
|
-
priority = 'unknown'
|
749
|
-
end
|
750
|
-
else
|
751
|
-
raise Error, get_last_error
|
752
|
-
end
|
811
|
+
task = multi_to_wide(task)
|
812
|
+
lpVtbl = 0.chr * 4
|
813
|
+
table = 0.chr * 36
|
753
814
|
|
754
|
-
|
815
|
+
memcpy(lpVtbl, @pITS, 4)
|
816
|
+
memcpy(table, lpVtbl.unpack('L').first, 36)
|
817
|
+
table = table.unpack('L*')
|
818
|
+
|
819
|
+
newWorkItem = Win32::API::Function.new(table[8], 'PPPPP', 'L')
|
820
|
+
|
821
|
+
ptr = 0.chr * 4
|
822
|
+
|
823
|
+
hr = newWorkItem.call(@pITS, task, CLSID_CTask, IID_ITask, ptr)
|
824
|
+
|
825
|
+
if FAILED(hr)
|
826
|
+
raise Error, get_last_error
|
755
827
|
end
|
756
828
|
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
def priority=(priority)
|
761
|
-
raise Error, 'null pointer' if @pITS.nil?
|
762
|
-
raise Error, 'No currently active task' if @pITask.nil?
|
763
|
-
raise TypeError unless priority.is_a?(Numeric)
|
829
|
+
@pITask = ptr.unpack('L').first
|
830
|
+
lpVtbl = 0.chr * 4
|
831
|
+
table = 0.chr * 16
|
764
832
|
|
765
|
-
|
766
|
-
|
833
|
+
# Without the 'enum.include?' check above the code segfaults here if the
|
834
|
+
# task already exists. This should probably be handled properly instead
|
835
|
+
# of simply avoiding the issue.
|
767
836
|
|
768
|
-
|
769
|
-
|
770
|
-
|
837
|
+
memcpy(lpVtbl, @pITask, 4)
|
838
|
+
memcpy(table, lpVtbl.unpack('L').first, 16)
|
839
|
+
table = table.unpack('L*')
|
771
840
|
|
772
|
-
|
773
|
-
|
841
|
+
createTrigger = Win32::API::Function.new(table[3], 'PPP', 'L')
|
842
|
+
p1 = 0.chr * 4
|
843
|
+
p2 = 0.chr * 4
|
774
844
|
|
775
|
-
|
776
|
-
raise Error, get_last_error(hr)
|
777
|
-
end
|
845
|
+
hr = createTrigger.call(@pITask, p1, p2)
|
778
846
|
|
779
|
-
|
847
|
+
if hr != S_OK
|
848
|
+
raise Error, get_last_error
|
780
849
|
end
|
781
850
|
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
table = table.unpack('L*')
|
849
|
-
|
850
|
-
release = Win32::API::Function.new(table[2], 'P', 'L')
|
851
|
-
setTrigger = Win32::API::Function.new(table[3], 'PP', 'L')
|
852
|
-
|
853
|
-
type1 = 0
|
854
|
-
type2 = 0
|
855
|
-
tmp = trigger['type']
|
856
|
-
tmp = nil unless tmp.is_a?(Hash)
|
857
|
-
|
858
|
-
case trigger['trigger_type']
|
859
|
-
when TASK_TIME_TRIGGER_DAILY
|
860
|
-
if tmp && tmp['days_interval']
|
861
|
-
type1 = [tmp['days_interval'],0].pack('SS').unpack('L').first
|
862
|
-
end
|
863
|
-
when TASK_TIME_TRIGGER_WEEKLY
|
864
|
-
if tmp && tmp['weeks_interval'] && tmp['days_of_week']
|
865
|
-
type1 = [tmp['weeks_interval'],tmp['days_of_week']].pack('SS').unpack('L').first
|
866
|
-
end
|
867
|
-
when TASK_TIME_TRIGGER_MONTHLYDATE
|
868
|
-
if tmp && tmp['months'] && tmp['days']
|
869
|
-
type2 = [tmp['months'],0].pack('SS').unpack('L').first
|
870
|
-
type1 = tmp['days']
|
871
|
-
end
|
872
|
-
when TASK_TIME_TRIGGER_MONTHLYDOW
|
873
|
-
if tmp && tmp['weeks'] && tmp['days_of_week'] && tmp['months']
|
874
|
-
type1 = [tmp['weeks'],tmp['days_of_week']].pack('SS').unpack('L').first
|
875
|
-
type2 = [tmp['months'],0].pack('SS').unpack('L').first
|
876
|
-
end
|
877
|
-
when TASK_TIME_TRIGGER_ONCE
|
878
|
-
# Do nothing. The Type member of the TASK_TRIGGER struct is ignored.
|
879
|
-
else
|
880
|
-
raise Error, 'Unknown trigger type'
|
881
|
-
end
|
882
|
-
|
883
|
-
pTrigger = [
|
884
|
-
48,
|
885
|
-
0,
|
886
|
-
trigger['start_year'] || 0,
|
887
|
-
trigger['start_month'] || 0,
|
888
|
-
trigger['start_day'] || 0,
|
889
|
-
trigger['end_year'] || 0,
|
890
|
-
trigger['end_month'] || 0,
|
891
|
-
trigger['end_day'] || 0,
|
892
|
-
trigger['start_hour'] || 0,
|
893
|
-
trigger['start_minute'] || 0,
|
894
|
-
trigger['minutes_duration'] || 0,
|
895
|
-
trigger['minutes_interval'] || 0,
|
896
|
-
trigger['flags'] || 0,
|
897
|
-
trigger['trigger_type'] || 0,
|
898
|
-
type1,
|
899
|
-
type2,
|
900
|
-
0,
|
901
|
-
trigger['random_minutes_interval'] || 0
|
902
|
-
].pack('S10L4LLSS')
|
903
|
-
|
904
|
-
hr = setTrigger.call(pITaskTrigger, pTrigger)
|
905
|
-
|
906
|
-
if hr != S_OK
|
907
|
-
raise Error, get_last_error
|
908
|
-
end
|
909
|
-
|
910
|
-
release.call(pITaskTrigger)
|
911
|
-
|
912
|
-
self
|
851
|
+
pITaskTrigger = p2.unpack('L').first
|
852
|
+
lpVtbl = 0.chr * 4
|
853
|
+
table = 0.chr * 16
|
854
|
+
|
855
|
+
memcpy(lpVtbl, pITaskTrigger, 4)
|
856
|
+
memcpy(table, lpVtbl.unpack('L').first, 16)
|
857
|
+
table = table.unpack('L*')
|
858
|
+
|
859
|
+
release = Win32::API::Function.new(table[2], 'P', 'L')
|
860
|
+
setTrigger = Win32::API::Function.new(table[3], 'PP', 'L')
|
861
|
+
|
862
|
+
type1 = 0
|
863
|
+
type2 = 0
|
864
|
+
tmp = trigger['type']
|
865
|
+
tmp = nil unless tmp.is_a?(Hash)
|
866
|
+
|
867
|
+
case trigger['trigger_type']
|
868
|
+
when TASK_TIME_TRIGGER_DAILY
|
869
|
+
if tmp && tmp['days_interval']
|
870
|
+
type1 = [tmp['days_interval'],0].pack('SS').unpack('L').first
|
871
|
+
end
|
872
|
+
when TASK_TIME_TRIGGER_WEEKLY
|
873
|
+
if tmp && tmp['weeks_interval'] && tmp['days_of_week']
|
874
|
+
type1 = [tmp['weeks_interval'],tmp['days_of_week']].pack('SS').unpack('L').first
|
875
|
+
end
|
876
|
+
when TASK_TIME_TRIGGER_MONTHLYDATE
|
877
|
+
if tmp && tmp['months'] && tmp['days']
|
878
|
+
type2 = [tmp['months'],0].pack('SS').unpack('L').first
|
879
|
+
type1 = tmp['days']
|
880
|
+
end
|
881
|
+
when TASK_TIME_TRIGGER_MONTHLYDOW
|
882
|
+
if tmp && tmp['weeks'] && tmp['days_of_week'] && tmp['months']
|
883
|
+
type1 = [tmp['weeks'],tmp['days_of_week']].pack('SS').unpack('L').first
|
884
|
+
type2 = [tmp['months'],0].pack('SS').unpack('L').first
|
885
|
+
end
|
886
|
+
when TASK_TIME_TRIGGER_ONCE
|
887
|
+
# Do nothing. The Type member of the TASK_TRIGGER struct is ignored.
|
888
|
+
else
|
889
|
+
raise Error, 'Unknown trigger type'
|
890
|
+
end
|
891
|
+
|
892
|
+
pTrigger = [
|
893
|
+
48,
|
894
|
+
0,
|
895
|
+
trigger['start_year'] || 0,
|
896
|
+
trigger['start_month'] || 0,
|
897
|
+
trigger['start_day'] || 0,
|
898
|
+
trigger['end_year'] || 0,
|
899
|
+
trigger['end_month'] || 0,
|
900
|
+
trigger['end_day'] || 0,
|
901
|
+
trigger['start_hour'] || 0,
|
902
|
+
trigger['start_minute'] || 0,
|
903
|
+
trigger['minutes_duration'] || 0,
|
904
|
+
trigger['minutes_interval'] || 0,
|
905
|
+
trigger['flags'] || 0,
|
906
|
+
trigger['trigger_type'] || 0,
|
907
|
+
type1,
|
908
|
+
type2,
|
909
|
+
0,
|
910
|
+
trigger['random_minutes_interval'] || 0
|
911
|
+
].pack('S10L4LLSS')
|
912
|
+
|
913
|
+
hr = setTrigger.call(pITaskTrigger, pTrigger)
|
914
|
+
|
915
|
+
if hr != S_OK
|
916
|
+
raise Error, get_last_error
|
913
917
|
end
|
914
918
|
|
915
|
-
|
919
|
+
release.call(pITaskTrigger)
|
920
|
+
end
|
916
921
|
|
917
|
-
|
918
|
-
#
|
919
|
-
def trigger_count
|
920
|
-
raise Error, "null pointer" if @pITS.nil?
|
921
|
-
raise Error, "No currently active task" if @pITask.nil?
|
922
|
+
alias :new_task :new_work_item
|
922
923
|
|
923
|
-
|
924
|
-
|
924
|
+
# Returns the number of triggers associated with the active task.
|
925
|
+
#
|
926
|
+
def trigger_count
|
927
|
+
raise Error, "null pointer" if @pITS.nil?
|
928
|
+
raise Error, "No currently active task" if @pITask.nil?
|
925
929
|
|
926
|
-
|
927
|
-
|
928
|
-
table = table.unpack('L*')
|
930
|
+
lpVtbl = 0.chr * 4
|
931
|
+
table = 0.chr * 24
|
929
932
|
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
+
memcpy(lpVtbl, @pITask,4)
|
934
|
+
memcpy(table, lpVtbl.unpack('L').first, 24)
|
935
|
+
table = table.unpack('L*')
|
933
936
|
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
raise Error, get_last_error
|
938
|
-
end
|
937
|
+
getTriggerCount = Win32::API::Function.new(table[5], 'PP', 'L')
|
938
|
+
ptr = 0.chr * 4
|
939
|
+
hr = getTriggerCount.call(@pITask, ptr)
|
939
940
|
|
940
|
-
|
941
|
+
if hr >= S_OK
|
942
|
+
count = ptr.unpack('L').first
|
943
|
+
else
|
944
|
+
raise Error, get_last_error
|
941
945
|
end
|
942
946
|
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
947
|
+
count
|
948
|
+
end
|
949
|
+
|
950
|
+
# Returns a string that describes the current trigger at the specified
|
951
|
+
# index for the active task.
|
952
|
+
#
|
953
|
+
# Example: "At 7:14 AM every day, starting 4/11/2009"
|
954
|
+
#
|
955
|
+
def trigger_string(index)
|
956
|
+
raise Error, 'null pointer' if @pITS.nil?
|
957
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
958
|
+
raise TypeError unless index.is_a?(Numeric)
|
959
|
+
|
960
|
+
lpVtbl = 0.chr * 4
|
961
|
+
table = 0.chr * 32
|
962
|
+
|
963
|
+
memcpy(lpVtbl, @pITask, 4)
|
964
|
+
memcpy(table, lpVtbl.unpack('L').first, 32)
|
965
|
+
table = table.unpack('L*')
|
966
|
+
|
967
|
+
getTriggerString = Win32::API::Function.new(table[7], 'PLP', 'L')
|
968
|
+
ptr = 0.chr * 4
|
969
|
+
hr = getTriggerString.call(@pITask, index, ptr)
|
970
|
+
|
971
|
+
if hr == S_OK
|
972
|
+
str = 0.chr * 256
|
973
|
+
wcscpy(str, ptr.unpack('L').first)
|
974
|
+
trigger = wide_to_multi(str)
|
975
|
+
CoTaskMemFree(ptr.unpack('L').first)
|
976
|
+
else
|
977
|
+
raise Error, get_last_error
|
974
978
|
end
|
975
979
|
|
976
|
-
|
977
|
-
|
978
|
-
def delete_trigger(index)
|
979
|
-
raise Error, 'null pointer' if @pITS.nil?
|
980
|
-
raise Error, 'No currently active task' if @pITask.nil?
|
980
|
+
trigger
|
981
|
+
end
|
981
982
|
|
982
|
-
|
983
|
-
|
983
|
+
# Deletes the trigger at the specified index.
|
984
|
+
#
|
985
|
+
def delete_trigger(index)
|
986
|
+
raise Error, 'null pointer' if @pITS.nil?
|
987
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
984
988
|
|
985
|
-
|
986
|
-
|
987
|
-
table = table.unpack('L*')
|
989
|
+
lpVtbl = 0.chr * 4
|
990
|
+
table = 0.chr * 20
|
988
991
|
|
989
|
-
|
990
|
-
|
992
|
+
memcpy(lpVtbl, @pITask, 4)
|
993
|
+
memcpy(table, lpVtbl.unpack('L').first, 20)
|
994
|
+
table = table.unpack('L*')
|
991
995
|
|
992
|
-
|
993
|
-
|
994
|
-
end
|
996
|
+
deleteTrigger = Win32::API::Function.new(table[4], 'PL', 'L')
|
997
|
+
hr = deleteTrigger.call(@pITask,index)
|
995
998
|
|
996
|
-
|
999
|
+
if hr != S_OK
|
1000
|
+
raise Error, get_last_error
|
997
1001
|
end
|
998
1002
|
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
lpVtbl = 0.chr * 4
|
1023
|
-
table = 0.chr * 20
|
1024
|
-
|
1025
|
-
memcpy(lpVtbl, pITaskTrigger, 4)
|
1026
|
-
memcpy(table, lpVtbl.unpack('L').first, 20)
|
1027
|
-
table = table.unpack('L*')
|
1028
|
-
|
1029
|
-
release = Win32::API::Function.new(table[2], 'P', 'L')
|
1030
|
-
getTrigger = Win32::API::Function.new(table[4], 'PP', 'L')
|
1031
|
-
|
1032
|
-
pTrigger = [48].pack('S') + 0.chr * 46
|
1033
|
-
hr = getTrigger.call(pITaskTrigger, pTrigger)
|
1034
|
-
|
1035
|
-
if hr != S_OK
|
1036
|
-
error = get_last_error
|
1037
|
-
release.call(pITaskTrigger)
|
1038
|
-
raise Error, error
|
1039
|
-
end
|
1040
|
-
|
1041
|
-
tr = pTrigger.unpack('S10L4LLSS')
|
1042
|
-
|
1043
|
-
trigger = {}
|
1044
|
-
trigger['start_year'] = tr[2]
|
1045
|
-
trigger['start_month'] = tr[3]
|
1046
|
-
trigger['start_day'] = tr[4]
|
1047
|
-
trigger['end_year'] = tr[5]
|
1048
|
-
trigger['end_month'] = tr[6]
|
1049
|
-
trigger['end_day'] = tr[7]
|
1050
|
-
trigger['start_hour'] = tr[8]
|
1051
|
-
trigger['start_minute'] = tr[9]
|
1052
|
-
trigger['minutes_duration'] = tr[10]
|
1053
|
-
trigger['minutes_interval'] = tr[11]
|
1054
|
-
trigger['flags'] = tr[12]
|
1055
|
-
trigger['trigger_type'] = tr[13]
|
1056
|
-
trigger['random_minutes_interval'] = tr[17]
|
1057
|
-
|
1058
|
-
case tr[13]
|
1059
|
-
when TASK_TIME_TRIGGER_DAILY
|
1060
|
-
tmp = {}
|
1061
|
-
tmp['days_interval'] = [tr[14]].pack('L').unpack('SS').first
|
1062
|
-
trigger['type'] = tmp
|
1063
|
-
when TASK_TIME_TRIGGER_WEEKLY
|
1064
|
-
tmp = {}
|
1065
|
-
tmp['weeks_interval'],tmp['days_of_week'] = [tr[14]].pack('L').unpack('SS')
|
1066
|
-
trigger['type'] = tmp
|
1067
|
-
when TASK_TIME_TRIGGER_MONTHLYDATE
|
1068
|
-
tmp = {}
|
1069
|
-
tmp['days'] = tr[14]
|
1070
|
-
tmp['months'] = [tr[15]].pack('L').unpack('SS').first
|
1071
|
-
trigger['type'] = tmp
|
1072
|
-
when TASK_TIME_TRIGGER_MONTHLYDOW
|
1073
|
-
tmp = {}
|
1074
|
-
tmp['weeks'],tmp['days_of_week'] = [tr[14]].pack('L').unpack('SS')
|
1075
|
-
tmp['months'] = [tr[15]].pack('L').unpack('SS').first
|
1076
|
-
trigger['type'] = tmp
|
1077
|
-
when TASK_TIME_TRIGGER_ONCE
|
1078
|
-
tmp = {}
|
1079
|
-
tmp['once'] = nil
|
1080
|
-
trigger['type'] = tmp
|
1081
|
-
else
|
1082
|
-
raise Error, 'Unknown trigger type'
|
1083
|
-
end
|
1084
|
-
|
1085
|
-
release.call(pITaskTrigger)
|
1086
|
-
|
1087
|
-
trigger
|
1003
|
+
index
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
# Returns a hash that describes the trigger at the given index for the
|
1007
|
+
# current task.
|
1008
|
+
#
|
1009
|
+
def trigger(index)
|
1010
|
+
raise Error, 'null pointer' if @pITS.nil?
|
1011
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
1012
|
+
|
1013
|
+
lpVtbl = 0.chr * 4
|
1014
|
+
table = 0.chr * 28
|
1015
|
+
|
1016
|
+
memcpy(lpVtbl, @pITask, 4)
|
1017
|
+
memcpy(table, lpVtbl.unpack('L').first, 28)
|
1018
|
+
table = table.unpack('L*')
|
1019
|
+
|
1020
|
+
getTrigger = Win32::API::Function.new(table[6], 'PLP', 'L')
|
1021
|
+
ptr = 0.chr * 4
|
1022
|
+
hr = getTrigger.call(@pITask, index, ptr)
|
1023
|
+
|
1024
|
+
if hr != S_OK
|
1025
|
+
raise Error, get_last_error
|
1088
1026
|
end
|
1089
1027
|
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
hr = createTrigger.call(@pITask, p1, p2)
|
1110
|
-
|
1111
|
-
if hr != S_OK
|
1112
|
-
raise Error, get_last_error
|
1113
|
-
end
|
1114
|
-
|
1115
|
-
pITaskTrigger = p2.unpack('L').first
|
1116
|
-
lpVtbl = 0.chr * 4
|
1117
|
-
table = 0.chr * 16
|
1118
|
-
|
1119
|
-
memcpy(lpVtbl, pITaskTrigger, 4)
|
1120
|
-
memcpy(table, lpVtbl.unpack('L').first, 16)
|
1121
|
-
table = table.unpack('L*')
|
1122
|
-
|
1123
|
-
release = Win32::API::Function.new(table[2], 'P', 'L')
|
1124
|
-
setTrigger = Win32::API::Function.new(table[3], 'PP', 'L')
|
1125
|
-
|
1126
|
-
type1 = 0
|
1127
|
-
type2 = 0
|
1128
|
-
tmp = trigger['type']
|
1129
|
-
tmp = nil unless tmp.is_a?(Hash)
|
1130
|
-
|
1131
|
-
case trigger['trigger_type']
|
1132
|
-
when TASK_TIME_TRIGGER_DAILY
|
1133
|
-
if tmp && tmp['days_interval']
|
1134
|
-
type1 = [tmp['days_interval'],0].pack('SS').unpack('L').first
|
1135
|
-
end
|
1136
|
-
when TASK_TIME_TRIGGER_WEEKLY
|
1137
|
-
if tmp && tmp['weeks_interval'] && tmp['days_of_week']
|
1138
|
-
type1 = [tmp['weeks_interval'],tmp['days_of_week']].pack('SS').unpack('L').first
|
1139
|
-
end
|
1140
|
-
when TASK_TIME_TRIGGER_MONTHLYDATE
|
1141
|
-
if tmp && tmp['months'] && tmp['days']
|
1142
|
-
type2 = [tmp['months'],0].pack('SS').unpack('L').first
|
1143
|
-
type1 = tmp['days']
|
1144
|
-
end
|
1145
|
-
when TASK_TIME_TRIGGER_MONTHLYDOW
|
1146
|
-
if tmp && tmp['weeks'] && tmp['days_of_week'] && tmp['months']
|
1147
|
-
type1 = [tmp['weeks'],tmp['days_of_week']].pack('SS').unpack('L').first
|
1148
|
-
type2 = [tmp['months'],0].pack('SS').unpack('L').first
|
1149
|
-
end
|
1150
|
-
when TASK_TIME_TRIGGER_ONCE
|
1151
|
-
# Do nothing. The Type member of the TASK_TRIGGER struct is ignored.
|
1152
|
-
else
|
1153
|
-
raise Error, 'Unknown trigger type'
|
1154
|
-
end
|
1155
|
-
|
1156
|
-
pTrigger = [
|
1157
|
-
48,
|
1158
|
-
0,
|
1159
|
-
trigger['start_year'] || 0,
|
1160
|
-
trigger['start_month'] || 0,
|
1161
|
-
trigger['start_day'] || 0,
|
1162
|
-
trigger['end_year'] || 0,
|
1163
|
-
trigger['end_month'] || 0,
|
1164
|
-
trigger['end_day'] || 0,
|
1165
|
-
trigger['start_hour'] || 0,
|
1166
|
-
trigger['start_minute'] || 0,
|
1167
|
-
trigger['minutes_duration'] || 0,
|
1168
|
-
trigger['minutes_interval'] || 0,
|
1169
|
-
trigger['flags'] || 0,
|
1170
|
-
trigger['trigger_type'] || 0,
|
1171
|
-
type1,
|
1172
|
-
type2,
|
1173
|
-
0,
|
1174
|
-
trigger['random_minutes_interval'] || 0
|
1175
|
-
].pack('S10L4LLSS')
|
1176
|
-
|
1177
|
-
hr = setTrigger.call(pITaskTrigger, pTrigger)
|
1178
|
-
|
1179
|
-
if hr != S_OK
|
1180
|
-
raise Error, get_last_error
|
1181
|
-
end
|
1182
|
-
|
1183
|
-
release.call(pITaskTrigger)
|
1184
|
-
|
1185
|
-
trigger
|
1028
|
+
pITaskTrigger = ptr.unpack('L').first
|
1029
|
+
lpVtbl = 0.chr * 4
|
1030
|
+
table = 0.chr * 20
|
1031
|
+
|
1032
|
+
memcpy(lpVtbl, pITaskTrigger, 4)
|
1033
|
+
memcpy(table, lpVtbl.unpack('L').first, 20)
|
1034
|
+
table = table.unpack('L*')
|
1035
|
+
|
1036
|
+
release = Win32::API::Function.new(table[2], 'P', 'L')
|
1037
|
+
getTrigger = Win32::API::Function.new(table[4], 'PP', 'L')
|
1038
|
+
|
1039
|
+
pTrigger = [48].pack('S') + 0.chr * 46
|
1040
|
+
hr = getTrigger.call(pITaskTrigger, pTrigger)
|
1041
|
+
|
1042
|
+
if hr != S_OK
|
1043
|
+
error = get_last_error
|
1044
|
+
release.call(pITaskTrigger)
|
1045
|
+
raise Error, error
|
1186
1046
|
end
|
1187
1047
|
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
end
|
1231
|
-
when TASK_TIME_TRIGGER_WEEKLY
|
1232
|
-
if tmp && tmp['weeks_interval'] && tmp['days_of_week']
|
1233
|
-
type1 = [tmp['weeks_interval'],tmp['days_of_week']].pack('SS').unpack('L').first
|
1234
|
-
end
|
1235
|
-
when TASK_TIME_TRIGGER_MONTHLYDATE
|
1236
|
-
if tmp && tmp['months'] && tmp['days']
|
1237
|
-
type2 = [tmp['months'],0].pack('SS').unpack('L').first
|
1238
|
-
type1 = tmp['days']
|
1239
|
-
end
|
1240
|
-
when TASK_TIME_TRIGGER_MONTHLYDOW
|
1241
|
-
if tmp && tmp['weeks'] && tmp['days_of_week'] && tmp['months']
|
1242
|
-
type1 = [tmp['weeks'],tmp['days_of_week']].pack('SS').unpack('L').first
|
1243
|
-
type2 = [tmp['months'],0].pack('SS').unpack('L').first
|
1244
|
-
end
|
1245
|
-
when TASK_TIME_TRIGGER_ONCE
|
1246
|
-
# Do nothing. The Type member of the TASK_TRIGGER struct is ignored.
|
1247
|
-
else
|
1248
|
-
raise Error, 'Unknown trigger type'
|
1249
|
-
end
|
1250
|
-
|
1251
|
-
pTrigger = [
|
1252
|
-
48,
|
1253
|
-
0,
|
1254
|
-
trigger['start_year'] || 0,
|
1255
|
-
trigger['start_month'] || 0,
|
1256
|
-
trigger['start_day'] || 0,
|
1257
|
-
trigger['end_year'] || 0,
|
1258
|
-
trigger['end_month'] || 0,
|
1259
|
-
trigger['end_day'] || 0,
|
1260
|
-
trigger['start_hour'] || 0,
|
1261
|
-
trigger['start_minute'] || 0,
|
1262
|
-
trigger['minutes_duration'] || 0,
|
1263
|
-
trigger['minutes_interval'] || 0,
|
1264
|
-
trigger['flags'] || 0,
|
1265
|
-
trigger['trigger_type'] || 0,
|
1266
|
-
type1,
|
1267
|
-
type2,
|
1268
|
-
0,
|
1269
|
-
trigger['random_minutes_interval'] || 0
|
1270
|
-
].pack('S10L4LLSS')
|
1271
|
-
|
1272
|
-
hr = setTrigger.call(pITaskTrigger, pTrigger)
|
1273
|
-
|
1274
|
-
if hr != S_OK
|
1275
|
-
raise Error, get_last_error
|
1276
|
-
end
|
1277
|
-
|
1278
|
-
release.call(pITaskTrigger)
|
1279
|
-
true
|
1048
|
+
tr = pTrigger.unpack('S10L4LLSS')
|
1049
|
+
|
1050
|
+
trigger = {}
|
1051
|
+
trigger['start_year'] = tr[2]
|
1052
|
+
trigger['start_month'] = tr[3]
|
1053
|
+
trigger['start_day'] = tr[4]
|
1054
|
+
trigger['end_year'] = tr[5]
|
1055
|
+
trigger['end_month'] = tr[6]
|
1056
|
+
trigger['end_day'] = tr[7]
|
1057
|
+
trigger['start_hour'] = tr[8]
|
1058
|
+
trigger['start_minute'] = tr[9]
|
1059
|
+
trigger['minutes_duration'] = tr[10]
|
1060
|
+
trigger['minutes_interval'] = tr[11]
|
1061
|
+
trigger['flags'] = tr[12]
|
1062
|
+
trigger['trigger_type'] = tr[13]
|
1063
|
+
trigger['random_minutes_interval'] = tr[17]
|
1064
|
+
|
1065
|
+
case tr[13]
|
1066
|
+
when TASK_TIME_TRIGGER_DAILY
|
1067
|
+
tmp = {}
|
1068
|
+
tmp['days_interval'] = [tr[14]].pack('L').unpack('SS').first
|
1069
|
+
trigger['type'] = tmp
|
1070
|
+
when TASK_TIME_TRIGGER_WEEKLY
|
1071
|
+
tmp = {}
|
1072
|
+
tmp['weeks_interval'],tmp['days_of_week'] = [tr[14]].pack('L').unpack('SS')
|
1073
|
+
trigger['type'] = tmp
|
1074
|
+
when TASK_TIME_TRIGGER_MONTHLYDATE
|
1075
|
+
tmp = {}
|
1076
|
+
tmp['days'] = tr[14]
|
1077
|
+
tmp['months'] = [tr[15]].pack('L').unpack('SS').first
|
1078
|
+
trigger['type'] = tmp
|
1079
|
+
when TASK_TIME_TRIGGER_MONTHLYDOW
|
1080
|
+
tmp = {}
|
1081
|
+
tmp['weeks'],tmp['days_of_week'] = [tr[14]].pack('L').unpack('SS')
|
1082
|
+
tmp['months'] = [tr[15]].pack('L').unpack('SS').first
|
1083
|
+
trigger['type'] = tmp
|
1084
|
+
when TASK_TIME_TRIGGER_ONCE
|
1085
|
+
tmp = {}
|
1086
|
+
tmp['once'] = nil
|
1087
|
+
trigger['type'] = tmp
|
1088
|
+
else
|
1089
|
+
raise Error, 'Unknown trigger type'
|
1280
1090
|
end
|
1281
1091
|
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1092
|
+
release.call(pITaskTrigger)
|
1093
|
+
|
1094
|
+
trigger
|
1095
|
+
end
|
1096
|
+
|
1097
|
+
# Sets the trigger for the currently active task.
|
1098
|
+
#
|
1099
|
+
def trigger=(trigger)
|
1100
|
+
raise Error, 'null pointer' if @pITS.nil?
|
1101
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
1102
|
+
raise TypeError unless trigger.is_a?(Hash)
|
1103
|
+
|
1104
|
+
trigger = transform_and_validate(trigger)
|
1105
|
+
|
1106
|
+
lpVtbl = 0.chr * 4
|
1107
|
+
table = 0.chr * 16
|
1108
|
+
|
1109
|
+
memcpy(lpVtbl, @pITask, 4)
|
1110
|
+
memcpy(table, lpVtbl.unpack('L').first, 16)
|
1111
|
+
table = table.unpack('L*')
|
1112
|
+
|
1113
|
+
createTrigger = Win32::API::Function.new(table[3], 'PPP', 'L')
|
1287
1114
|
|
1288
|
-
|
1289
|
-
|
1115
|
+
p1 = 0.chr * 4
|
1116
|
+
p2 = 0.chr * 4
|
1290
1117
|
|
1291
|
-
|
1292
|
-
memcpy(table, lpVtbl.unpack('L').first, 120)
|
1293
|
-
table = table.unpack('L*')
|
1118
|
+
hr = createTrigger.call(@pITask, p1, p2)
|
1294
1119
|
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1120
|
+
if hr != S_OK
|
1121
|
+
raise Error, get_last_error
|
1122
|
+
end
|
1298
1123
|
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1124
|
+
pITaskTrigger = p2.unpack('L').first
|
1125
|
+
lpVtbl = 0.chr * 4
|
1126
|
+
table = 0.chr * 16
|
1127
|
+
|
1128
|
+
memcpy(lpVtbl, pITaskTrigger, 4)
|
1129
|
+
memcpy(table, lpVtbl.unpack('L').first, 16)
|
1130
|
+
table = table.unpack('L*')
|
1131
|
+
|
1132
|
+
release = Win32::API::Function.new(table[2], 'P', 'L')
|
1133
|
+
setTrigger = Win32::API::Function.new(table[3], 'PP', 'L')
|
1134
|
+
|
1135
|
+
type1 = 0
|
1136
|
+
type2 = 0
|
1137
|
+
tmp = trigger['type']
|
1138
|
+
tmp = nil unless tmp.is_a?(Hash)
|
1139
|
+
|
1140
|
+
case trigger['trigger_type']
|
1141
|
+
when TASK_TIME_TRIGGER_DAILY
|
1142
|
+
if tmp && tmp['days_interval']
|
1143
|
+
type1 = [tmp['days_interval'],0].pack('SS').unpack('L').first
|
1144
|
+
end
|
1145
|
+
when TASK_TIME_TRIGGER_WEEKLY
|
1146
|
+
if tmp && tmp['weeks_interval'] && tmp['days_of_week']
|
1147
|
+
type1 = [tmp['weeks_interval'],tmp['days_of_week']].pack('SS').unpack('L').first
|
1148
|
+
end
|
1149
|
+
when TASK_TIME_TRIGGER_MONTHLYDATE
|
1150
|
+
if tmp && tmp['months'] && tmp['days']
|
1151
|
+
type2 = [tmp['months'],0].pack('SS').unpack('L').first
|
1152
|
+
type1 = tmp['days']
|
1153
|
+
end
|
1154
|
+
when TASK_TIME_TRIGGER_MONTHLYDOW
|
1155
|
+
if tmp && tmp['weeks'] && tmp['days_of_week'] && tmp['months']
|
1156
|
+
type1 = [tmp['weeks'],tmp['days_of_week']].pack('SS').unpack('L').first
|
1157
|
+
type2 = [tmp['months'],0].pack('SS').unpack('L').first
|
1158
|
+
end
|
1159
|
+
when TASK_TIME_TRIGGER_ONCE
|
1160
|
+
# Do nothing. The Type member of the TASK_TRIGGER struct is ignored.
|
1161
|
+
else
|
1162
|
+
raise Error, 'Unknown trigger type'
|
1163
|
+
end
|
1302
1164
|
|
1303
|
-
|
1165
|
+
pTrigger = [
|
1166
|
+
48,
|
1167
|
+
0,
|
1168
|
+
trigger['start_year'] || 0,
|
1169
|
+
trigger['start_month'] || 0,
|
1170
|
+
trigger['start_day'] || 0,
|
1171
|
+
trigger['end_year'] || 0,
|
1172
|
+
trigger['end_month'] || 0,
|
1173
|
+
trigger['end_day'] || 0,
|
1174
|
+
trigger['start_hour'] || 0,
|
1175
|
+
trigger['start_minute'] || 0,
|
1176
|
+
trigger['minutes_duration'] || 0,
|
1177
|
+
trigger['minutes_interval'] || 0,
|
1178
|
+
trigger['flags'] || 0,
|
1179
|
+
trigger['trigger_type'] || 0,
|
1180
|
+
type1,
|
1181
|
+
type2,
|
1182
|
+
0,
|
1183
|
+
trigger['random_minutes_interval'] || 0
|
1184
|
+
].pack('S10L4LLSS')
|
1185
|
+
|
1186
|
+
hr = setTrigger.call(pITaskTrigger, pTrigger)
|
1187
|
+
|
1188
|
+
if hr != S_OK
|
1189
|
+
raise Error, get_last_error
|
1304
1190
|
end
|
1305
1191
|
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
raise Error, 'No currently active task' if @pITask.nil?
|
1192
|
+
release.call(pITaskTrigger)
|
1193
|
+
|
1194
|
+
trigger
|
1195
|
+
end
|
1311
1196
|
|
1312
|
-
|
1313
|
-
|
1197
|
+
# Adds a trigger at the specified index.
|
1198
|
+
#
|
1199
|
+
def add_trigger(index, trigger)
|
1200
|
+
raise Error, 'null pointer' if @pITS.nil?
|
1201
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
1202
|
+
raise TypeError unless trigger.is_a?(Hash)
|
1314
1203
|
|
1315
|
-
|
1316
|
-
memcpy(table, lpVtbl.unpack('L').first, 116)
|
1317
|
-
table = table.unpack('L*')
|
1204
|
+
trigger = transform_and_validate(trigger)
|
1318
1205
|
|
1319
|
-
|
1320
|
-
|
1206
|
+
lpVtbl = 0.chr * 4
|
1207
|
+
table = 0.chr * 28
|
1321
1208
|
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1209
|
+
memcpy(lpVtbl, @pITask, 4)
|
1210
|
+
memcpy(table, lpVtbl.unpack('L').first, 28)
|
1211
|
+
table = table.unpack('L*')
|
1325
1212
|
|
1326
|
-
|
1213
|
+
getTrigger = Win32::API::Function.new(table[6], 'PLP', 'L')
|
1214
|
+
ptr = 0.chr * 4
|
1215
|
+
hr = getTrigger.call(@pITask, index, ptr)
|
1216
|
+
|
1217
|
+
if hr != S_OK
|
1218
|
+
raise Error, get_last_error
|
1327
1219
|
end
|
1328
1220
|
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1221
|
+
pITaskTrigger = ptr.unpack('L').first
|
1222
|
+
lpVtbl = 0.chr * 4
|
1223
|
+
table = 0.chr * 16
|
1224
|
+
|
1225
|
+
memcpy(lpVtbl, pITaskTrigger,4)
|
1226
|
+
memcpy(table, lpVtbl.unpack('L').first,16)
|
1227
|
+
table = table.unpack('L*')
|
1228
|
+
|
1229
|
+
release = Win32::API::Function.new(table[2], 'P', 'L')
|
1230
|
+
setTrigger = Win32::API::Function.new(table[3], 'PP', 'L')
|
1231
|
+
|
1232
|
+
type1 = 0
|
1233
|
+
type2 = 0
|
1234
|
+
tmp = trigger['type']
|
1235
|
+
tmp = nil unless tmp.is_a?(Hash)
|
1236
|
+
|
1237
|
+
case trigger['trigger_type']
|
1238
|
+
when TASK_TIME_TRIGGER_DAILY
|
1239
|
+
if tmp && tmp['days_interval']
|
1240
|
+
type1 = [tmp['days_interval'],0].pack('SS').unpack('L').first
|
1241
|
+
end
|
1242
|
+
when TASK_TIME_TRIGGER_WEEKLY
|
1243
|
+
if tmp && tmp['weeks_interval'] && tmp['days_of_week']
|
1244
|
+
type1 = [tmp['weeks_interval'],tmp['days_of_week']].pack('SS').unpack('L').first
|
1245
|
+
end
|
1246
|
+
when TASK_TIME_TRIGGER_MONTHLYDATE
|
1247
|
+
if tmp && tmp['months'] && tmp['days']
|
1248
|
+
type2 = [tmp['months'],0].pack('SS').unpack('L').first
|
1249
|
+
type1 = tmp['days']
|
1250
|
+
end
|
1251
|
+
when TASK_TIME_TRIGGER_MONTHLYDOW
|
1252
|
+
if tmp && tmp['weeks'] && tmp['days_of_week'] && tmp['months']
|
1253
|
+
type1 = [tmp['weeks'],tmp['days_of_week']].pack('SS').unpack('L').first
|
1254
|
+
type2 = [tmp['months'],0].pack('SS').unpack('L').first
|
1255
|
+
end
|
1256
|
+
when TASK_TIME_TRIGGER_ONCE
|
1257
|
+
# Do nothing. The Type member of the TASK_TRIGGER struct is ignored.
|
1258
|
+
else
|
1259
|
+
raise Error, 'Unknown trigger type'
|
1260
|
+
end
|
1363
1261
|
|
1364
|
-
|
1262
|
+
pTrigger = [
|
1263
|
+
48,
|
1264
|
+
0,
|
1265
|
+
trigger['start_year'] || 0,
|
1266
|
+
trigger['start_month'] || 0,
|
1267
|
+
trigger['start_day'] || 0,
|
1268
|
+
trigger['end_year'] || 0,
|
1269
|
+
trigger['end_month'] || 0,
|
1270
|
+
trigger['end_day'] || 0,
|
1271
|
+
trigger['start_hour'] || 0,
|
1272
|
+
trigger['start_minute'] || 0,
|
1273
|
+
trigger['minutes_duration'] || 0,
|
1274
|
+
trigger['minutes_interval'] || 0,
|
1275
|
+
trigger['flags'] || 0,
|
1276
|
+
trigger['trigger_type'] || 0,
|
1277
|
+
type1,
|
1278
|
+
type2,
|
1279
|
+
0,
|
1280
|
+
trigger['random_minutes_interval'] || 0
|
1281
|
+
].pack('S10L4LLSS')
|
1282
|
+
|
1283
|
+
hr = setTrigger.call(pITaskTrigger, pTrigger)
|
1284
|
+
|
1285
|
+
if hr != S_OK
|
1286
|
+
raise Error, get_last_error
|
1365
1287
|
end
|
1366
1288
|
|
1367
|
-
|
1368
|
-
|
1369
|
-
def exit_code
|
1370
|
-
raise Error, 'null pointer' if @pITask.nil?
|
1371
|
-
raise Error, 'No currently active task' if @pITask.nil?
|
1289
|
+
release.call(pITaskTrigger)
|
1290
|
+
end
|
1372
1291
|
|
1373
|
-
|
1374
|
-
|
1292
|
+
# Returns the flags (integer) that modify the behavior of the work item. You
|
1293
|
+
# must OR the return value to determine the flags yourself.
|
1294
|
+
#
|
1295
|
+
def flags
|
1296
|
+
raise Error, 'null pointer' if @pITask.nil?
|
1375
1297
|
|
1376
|
-
|
1377
|
-
|
1378
|
-
table = table.unpack('L*')
|
1298
|
+
lpVtbl = 0.chr * 4
|
1299
|
+
table = 0.chr * 120
|
1379
1300
|
|
1380
|
-
|
1381
|
-
|
1382
|
-
|
1301
|
+
memcpy(lpVtbl, @pITask, 4)
|
1302
|
+
memcpy(table, lpVtbl.unpack('L').first, 120)
|
1303
|
+
table = table.unpack('L*')
|
1383
1304
|
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1305
|
+
getFlags = Win32::API::Function.new(table[29], 'PP', 'L')
|
1306
|
+
ptr = 0.chr * 4
|
1307
|
+
hr = getFlags.call(@pITask, ptr)
|
1387
1308
|
|
1388
|
-
|
1309
|
+
if hr != S_OK
|
1310
|
+
raise Error, get_last_error
|
1389
1311
|
end
|
1390
1312
|
|
1391
|
-
|
1392
|
-
|
1393
|
-
def comment
|
1394
|
-
raise Error, 'null pointer' if @pITask.nil?
|
1395
|
-
raise Error, 'No currently active task' if @pITask.nil?
|
1313
|
+
flags = ptr.unpack('L').first
|
1314
|
+
end
|
1396
1315
|
|
1397
|
-
|
1398
|
-
|
1316
|
+
# Sets an OR'd value of flags that modify the behavior of the work item.
|
1317
|
+
#
|
1318
|
+
def flags=(flags)
|
1319
|
+
raise Error, 'null pointer' if @pITS.nil?
|
1320
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
1399
1321
|
|
1400
|
-
|
1401
|
-
|
1402
|
-
table = table.unpack('L*')
|
1322
|
+
lpVtbl = 0.chr * 4
|
1323
|
+
table = 0.chr * 116
|
1403
1324
|
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1325
|
+
memcpy(lpVtbl, @pITask, 4)
|
1326
|
+
memcpy(table, lpVtbl.unpack('L').first, 116)
|
1327
|
+
table = table.unpack('L*')
|
1407
1328
|
|
1408
|
-
|
1409
|
-
|
1410
|
-
end
|
1329
|
+
setFlags = Win32::API::Function.new(table[28], 'PL', 'L')
|
1330
|
+
hr = setFlags.call(@pITask, flags)
|
1411
1331
|
|
1412
|
-
|
1413
|
-
|
1414
|
-
CoTaskMemFree(ptr.unpack('L').first)
|
1415
|
-
wide_to_multi(str)
|
1332
|
+
if hr != S_OK
|
1333
|
+
raise Error, get_last_error
|
1416
1334
|
end
|
1417
1335
|
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1336
|
+
flags
|
1337
|
+
end
|
1338
|
+
|
1339
|
+
# Returns the status of the currently active task. Possible values are
|
1340
|
+
# 'ready', 'running', 'not scheduled' or 'unknown'.
|
1341
|
+
#
|
1342
|
+
def status
|
1343
|
+
raise Error, 'null pointer' if @pITask.nil?
|
1344
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
1424
1345
|
|
1425
|
-
|
1426
|
-
|
1346
|
+
lpVtbl = 0.chr * 4
|
1347
|
+
table = 0.chr * 68
|
1427
1348
|
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1349
|
+
memcpy(lpVtbl,@pITask,4)
|
1350
|
+
memcpy(table,lpVtbl.unpack('L').first,68)
|
1351
|
+
table = table.unpack('L*')
|
1431
1352
|
|
1432
|
-
|
1433
|
-
|
1434
|
-
|
1353
|
+
getStatus = Win32::API::Function.new(table[16], 'PP', 'L')
|
1354
|
+
ptr = 0.chr * 4
|
1355
|
+
hr = getStatus.call(@pITask, ptr)
|
1435
1356
|
|
1436
|
-
|
1437
|
-
|
1438
|
-
|
1357
|
+
if hr != S_OK
|
1358
|
+
raise Error,get_last_error
|
1359
|
+
end
|
1439
1360
|
|
1440
|
-
|
1361
|
+
st = ptr.unpack('L').first
|
1362
|
+
|
1363
|
+
case st
|
1364
|
+
when 0x00041300 # SCHED_S_TASK_READY
|
1365
|
+
status = 'ready'
|
1366
|
+
when 0x00041301 # SCHED_S_TASK_RUNNING
|
1367
|
+
status = 'running'
|
1368
|
+
when 0x00041305 # SCHED_S_TASK_NOT_SCHEDULED
|
1369
|
+
status = 'not scheduled'
|
1370
|
+
else
|
1371
|
+
status = 'unknown'
|
1441
1372
|
end
|
1442
1373
|
|
1443
|
-
|
1444
|
-
|
1445
|
-
def creator
|
1446
|
-
raise Error, 'null pointer' if @pITask.nil?
|
1447
|
-
raise Error, 'No currently active task' if @pITask.nil?
|
1374
|
+
status
|
1375
|
+
end
|
1448
1376
|
|
1449
|
-
|
1450
|
-
|
1377
|
+
# Returns the exit code from the last scheduled run.
|
1378
|
+
#
|
1379
|
+
def exit_code
|
1380
|
+
raise Error, 'null pointer' if @pITask.nil?
|
1381
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
1451
1382
|
|
1452
|
-
|
1453
|
-
|
1454
|
-
table = table.unpack('L*')
|
1383
|
+
lpVtbl = 0.chr * 4
|
1384
|
+
table = 0.chr * 72
|
1455
1385
|
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1386
|
+
memcpy(lpVtbl, @pITask, 4)
|
1387
|
+
memcpy(table, lpVtbl.unpack('L').first, 72)
|
1388
|
+
table = table.unpack('L*')
|
1459
1389
|
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1390
|
+
getExitCode = Win32::API::Function.new(table[17], 'PP', 'L')
|
1391
|
+
ptr = 0.chr * 4
|
1392
|
+
hr = getExitCode.call(@pITask, ptr)
|
1463
1393
|
|
1464
|
-
|
1465
|
-
|
1466
|
-
CoTaskMemFree(ptr.unpack('L').first)
|
1467
|
-
wide_to_multi(str)
|
1394
|
+
if hr > 0x80000000
|
1395
|
+
raise Error, get_last_error
|
1468
1396
|
end
|
1469
1397
|
|
1470
|
-
|
1471
|
-
|
1472
|
-
def creator=(creator)
|
1473
|
-
raise Error, 'null pointer' if @pITask.nil?
|
1474
|
-
raise Error, 'No currently active task' if @pITask.nil?
|
1475
|
-
raise TypeError unless creator.is_a?(String)
|
1398
|
+
ptr.unpack('L').first
|
1399
|
+
end
|
1476
1400
|
|
1477
|
-
|
1478
|
-
|
1401
|
+
# Returns the comment associated with the task, if any.
|
1402
|
+
#
|
1403
|
+
def comment
|
1404
|
+
raise Error, 'null pointer' if @pITask.nil?
|
1405
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
1479
1406
|
|
1480
|
-
|
1481
|
-
|
1482
|
-
table = table.unpack('L*')
|
1407
|
+
lpVtbl = 0.chr * 4
|
1408
|
+
table = 0.chr * 80
|
1483
1409
|
|
1484
|
-
|
1485
|
-
|
1486
|
-
|
1410
|
+
memcpy(lpVtbl, @pITask, 4)
|
1411
|
+
memcpy(table, lpVtbl.unpack('L').first, 80)
|
1412
|
+
table = table.unpack('L*')
|
1487
1413
|
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
1414
|
+
getComment = Win32::API::Function.new(table[19], 'PP', 'L')
|
1415
|
+
ptr = 0.chr * 4
|
1416
|
+
hr = getComment.call(@pITask, ptr)
|
1491
1417
|
|
1492
|
-
|
1418
|
+
if hr != S_OK
|
1419
|
+
raise Error,get_last_error
|
1493
1420
|
end
|
1494
1421
|
|
1495
|
-
|
1496
|
-
|
1497
|
-
|
1498
|
-
|
1499
|
-
|
1422
|
+
str = 0.chr * 256
|
1423
|
+
wcscpy(str, ptr.unpack('L').first)
|
1424
|
+
CoTaskMemFree(ptr.unpack('L').first)
|
1425
|
+
wide_to_multi(str)
|
1426
|
+
end
|
1427
|
+
|
1428
|
+
# Sets the comment for the task.
|
1429
|
+
#
|
1430
|
+
def comment=(comment)
|
1431
|
+
raise Error, 'null pointer' if @pITask.nil?
|
1432
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
1433
|
+
raise TypeError unless comment.is_a?(String)
|
1434
|
+
|
1435
|
+
lpVtbl = 0.chr * 4
|
1436
|
+
table = 0.chr * 76
|
1437
|
+
|
1438
|
+
memcpy(lpVtbl, @pITask, 4)
|
1439
|
+
memcpy(table, lpVtbl.unpack('L').first, 76)
|
1440
|
+
table = table.unpack('L*')
|
1500
1441
|
|
1501
|
-
|
1502
|
-
|
1442
|
+
setComment = Win32::API::Function.new(table[18], 'PP', 'L')
|
1443
|
+
comment_w = multi_to_wide(comment)
|
1444
|
+
hr = setComment.call(@pITask, comment_w)
|
1503
1445
|
|
1504
|
-
|
1505
|
-
|
1506
|
-
|
1446
|
+
if hr != S_OK
|
1447
|
+
raise Error, get_last_error
|
1448
|
+
end
|
1449
|
+
|
1450
|
+
comment
|
1451
|
+
end
|
1452
|
+
|
1453
|
+
# Returns the name of the user who created the task.
|
1454
|
+
#
|
1455
|
+
def creator
|
1456
|
+
raise Error, 'null pointer' if @pITask.nil?
|
1457
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
1507
1458
|
|
1508
|
-
|
1509
|
-
|
1510
|
-
hr = getNextRunTime.call(@pITask, st)
|
1459
|
+
lpVtbl = 0.chr * 4
|
1460
|
+
table = 0.chr * 88
|
1511
1461
|
|
1512
|
-
|
1513
|
-
|
1514
|
-
|
1462
|
+
memcpy(lpVtbl, @pITask, 4)
|
1463
|
+
memcpy(table, lpVtbl.unpack('L').first, 88)
|
1464
|
+
table = table.unpack('L*')
|
1515
1465
|
|
1516
|
-
|
1517
|
-
|
1466
|
+
getCreator = Win32::API::Function.new(table[21], 'PP', 'L')
|
1467
|
+
ptr = 0.chr * 4
|
1468
|
+
hr = getCreator.call(@pITask, ptr)
|
1518
1469
|
|
1519
|
-
|
1470
|
+
if hr != S_OK
|
1471
|
+
raise Error, get_last_error
|
1520
1472
|
end
|
1521
1473
|
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1539
|
-
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1544
|
-
|
1545
|
-
|
1546
|
-
|
1547
|
-
|
1548
|
-
end
|
1549
|
-
|
1550
|
-
time
|
1474
|
+
str = 0.chr * 256
|
1475
|
+
wcscpy(str, ptr.unpack('L').first)
|
1476
|
+
CoTaskMemFree(ptr.unpack('L').first)
|
1477
|
+
wide_to_multi(str)
|
1478
|
+
end
|
1479
|
+
|
1480
|
+
# Sets the creator for the task.
|
1481
|
+
#
|
1482
|
+
def creator=(creator)
|
1483
|
+
raise Error, 'null pointer' if @pITask.nil?
|
1484
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
1485
|
+
raise TypeError unless creator.is_a?(String)
|
1486
|
+
|
1487
|
+
lpVtbl = 0.chr * 4
|
1488
|
+
table = 0.chr * 84
|
1489
|
+
|
1490
|
+
memcpy(lpVtbl, @pITask, 4)
|
1491
|
+
memcpy(table, lpVtbl.unpack('L').first, 84)
|
1492
|
+
table = table.unpack('L*')
|
1493
|
+
|
1494
|
+
setCreator = Win32::API::Function.new(table[20], 'PP', 'L')
|
1495
|
+
creator_w = multi_to_wide(creator)
|
1496
|
+
hr = setCreator.call(@pITask, creator_w)
|
1497
|
+
|
1498
|
+
if hr != S_OK
|
1499
|
+
raise Error, get_last_error
|
1551
1500
|
end
|
1552
1501
|
|
1553
|
-
|
1554
|
-
|
1555
|
-
#
|
1556
|
-
def max_run_time
|
1557
|
-
raise Error, 'null pointer' if @pITask.nil?
|
1558
|
-
raise Error, 'No currently active task' if @pITask.nil?
|
1502
|
+
creator
|
1503
|
+
end
|
1559
1504
|
|
1560
|
-
|
1561
|
-
|
1505
|
+
# Returns a Time object that indicates the next time the task will run.
|
1506
|
+
#
|
1507
|
+
def next_run_time
|
1508
|
+
raise Error, 'null pointer' if @pITask.nil?
|
1509
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
1562
1510
|
|
1563
|
-
|
1564
|
-
|
1565
|
-
table = table.unpack('L*')
|
1511
|
+
lpVtbl = 0.chr * 4
|
1512
|
+
table = 0.chr * 40
|
1566
1513
|
|
1567
|
-
|
1514
|
+
memcpy(lpVtbl, @pITask, 4)
|
1515
|
+
memcpy(table, lpVtbl.unpack('L').first, 40)
|
1516
|
+
table = table.unpack('L*')
|
1568
1517
|
|
1569
|
-
|
1570
|
-
|
1518
|
+
getNextRunTime = Win32::API::Function.new(table[9], 'PP', 'L')
|
1519
|
+
st = 0.chr * 16
|
1520
|
+
hr = getNextRunTime.call(@pITask, st)
|
1571
1521
|
|
1572
|
-
|
1573
|
-
|
1574
|
-
|
1522
|
+
if hr != S_OK
|
1523
|
+
raise Error, get_last_error
|
1524
|
+
end
|
1575
1525
|
|
1576
|
-
|
1526
|
+
a1,a2,_,a3,a4,a5,a6,a7 = st.unpack('S*')
|
1527
|
+
a7 *= 1000
|
1528
|
+
|
1529
|
+
Time.local(a1,a2,a3,a4,a5,a6,a7)
|
1530
|
+
end
|
1531
|
+
|
1532
|
+
# Returns a Time object indicating the most recent time the task ran or
|
1533
|
+
# nil if the task has never run.
|
1534
|
+
#
|
1535
|
+
def most_recent_run_time
|
1536
|
+
raise Error, 'null pointer' if @pITask.nil?
|
1537
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
1538
|
+
|
1539
|
+
lpVtbl = 0.chr * 4
|
1540
|
+
table = 0.chr * 64
|
1541
|
+
|
1542
|
+
memcpy(lpVtbl, @pITask, 4)
|
1543
|
+
memcpy(table, lpVtbl.unpack('L').first, 64)
|
1544
|
+
table = table.unpack('L*')
|
1545
|
+
|
1546
|
+
getMostRecentRunTime = Win32::API::Function.new(table[15], 'PP', 'L')
|
1547
|
+
st = 0.chr * 16
|
1548
|
+
hr = getMostRecentRunTime.call(@pITask, st)
|
1549
|
+
|
1550
|
+
if hr == 0x00041303 # SCHED_S_TASK_HAS_NOT_RUN
|
1551
|
+
time = nil
|
1552
|
+
elsif hr == S_OK
|
1553
|
+
a1, a2, _, a3, a4, a5, a6, a7 = st.unpack('S*')
|
1554
|
+
a7 *= 1000
|
1555
|
+
time = Time.local(a1, a2, a3, a4, a5, a6, a7)
|
1556
|
+
else
|
1557
|
+
raise Error, get_last_error
|
1577
1558
|
end
|
1578
1559
|
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
|
1588
|
-
|
1589
|
-
|
1590
|
-
|
1591
|
-
|
1592
|
-
|
1593
|
-
|
1594
|
-
|
1595
|
-
|
1596
|
-
|
1597
|
-
|
1598
|
-
|
1599
|
-
|
1600
|
-
|
1601
|
-
|
1560
|
+
time
|
1561
|
+
end
|
1562
|
+
|
1563
|
+
# Returns the maximum length of time, in milliseconds, that the task
|
1564
|
+
# will run before terminating.
|
1565
|
+
#
|
1566
|
+
def max_run_time
|
1567
|
+
raise Error, 'null pointer' if @pITask.nil?
|
1568
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
1569
|
+
|
1570
|
+
lpVtbl = 0.chr * 4
|
1571
|
+
table = 0.chr * 176
|
1572
|
+
|
1573
|
+
memcpy(lpVtbl, @pITask, 4)
|
1574
|
+
memcpy(table, lpVtbl.unpack('L').first, 176)
|
1575
|
+
table = table.unpack('L*')
|
1576
|
+
|
1577
|
+
getMaxRunTime = Win32::API::Function.new(table[43], 'PP', 'L')
|
1578
|
+
|
1579
|
+
ptr = 0.chr * 4
|
1580
|
+
hr = getMaxRunTime.call(@pITask, ptr)
|
1581
|
+
|
1582
|
+
if hr != S_OK
|
1583
|
+
raise Error, get_last_error
|
1602
1584
|
end
|
1603
|
-
|
1604
|
-
|
1605
|
-
|
1606
|
-
|
1607
|
-
|
1608
|
-
|
1609
|
-
|
1610
|
-
|
1611
|
-
|
1612
|
-
|
1613
|
-
|
1585
|
+
|
1586
|
+
max_run_time = ptr.unpack('L').first
|
1587
|
+
end
|
1588
|
+
|
1589
|
+
# Sets the maximum length of time, in milliseconds, that the task can run
|
1590
|
+
# before terminating. Returns the value you specified if successful.
|
1591
|
+
#
|
1592
|
+
def max_run_time=(max_run_time)
|
1593
|
+
raise Error, 'null pointer' if @pITask.nil?
|
1594
|
+
raise Error, 'No currently active task' if @pITask.nil?
|
1595
|
+
raise TypeError unless max_run_time.is_a?(Numeric)
|
1596
|
+
|
1597
|
+
lpVtbl = 0.chr * 4
|
1598
|
+
table = 0.chr * 172
|
1599
|
+
|
1600
|
+
memcpy(lpVtbl, @pITask, 4)
|
1601
|
+
memcpy(table, lpVtbl.unpack('L').first, 172)
|
1602
|
+
table = table.unpack('L*')
|
1603
|
+
|
1604
|
+
setMaxRunTime = Win32::API::Function.new(table[42], 'PL', 'L')
|
1605
|
+
hr = setMaxRunTime.call(@pITask, max_run_time)
|
1606
|
+
|
1607
|
+
if hr != S_OK
|
1608
|
+
raise Error,get_last_error
|
1614
1609
|
end
|
1615
1610
|
|
1616
|
-
|
1617
|
-
|
1618
|
-
|
1619
|
-
|
1620
|
-
|
1621
|
-
|
1622
|
-
|
1623
|
-
|
1624
|
-
|
1625
|
-
|
1626
|
-
|
1627
|
-
|
1628
|
-
|
1629
|
-
|
1630
|
-
|
1631
|
-
|
1632
|
-
|
1633
|
-
|
1634
|
-
|
1635
|
-
|
1636
|
-
|
1637
|
-
|
1638
|
-
|
1639
|
-
|
1640
|
-
|
1641
|
-
|
1642
|
-
|
1643
|
-
|
1644
|
-
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
1648
|
-
|
1649
|
-
|
1650
|
-
|
1651
|
-
|
1652
|
-
|
1653
|
-
|
1654
|
-
|
1655
|
-
|
1656
|
-
|
1657
|
-
|
1658
|
-
|
1659
|
-
|
1660
|
-
|
1661
|
-
|
1662
|
-
|
1663
|
-
|
1664
|
-
|
1611
|
+
max_run_time
|
1612
|
+
end
|
1613
|
+
|
1614
|
+
# Returns whether or not the scheduled task exists.
|
1615
|
+
def exists?(job_name)
|
1616
|
+
bool = false
|
1617
|
+
Dir.foreach('C:/Windows/Tasks'){ |file|
|
1618
|
+
if File.basename(file, '.job') == job_name
|
1619
|
+
bool = true
|
1620
|
+
break
|
1621
|
+
end
|
1622
|
+
}
|
1623
|
+
bool
|
1624
|
+
end
|
1625
|
+
|
1626
|
+
private
|
1627
|
+
|
1628
|
+
# :stopdoc:
|
1629
|
+
|
1630
|
+
# Used for the new_work_item method
|
1631
|
+
ValidTriggerKeys = [
|
1632
|
+
'end_day',
|
1633
|
+
'end_month',
|
1634
|
+
'end_year',
|
1635
|
+
'flags',
|
1636
|
+
'minutes_duration',
|
1637
|
+
'minutes_interval',
|
1638
|
+
'random_minutes_interval',
|
1639
|
+
'start_day',
|
1640
|
+
'start_hour',
|
1641
|
+
'start_minute',
|
1642
|
+
'start_month',
|
1643
|
+
'start_year',
|
1644
|
+
'trigger_type',
|
1645
|
+
'type'
|
1646
|
+
]
|
1647
|
+
|
1648
|
+
ValidTypeKeys = [
|
1649
|
+
'days_interval',
|
1650
|
+
'weeks_interval',
|
1651
|
+
'days_of_week',
|
1652
|
+
'months',
|
1653
|
+
'days',
|
1654
|
+
'weeks'
|
1655
|
+
]
|
1656
|
+
|
1657
|
+
# Private method that validates keys, and converts all keys to lowercase
|
1658
|
+
# strings.
|
1659
|
+
#
|
1660
|
+
def transform_and_validate(hash)
|
1661
|
+
new_hash = {}
|
1662
|
+
|
1663
|
+
hash.each{ |key, value|
|
1664
|
+
key = key.to_s.downcase
|
1665
|
+
if key == 'type'
|
1666
|
+
new_type_hash = {}
|
1667
|
+
raise ArgumentError unless value.is_a?(Hash)
|
1668
|
+
value.each{ |subkey, subvalue|
|
1669
|
+
subkey = subkey.to_s.downcase
|
1670
|
+
if ValidTypeKeys.include?(subkey)
|
1671
|
+
new_type_hash[subkey] = subvalue
|
1665
1672
|
else
|
1666
|
-
|
1667
|
-
new_hash[key] = value
|
1668
|
-
else
|
1669
|
-
raise ArgumentError, "Invalid key '#{key}'"
|
1670
|
-
end
|
1673
|
+
raise ArgumentError, "Invalid type key '#{subkey}'"
|
1671
1674
|
end
|
1672
|
-
|
1673
|
-
|
1674
|
-
|
1675
|
-
|
1676
|
-
|
1675
|
+
}
|
1676
|
+
new_hash[key] = new_type_hash
|
1677
|
+
else
|
1678
|
+
if ValidTriggerKeys.include?(key)
|
1679
|
+
new_hash[key] = value
|
1680
|
+
else
|
1681
|
+
raise ArgumentError, "Invalid key '#{key}'"
|
1682
|
+
end
|
1683
|
+
end
|
1684
|
+
}
|
1685
|
+
|
1686
|
+
new_hash
|
1687
|
+
end
|
1688
|
+
end
|
1677
1689
|
end
|