2 * Copyright 2014 Dmitry Timoshkov
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.
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.
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
29 #include "taskschd_private.h"
31 #include "wine/unicode.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(taskschd
);
36 static const char root
[] = "Software\\Microsoft\\Windows NT\\CurrentVersion\\Schedule\\TaskCache\\Tree";
40 ITaskFolder ITaskFolder_iface
;
45 static inline TaskFolder
*impl_from_ITaskFolder(ITaskFolder
*iface
)
47 return CONTAINING_RECORD(iface
, TaskFolder
, ITaskFolder_iface
);
50 static ULONG WINAPI
TaskFolder_AddRef(ITaskFolder
*iface
)
52 TaskFolder
*folder
= impl_from_ITaskFolder(iface
);
53 return InterlockedIncrement(&folder
->ref
);
56 static ULONG WINAPI
TaskFolder_Release(ITaskFolder
*iface
)
58 TaskFolder
*folder
= impl_from_ITaskFolder(iface
);
59 LONG ref
= InterlockedDecrement(&folder
->ref
);
63 TRACE("destroying %p\n", iface
);
64 heap_free(folder
->path
);
71 static HRESULT WINAPI
TaskFolder_QueryInterface(ITaskFolder
*iface
, REFIID riid
, void **obj
)
73 if (!riid
|| !obj
) return E_INVALIDARG
;
75 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
77 if (IsEqualGUID(riid
, &IID_ITaskFolder
) ||
78 IsEqualGUID(riid
, &IID_IDispatch
) ||
79 IsEqualGUID(riid
, &IID_IUnknown
))
81 ITaskFolder_AddRef(iface
);
86 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
91 static HRESULT WINAPI
TaskFolder_GetTypeInfoCount(ITaskFolder
*iface
, UINT
*count
)
93 FIXME("%p,%p: stub\n", iface
, count
);
97 static HRESULT WINAPI
TaskFolder_GetTypeInfo(ITaskFolder
*iface
, UINT index
, LCID lcid
, ITypeInfo
**info
)
99 FIXME("%p,%u,%u,%p: stub\n", iface
, index
, lcid
, info
);
103 static HRESULT WINAPI
TaskFolder_GetIDsOfNames(ITaskFolder
*iface
, REFIID riid
, LPOLESTR
*names
,
104 UINT count
, LCID lcid
, DISPID
*dispid
)
106 FIXME("%p,%s,%p,%u,%u,%p: stub\n", iface
, debugstr_guid(riid
), names
, count
, lcid
, dispid
);
110 static HRESULT WINAPI
TaskFolder_Invoke(ITaskFolder
*iface
, DISPID dispid
, REFIID riid
, LCID lcid
, WORD flags
,
111 DISPPARAMS
*params
, VARIANT
*result
, EXCEPINFO
*excepinfo
, UINT
*argerr
)
113 FIXME("%p,%d,%s,%04x,%04x,%p,%p,%p,%p: stub\n", iface
, dispid
, debugstr_guid(riid
), lcid
, flags
,
114 params
, result
, excepinfo
, argerr
);
118 static HRESULT WINAPI
TaskFolder_get_Name(ITaskFolder
*iface
, BSTR
*name
)
120 TaskFolder
*folder
= impl_from_ITaskFolder(iface
);
123 TRACE("%p,%p\n", iface
, name
);
125 if (!name
) return E_POINTER
;
127 p_name
= strrchrW(folder
->path
, '\\');
129 p_name
= folder
->path
;
131 if (p_name
[1] != 0) p_name
++;
133 *name
= SysAllocString(p_name
);
134 if (!*name
) return E_OUTOFMEMORY
;
139 static HRESULT
reg_create_folder(const WCHAR
*path
, HKEY
*hfolder
)
142 DWORD ret
, disposition
;
144 ret
= RegCreateKeyA(HKEY_LOCAL_MACHINE
, root
, &hroot
);
145 if (ret
) return HRESULT_FROM_WIN32(ret
);
147 while (*path
== '\\') path
++;
148 ret
= RegCreateKeyExW(hroot
, path
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, hfolder
, &disposition
);
149 if (ret
== ERROR_FILE_NOT_FOUND
)
150 ret
= ERROR_PATH_NOT_FOUND
;
152 if (ret
== ERROR_SUCCESS
&& disposition
== REG_OPENED_EXISTING_KEY
)
154 RegCloseKey(*hfolder
);
155 ret
= ERROR_ALREADY_EXISTS
;
160 return HRESULT_FROM_WIN32(ret
);
163 static HRESULT
reg_open_folder(const WCHAR
*path
, HKEY
*hfolder
)
168 ret
= RegCreateKeyA(HKEY_LOCAL_MACHINE
, root
, &hroot
);
169 if (ret
) return HRESULT_FROM_WIN32(ret
);
171 while (*path
== '\\') path
++;
172 ret
= RegOpenKeyExW(hroot
, path
, 0, KEY_ALL_ACCESS
, hfolder
);
173 if (ret
== ERROR_FILE_NOT_FOUND
)
174 ret
= ERROR_PATH_NOT_FOUND
;
178 return HRESULT_FROM_WIN32(ret
);
181 static HRESULT
reg_delete_folder(const WCHAR
*path
, const WCHAR
*name
)
186 ret
= RegCreateKeyA(HKEY_LOCAL_MACHINE
, root
, &hroot
);
187 if (ret
) return HRESULT_FROM_WIN32(ret
);
189 while (*path
== '\\') path
++;
190 ret
= RegOpenKeyExW(hroot
, path
, 0, DELETE
, &hfolder
);
194 while (*name
== '\\') name
++;
195 if (ret
== ERROR_SUCCESS
)
197 ret
= RegDeleteKeyW(hfolder
, name
);
198 RegCloseKey(hfolder
);
201 return HRESULT_FROM_WIN32(ret
);
204 static inline void reg_close_folder(HKEY hfolder
)
206 RegCloseKey(hfolder
);
209 static HRESULT WINAPI
TaskFolder_get_Path(ITaskFolder
*iface
, BSTR
*path
)
211 TaskFolder
*folder
= impl_from_ITaskFolder(iface
);
213 TRACE("%p,%p\n", iface
, path
);
215 if (!path
) return E_POINTER
;
217 *path
= SysAllocString(folder
->path
);
218 if (!*path
) return E_OUTOFMEMORY
;
223 static HRESULT WINAPI
TaskFolder_GetFolder(ITaskFolder
*iface
, BSTR path
, ITaskFolder
**new_folder
)
225 TaskFolder
*folder
= impl_from_ITaskFolder(iface
);
227 TRACE("%p,%s,%p\n", iface
, debugstr_w(path
), folder
);
229 if (!path
) return E_INVALIDARG
;
230 if (!new_folder
) return E_POINTER
;
232 return TaskFolder_create(folder
->path
, path
, new_folder
, FALSE
);
235 static HRESULT WINAPI
TaskFolder_GetFolders(ITaskFolder
*iface
, LONG flags
, ITaskFolderCollection
**folders
)
237 TaskFolder
*folder
= impl_from_ITaskFolder(iface
);
239 TRACE("%p,%x,%p: stub\n", iface
, flags
, folders
);
241 if (!folders
) return E_POINTER
;
244 FIXME("unsupported flags %x\n", flags
);
246 return TaskFolderCollection_create(folder
->path
, folders
);
249 static inline BOOL
is_variant_null(const VARIANT
*var
)
251 return V_VT(var
) == VT_EMPTY
|| V_VT(var
) == VT_NULL
||
252 (V_VT(var
) == VT_BSTR
&& (V_BSTR(var
) == NULL
|| !*V_BSTR(var
)));
255 static HRESULT WINAPI
TaskFolder_CreateFolder(ITaskFolder
*iface
, BSTR path
, VARIANT sddl
, ITaskFolder
**new_folder
)
257 TaskFolder
*folder
= impl_from_ITaskFolder(iface
);
258 ITaskFolder
*tmp_folder
= NULL
;
261 TRACE("%p,%s,%s,%p\n", iface
, debugstr_w(path
), debugstr_variant(&sddl
), folder
);
263 if (!path
) return E_INVALIDARG
;
265 if (!new_folder
) new_folder
= &tmp_folder
;
267 if (!is_variant_null(&sddl
))
268 FIXME("security descriptor %s is ignored\n", debugstr_variant(&sddl
));
270 hr
= TaskFolder_create(folder
->path
, path
, new_folder
, TRUE
);
272 ITaskFolder_Release(tmp_folder
);
277 static WCHAR
*get_full_path(const WCHAR
*parent
, const WCHAR
*path
)
279 static const WCHAR bslash
[] = { '\\', 0 };
283 if (path
) len
= strlenW(path
);
285 if (parent
) len
+= strlenW(parent
);
287 /* +1 if parent is not '\' terminated */
288 folder_path
= heap_alloc((len
+ 2) * sizeof(WCHAR
));
289 if (!folder_path
) return NULL
;
294 strcpyW(folder_path
, parent
);
298 len
= strlenW(folder_path
);
299 if (!len
|| folder_path
[len
- 1] != '\\')
300 strcatW(folder_path
, bslash
);
302 while (*path
== '\\') path
++;
303 strcatW(folder_path
, path
);
306 len
= strlenW(folder_path
);
308 strcatW(folder_path
, bslash
);
313 static HRESULT WINAPI
TaskFolder_DeleteFolder(ITaskFolder
*iface
, BSTR name
, LONG flags
)
315 TaskFolder
*folder
= impl_from_ITaskFolder(iface
);
319 TRACE("%p,%s,%x\n", iface
, debugstr_w(name
), flags
);
321 if (!name
|| !*name
) return E_ACCESSDENIED
;
324 FIXME("unsupported flags %x\n", flags
);
326 folder_path
= get_full_path(folder
->path
, name
);
327 if (!folder_path
) return E_OUTOFMEMORY
;
329 hr
= SchRpcDelete(folder_path
, 0);
330 heap_free(folder_path
);
331 if (hr
!= S_OK
) return hr
;
333 return reg_delete_folder(folder
->path
, name
);
336 static HRESULT WINAPI
TaskFolder_GetTask(ITaskFolder
*iface
, BSTR name
, IRegisteredTask
**task
)
338 TaskFolder
*folder
= impl_from_ITaskFolder(iface
);
340 TRACE("%p,%s,%p\n", iface
, debugstr_w(name
), task
);
342 if (!task
) return E_POINTER
;
344 return RegisteredTask_create(folder
->path
, name
, NULL
, 0, task
, FALSE
);
347 static HRESULT WINAPI
TaskFolder_GetTasks(ITaskFolder
*iface
, LONG flags
, IRegisteredTaskCollection
**tasks
)
349 TaskFolder
*folder
= impl_from_ITaskFolder(iface
);
351 TRACE("%p,%x,%p: stub\n", iface
, flags
, tasks
);
353 if (!tasks
) return E_POINTER
;
355 return RegisteredTaskCollection_create(folder
->path
, tasks
);
358 static HRESULT WINAPI
TaskFolder_DeleteTask(ITaskFolder
*iface
, BSTR name
, LONG flags
)
360 FIXME("%p,%s,%x: stub\n", iface
, debugstr_w(name
), flags
);
364 static HRESULT WINAPI
TaskFolder_RegisterTask(ITaskFolder
*iface
, BSTR name
, BSTR xml
, LONG flags
,
365 VARIANT user
, VARIANT password
, TASK_LOGON_TYPE logon
,
366 VARIANT sddl
, IRegisteredTask
**task
)
368 ITaskDefinition
*taskdef
;
371 TRACE("%p,%s,%s,%x,%s,%s,%d,%s,%p\n", iface
, debugstr_w(name
), debugstr_w(xml
), flags
,
372 debugstr_variant(&user
), debugstr_variant(&password
), logon
, debugstr_variant(&sddl
), task
);
374 if (!xml
) return HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER
);
376 hr
= TaskDefinition_create(&taskdef
);
377 if (hr
!= S_OK
) return hr
;
379 hr
= ITaskDefinition_put_XmlText(taskdef
, xml
);
381 hr
= ITaskFolder_RegisterTaskDefinition(iface
, name
, taskdef
, flags
, user
, password
, logon
, sddl
, task
);
383 ITaskDefinition_Release(taskdef
);
387 static HRESULT WINAPI
TaskFolder_RegisterTaskDefinition(ITaskFolder
*iface
, BSTR name
, ITaskDefinition
*definition
, LONG flags
,
388 VARIANT user
, VARIANT password
, TASK_LOGON_TYPE logon
,
389 VARIANT sddl
, IRegisteredTask
**task
)
391 TaskFolder
*folder
= impl_from_ITaskFolder(iface
);
392 IRegisteredTask
*regtask
= NULL
;
395 FIXME("%p,%s,%p,%x,%s,%s,%d,%s,%p: stub\n", iface
, debugstr_w(name
), definition
, flags
,
396 debugstr_variant(&user
), debugstr_variant(&password
), logon
, debugstr_variant(&sddl
), task
);
398 if (!is_variant_null(&sddl
))
399 FIXME("security descriptor %s is ignored\n", debugstr_variant(&sddl
));
401 if (!is_variant_null(&user
) || !is_variant_null(&password
))
402 FIXME("user/password are ignored\n");
404 if (!task
) task
= ®task
;
406 hr
= RegisteredTask_create(folder
->path
, name
, definition
, logon
, task
, TRUE
);
409 IRegisteredTask_Release(regtask
);
414 static HRESULT WINAPI
TaskFolder_GetSecurityDescriptor(ITaskFolder
*iface
, LONG info
, BSTR
*sddl
)
416 FIXME("%p,%x,%p: stub\n", iface
, info
, sddl
);
420 static HRESULT WINAPI
TaskFolder_SetSecurityDescriptor(ITaskFolder
*iface
, BSTR sddl
, LONG flags
)
422 FIXME("%p,%s,%x: stub\n", iface
, debugstr_w(sddl
), flags
);
426 static const ITaskFolderVtbl TaskFolder_vtbl
=
428 TaskFolder_QueryInterface
,
431 TaskFolder_GetTypeInfoCount
,
432 TaskFolder_GetTypeInfo
,
433 TaskFolder_GetIDsOfNames
,
437 TaskFolder_GetFolder
,
438 TaskFolder_GetFolders
,
439 TaskFolder_CreateFolder
,
440 TaskFolder_DeleteFolder
,
443 TaskFolder_DeleteTask
,
444 TaskFolder_RegisterTask
,
445 TaskFolder_RegisterTaskDefinition
,
446 TaskFolder_GetSecurityDescriptor
,
447 TaskFolder_SetSecurityDescriptor
450 HRESULT
TaskFolder_create(const WCHAR
*parent
, const WCHAR
*path
, ITaskFolder
**obj
, BOOL create
)
459 int len
= strlenW(path
);
460 if (len
&& path
[len
- 1] == '\\') return ERROR_INVALID_NAME
;
463 folder_path
= get_full_path(parent
, path
);
464 if (!folder_path
) return E_OUTOFMEMORY
;
468 hr
= SchRpcCreateFolder(folder_path
, NULL
, 0);
472 DWORD start_index
, count
, i
;
477 hr
= SchRpcEnumFolders(folder_path
, 0, &start_index
, 0, &count
, &names
);
480 for (i
= 0; i
< count
; i
++)
481 MIDL_user_free(names
[i
]);
482 MIDL_user_free(names
);
486 if (hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
))
487 hr
= HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
);
493 heap_free(folder_path
);
497 hr
= create
? reg_create_folder(folder_path
, &hfolder
) : reg_open_folder(folder_path
, &hfolder
);
500 heap_free(folder_path
);
504 reg_close_folder(hfolder
);
506 folder
= heap_alloc(sizeof(*folder
));
509 heap_free(folder_path
);
510 return E_OUTOFMEMORY
;
513 folder
->ITaskFolder_iface
.lpVtbl
= &TaskFolder_vtbl
;
515 folder
->path
= folder_path
;
516 *obj
= &folder
->ITaskFolder_iface
;
518 TRACE("created %p\n", *obj
);