xref: /reactos/dll/win32/mstask/task_trigger.c (revision c2c66aff)
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 }
305