1 /*
2 * Copyright 2012 Detlef Riekenberg
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #define COBJMACROS
20
21 #include "initguid.h"
22 #include "taskschd.h"
23
24 #include "wine/debug.h"
25 #include "wine/unicode.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(schtasks);
28
29 static const WCHAR change_optW[] = {'/','c','h','a','n','g','e',0};
30 static const WCHAR create_optW[] = {'/','c','r','e','a','t','e',0};
31 static const WCHAR delete_optW[] = {'/','d','e','l','e','t','e',0};
32 static const WCHAR enable_optW[] = {'/','e','n','a','b','l','e',0};
33 static const WCHAR f_optW[] = {'/','f',0};
34 static const WCHAR ru_optW[] = {'/','r','u',0};
35 static const WCHAR tn_optW[] = {'/','t','n',0};
36 static const WCHAR tr_optW[] = {'/','t','r',0};
37 static const WCHAR xml_optW[] = {'/','x','m','l',0};
38
get_tasks_root_folder(void)39 static ITaskFolder *get_tasks_root_folder(void)
40 {
41 ITaskService *service;
42 ITaskFolder *root;
43 VARIANT empty;
44 HRESULT hres;
45
46 hres = CoCreateInstance(&CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER,
47 &IID_ITaskService, (void**)&service);
48 if (FAILED(hres))
49 return NULL;
50
51 V_VT(&empty) = VT_EMPTY;
52 hres = ITaskService_Connect(service, empty, empty, empty, empty);
53 if (FAILED(hres)) {
54 FIXME("Connect failed: %08x\n", hres);
55 return NULL;
56 }
57
58 hres = ITaskService_GetFolder(service, NULL, &root);
59 ITaskService_Release(service);
60 if (FAILED(hres)) {
61 FIXME("GetFolder failed: %08x\n", hres);
62 return NULL;
63 }
64
65 return root;
66 }
67
get_registered_task(const WCHAR * name)68 static IRegisteredTask *get_registered_task(const WCHAR *name)
69 {
70 IRegisteredTask *registered_task;
71 ITaskFolder *root;
72 BSTR str;
73 HRESULT hres;
74
75 root = get_tasks_root_folder();
76 if (!root)
77 return NULL;
78
79 str = SysAllocString(name);
80 hres = ITaskFolder_GetTask(root, str, ®istered_task);
81 SysFreeString(str);
82 ITaskFolder_Release(root);
83 if (FAILED(hres)) {
84 FIXME("GetTask failed: %08x\n", hres);
85 return NULL;
86 }
87
88 return registered_task;
89 }
90
read_file_to_bstr(const WCHAR * file_name)91 static BSTR read_file_to_bstr(const WCHAR *file_name)
92 {
93 LARGE_INTEGER file_size;
94 DWORD read_size, size;
95 unsigned char *data;
96 HANDLE file;
97 BOOL r = FALSE;
98 BSTR ret;
99
100 file = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
101 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
102 if (file == INVALID_HANDLE_VALUE) {
103 FIXME("Could not open file\n");
104 return NULL;
105 }
106
107 if (!GetFileSizeEx(file, &file_size) || !file_size.QuadPart) {
108 FIXME("Empty file\n");
109 CloseHandle(file);
110 return NULL;
111 }
112
113 data = HeapAlloc(GetProcessHeap(), 0, file_size.QuadPart);
114 if (data)
115 r = ReadFile(file, data, file_size.QuadPart, &read_size, NULL);
116 CloseHandle(file);
117 if (!r) {
118 FIXME("Read filed\n");
119 HeapFree(GetProcessHeap(), 0, data);
120 return NULL;
121 }
122
123 if (read_size > 2 && data[0] == 0xff && data[1] == 0xfe) { /* UTF-16 BOM */
124 ret = SysAllocStringLen((const WCHAR *)(data + 2), (read_size - 2) / sizeof(WCHAR));
125 }else {
126 size = MultiByteToWideChar(CP_ACP, 0, (const char *)data, read_size, NULL, 0);
127 ret = SysAllocStringLen(NULL, size);
128 if (ret)
129 MultiByteToWideChar(CP_ACP, 0, (const char *)data, read_size, ret, size);
130 }
131 HeapFree(GetProcessHeap(), 0, data);
132
133 return ret;
134 }
135
change_command(int argc,WCHAR * argv[])136 static int change_command(int argc, WCHAR *argv[])
137 {
138 BOOL have_option = FALSE, enable = FALSE;
139 const WCHAR *task_name = NULL;
140 IRegisteredTask *task;
141 HRESULT hres;
142
143 while (argc) {
144 if(!strcmpiW(argv[0], tn_optW)) {
145 if (argc < 2) {
146 FIXME("Missing /tn value\n");
147 return 1;
148 }
149
150 if (task_name) {
151 FIXME("Duplicated /tn argument\n");
152 return 1;
153 }
154
155 task_name = argv[1];
156 argc -= 2;
157 argv += 2;
158 }else if (!strcmpiW(argv[0], enable_optW)) {
159 enable = TRUE;
160 have_option = TRUE;
161 argc--;
162 argv++;
163 }else if (!strcmpiW(argv[0], tr_optW)) {
164 if (argc < 2) {
165 FIXME("Missing /tr value\n");
166 return 1;
167 }
168
169 FIXME("Unsupported /tr option %s\n", debugstr_w(argv[1]));
170 have_option = TRUE;
171 argc -= 2;
172 argv += 2;
173 }else {
174 FIXME("Unsupported arguments %s\n", debugstr_w(argv[0]));
175 return 1;
176 }
177 }
178
179 if (!task_name) {
180 FIXME("Missing /tn option\n");
181 return 1;
182 }
183
184 if (!have_option) {
185 FIXME("Missing change options\n");
186 return 1;
187 }
188
189 task = get_registered_task(task_name);
190 if (!task)
191 return 1;
192
193 if (enable) {
194 hres = IRegisteredTask_put_Enabled(task, VARIANT_TRUE);
195 if (FAILED(hres)) {
196 IRegisteredTask_Release(task);
197 FIXME("put_Enabled failed: %08x\n", hres);
198 return 1;
199 }
200 }
201
202 IRegisteredTask_Release(task);
203 return 0;
204 }
205
create_command(int argc,WCHAR * argv[])206 static int create_command(int argc, WCHAR *argv[])
207 {
208 const WCHAR *task_name = NULL, *xml_file = NULL;
209 ITaskFolder *root = NULL;
210 LONG flags = TASK_CREATE;
211 IRegisteredTask *task;
212 VARIANT empty;
213 BSTR str, xml;
214 HRESULT hres;
215
216 while (argc) {
217 if (!strcmpiW(argv[0], xml_optW)) {
218 if (argc < 2) {
219 FIXME("Missing /xml value\n");
220 return 1;
221 }
222
223 if (xml_file) {
224 FIXME("Duplicated /xml argument\n");
225 return 1;
226 }
227
228 xml_file = argv[1];
229 argc -= 2;
230 argv += 2;
231 }else if(!strcmpiW(argv[0], tn_optW)) {
232 if (argc < 2) {
233 FIXME("Missing /tn value\n");
234 return 1;
235 }
236
237 if (task_name) {
238 FIXME("Duplicated /tn argument\n");
239 return 1;
240 }
241
242 task_name = argv[1];
243 argc -= 2;
244 argv += 2;
245 }else if(!strcmpiW(argv[0], f_optW)) {
246 flags = TASK_CREATE_OR_UPDATE;
247 argc--;
248 argv++;
249 }else if (!strcmpiW(argv[0], ru_optW)) {
250 if (argc < 2) {
251 FIXME("Missing /ru value\n");
252 return 1;
253 }
254
255 FIXME("Unsupported /ru option %s\n", debugstr_w(argv[1]));
256 argc -= 2;
257 argv += 2;
258 }else {
259 FIXME("Unsupported argument %s\n", debugstr_w(argv[0]));
260 return 1;
261 }
262 }
263
264 if (!task_name) {
265 FIXME("Missing /tn argument\n");
266 return 1;
267 }
268
269 if (!xml_file) {
270 FIXME("Missing /xml argument\n");
271 return E_FAIL;
272 }
273
274 xml = read_file_to_bstr(xml_file);
275 if (!xml)
276 return 1;
277
278 root = get_tasks_root_folder();
279 if (!root) {
280 SysFreeString(xml);
281 return 1;
282 }
283
284 V_VT(&empty) = VT_EMPTY;
285 str = SysAllocString(task_name);
286 hres = ITaskFolder_RegisterTask(root, str, xml, flags, empty, empty,
287 TASK_LOGON_NONE, empty, &task);
288 SysFreeString(str);
289 SysFreeString(xml);
290 ITaskFolder_Release(root);
291 if (FAILED(hres))
292 return 1;
293
294 IRegisteredTask_Release(task);
295 return 0;
296 }
297
delete_command(int argc,WCHAR * argv[])298 static int delete_command(int argc, WCHAR *argv[])
299 {
300 const WCHAR *task_name = NULL;
301 ITaskFolder *root = NULL;
302 BSTR str;
303 HRESULT hres;
304
305 while (argc) {
306 if (!strcmpiW(argv[0], f_optW)) {
307 TRACE("force opt\n");
308 argc--;
309 argv++;
310 }else if(!strcmpiW(argv[0], tn_optW)) {
311 if (argc < 2) {
312 FIXME("Missing /tn value\n");
313 return 1;
314 }
315
316 if (task_name) {
317 FIXME("Duplicated /tn argument\n");
318 return 1;
319 }
320
321 task_name = argv[1];
322 argc -= 2;
323 argv += 2;
324 }else {
325 FIXME("Unsupported argument %s\n", debugstr_w(argv[0]));
326 return 1;
327 }
328 }
329
330 if (!task_name) {
331 FIXME("Missing /tn argument\n");
332 return 1;
333 }
334
335 root = get_tasks_root_folder();
336 if (!root)
337 return 1;
338
339 str = SysAllocString(task_name);
340 hres = ITaskFolder_DeleteTask(root, str, 0);
341 SysFreeString(str);
342 ITaskFolder_Release(root);
343 if (FAILED(hres))
344 return 1;
345
346 return 0;
347 }
348
wmain(int argc,WCHAR * argv[])349 int wmain(int argc, WCHAR *argv[])
350 {
351 int i, ret = 0;
352
353 for (i = 0; i < argc; i++)
354 TRACE(" %s", wine_dbgstr_w(argv[i]));
355 TRACE("\n");
356
357 CoInitialize(NULL);
358
359 if (argc < 2)
360 FIXME("Print current tasks state\n");
361 else if (!strcmpiW(argv[1], change_optW))
362 ret = change_command(argc - 2, argv + 2);
363 else if (!strcmpiW(argv[1], create_optW))
364 ret = create_command(argc - 2, argv + 2);
365 else if (!strcmpiW(argv[1], delete_optW))
366 ret = delete_command(argc - 2, argv + 2);
367 else
368 FIXME("Unsupported command %s\n", debugstr_w(argv[1]));
369
370 CoUninitialize();
371 return ret;
372 }
373