* Sync up to trunk head (r64829).
[reactos.git] / dll / win32 / mstask / task_trigger.c
1 /*
2 * Copyright (C) 2008 Google (Roy Shea)
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 #include "mstask_private.h"
20
21 #include <winternl.h>
22
23 typedef struct
24 {
25 ITaskTrigger ITaskTrigger_iface;
26 LONG ref;
27 TASK_TRIGGER triggerCond;
28 } TaskTriggerImpl;
29
30 static inline TaskTriggerImpl *impl_from_ITaskTrigger(ITaskTrigger *iface)
31 {
32 return CONTAINING_RECORD(iface, TaskTriggerImpl, ITaskTrigger_iface);
33 }
34
35 static HRESULT WINAPI MSTASK_ITaskTrigger_QueryInterface(
36 ITaskTrigger* iface,
37 REFIID riid,
38 void **ppvObject)
39 {
40 TaskTriggerImpl *This = impl_from_ITaskTrigger(iface);
41
42 TRACE("IID: %s\n", debugstr_guid(riid));
43 if (ppvObject == NULL)
44 return E_POINTER;
45
46 if (IsEqualGUID(riid, &IID_IUnknown) ||
47 IsEqualGUID(riid, &IID_ITaskTrigger))
48 {
49 *ppvObject = &This->ITaskTrigger_iface;
50 ITaskTrigger_AddRef(iface);
51 return S_OK;
52 }
53
54 WARN("Unknown interface: %s\n", debugstr_guid(riid));
55 *ppvObject = NULL;
56 return E_NOINTERFACE;
57 }
58
59 static ULONG WINAPI MSTASK_ITaskTrigger_AddRef(
60 ITaskTrigger* iface)
61 {
62 TaskTriggerImpl *This = impl_from_ITaskTrigger(iface);
63 ULONG ref;
64 TRACE("\n");
65 ref = InterlockedIncrement(&This->ref);
66 return ref;
67 }
68
69 static ULONG WINAPI MSTASK_ITaskTrigger_Release(
70 ITaskTrigger* iface)
71 {
72 TaskTriggerImpl *This = impl_from_ITaskTrigger(iface);
73 ULONG ref;
74 TRACE("\n");
75 ref = InterlockedDecrement(&This->ref);
76 if (ref == 0)
77 {
78 HeapFree(GetProcessHeap(), 0, This);
79 InterlockedDecrement(&dll_ref);
80 }
81 return ref;
82 }
83
84 static HRESULT WINAPI MSTASK_ITaskTrigger_SetTrigger(
85 ITaskTrigger* iface,
86 const PTASK_TRIGGER pTrigger)
87 {
88 TaskTriggerImpl * This = impl_from_ITaskTrigger(iface);
89 TIME_FIELDS field_time;
90 LARGE_INTEGER sys_time;
91 TASK_TRIGGER tmp_trigger_cond;
92
93 TRACE("(%p, %p)\n", iface, pTrigger);
94
95 /* Verify valid structure size */
96 if (pTrigger->cbTriggerSize != sizeof(*pTrigger))
97 return E_INVALIDARG;
98 tmp_trigger_cond.cbTriggerSize = pTrigger->cbTriggerSize;
99
100 /* Reserved field must be zero */
101 tmp_trigger_cond.Reserved1 = 0;
102
103 /* Verify and set valid start date and time */
104 memset(&field_time, 0, sizeof(field_time));
105 field_time.Year = pTrigger->wBeginYear;
106 field_time.Month = pTrigger->wBeginMonth;
107 field_time.Day = pTrigger->wBeginDay;
108 field_time.Hour = pTrigger->wStartHour;
109 field_time.Minute = pTrigger->wStartMinute;
110 if (!RtlTimeFieldsToTime(&field_time, &sys_time))
111 return E_INVALIDARG;
112 tmp_trigger_cond.wBeginYear = pTrigger->wBeginYear;
113 tmp_trigger_cond.wBeginMonth = pTrigger->wBeginMonth;
114 tmp_trigger_cond.wBeginDay = pTrigger->wBeginDay;
115 tmp_trigger_cond.wStartHour = pTrigger->wStartHour;
116 tmp_trigger_cond.wStartMinute = pTrigger->wStartMinute;
117
118 /* Verify valid end date if TASK_TRIGGER_FLAG_HAS_END_DATE flag is set */
119 if (pTrigger->rgFlags & TASK_TRIGGER_FLAG_HAS_END_DATE)
120 {
121 memset(&field_time, 0, sizeof(field_time));
122 field_time.Year = pTrigger->wEndYear;
123 field_time.Month = pTrigger->wEndMonth;
124 field_time.Day = pTrigger->wEndDay;
125 if (!RtlTimeFieldsToTime(&field_time, &sys_time))
126 return E_INVALIDARG;
127 }
128
129 /* Set valid end date independent of TASK_TRIGGER_FLAG_HAS_END_DATE flag */
130 tmp_trigger_cond.wEndYear = pTrigger->wEndYear;
131 tmp_trigger_cond.wEndMonth = pTrigger->wEndMonth;
132 tmp_trigger_cond.wEndDay = pTrigger->wEndDay;
133
134 /* Verify duration and interval pair */
135 if (pTrigger->MinutesDuration <= pTrigger->MinutesInterval &&
136 pTrigger->MinutesInterval > 0)
137 return E_INVALIDARG;
138 tmp_trigger_cond.MinutesDuration = pTrigger->MinutesDuration;
139 tmp_trigger_cond.MinutesInterval = pTrigger->MinutesInterval;
140
141 /* Copy over flags */
142 tmp_trigger_cond.rgFlags = pTrigger->rgFlags;
143
144 /* Set TriggerType dependent fields of Type union */
145 tmp_trigger_cond.TriggerType = pTrigger->TriggerType;
146 switch (pTrigger->TriggerType)
147 {
148 case TASK_TIME_TRIGGER_DAILY:
149 tmp_trigger_cond.Type.Daily.DaysInterval =
150 pTrigger->Type.Daily.DaysInterval;
151 break;
152 case TASK_TIME_TRIGGER_WEEKLY:
153 tmp_trigger_cond.Type.Weekly.WeeksInterval =
154 pTrigger->Type.Weekly.WeeksInterval;
155 tmp_trigger_cond.Type.Weekly.rgfDaysOfTheWeek =
156 pTrigger->Type.Weekly.rgfDaysOfTheWeek;
157 break;
158 case TASK_TIME_TRIGGER_MONTHLYDATE:
159 tmp_trigger_cond.Type.MonthlyDate.rgfDays =
160 pTrigger->Type.MonthlyDate.rgfDays;
161 tmp_trigger_cond.Type.MonthlyDate.rgfMonths =
162 pTrigger->Type.MonthlyDate.rgfMonths;
163 break;
164 case TASK_TIME_TRIGGER_MONTHLYDOW:
165 tmp_trigger_cond.Type.MonthlyDOW.wWhichWeek =
166 pTrigger->Type.MonthlyDOW.wWhichWeek;
167 tmp_trigger_cond.Type.MonthlyDOW.rgfDaysOfTheWeek =
168 pTrigger->Type.MonthlyDOW.rgfDaysOfTheWeek;
169 tmp_trigger_cond.Type.MonthlyDOW.rgfMonths =
170 pTrigger->Type.MonthlyDOW.rgfMonths;
171 break;
172 case TASK_TIME_TRIGGER_ONCE:
173 case TASK_EVENT_TRIGGER_ON_IDLE:
174 case TASK_EVENT_TRIGGER_AT_SYSTEMSTART:
175 case TASK_EVENT_TRIGGER_AT_LOGON:
176 default:
177 tmp_trigger_cond.Type = This->triggerCond.Type;
178 break;
179 }
180
181 /* Reserved field must be zero */
182 tmp_trigger_cond.Reserved2 = 0;
183
184 /* wRandomMinutesInterval not currently used and is initialized to zero */
185 tmp_trigger_cond.wRandomMinutesInterval = 0;
186
187 /* Update object copy of triggerCond */
188 This->triggerCond = tmp_trigger_cond;
189
190 return S_OK;
191 }
192
193 static HRESULT WINAPI MSTASK_ITaskTrigger_GetTrigger(
194 ITaskTrigger* iface,
195 PTASK_TRIGGER pTrigger)
196 {
197 TaskTriggerImpl * This = impl_from_ITaskTrigger(iface);
198
199 TRACE("(%p, %p)\n", iface, pTrigger);
200
201 /* Native implementation doesn't verify equivalent cbTriggerSize fields */
202
203 /* Copy relevant fields of the structure */
204 pTrigger->cbTriggerSize = This->triggerCond.cbTriggerSize;
205 pTrigger->Reserved1 = 0;
206 pTrigger->wBeginYear = This->triggerCond.wBeginYear;
207 pTrigger->wBeginMonth = This->triggerCond.wBeginMonth;
208 pTrigger->wBeginDay = This->triggerCond.wBeginDay;
209 pTrigger->wEndYear = This->triggerCond.wEndYear;
210 pTrigger->wEndMonth = This->triggerCond.wEndMonth;
211 pTrigger->wEndDay = This->triggerCond.wEndDay;
212 pTrigger->wStartHour = This->triggerCond.wStartHour;
213 pTrigger->wStartMinute = This->triggerCond.wStartMinute;
214 pTrigger->MinutesDuration = This->triggerCond.MinutesDuration;
215 pTrigger->MinutesInterval = This->triggerCond.MinutesInterval;
216 pTrigger->rgFlags = This->triggerCond.rgFlags;
217 pTrigger->TriggerType = This->triggerCond.TriggerType;
218 switch (This->triggerCond.TriggerType)
219 {
220 case TASK_TIME_TRIGGER_DAILY:
221 pTrigger->Type.Daily.DaysInterval =
222 This->triggerCond.Type.Daily.DaysInterval;
223 break;
224 case TASK_TIME_TRIGGER_WEEKLY:
225 pTrigger->Type.Weekly.WeeksInterval =
226 This->triggerCond.Type.Weekly.WeeksInterval;
227 pTrigger->Type.Weekly.rgfDaysOfTheWeek =
228 This->triggerCond.Type.Weekly.rgfDaysOfTheWeek;
229 break;
230 case TASK_TIME_TRIGGER_MONTHLYDATE:
231 pTrigger->Type.MonthlyDate.rgfDays =
232 This->triggerCond.Type.MonthlyDate.rgfDays;
233 pTrigger->Type.MonthlyDate.rgfMonths =
234 This->triggerCond.Type.MonthlyDate.rgfMonths;
235 break;
236 case TASK_TIME_TRIGGER_MONTHLYDOW:
237 pTrigger->Type.MonthlyDOW.wWhichWeek =
238 This->triggerCond.Type.MonthlyDOW.wWhichWeek;
239 pTrigger->Type.MonthlyDOW.rgfDaysOfTheWeek =
240 This->triggerCond.Type.MonthlyDOW.rgfDaysOfTheWeek;
241 pTrigger->Type.MonthlyDOW.rgfMonths =
242 This->triggerCond.Type.MonthlyDOW.rgfMonths;
243 break;
244 case TASK_TIME_TRIGGER_ONCE:
245 case TASK_EVENT_TRIGGER_ON_IDLE:
246 case TASK_EVENT_TRIGGER_AT_SYSTEMSTART:
247 case TASK_EVENT_TRIGGER_AT_LOGON:
248 default:
249 break;
250 }
251 pTrigger->Reserved2 = 0;
252 pTrigger->wRandomMinutesInterval = 0;
253 return S_OK;
254 }
255
256 static HRESULT WINAPI MSTASK_ITaskTrigger_GetTriggerString(
257 ITaskTrigger* iface,
258 LPWSTR *ppwszTrigger)
259 {
260 FIXME("Not implemented\n");
261 return E_NOTIMPL;
262 }
263
264 static const ITaskTriggerVtbl MSTASK_ITaskTriggerVtbl =
265 {
266 MSTASK_ITaskTrigger_QueryInterface,
267 MSTASK_ITaskTrigger_AddRef,
268 MSTASK_ITaskTrigger_Release,
269 MSTASK_ITaskTrigger_SetTrigger,
270 MSTASK_ITaskTrigger_GetTrigger,
271 MSTASK_ITaskTrigger_GetTriggerString
272 };
273
274 HRESULT TaskTriggerConstructor(LPVOID *ppObj)
275 {
276 TaskTriggerImpl *This;
277 SYSTEMTIME time;
278 TRACE("(%p)\n", ppObj);
279
280 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
281 if (!This)
282 return E_OUTOFMEMORY;
283
284 This->ITaskTrigger_iface.lpVtbl = &MSTASK_ITaskTriggerVtbl;
285 This->ref = 1;
286
287 /* Most fields of triggerCond default to zero. Initialize other
288 * fields to default values. */
289 memset(&This->triggerCond, 0, sizeof(TASK_TRIGGER));
290 GetLocalTime(&time);
291 This->triggerCond.cbTriggerSize = sizeof(This->triggerCond);
292 This->triggerCond.wBeginYear = time.wYear;
293 This->triggerCond.wBeginMonth = time.wMonth;
294 This->triggerCond.wBeginDay = time.wDay;
295 This->triggerCond.wStartHour = time.wHour;
296 This->triggerCond.wStartMinute = time.wMinute;
297 This->triggerCond.rgFlags = TASK_TRIGGER_FLAG_DISABLED;
298 This->triggerCond.TriggerType = TASK_TIME_TRIGGER_DAILY,
299 This->triggerCond.Type.Daily.DaysInterval = 1;
300
301 *ppObj = &This->ITaskTrigger_iface;
302 InterlockedIncrement(&dll_ref);
303 return S_OK;
304 }