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