2 * Copyright (C) 2008 Google (Roy Shea)
3 * Copyright (C) 2018 Dmitry Timoshkov
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "mstask_private.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(mstask
);
37 ITaskScheduler ITaskScheduler_iface
;
39 ITaskService
*service
;
44 IEnumWorkItems IEnumWorkItems_iface
;
49 static inline TaskSchedulerImpl
*impl_from_ITaskScheduler(ITaskScheduler
*iface
)
51 return CONTAINING_RECORD(iface
, TaskSchedulerImpl
, ITaskScheduler_iface
);
54 static inline EnumWorkItemsImpl
*impl_from_IEnumWorkItems(IEnumWorkItems
*iface
)
56 return CONTAINING_RECORD(iface
, EnumWorkItemsImpl
, IEnumWorkItems_iface
);
59 static void TaskSchedulerDestructor(TaskSchedulerImpl
*This
)
62 ITaskService_Release(This
->service
);
64 InterlockedDecrement(&dll_ref
);
67 static HRESULT WINAPI
EnumWorkItems_QueryInterface(IEnumWorkItems
*iface
, REFIID riid
, void **obj
)
69 EnumWorkItemsImpl
*This
= impl_from_IEnumWorkItems(iface
);
71 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
73 if (IsEqualGUID(riid
, &IID_IEnumWorkItems
) || IsEqualGUID(riid
, &IID_IUnknown
))
75 *obj
= &This
->IEnumWorkItems_iface
;
76 IEnumWorkItems_AddRef(iface
);
84 static ULONG WINAPI
EnumWorkItems_AddRef(IEnumWorkItems
*iface
)
86 EnumWorkItemsImpl
*This
= impl_from_IEnumWorkItems(iface
);
87 ULONG ref
= InterlockedIncrement(&This
->ref
);
88 TRACE("(%p)->(%u)\n", This
, ref
);
92 static ULONG WINAPI
EnumWorkItems_Release(IEnumWorkItems
*iface
)
94 EnumWorkItemsImpl
*This
= impl_from_IEnumWorkItems(iface
);
95 ULONG ref
= InterlockedDecrement(&This
->ref
);
97 TRACE("(%p)->(%u)\n", This
, ref
);
101 if (This
->handle
!= INVALID_HANDLE_VALUE
)
102 FindClose(This
->handle
);
104 InterlockedDecrement(&dll_ref
);
110 static void free_list(LPWSTR
*list
, LONG count
)
114 for (i
= 0; i
< count
; i
++)
115 CoTaskMemFree(list
[i
]);
120 static inline BOOL
is_file(const WIN32_FIND_DATAW
*data
)
122 return !(data
->dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
);
125 static HRESULT WINAPI
EnumWorkItems_Next(IEnumWorkItems
*iface
, ULONG count
, LPWSTR
**names
, ULONG
*fetched
)
127 static const WCHAR tasksW
[] = { '\\','T','a','s','k','s','\\','*',0 };
128 EnumWorkItemsImpl
*This
= impl_from_IEnumWorkItems(iface
);
129 WCHAR path
[MAX_PATH
];
130 WIN32_FIND_DATAW data
;
131 ULONG enumerated
, allocated
, dummy
;
133 HRESULT hr
= S_FALSE
;
135 TRACE("(%p)->(%u %p %p)\n", This
, count
, names
, fetched
);
137 if (!count
|| !names
|| (!fetched
&& count
> 1)) return E_INVALIDARG
;
139 if (!fetched
) fetched
= &dummy
;
147 list
= CoTaskMemAlloc(allocated
* sizeof(list
[0]));
148 if (!list
) return E_OUTOFMEMORY
;
150 if (This
->handle
== INVALID_HANDLE_VALUE
)
152 GetWindowsDirectoryW(path
, MAX_PATH
);
153 lstrcatW(path
, tasksW
);
154 This
->handle
= FindFirstFileW(path
, &data
);
155 if (This
->handle
== INVALID_HANDLE_VALUE
)
160 if (!FindNextFileW(This
->handle
, &data
))
168 if (enumerated
>= allocated
)
172 new_list
= CoTaskMemRealloc(list
, allocated
* sizeof(list
[0]));
181 list
[enumerated
] = CoTaskMemAlloc((lstrlenW(data
.cFileName
) + 1) * sizeof(WCHAR
));
182 if (!list
[enumerated
])
188 lstrcpyW(list
[enumerated
], data
.cFileName
);
191 if (enumerated
>= count
)
197 } while (FindNextFileW(This
->handle
, &data
));
200 free_list(list
, enumerated
);
203 *fetched
= enumerated
;
210 static HRESULT WINAPI
EnumWorkItems_Skip(IEnumWorkItems
*iface
, ULONG count
)
216 TRACE("(%p)->(%u)\n", iface
, count
);
218 hr
= EnumWorkItems_Next(iface
, count
, &names
, &fetched
);
220 free_list(names
, fetched
);
225 static HRESULT WINAPI
EnumWorkItems_Reset(IEnumWorkItems
*iface
)
227 EnumWorkItemsImpl
*This
= impl_from_IEnumWorkItems(iface
);
229 TRACE("(%p)\n", This
);
231 if (This
->handle
!= INVALID_HANDLE_VALUE
)
233 FindClose(This
->handle
);
234 This
->handle
= INVALID_HANDLE_VALUE
;
240 static HRESULT WINAPI
EnumWorkItems_Clone(IEnumWorkItems
*iface
, IEnumWorkItems
**cloned
)
242 EnumWorkItemsImpl
*This
= impl_from_IEnumWorkItems(iface
);
243 FIXME("(%p)->(%p): stub\n", This
, cloned
);
247 static const IEnumWorkItemsVtbl EnumWorkItemsVtbl
= {
248 EnumWorkItems_QueryInterface
,
249 EnumWorkItems_AddRef
,
250 EnumWorkItems_Release
,
257 static HRESULT
create_task_enum(IEnumWorkItems
**ret
)
259 EnumWorkItemsImpl
*tasks
;
263 tasks
= heap_alloc(sizeof(*tasks
));
265 return E_OUTOFMEMORY
;
267 tasks
->IEnumWorkItems_iface
.lpVtbl
= &EnumWorkItemsVtbl
;
269 tasks
->handle
= INVALID_HANDLE_VALUE
;
271 *ret
= &tasks
->IEnumWorkItems_iface
;
272 InterlockedIncrement(&dll_ref
);
276 static HRESULT WINAPI
MSTASK_ITaskScheduler_QueryInterface(
277 ITaskScheduler
* iface
,
281 TaskSchedulerImpl
* This
= impl_from_ITaskScheduler(iface
);
283 TRACE("IID: %s\n", debugstr_guid(riid
));
285 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
286 IsEqualGUID(riid
, &IID_ITaskScheduler
))
288 *ppvObject
= &This
->ITaskScheduler_iface
;
289 ITaskScheduler_AddRef(iface
);
294 return E_NOINTERFACE
;
297 static ULONG WINAPI
MSTASK_ITaskScheduler_AddRef(
298 ITaskScheduler
* iface
)
300 TaskSchedulerImpl
*This
= impl_from_ITaskScheduler(iface
);
302 return InterlockedIncrement(&This
->ref
);
305 static ULONG WINAPI
MSTASK_ITaskScheduler_Release(
306 ITaskScheduler
* iface
)
308 TaskSchedulerImpl
* This
= impl_from_ITaskScheduler(iface
);
311 ref
= InterlockedDecrement(&This
->ref
);
313 TaskSchedulerDestructor(This
);
317 static HRESULT WINAPI
MSTASK_ITaskScheduler_SetTargetComputer(
318 ITaskScheduler
*iface
, LPCWSTR comp_name
)
320 TaskSchedulerImpl
*This
= impl_from_ITaskScheduler(iface
);
321 VARIANT v_null
, v_comp
;
324 TRACE("(%p)->(%s)\n", This
, debugstr_w(comp_name
));
326 V_VT(&v_null
) = VT_NULL
;
327 V_VT(&v_comp
) = VT_BSTR
;
328 V_BSTR(&v_comp
) = SysAllocString(comp_name
);
329 hr
= ITaskService_Connect(This
->service
, v_comp
, v_null
, v_null
, v_null
);
330 SysFreeString(V_BSTR(&v_comp
));
334 static HRESULT WINAPI
MSTASK_ITaskScheduler_GetTargetComputer(
335 ITaskScheduler
*iface
, LPWSTR
*comp_name
)
337 TaskSchedulerImpl
*This
= impl_from_ITaskScheduler(iface
);
342 TRACE("(%p)->(%p)\n", This
, comp_name
);
347 hr
= ITaskService_get_TargetServer(This
->service
, &bstr
);
348 if (hr
!= S_OK
) return hr
;
350 /* extra space for two '\' and a zero */
351 buffer
= CoTaskMemAlloc((SysStringLen(bstr
) + 3) * sizeof(WCHAR
));
356 lstrcpyW(buffer
+ 2, bstr
);
370 static HRESULT WINAPI
MSTASK_ITaskScheduler_Enum(
371 ITaskScheduler
* iface
,
372 IEnumWorkItems
**tasks
)
374 TaskSchedulerImpl
*This
= impl_from_ITaskScheduler(iface
);
376 TRACE("(%p)->(%p)\n", This
, tasks
);
381 return create_task_enum(tasks
);
384 static HRESULT WINAPI
MSTASK_ITaskScheduler_Activate(ITaskScheduler
*iface
,
385 LPCWSTR task_name
, REFIID riid
, IUnknown
**unknown
)
391 TRACE("%p, %s, %s, %p\n", iface
, debugstr_w(task_name
), debugstr_guid(riid
), unknown
);
393 hr
= ITaskScheduler_NewWorkItem(iface
, task_name
, &CLSID_CTask
, riid
, (IUnknown
**)&task
);
394 if (hr
!= S_OK
) return hr
;
396 hr
= ITask_QueryInterface(task
, &IID_IPersistFile
, (void **)&pfile
);
401 hr
= IPersistFile_GetCurFile(pfile
, &curfile
);
404 hr
= IPersistFile_Load(pfile
, curfile
, STGM_READ
| STGM_SHARE_DENY_WRITE
);
405 CoTaskMemFree(curfile
);
408 IPersistFile_Release(pfile
);
412 *unknown
= (IUnknown
*)task
;
418 static HRESULT WINAPI
MSTASK_ITaskScheduler_Delete(ITaskScheduler
*iface
, LPCWSTR name
)
420 static const WCHAR tasksW
[] = { '\\','T','a','s','k','s','\\',0 };
421 static const WCHAR jobW
[] = { '.','j','o','b',0 };
422 WCHAR task_name
[MAX_PATH
];
424 TRACE("%p, %s\n", iface
, debugstr_w(name
));
426 if (strchrW(name
, '.')) return E_INVALIDARG
;
428 GetWindowsDirectoryW(task_name
, MAX_PATH
);
429 lstrcatW(task_name
, tasksW
);
430 lstrcatW(task_name
, name
);
431 lstrcatW(task_name
, jobW
);
433 if (!DeleteFileW(task_name
))
434 return HRESULT_FROM_WIN32(GetLastError());
439 static HRESULT WINAPI
MSTASK_ITaskScheduler_NewWorkItem(
440 ITaskScheduler
* iface
,
446 TaskSchedulerImpl
*This
= impl_from_ITaskScheduler(iface
);
448 TRACE("(%p, %s, %s, %s, %p)\n", iface
, debugstr_w(task_name
),
449 debugstr_guid(rclsid
), debugstr_guid(riid
), task
);
451 if (!IsEqualGUID(rclsid
, &CLSID_CTask
))
452 return CLASS_E_CLASSNOTAVAILABLE
;
454 if (!IsEqualGUID(riid
, &IID_ITask
))
455 return E_NOINTERFACE
;
457 return TaskConstructor(This
->service
, task_name
, (ITask
**)task
);
460 static HRESULT WINAPI
MSTASK_ITaskScheduler_AddWorkItem(ITaskScheduler
*iface
, LPCWSTR name
, IScheduledWorkItem
*item
)
462 static const WCHAR tasksW
[] = { '\\','T','a','s','k','s','\\',0 };
463 static const WCHAR jobW
[] = { '.','j','o','b',0 };
464 WCHAR task_name
[MAX_PATH
];
468 TRACE("%p, %s, %p\n", iface
, debugstr_w(name
), item
);
470 if (strchrW(name
, '.')) return E_INVALIDARG
;
472 GetWindowsDirectoryW(task_name
, MAX_PATH
);
473 lstrcatW(task_name
, tasksW
);
474 lstrcatW(task_name
, name
);
475 lstrcatW(task_name
, jobW
);
477 hr
= IScheduledWorkItem_QueryInterface(item
, &IID_IPersistFile
, (void **)&pfile
);
480 hr
= IPersistFile_Save(pfile
, task_name
, TRUE
);
481 IPersistFile_Release(pfile
);
486 static HRESULT WINAPI
MSTASK_ITaskScheduler_IsOfType(
487 ITaskScheduler
* iface
,
491 FIXME("%p, %s, %s: stub\n", iface
, debugstr_w(pwszName
),
492 debugstr_guid(riid
));
496 static const ITaskSchedulerVtbl MSTASK_ITaskSchedulerVtbl
=
498 MSTASK_ITaskScheduler_QueryInterface
,
499 MSTASK_ITaskScheduler_AddRef
,
500 MSTASK_ITaskScheduler_Release
,
501 MSTASK_ITaskScheduler_SetTargetComputer
,
502 MSTASK_ITaskScheduler_GetTargetComputer
,
503 MSTASK_ITaskScheduler_Enum
,
504 MSTASK_ITaskScheduler_Activate
,
505 MSTASK_ITaskScheduler_Delete
,
506 MSTASK_ITaskScheduler_NewWorkItem
,
507 MSTASK_ITaskScheduler_AddWorkItem
,
508 MSTASK_ITaskScheduler_IsOfType
511 HRESULT
TaskSchedulerConstructor(LPVOID
*ppObj
)
513 TaskSchedulerImpl
*This
;
514 ITaskService
*service
;
518 TRACE("(%p)\n", ppObj
);
520 hr
= CoCreateInstance(&CLSID_TaskScheduler
, NULL
, CLSCTX_INPROC_SERVER
, &IID_ITaskService
, (void **)&service
);
521 if (hr
!= S_OK
) return hr
;
523 V_VT(&v_null
) = VT_NULL
;
524 hr
= ITaskService_Connect(service
, v_null
, v_null
, v_null
, v_null
);
527 ITaskService_Release(service
);
531 This
= heap_alloc(sizeof(*This
));
534 ITaskService_Release(service
);
535 return E_OUTOFMEMORY
;
538 This
->ITaskScheduler_iface
.lpVtbl
= &MSTASK_ITaskSchedulerVtbl
;
539 This
->service
= service
;
542 *ppObj
= &This
->ITaskScheduler_iface
;
543 InterlockedIncrement(&dll_ref
);