[Adapdev-commits] Adapdev/src/Adapdev/Scheduling/Task ScheduledTasks.cs,1.2,1.3 Scheduler.cs,1.2,1.3
Status: Beta
Brought to you by:
intesar66
Update of /cvsroot/adapdev/Adapdev/src/Adapdev/Scheduling/Task In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19977/src/Adapdev/Scheduling/Task Added Files: ScheduledTasks.cs Scheduler.cs Task.cs TaskList.cs TaskSchedulerInterop.cs Trigger.cs TriggerList.cs Log Message: Reposting to the repository after it got hosed --- NEW FILE: Task.cs --- // Original Copyright (c) 2004 Dennis Austin. http://www.codeproject.com/csharp/tsnewlib.asp #region Modified Copyright / License Information /* Copyright 2004 - 2005 Adapdev Technologies, LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================ Author Log ============================ III Full Name SMM Sean McCormack (Adapdev) ============================ Change Log ============================ III MMDDYY Change */ #endregion using System; using System.IO; using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters.Binary; namespace Adapdev.Scheduling.Task { #region Enums /// <summary> /// Options for a task, used for the Flags property of a Task. Uses the /// "Flags" attribute, so these values are combined with |. /// Some flags are documented as Windows 95 only, but they have a /// user interface in Windows XP so that may not be true. /// </summary> [Flags] public enum TaskFlags { /// <summary> /// The precise meaning of this flag is elusive. The MSDN documentation describes it /// only for use in converting jobs from the Windows NT "AT" service to the newer /// Task Scheduler. No other use for the flag is documented. /// </summary> Interactive = 0x1, /// <summary> /// The task will be deleted when there are no more scheduled run times. /// </summary> DeleteWhenDone = 0x2, /// <summary> /// The task is disabled. Used to temporarily prevent a task from being triggered normally. /// </summary> Disabled = 0x4, /// <summary> /// The task begins only if the computer is idle at the scheduled start time. /// The computer is not considered idle until the task's <see cref="Task.IdleWaitMinutes"/> time /// elapses with no user input. /// </summary> StartOnlyIfIdle = 0x10, /// <summary> /// The task terminates if the computer makes an idle to non-idle transition while the task is running. /// For information regarding idle triggers, see <see cref="OnIdleTrigger"/>. /// </summary> KillOnIdleEnd = 0x20, /// <summary> /// The task does not start if the computer is running on battery power. /// </summary> DontStartIfOnBatteries = 0x40, /// <summary> /// The task ends, and the associated application quits if the computer switches /// to battery power. /// </summary> KillIfGoingOnBatteries = 0x80, /// <summary> /// The task runs only if the system is docked. /// (Not mentioned in current MSDN documentation; probably obsolete.) /// </summary> RunOnlyIfDocked = 0x100, /// <summary> /// The task item is hidden. /// /// This is implemented by setting the job file's hidden attribute. Testing revealed that clearing /// this flag doesn't clear the file attribute, so the library sets the file attribute directly. This /// flag is kept in sync with the task's Hidden property, so they function equivalently. /// </summary> Hidden = 0x200, /// <summary> /// The task runs only if there is currently a valid Internet connection. /// Not currently implemented. (Check current MSDN documentation for updates.) /// </summary> RunIfConnectedToInternet = 0x400, /// <summary> /// The task starts again if the computer makes a non-idle to idle transition before all the /// task's task_triggers elapse. (Use this flag in conjunction with KillOnIdleEnd.) /// </summary> RestartOnIdleResume = 0x800, /// <summary> /// Wake the computer to run this task. Seems to be misnamed, but the name is taken from /// the low-level interface. /// /// </summary> SystemRequired = 0x1000, /// <summary> /// The task runs only if the user specified in SetAccountInformation() is /// logged on interactively. This flag has no effect on tasks set to run in /// the local SYSTEM account. /// </summary> RunOnlyIfLoggedOn = 0x2000 } /// <summary> /// Status values returned for a task. Some values have been determined to occur although /// they do no appear in the Task Scheduler system documentation. /// </summary> public enum TaskStatus { /// <summary> /// The task is ready to run at its next scheduled time. /// </summary> Ready = HResult.SCHED_S_TASK_READY, /// <summary> /// The task is currently running. /// </summary> Running = HResult.SCHED_S_TASK_RUNNING, /// <summary> /// One or more of the properties that are needed to run this task on a schedule have not been set. /// </summary> NotScheduled = HResult.SCHED_S_TASK_NOT_SCHEDULED, /// <summary> /// The task has not yet run. /// </summary> NeverRun = HResult.SCHED_S_TASK_HAS_NOT_RUN, /// <summary> /// The task will not run at the scheduled times because it has been disabled. /// </summary> Disabled = HResult.SCHED_S_TASK_DISABLED, /// <summary> /// There are no more runs scheduled for this task. /// </summary> NoMoreRuns = HResult.SCHED_S_TASK_NO_MORE_RUNS, /// <summary> /// The last run of the task was terminated by the user. /// </summary> Terminated = HResult.SCHED_S_TASK_TERMINATED, /// <summary> /// Either the task has no triggers or the existing triggers are disabled or not set. /// </summary> NoTriggers = HResult.SCHED_S_TASK_NO_VALID_TRIGGERS, /// <summary> /// Event triggers don't have set run times. /// </summary> NoTriggerTime = HResult.SCHED_S_EVENT_TRIGGER } #endregion /// <summary> /// Represents an item in the Scheduled Tasks folder. There are no public constructors for Task. /// New instances are generated by a <see cref="ScheduledTasks"/> object using Open or Create methods. /// A task object holds COM interfaces; call its <see cref="Close"/> method to release them. /// </summary> public class Task : IDisposable { #region Fields /// <summary> /// Internal COM interface /// </summary> private ITask iTask; /// <summary> /// Name of this task (with no .job extension) /// </summary> private string name; /// <summary> /// List of triggers for this task /// </summary> private TriggerList triggers; #endregion #region Constructors /// <summary> /// Internal constructor for a task, used by <see cref="ScheduledTasks"/>. /// </summary> /// <param name="iTask">Instance of an ITask.</param> /// <param name="taskName">Name of the task.</param> internal Task(ITask iTask, string taskName) { this.iTask = iTask; if (taskName.EndsWith(".job")) name = taskName.Substring(0, taskName.Length-4); else name = taskName; triggers = null; this.Hidden = GetHiddenFileAttr(); } #endregion #region Properties /// <summary> /// Gets the name of the task. The name is also the filename (plus a .job extension) /// the Task Scheduler uses to store the task information. To change the name of a /// task, use <see cref="Save()"/> to save it as a new name and then delete /// the old task. /// </summary> public string Name { get { return name; } } /// <summary> /// Gets the list of triggers associated with the task. /// </summary> public TriggerList Triggers { get { if (triggers == null) { // Trigger list has not been requested before; create it triggers = new TriggerList(iTask); } return triggers; } } /// <summary> /// Gets/sets the application filename that task is to run. Get returns /// an absolute pathname. A name searched with the PATH environment variable can /// be assigned, and the path search is done when the task is saved. /// </summary> public string ApplicationName { get { IntPtr lpwstr; iTask.GetApplicationName(out lpwstr); return CoTaskMem.LPWStrToString(lpwstr); } set { iTask.SetApplicationName(value); } } /// <summary> /// Gets the name of the account under which the task process will run. /// </summary> public string AccountName { get { IntPtr lpwstr = IntPtr.Zero; iTask.GetAccountInformation(out lpwstr); return CoTaskMem.LPWStrToString(lpwstr); } } /// <summary> /// Gets/sets the comment associated with the task. The comment appears in the /// Scheduled Tasks user interface. /// </summary> public string Comment { get { IntPtr lpwstr; iTask.GetComment(out lpwstr); return CoTaskMem.LPWStrToString(lpwstr); } set { iTask.SetComment(value); } } /// <summary> /// Gets/sets the creator of the task. If no value is supplied, the system /// fills in the account name of the caller when the task is saved. /// </summary> public string Creator { get { IntPtr lpwstr; iTask.GetCreator(out lpwstr); return CoTaskMem.LPWStrToString(lpwstr); } set { iTask.SetCreator(value); } } /// <summary> /// Gets/sets the number of times to retry task execution after failure. (Not implemented.) /// </summary> private short ErrorRetryCount { get { ushort ret; iTask.GetErrorRetryCount(out ret); return (short)ret; } set { iTask.SetErrorRetryCount((ushort)value); } } /// <summary> /// Gets/sets the time interval, in minutes, to delay between error retries. (Not implemented.) /// </summary> private short ErrorRetryInterval { get { ushort ret; iTask.GetErrorRetryInterval(out ret); return (short)ret; } set { iTask.SetErrorRetryInterval((ushort)value); } } /// <summary> /// Gets the Win32 exit code from the last execution of the task. If the task failed /// to start on its last run, the reason is returned as an exception. Not updated while /// in an open task; the property does not change unless the task is closed and re-opened. /// <exception>Various exceptions for a task that couldn't be run.</exception> /// </summary> public int ExitCode { get { uint ret = 0; iTask.GetExitCode(out ret); return (int)ret; } } /// <summary> /// Gets/sets the <see cref="TaskFlags"/> associated with the current task. /// </summary> public TaskFlags Flags { get { uint ret; iTask.GetFlags(out ret); return (TaskFlags)ret; } set { iTask.SetFlags((uint)value); } } /// <summary> /// Gets/sets how long the system must remain idle, even after the trigger /// would normally fire, before the task will run. /// </summary> public short IdleWaitMinutes { get { ushort ret, nothing; iTask.GetIdleWait(out ret, out nothing); return (short)ret; } set { ushort m = (ushort)IdleWaitDeadlineMinutes; iTask.SetIdleWait((ushort)value, m); } } /// <summary> /// Gets/sets the maximum number of minutes that Task Scheduler will wait for a /// required idle period to occur. /// </summary> public short IdleWaitDeadlineMinutes { get { ushort ret, nothing; iTask.GetIdleWait(out nothing, out ret); return (short)ret; } set { ushort m = (ushort)IdleWaitMinutes; iTask.SetIdleWait(m, (ushort)value); } } /// <summary> /// <p>Gets/sets the maximum length of time the task is permitted to run. /// Setting MaxRunTime also affects the value of <see cref="Task.MaxRunTimeLimited"/>. /// </p> /// <p>The longest MaxRunTime implemented is 0xFFFFFFFE milliseconds, or /// about 50 days. If you set a TimeSpan longer than that, the /// MaxRunTime will be unlimited.</p> /// </summary> /// <Remarks> /// </Remarks> public TimeSpan MaxRunTime { get { uint ret; iTask.GetMaxRunTime(out ret); return new TimeSpan((long)ret * TimeSpan.TicksPerMillisecond); } set { double proposed = ((TimeSpan)value).TotalMilliseconds; if (proposed >= uint.MaxValue) { iTask.SetMaxRunTime(uint.MaxValue); } else { iTask.SetMaxRunTime((uint)proposed); } //iTask.SetMaxRunTime((uint)((TimeSpan)value).TotalMilliseconds); } } /// <summary> /// <p>If the maximum run time is limited, the task will be terminated after /// <see cref="Task.MaxRunTime"/> expires. Setting the value to FALSE, i.e. unlimited, /// invalidates MaxRunTime.</p> /// <p>The Task Scheduler service will try to send a WM_CLOSE message when it needs to terminate /// a task. If the message can't be sent, or the task does not respond with three minutes, /// the task will be terminated using TerminateProcess.</p> /// </summary> public bool MaxRunTimeLimited { get { uint ret; iTask.GetMaxRunTime(out ret); return (ret == uint.MaxValue); } set { if (value) { uint ret; iTask.GetMaxRunTime(out ret); if (ret == uint.MaxValue) { iTask.SetMaxRunTime(72*360*1000); //72 hours. Thats what Explorer sets. } } else { iTask.SetMaxRunTime(uint.MaxValue); } } } /// <summary> /// Gets the most recent time the task began running. <see cref="DateTime.MinValue"/> /// returned if the task has not run. /// </summary> public DateTime MostRecentRunTime { get { SystemTime st = new SystemTime(); iTask.GetMostRecentRunTime(ref st); if (st.Year == 0) return DateTime.MinValue; return new DateTime((int)st.Year, (int)st.Month, (int)st.Day, (int)st.Hour, (int)st.Minute, (int)st.Second, (int)st.Milliseconds); } } /// <summary> /// Gets the next time the task will run. Returns <see cref="DateTime.MinValue"/> /// if the task is not scheduled to run. /// </summary> public DateTime NextRunTime { get { SystemTime st = new SystemTime(); iTask.GetNextRunTime(ref st); if (st.Year == 0) return DateTime.MinValue; return new DateTime((int)st.Year, (int)st.Month, (int)st.Day, (int)st.Hour, (int)st.Minute, (int)st.Second, (int)st.Milliseconds); } } /// <summary> /// Gets/sets the command-line parameters for the task. /// </summary> public string Parameters { get { IntPtr lpwstr; iTask.GetParameters(out lpwstr); return CoTaskMem.LPWStrToString(lpwstr); } set { iTask.SetParameters(value); } } /// <summary> /// Gets/sets the priority for the task process. /// Note: ProcessPriorityClass defines two levels (AboveNormal and BelowNormal) that are /// not documented in the task scheduler interface and can't be use on Win 98 platforms. /// </summary> public System.Diagnostics.ProcessPriorityClass Priority { get { uint ret; iTask.GetPriority(out ret); return (System.Diagnostics.ProcessPriorityClass)ret; } set { if (value==System.Diagnostics.ProcessPriorityClass.AboveNormal || value==System.Diagnostics.ProcessPriorityClass.BelowNormal ) { throw new ArgumentException("Unsupported Priority Level"); } iTask.SetPriority((uint)value); } } /// <summary> /// Gets the status of the task. Returns <see cref="TaskStatus"/>. /// Not updated while a task is open. /// </summary> public TaskStatus Status { get { int ret; iTask.GetStatus(out ret); return (TaskStatus)ret; } } /// <summary> /// Extended Flags associated with a task. These are associated with the ITask com interface /// and none are currently defined. /// </summary> private int FlagsEx { get { uint ret; iTask.GetTaskFlags(out ret); return (int)ret; } set { iTask.SetTaskFlags((uint)value); } } /// <summary> /// Gets/sets the initial working directory for the task. /// </summary> public string WorkingDirectory { get { IntPtr lpwstr; iTask.GetWorkingDirectory(out lpwstr); return CoTaskMem.LPWStrToString(lpwstr); } set { iTask.SetWorkingDirectory(value); } } /// <summary> /// Hidden tasks are stored in files with /// the hidden file attribute so they don't appear in the Explorer user interface. /// Because there is a special interface for Scheduled Tasks, they don't appear /// even if Explorer is set to show hidden files. /// Functionally equivalent to TaskFlags.Hidden. /// </summary> public bool Hidden { get { return (this.Flags & TaskFlags.Hidden) != 0; } set { if (value) { this.Flags |= TaskFlags.Hidden; } else { this.Flags &= ~TaskFlags.Hidden; } } } /// <summary> /// Gets/sets arbitrary data associated with the task. The tag can be used for any purpose /// by the client, and is not used by the Task Scheduler. Known as WorkItemData in the /// IWorkItem com interface. /// </summary> public object Tag { get { ushort DataLen; IntPtr Data; iTask.GetWorkItemData(out DataLen, out Data); byte[] bytes = new byte[DataLen]; Marshal.Copy(Data, bytes, 0, DataLen); MemoryStream stream = new MemoryStream(bytes, false); BinaryFormatter b = new BinaryFormatter(); return b.Deserialize(stream); } set { if (!value.GetType().IsSerializable) throw new ArgumentException("Objects set as Data for Tasks must be serializable", "value"); BinaryFormatter b = new BinaryFormatter(); MemoryStream stream = new MemoryStream(); b.Serialize(stream, value); iTask.SetWorkItemData((ushort)stream.Length, stream.GetBuffer()); } } #endregion #region Methods /// <summary> /// Set the hidden attribute on the file corresponding to this task. /// </summary> /// <param name="set">Set the attribute accordingly.</param> private void SetHiddenFileAttr(bool set) { UCOMIPersistFile iFile = (UCOMIPersistFile)iTask; string fileName; iFile.GetCurFile(out fileName); System.IO.FileAttributes attr; attr = System.IO.File.GetAttributes(fileName); if (set) attr |= System.IO.FileAttributes.Hidden; else attr &= ~System.IO.FileAttributes.Hidden; System.IO.File.SetAttributes(fileName, attr); } /// <summary> /// Get the hidden attribute from the file corresponding to this task. /// </summary> /// <returns>The value of the attribute.</returns> private bool GetHiddenFileAttr() { UCOMIPersistFile iFile = (UCOMIPersistFile)iTask; string fileName; iFile.GetCurFile(out fileName); System.IO.FileAttributes attr; try { attr = System.IO.File.GetAttributes(fileName); return (attr & System.IO.FileAttributes.Hidden) != 0; } catch { return false; } } /// <summary> /// Calculate the next time the task would be scheduled /// to run after a given arbitrary time. If the task will not run /// (perhaps disabled) then returns <see cref="DateTime.MinValue"/>. /// </summary> /// <param name="after">The time to calculate from.</param> /// <returns>The next time the task would run.</returns> public DateTime NextRunTimeAfter(DateTime after) { //Add one second to get a run time strictly greater than the specified time. after = after.AddSeconds(1); //Convert to a valid SystemTime SystemTime stAfter = new SystemTime(); stAfter.Year = (ushort)after.Year; stAfter.Month = (ushort)after.Month; stAfter.Day = (ushort)after.Day; stAfter.DayOfWeek = (ushort)after.DayOfWeek; stAfter.Hour = (ushort)after.Hour; stAfter.Minute = (ushort)after.Minute; stAfter.Second = (ushort)after.Second; SystemTime stLimit = new SystemTime(); // Would like to pass null as the second parameter to GetRunTimes, indicating that // the interval is unlimited. Can't figure out how to do that, so use a big time value. stLimit = stAfter; stLimit.Year = (ushort)DateTime.MaxValue.Year; IntPtr pTimes; ushort nFetch = 1; iTask.GetRunTimes(ref stAfter, ref stLimit, ref nFetch, out pTimes); if (nFetch == 1) { SystemTime stNext = new SystemTime(); stNext = (SystemTime)Marshal.PtrToStructure(pTimes, typeof(SystemTime)); Marshal.FreeCoTaskMem(pTimes); return new DateTime(stNext.Year, stNext.Month, stNext.Day, stNext.Hour, stNext.Minute, stNext.Second); } else { return DateTime.MinValue; } } /// <summary> /// Schedules the task for immediate execution. /// The system works from the saved version of the task, so call <see cref="Save()"/> before running. /// If the task has never been saved, it throws an argument exception. Problems starting /// the task are reported by the <see cref="ExitCode"/> property, not by exceptions on Run. /// </summary> /// <remarks>The system never updates an open task, so you don't get current results for /// the <see cref="Status"/> or the <see cref="ExitCode"/> properties until you close /// and reopen the task. /// </remarks> /// <exception cref="ArgumentException"></exception> public void Run() { iTask.Run(); } /// <summary> /// Saves changes to the established task name. /// </summary> /// <overloads>Saves changes that have been made to this Task.</overloads> /// <remarks>The account name is checked for validity /// when a Task is saved. The password is not checked, but the account name /// must be valid (or empty). /// </remarks> /// <exception cref="COMException">Unable to establish existence of the account specified.</exception> public void Save() { UCOMIPersistFile iFile = (UCOMIPersistFile)iTask; iFile.Save(null, false); SetHiddenFileAttr(Hidden); //Do the Task Scheduler's work for it because it doesn't reset properly } /// <summary> /// Saves the Task with a new name. The task with the old name continues to /// exist in whatever state it was last saved. It is no longer open, because. /// the Task object is associated with the new name from now on. /// If there is already a task using the new name, it is overwritten. /// </summary> /// <remarks>See the <see cref="Save()"/>() overload.</remarks> /// <param name="name">The new name to be used for this task.</param> /// <exception cref="COMException">Unable to establish existence of the account specified.</exception> public void Save(string name) { UCOMIPersistFile iFile = (UCOMIPersistFile)iTask; string path; iFile.GetCurFile(out path); string newPath; newPath = Path.GetDirectoryName(path) + Path.DirectorySeparatorChar + name + Path.GetExtension(path); iFile.Save(newPath, true); iFile.SaveCompleted(newPath); /* probably unnecessary */ this.name = name; SetHiddenFileAttr(Hidden); //Do the Task Scheduler's work for it because it doesn't reset properly } /// <summary> /// Release COM interfaces for this Task. After a Task is closed, accessing its /// members throws a null reference exception. /// </summary> public void Close() { if (triggers != null) { triggers.Dispose(); } Marshal.ReleaseComObject(iTask); iTask = null; } /// <summary> /// For compatibility with earlier versions. New clients should use <see cref="DisplayPropertySheet()"/>. /// </summary> /// <remarks> /// Display the property pages of this task for user editing. If the user clicks OK, the /// task's properties are updated and the task is also automatically saved. /// </remarks> public void DisplayForEdit() { iTask.EditWorkItem(0, 0); } /// <summary> /// Argument for DisplayForEdit to determine which property pages to display. /// </summary> [Flags] public enum PropPages { /// <summary> /// The task property page /// </summary> Task = 0x01, /// <summary> /// The schedule property page /// </summary> Schedule = 0x02, /// <summary> /// The setting property page /// </summary> Settings = 0x04 } /// /// <summary> /// Display all property pages. /// </summary> /// <remarks> /// The method does not return until the user has dismissed the dialog box. /// If the dialog box is dismissed with the OK button, returns true and /// updates properties in the task. /// The changes are not made permanent, however, until the task is saved. (Save() method.) /// </remarks> /// <returns><c>true</c> if dialog box was dismissed with OK, otherwise <c>false</c>.</returns> /// <overloads>Display the property pages of this task for user editing.</overloads> public bool DisplayPropertySheet() { //iTask.EditWorkItem(0, 0); //This implementation saves automatically, so we don't use it. return DisplayPropertySheet(PropPages.Task | PropPages.Schedule | PropPages.Settings); } /// <summary> /// Display only the specified property pages. /// </summary> /// <remarks> /// See the <see cref="DisplayPropertySheet()"/>() overload. /// </remarks> /// <param name="pages">Controls which pages are presented</param> /// <returns><c>true</c> if dialog box was dismissed with OK, otherwise <c>false</c>.</returns> public bool DisplayPropertySheet(PropPages pages) { PropSheetHeader hdr = new PropSheetHeader(); IProvideTaskPage iProvideTaskPage = (IProvideTaskPage)iTask; IntPtr[] hPages = new IntPtr[3]; IntPtr hPage; int nPages = 0; if ((pages & PropPages.Task) != 0) { //get task page iProvideTaskPage.GetPage(0, false, out hPage); hPages[nPages++] = hPage; } if ((pages & PropPages.Schedule) != 0) { //get task page iProvideTaskPage.GetPage(1, false, out hPage); hPages[nPages++] = hPage; } if ((pages & PropPages.Settings) != 0) { //get task page iProvideTaskPage.GetPage(2, false, out hPage); hPages[nPages++] = hPage; } if (nPages == 0) throw (new ArgumentException("No Property Pages to display")); hdr.dwSize = (uint)Marshal.SizeOf(hdr); hdr.dwFlags = (uint) (PropSheetFlags.PSH_DEFAULT | PropSheetFlags.PSH_NOAPPLYNOW); hdr.pszCaption = this.Name; hdr.nPages = (uint)nPages; GCHandle gch = GCHandle.Alloc(hPages, GCHandleType.Pinned); hdr.phpage = gch.AddrOfPinnedObject(); int res = PropertySheetDisplay.PropertySheet(ref hdr); gch.Free(); if (res < 0) throw (new Exception("Property Sheet failed to display")); return res>0; } /// <summary> /// Sets the account under which the task will run. Supply the account name and /// password as parameters. For the localsystem account, pass an empty string for /// the account name and null for the password. See Remarks. /// </summary> /// <param name="accountName">Full account name.</param> /// <param name="password">Password for the account.</param> /// <remarks> /// <p>To have the task to run under the local system account, pass the empty string ("") /// as accountName and null as the password. The caller must be running in /// an administrator account or in the local system account. /// </p> /// <p> /// You can also specify a null password if the task has the flag RunOnlyIfLoggedOn set. /// This allows you to schedule a task for an account for which you don't know the password, /// but the account must be logged on interactively at the time the task runs.</p> /// </remarks> public void SetAccountInformation(string accountName, string password) { iTask.SetAccountInformation(accountName, password); } /// <summary> /// Request that the task be terminated if it is currently running. The call returns /// immediately, although the task may continue briefly. For Windows programs, a WM_CLOSE /// message is sent first and the task is given three minutes to shut down voluntarily. /// Should it not, or if the task is not a Windows program, TerminateProcess is used. /// </summary> /// <exception cref="COMException">The task is not running.</exception> public void Terminate() { iTask.Terminate(); } /// <summary> /// Overridden. Outputs the name of the task, the application and parameters. /// </summary> /// <returns>String representing task.</returns> public override string ToString() { return string.Format("{0} (\"{1}\" {2})", name, ApplicationName, Parameters); } #endregion #region Implementation of IDisposable /// <summary> /// A synonym for Close. /// </summary> public void Dispose() { this.Close(); } #endregion } } --- NEW FILE: ScheduledTasks.cs --- // Original Copyright (c) 2004 Dennis Austin. http://www.codeproject.com/csharp/tsnewlib.asp #region Modified Copyright / License Information /* Copyright 2004 - 2005 Adapdev Technologies, LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================ Author Log ============================ III Full Name SMM Sean McCormack (Adapdev) ============================ Change Log ============================ III MMDDYY Change */ #endregion using System; using System.IO; using System.Runtime.InteropServices; namespace Adapdev.Scheduling.Task { /// <summary> /// ScheduledTasks represents the a computer's Scheduled Tasks folder. Using a ScheduledTasks /// object, you can discover the names of the tasks in the folder and you can open a task /// to work with it. You can also create or delete tasks. /// </summary> /// <remarks> /// A ScheduledTasks object holds a COM interface that can be released by calling <see cref="Dispose()"/>. /// </remarks> public class ScheduledTasks : IDisposable { /// <summary> /// Underlying COM interface. /// </summary> private ITaskScheduler its = null; // --- Contructors --- /// <summary> /// Constructor to use Scheduled tasks of a remote computer identified by a UNC /// name. The calling process must have administrative privileges on the remote machine. /// May throw exception if the computer's task scheduler cannot be reached, and may /// give strange results if the argument is not in UNC format. /// </summary> /// <param name="computer">The remote computer's UNC name, e.g. "\\DALLAS".</param> /// <exception cref="ArgumentException">The Task Scheduler could not be accessed.</exception> public ScheduledTasks(string computer) : this() { its.SetTargetComputer(computer); } /// <summary> /// Constructor to use Scheduled Tasks of the local computer. /// </summary> public ScheduledTasks() { CTaskScheduler cts = new CTaskScheduler(); its = (ITaskScheduler)cts; } // --- Methods --- private string[] GrowStringArray(string[] s, uint n) { string[] sl = new string[s.Length + n]; for (int i=0; i<s.Length; i++) { sl[i] = s[i];} return sl; } /// <summary> /// Return the names of all scheduled tasks. The names returned include the file extension ".job"; /// methods requiring a task name can take the name with or without the extension. /// </summary> /// <returns>The names in a string array.</returns> public string[] GetTaskNames() { const int TASKS_TO_FETCH = 10; string[] taskNames = {}; int nTaskNames = 0; IEnumWorkItems ienum; its.Enum(out ienum); uint nFetchedTasks; IntPtr pNames; while ( ienum.Next( TASKS_TO_FETCH, out pNames, out nFetchedTasks ) >= 0 && nFetchedTasks > 0 ) { taskNames = GrowStringArray(taskNames, nFetchedTasks); while ( nFetchedTasks > 0 ) { IntPtr name = Marshal.ReadIntPtr( pNames, (int)--nFetchedTasks * IntPtr.Size ); taskNames[nTaskNames++] = Marshal.PtrToStringUni(name); Marshal.FreeCoTaskMem(name); } Marshal.FreeCoTaskMem( pNames ); } return taskNames; } /// <summary> /// Creates a new task on the system with the given <paramref name="name" />. /// </summary> /// <remarks>Task names follow normal filename character restrictions. The name /// will be come the name of the file used to store the task (with .job added).</remarks> /// <param name="name">Name for the new task.</param> /// <returns>Instance of new task.</returns> /// <exception cref="ArgumentException">There is an existing task with the given name.</exception> public Task CreateTask(string name) { Task tester = OpenTask(name); if (tester != null) { tester.Close(); throw new ArgumentException("The task \"" + name + "\" already exists."); } try { object o; its.NewWorkItem(name, ref CTaskGuid, ref ITaskGuid, out o); ITask iTask = (ITask)o; return new Task(iTask, name); } catch { return null; } } /// <summary> /// Deletes the task of the given <paramref name="name" />. /// </summary> /// <remarks>If you delete a task that is open, a subsequent save will throw an /// exception. You can save to a filename, however, to create a new task.</remarks> /// <param name="name">Name of task to delete.</param> /// <returns>True if the task was deleted, false if the task wasn't found.</returns> public bool DeleteTask(string name) { try { its.Delete(name); return true; } catch { return false; } } /// <summary> /// Opens the task with the given <paramref name="name" />. An open task holds COM interfaces /// which are released by the Task's Close() method. /// </summary> /// <remarks>If the task does not exist, null is returned.</remarks> /// <param name="name">Name of task to open.</param> /// <returns>An instance of a Task, or null if the task name couldn't be found.</returns> public Task OpenTask(string name) { try { object o; its.Activate(name, ref ITaskGuid, out o); ITask iTask = (ITask)o; return new Task(iTask, name); } catch { return null; } } #region Implementation of IDisposable /// <summary> /// The internal COM interface is released. Further access to the /// object will throw null reference exceptions. /// </summary> public void Dispose() { Marshal.ReleaseComObject(its); its = null; } #endregion // Two Guids for calls to ITaskScheduler methods Activate(), NewWorkItem(), and IsOfType() internal static Guid ITaskGuid; internal static Guid CTaskGuid; static ScheduledTasks() { ITaskGuid = Marshal.GenerateGuidForType(typeof(ITask)); CTaskGuid = Marshal.GenerateGuidForType(typeof(CTask)); } } } --- NEW FILE: Trigger.cs --- // Original Copyright (c) 2004 Dennis Austin. http://www.codeproject.com/csharp/tsnewlib.asp #region Modified Copyright / License Information /* Copyright 2004 - 2005 Adapdev Technologies, LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============================ Author Log ============================ III Full Name SMM Sean McCormack (Adapdev) ============================ Change Log ============================ III MMDDYY Change */ #endregion using System; using System.Runtime.InteropServices; namespace Adapdev.Scheduling.Task { #region Enums /// <summary> /// Valid types of triggers /// </summary> internal enum TriggerType { /// <summary> /// Trigger is set to run the task a single time. /// </summary> RunOnce = 0, /// <summary> /// Trigger is set to run the task on a daily interval. /// </summary> RunDaily = 1, /// <summary> /// Trigger is set to run the work item on specific days of a specific week of a specific month. /// </summary> RunWeekly = 2, /// <summary> /// Trigger is set to run the task on a specific day(s) of the month. /// </summary> RunMonthly = 3, /// <summary> /// Trigger is set to run the task on specific days, weeks, and months. /// </summary> RunMonthlyDOW = 4, /// <summary> /// Trigger is set to run the task if the system remains idle for the amount of time specified by the idle wait time of the task. /// </summary> OnIdle = 5, /// <summary> /// Trigger is set to run the task at system startup. /// </summary> OnSystemStart = 6, /// <summary> /// Trigger is set to run the task when a user logs on. /// </summary> OnLogon = 7 } /// <summary> /// Values for days of the week (Monday, Tuesday, etc.) These carry the Flags /// attribute so DaysOfTheWeek and be combined with | (or). /// </summary> [Flags] public enum DaysOfTheWeek : short { /// <summary> /// Sunday /// </summary> Sunday = 0x1, /// <summary> /// Monday /// </summary> Monday = 0x2, /// <summary> /// Tuesday /// </summary> Tuesday = 0x4, /// <summary> /// Wednesday /// </summary> Wednesday = 0x8, /// <summary> /// Thursday /// </summary> Thursday = 0x10, /// <summary> /// Friday /// </summary> Friday = 0x20, /// <summary> /// Saturday /// </summary> Saturday = 0x40 } /// <summary> /// Values for week of month (first, second, ..., last) /// </summary> public enum WhichWeek : short { /// <summary> /// First week of the month /// </summary> FirstWeek = 1, /// <summary> /// Second week of the month /// </summary> SecondWeek = 2, /// <summary> /// Third week of the month /// </summary> ThirdWeek = 3, /// <summary> /// Fourth week of the month /// </summary> FourthWeek = 4, /// <summary> /// Last week of the month /// </summary> LastWeek = 5 } /// <summary> /// Values for months of the year (January, February, etc.) These carry the Flags /// attribute so DaysOfTheWeek and be combined with | (or). /// </summary> [Flags] public enum MonthsOfTheYear : short { /// <summary> /// January /// </summary> January = 0x1, /// <summary> /// February /// </summary> February = 0x2, /// <summary> /// March /// </summary> March = 0x4, /// <summary> /// April /// </summary> April = 0x8, /// <summary> ///May /// </summary> May = 0x10, /// <summary> /// June /// </summary> June = 0x20, /// <summary> /// July /// </summary> July = 0x40, /// <summary> /// August /// </summary> August = 0x80, /// <summary> /// September /// </summary> September = 0x100, /// <summary> /// October /// </summary> October = 0x200, /// <summary> /// November /// </summary> November = 0x400, /// <summary> /// December /// </summary> December = 0x800 } #endregion /// <summary> /// Trigger is a generalization of all the concrete trigger classes, and any actual /// Trigger object is one of those types. When included in the TriggerList of a /// Task, a Trigger determines when a scheduled task will be run. /// </summary> /// <remarks> /// <para> /// Create a concrete trigger for a specific start condition and then call TriggerList.Add /// to include it in a task's TriggerList.</para> /// <para> /// A Trigger that is not yet in a Task's TriggerList is said to be unbound and it holds /// no resources (i.e. COM interfaces). Once it is added to a TriggerList, it is bound and /// holds a COM interface that is only released when the Trigger is removed from the list or /// the corresponding Task is closed.</para> /// <para> /// A Trigger that is already bound cannot be added to a TriggerList. To copy a Trigger from /// one list to another, use <see cref="Clone()"/> to create an unbound copy and then add the /// copy to the new list. To move a Trigger from one list to another, use <see cref="TriggerList.Remove"/> /// to extract the Trigger from the first list before adding it to the second.</para> /// </remarks> public abstract class Trigger : ICloneable { #region Enums /// <summary> /// Flags for triggers /// </summary> [Flags] private enum TaskTriggerFlags { HasEndDate = 0x1, KillAtDurationEnd = 0x2, Disabled = 0x4 } #endregion #region Fields private ITaskTrigger iTaskTrigger; //null for an unbound Trigger internal TaskTrigger taskTrigger; #endregion #region Constructors and Initializers /// <summary> /// Internal base constructor for an unbound Trigger. /// </summary> internal Trigger() { iTaskTrigger = null; taskTrigger = new TaskTrigger(); taskTrigger.TriggerSize = (ushort)Marshal.SizeOf(taskTrigger); taskTrigger.BeginYear = (ushort)DateTime.Today.Year; taskTrigger.BeginMonth = (ushort)DateTime.Today.Month; taskTrigger.BeginDay = (ushort)DateTime.Today.Day; } /// <summary> /// Internal constructor which initializes itself from /// from an ITaskTrigger interface. /// </summary> /// <param name="iTrigger">Instance of ITaskTrigger from system task scheduler.</param> internal Trigger(ITaskTrigger iTrigger) { if (iTrigger == null) throw new ArgumentNullException("iTrigger", "ITaskTrigger instance cannot be null"); taskTrigger = new TaskTrigger(); taskTrigger.TriggerSize = (ushort)Marshal.SizeOf(taskTrigger); iTrigger.GetTrigger(ref taskTrigger); iTaskTrigger = iTrigger; } #endregion #region Implement ICloneable /// <summary> /// Clone returns an unbound copy of the Trigger object. It can be use /// on either bound or unbound original. /// </summary> /// <returns></returns> public object Clone() { Trigger newTrigger = (Trigger)this.MemberwiseClone(); newTrigger.iTaskTrigger = null; // The clone is not bound return newTrigger; } #endregion #region Properties /// <summary> /// Get whether the Trigger is currently bound /// </summary> internal bool Bound { get { return iTaskTrigger != null; } } /// <summary> /// Gets/sets the beginning year, month, and day for the trigger. /// </summary> public DateTime BeginDate { get { return new DateTime(taskTrigger.BeginYear, taskTrigger.BeginMonth, taskTrigger.BeginDay); } set { taskTrigger.BeginYear = (ushort)value.Year; taskTrigger.BeginMonth = (ushort)value.Month; taskTrigger.BeginDay = (ushort)value.Day; SyncTrigger(); } } /// <summary> /// Gets/sets indication that the task uses an EndDate. Returns true if a value has been /// set for the EndDate property. Set can only be used to turn indication off. /// </summary> /// <exception cref="ArgumentException">Has EndDate becomes true only by setting the EndDate /// property.</exception> public bool HasEndDate { get { return ((taskTrigger.Flags & (uint)TaskTriggerFlags.HasEndDate) == (uint)TaskTriggerFlags.HasEndDate); } set { if (value) throw new ArgumentException("HasEndDate can only be set false"); taskTrigger.Flags &= ~(uint)TaskTriggerFlags.HasEndDate; SyncTrigger(); } } /// <summary> /// Gets/sets the ending year, month, and day for the trigger. After a value has been set /// with EndDate, HasEndDate becomes true. /// </summary> public DateTime EndDate { get { if (taskTrigger.EndYear == 0) return DateTime.MinValue; return new DateTime(taskTrigger.EndYear, taskTrigger.EndMonth, taskTrigger.EndDay); } set { taskTrigger.Flags |= (uint)TaskTriggerFlags.HasEndDate; taskTrigger.EndYear = (ushort)value.Year; taskTrigger.EndMonth = (ushort)value.Month; taskTrigger.EndDay = (ushort)value.Day; SyncTrigger(); } } /// <summary> /// Gets/sets the number of minutes after the trigger fires that it remains active. Used /// in conjunction with <see cref="IntervalMinutes"/> to run a task repeatedly for a period of time. /// For example, if you want to start a task at 8:00 A.M. repeatedly restart it until 5:00 P.M., /// there would be 540 minutes (9 hours) in the duration. /// Can also be used to terminate a task that is running when the DurationMinutes expire. Use /// <see cref="KillAtDurationEnd"/> to specify that task should be terminated at that time. /// </summary> /// <exception cref="ArgumentOutOfRangeException">Setting must be greater than or equal /// to the IntervalMinutes setting.</exception> public int DurationMinutes { get { return (int)taskTrigger.MinutesDuration; } set { if (value < taskTrigger.MinutesInterval) throw new ArgumentOutOfRangeException("DurationMinutes", value, "DurationMinutes must be greater than or equal the IntervalMinutes value"); taskTrigger.MinutesDuration = (ushort)value; SyncTrigger(); } } /// <summary> /// Gets/sets the number of minutes between executions for a task that is to be run repeatedly. /// Repetition continues until the interval specified in <see cref="DurationMinutes"/> expires. /// IntervalMinutes are counted from the start of the previous execution. /// </summary> /// <exception cref="ArgumentOutOfRangeException">Setting must be less than /// to the DurationMinutes setting.</exception> public int IntervalMinutes { get { return (int)taskTrigger.MinutesInterval; } set { if (value > taskTrigger.MinutesDuration) throw new ArgumentOutOfRangeException("IntervalMinutes", value, "IntervalMinutes must be less than or equal the DurationMinutes value"); taskTrigger.MinutesInterval = (uint)value; SyncTrigger(); } } /// <summary> /// Gets/sets whether task will be killed (terminated) when DurationMinutes expires. /// See <see cref="Trigger.DurationMinutes"/>. /// </summary> public bool KillAtDurationEnd { get { return ((taskTrigger.Flags & (uint)TaskTriggerFlags.KillAtDurationEnd) == (uint)TaskTriggerFlags.KillAtDurationEnd); } set { if (value) taskTrigger.Flags |= (uint)TaskTriggerFlags.KillAtDurationEnd; else taskTrigger.Flags &= ~(uint)TaskTriggerFlags.KillAtDurationEnd; SyncTrigger(); } } /// <summary> /// Gets/sets whether trigger is disabled. /// </summary> public bool Disabled { get { return ((taskTrigger.Flags & (uint)TaskTriggerFlags.Disabled) == (uint)TaskTriggerFlags.Disabled); } set { if (value) taskTrigger.Flags |= (uint)TaskTriggerFlags.Disabled; else taskTrigger.Flags &= ~(uint)TaskTriggerFlags.Disabled; SyncTrigger(); } } #endregion #region Methods /// <summary> /// Creates a new, bound Trigger object from an ITaskTrigger interface. The type of the /// concrete object created is determined by the type of ITaskTrigger. /// </summary> /// <param name="iTaskTrigger">Instance of ITaskTrigger.</param> /// <returns>One of the concrete classes derived from Trigger.</returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentException">Unable to recognize trigger type.</exception> internal static Trigger CreateTrigger(ITaskTrigger iTaskTrigger) { if (iTaskTrigger == null) throw new ArgumentNullException("iTaskTrigger", "Instance of ITaskTrigger cannot be null"); TaskTrigger sTaskTrigger = new TaskTrigger(); sTaskTrigger.TriggerSize = (ushort)Marshal.SizeOf(sTaskTrigger); iTaskTrigger.GetTrigger(ref sTaskTrigger); switch ((TriggerType)sTaskTrigger.Type) { case TriggerType.RunOnce: return new RunOnceTrigger(iTaskTrigger); case TriggerType.RunDaily: return new DailyTrigger(iTaskTrigger); case TriggerType.RunWeekly: return new WeeklyTrigger(iTaskTrigger); case TriggerType.RunMonthlyDOW: return new MonthlyDOWTrigger(iTaskTrigger); case TriggerType.RunMonthly: return new MonthlyTrigger(iTaskTrigger); case TriggerType.OnIdle: return new OnIdleTrigger(iTaskTrigger); case TriggerType.OnSystemStart: return new OnSystemStartTrigger(iTaskTrigger); case TriggerType.OnLogon: return new OnLogonTrigger(iTaskTrigger); default: throw new ArgumentException("Unable to recognize type of trigger referenced in iTaskTrigger", "iTaskTrigger"); } } /// <summary> /// When a bound Trigger is changed, the corresponding trigger in the system /// Task Scheduler is updated to stay in sync with the local structure. /// </summary> protected void SyncTrigger() { if (iTaskTrigger!=null) iTaskTrigger.SetTrigger(ref taskTrigger); } /// <summary> /// Bind a Trigger object to an ITaskTrigger interface. This causes the Trigger to /// sync itself with the interface and remain in sync whenever it is modified in the future. /// If the Trigger is already bound, an ArgumentException is thrown. /// </summary> /// <param name="iTaskTrigger">An interface representing a trigger in Task Scheduler.</param> /// <exception cref="ArgumentException">Attempt to bind and already bound trigger.</exception> internal void Bind(ITaskTrigger iTaskTrigger) { if (this.iTaskTrigger != null) throw new ArgumentException("Attempt to bind an already bound trigger"); this.iTaskTrigger = iTaskTrigger; iTaskTrigger.SetTrigger(ref taskTrigger); } /// <summary> /// Bind a Trigger to the same interface the argument trigger is bound to. /// </summary> /// <param name="trigger">A bound Trigger. </param> internal void Bind(Trigger trigger) { Bind(trigger.iTaskTrigger); } /// <summary> /// Break the connection between this Trigger and the system Task Scheduler. This /// releases COM resources used in bound Triggers. /// </summary> internal void Unbind() { if (iTaskTrigger != null) { Marshal.ReleaseComObject(iTaskTrigger); iTaskTrigger = null; } } /// <summary> /// Gets a string, supplied by the WindowsTask Scheduler, of a bound Trigger. /// For an unbound trigger, returns "Unbound Trigger". /// </summary> /// <returns>String representation of the trigger.</returns> public override string ToString() { if (iTaskTrigger != null) { IntPtr lpwstr; iTaskTrigger.GetTriggerString(out lpwstr); return CoTaskMem.LPWStrToString(lpwstr); } else { return "Unbound " + this.GetType().ToString(); } } /// <summary> /// Determines if two triggers are internally equal. Does not consider whether /// the Triggers are bound or not. /// </summary> /// <param name="obj">Value of trigger to compare.</param> /// <returns>true if triggers are equivalent.</returns> public override bool Equals(object obj) { return taskTrigger.Equals(((Trigger)obj).taskTrigger); } /// <summary> /// Gets a hash code for the current trigger. A Trigger has the same hash /// code whether it is bound or not. /// </summary> /// <returns>Hash code value.</returns> public override int GetHashCode() { return taskTrigger.GetHashCode(); } #endregion } /// <summary> /// Generalization of all triggers that have a start time. /// </summary> /// <remarks>StartableTrigger serves as a base class for triggers with a /// start time, but it has little use to clients.</remarks> public abstract class StartableTrigger : Trigger { /// <summary> /// Internal constructor, same as base. /// </summary> internal StartableTrigger() : base() { } /// <summary> /// Internal constructor from ITaskTrigger interface. /// </summary> /// <param name="iTrigger">ITaskTrigger from system Task Scheduler.</param> internal StartableTrigger(ITaskTrigger iTrigger) : base(iTrigger) { } /// <summary> /// Sets the start time of the trigger. /// </summary> /// <param name="hour">Hour of the day that the trigger will fire.</param> /// <param name="minute">Minute of the hour.</param> /// <exception cref="ArgumentOutOfRangeException">The hour is not between 0 and 23 or the minute is not between 0 and 59.</exception> protected void SetStartTime(ushort hour, ushort minute) { // if (hour < 0 || hour > 23) // throw new ArgumentOutOfRangeException("hour", hour, "hour must be between 0 and 23"); // if (minute < 0 || minute > 59) // throw new ArgumentOutOfRangeException("minute", minute, "minute must be between 0 and 59"); // taskTrigger.StartHour = hour; // taskTrigger.StartMinute = minute; // base.SyncTrigger(); StartHour = (short)hour; StartMinute = (short)minute; } /// <summary> /// Gets/sets hour of the day that trigger will fire (24 hour clock). /// </summary> public short StartHour { get { return (short)taskTrigger.StartHour; } set { if (value < 0 || value > 23) throw new ArgumentOutOfRangeException("hour", value, "hour must be between 0 and 23"); taskTrigger.StartHour = (ushort)value; base.SyncTrigger(); } } /// <summary> /// Gets/sets minute of the hour (specified in <see cref="StartHour"/>) that trigger will fire. /// </summary> public short StartMinute { get { return (short)taskTrigger.StartMinute; } set { if (value < 0 || value > 59) throw new ArgumentOutOfRangeException("minute", value, "minute must be between 0 and 59"); taskTrigger.StartMinute = (ushort)value; base.SyncTrigger(); } } } /// <summary> /// Trigger that fires once only. /// </summary> public class RunOnceTrigger : StartableTrigger { /// <summary> /// Create a RunOnceTrigger that fires when specified. /// </summary> /// <param name="runDateTime">Date and time to fire.</param> public RunOnceTrigger(DateTime runDateTime) : base() { taskTrigger.BeginYear = (ushort)runDateTime.Year; taskTrigger.BeginMonth = (ushort)runDateTime.Month; taskTrigger.BeginDay = (ushort)runDateTime.Day; SetStartTime((ushort)runDateTime.Hour, (ushort)runDateTime.Minute); taskTrigger.Type = TaskTriggerType.TIME_TRIGGER_ONCE; } /// <summary> /// Internal constructor to create from existing ITaskTrigger interface. /// </summary> /// <param name="iTrigger">ITaskTrigger from system Task Scheduler.</param> internal RunOnceTrigger(ITaskTrigger iTrigger) : base(iTrigger) { } } /// <summary> /// Trigger that fires at a specified time, every so many days. /// </summary> public class DailyTrigger : StartableTrigger { /// <summary> /// Creates a DailyTrigger that fires only at an interval of so many days. /// </summary> /// <param name="hour">Hour of day trigger will fire.</param> /// <param name="minutes">Minutes of the hour trigger will fire.</param> /// <param name="daysInterval">Number of days between task runs.</param> public DailyTrigger(short hour, short minutes, short daysInterval) : base() { SetStartTime((ushort)hour, (ushort)minutes); taskTrigger.Type = TaskTriggerType.TIME_TRIGGER_DAILY; taskTrigger.Data.daily.DaysInterval = (ushort)daysInterval; } /// <summary> /// Creates DailyTrigger that fires every day. /// </summary> /// <param name="hour">Hour of day trigger will fire.</param> /// <param name="minutes">Minutes of hour (specified in "hour") trigger will fire.</param> public DailyTrigger(short hour, short minutes) : this(hour, minutes, 1) { } /// <summary> /// Internal constructor to create from existing ITaskTrigger interface. /// </summary> /// <param name="iTrigger">ITaskTrigger from system Task Scheduler.</param> internal DailyTrigger(ITaskTrigger iTrigger) : base(iTrigger) { } /// <summary> /// Gets/sets the number of days between successive firings. /// </summary> public short DaysInterval { get { return (short)taskTrigger.Data.daily.DaysInterval; } set { taskTrigger.Data.daily.DaysInterval = (ushort)value; base.SyncTrigger(); } } } /// <summary> /// Trigger that fires at a specified time, on specified days of the week, /// every so many weeks. /// </summary> public class WeeklyTrigger : StartableTrigger { /// <summary> /// Creates a WeeklyTrigger that is eligible to fire only during certain weeks. /// </summary> /// <param name="hour">Hour of day trigger will fire.</param> /// <param name="minutes">Minutes of hour (specified in "hour") trigger will fire.</param> /// <param name="daysOfTheWeek">Days of the week task will run.</param> /// <param name="weeksInterval">Number of weeks between task runs.</param> public WeeklyTrigger(short hour, short minutes, DaysOfTheWeek daysOfTheWeek, short weeksInterval) : base() { SetStartTime((ushort)hour, (ushort)minutes); taskTrigger.Type = TaskTriggerType.TIME_TRIGGER_WEEKLY; taskTrigger.Data.weekly.WeeksInterval = (ushort)weeksInterval; taskTrigger.Data.weekly.DaysOfTheWeek = (ushort)daysOfTheWeek; } /// <summary> /// Creates a WeeklyTrigger that is eligible to fire during any week. /// </summary> /// <param name="hour">Hour of day trigger will fire.</param> /// <param name="minutes">Minutes of hour (specified in "hour") trigger will fire.</param> /// <param name="daysOfTheWeek">Days of the week task will run.</param> public WeeklyTrigger(short hour, short minutes, DaysOfTheWeek daysOfTheWeek) : this(hour, minutes, daysOfTheWeek, 1) { } /// <summary> /// Internal constructor to create from existing ITaskTrigger interface. /// </summary> /// <param name="iTrigger">ITaskTrigger interface from system Task Scheduler.</param> internal WeeklyTrigger(ITaskTrigger iTrigger) : base(iTrigger) { } /// <summary> /// Gets/sets number of weeks from one eligible week to the next. /// </summary> public short WeeksInterval { get { return (short)taskTrigger.Data.weekly.WeeksInterval; } set { taskTrigger.Data.weekly.WeeksInterval = (ushort)value; base.SyncTrigger(); } } /// <summary> /// Gets/sets the days of the week on which the trigger fires. /// </summary> public DaysOfTheWeek WeekDays { get { return (DaysOfTheWeek)taskTrigger.Data.weekly.DaysOfTheWeek; } set { taskTrigger.Data.weekly.DaysOfTheWeek = (ushort)value; base.SyncTrigger(); } } } /// <summary> /// Trigger that fires at a specified time, on specified days of the week, /// in specified weeks of the month, during specified months of the year. /// </summary> public class MonthlyDOWTrigger : StartableTrigger { /// <summary> /// Creates a MonthlyDOWTrigger that fires every month. /// </summary> /// <param name="hour">Hour of day trigger will fire.</param> /// <param name="minutes">Minute of the hour trigger will fire.</param> /// <param name="daysOfTheWeek">Days of the week trigger will fire.</param> /// <param name="whichWeeks">Weeks of the month trigger will fire.</param> /// <param name="months">Months of the year trigger will fire.</param> public MonthlyDOWTrigger(short hour, short minutes, DaysOfTheWeek daysOfTheWeek, WhichWeek whichWeeks, MonthsOfTheYear months) : base() { SetStartTime((ushort)hour, (ushort)minutes); taskTrigger.Type = TaskTriggerType.TIME_TRIGGER_MONTHLYDOW; taskTrigger.Data.monthlyDOW.WhichWeek = (ushort)whichWeeks; taskTrigger.Data.monthlyDOW.DaysOfTheWeek = (ushort)daysOfTheWeek; taskTrigger.Data.monthlyDOW.Months = (ushort)months; } /// <summary> /// Creates a MonthlyDOWTrigger that fires during specified months only. /// </summary> /// <param name="hour">Hour of day trigger will fire.</param> /// <param name="minutes">Minute of the hour trigger will fire.</param> /// <param name="daysOfTheWeek">Days of the week trigger will fire.</param> /// <param name="whichWeeks">Weeks of the month trigger will fire.</param> public MonthlyDOWTrigger(short hour, short minutes, DaysOfTheWeek daysOfTheWeek, WhichWeek whichWeeks) : this(hour, minutes, daysOfTheWeek, whichWeeks, MonthsOfTheYear.January|MonthsOfTheYear.February|MonthsOfTheYear.March|MonthsOfTheYear.April|MonthsOfTheYear.May|MonthsOfTheYear.June|MonthsOfTheYear.July|MonthsOfTheYear.August|MonthsOfTheYear.September|MonthsOfTheYear.October|MonthsOfTheYear.November|MonthsOfTheYear.December) { } /// <summary> /// Internal constructor to create from existing ITaskTrigger interface. /// </summary> /// <param name="iTrigger">ITaskTrigger from the system Task Scheduler.</param> internal MonthlyDOWTrigger(ITaskTrigger ... [truncated message content] |