異世界


2012年12月3日 星期一

Task Scheduler Managed Wrapper: 由程式來排程工作

資料來源:http://msdn.microsoft.com/zh-tw/ee922578.aspx

延伸閱讀 : http://taskscheduler.codeplex.com/wikipage?title=Examples&referringTitle=Home

 

Task Scheduler 基本概念

  • Task Scheduler 是由一個或數個 Task(工作)組成,一個 Task 代表一個任務,它會有幾個參數:
  1. 觸發器(trigger),指示此工作會在何時觸發。在 Task Scheduler 2.0 時,一個工作可以有多個觸發器。1.0 時則每個工作只能有一個觸發器。
  2. 動作(action),指示此工作會觸發哪些程式或指令。在 Task Scheduler 2.0 時,一個工作可以有多個動作(最多 32 個動作)。1.0 時則每個工作只能有一個動作。
  3. 執行權限(Principals, Security Context),指示此工作要用哪個帳戶或安全權限執行,所有動作都會使用相同的權限來呼叫。
  4. 條件(Settings),可以決定工作在何種情況下才會啟動。
  5. 登錄資料(Registration Information),記錄系統管理的相關資訊,像是建立者(author)或工作說明(description)。
  6. 資料(Data),此工作所需要的額外資訊。

 

  • Task 內部結構圖

image

 

  • Task Scheduler 的動作支援四種類型,分別為啟動程式、自動發信、顯示訊息以及 COM 自訂處理器(handler),其中只有 COM 自訂處理器一項必須要由程式來做以外,其他三種均可以透過使用者介面設定。
  • Task Scheduler Managed Wrapper Library

Task Scheduler Managed Wrapper Library 最早是在 Code Project 網站中的一個專案,由 David Hall 於 2002 年所開發,當時還只是 .NET Framework 1.0 的時代,在 Code Project 的專案內容中,David 說明了如何由 Platform SDK 所附的 mstask.idl,使用 Tlbimp.exe 產生引用的 C# 程式碼再移植到他的專案中的方法。裡面使用了許多的 COM Interoperability 的技巧,值得學習 COM Interop 的開發人員作為參考。

 

 

下列範例程式為簡單操作 Task Scheduler API 的範例:

using System;
using Microsoft.Win32.TaskScheduler;
 
class Program
{
   static void Main(string[] args)
   {
      // Get the service on the local machine
      TaskService ts = new TaskService();
 
      // Create a new task definition and assign properties
      TaskDefinition td = ts.NewTask();
      td.RegistrationInfo.Description = "Does something";
 
      // Create a trigger that will fire the task at this time every other day
      td.Triggers.Add(new DailyTrigger { DaysInterval = 2 });
 
      // Create an action that will launch Notepad whenever the trigger fires
      td.Actions.Add(new ExecAction("notepad.exe", "c:\\test.log", null));
 
      // Register the task in the root folder
      ts.RootFolder.RegisterTaskDefinition(@"Test", td);
 
      // Remove the task we just created
      ts.RootFolder.DeleteTask("Test");
   }
}


Task Scheduler Wrapper 的起點是 TaskService 類別,它提供了管理與列舉資料夾的功能,以及取得工作以及連線狀態的功能,並且也可以在建構時設定連結到指定的伺服器。

TaskFolder 物件是處理資料夾的物件,它具有下列功能:


  • 建立與刪除子資料夾(CreateFolder 與 DeleteFolder 方法)。
  • 登錄工作(RegisterTaskDefinition 方法)以及刪除工作(DeleteTask 方法)。
  • 取得子工作清單(Tasks 屬性)。
  • 取得子資料夾清單(SubFolders 屬性)。
  • 設定與取得 Security Descriptior 的 SDDL Form 資訊(GetSecurityDescriptorSddlForm 與 SetSecurityDescriptotSddlForm 方法)。

它的使用方法也很簡單,例如下列程式可以建立與刪除資料夾:



  • create folder



// create folder.
TaskService service = new TaskService();
TaskFolder folder = service.GetFolder(@"\");
 
folder.CreateFolder(this.txtFolderName.Text, folder.GetSecurityDescriptorSddlForm(AccessControlSections.Access));
 
folder = null;
service = null;



// create folder.
TaskService service = new TaskService();
TaskFolder folder = service.GetFolder(@"\");
 
folder.CreateFolder(this.txtFolderName.Text, folder.GetSecurityDescriptorSddlForm(AccessControlSections.Access));
 
folder = null;
service = null;

 



  • delete folder


// delete folder.
this._taskService = new TaskService();
 
TaskFolder folder = this._taskService.GetFolder(@"\MyFolder");
 
if (folder.Tasks.Count > 0)
{
    throw new InvaildOperationException("TASKS_EXIST");
}
 
if (folder.SubFolders.Count > 0)
{
    throw new InvaildOperationException("SUB_FOLDERS_EXIST");
}
 
TaskFolder folderParent = this._taskService.GetFolder(folder.Path.Replace(@"\" + folder.Name, ""));
folderParent.DeleteFolder(folder.Name);
 
folderParent = null;
folder = null;

image



  • 例如建立一個 Email 的 Action 的程式如下:

    EmailAction eAction = new EmailAction("Task fired", "sender@email.com", "recipient@email.com", "You just got a message", "smtp.company.com");
    eAction.Cc = "alternate@email.com";

 




  • 可用的 Trigger 均繼承自 Trigger 物件,支援的 Triggers 清單如下:

image


 




  • 例如設定每月執行的觸發器的程式如下:

    MonthlyTrigger mTrigger = new MonthlyTrigger();
    mTrigger.StartBoundary = DateTime.Today + TimeSpan.FromHours(10);
    mTrigger.DaysOfMonth = new int[] { 10, 20 };
    mTrigger.MonthsOfYear = MonthsOfTheYear.July | MonthsOfTheYear.November;


 


進階功能:COM 處理器


進階功能:COM 處理器


這是 Task Scheduler 2.0 才有的新功能,允許開發人員自行建立一個支援 Task Scheduler COM 工作的元件,讓 Task Scheduler 幫你執行,雖然它名為 COM 處理器,但是 .NET 程式可以利用 COM Interop 方式將元件公開給 COM 介面,如此就可以當做一個 COM 元件供外部存取。另外,COM 處理器的工作只可以在程式碼中實作,無法透過 GUI 介面處理,因此這個能力算是保留給開發人員使用的,也就是需要額外撰寫登錄 COM 工作的程式碼並在安裝程式使用(或是撰寫成獨立的小程式亦可)。

要建立 COM 處理器,請執行下列步驟:

1. 建立一個類別庫專案。


2. 加入 Microsoft.Win32.TaskScheduler.dll 以及 TimeSpan2.dll 的參考。


3. 建立一個新類別,並設定與實作 Microsoft.Win32.TaskScheduler 命名空間的 ITaskHandler 介面。


4. 設定專案要產生 Type Library,即註冊 COM Interop:




    5. 建置專案,並撰寫註冊COM Handler工作的程式碼,例如下列的程式碼:


    ComHandlerAction comAction = new ComHandlerAction(new Guid("{CE7D4428-8A77-4c5d-8A13-5CAB5D1EC734}"));
    comAction.Data = "Something specific the COM object needs to execute. This can be left unassigned as well.";


    6. 登錄完成的工作,可以在動作中看到『自訂處理常式』,代表是COM Handler,而且這個動作是無法被編輯的:



    ITaskHandler 介面具有四個方法,分別是 Start()、Pause()、Resume() 以及 Stop() 四個方法,代表啟動、暫停、繼續以及停止四個動作,由 Task Scheduler 視情況呼叫控制。其中 Start() 方法會傳入 Data 參數,這個參數是註冊 COM Handler 時所給定的 Data 屬性值,作為執行時的參數,而 Stop() 方法會需要傳回一個 RetCode,代表成功或失敗,若執行成功應傳回 0,若出現非零值時會被判斷是失敗。


    image




    下列程式碼是 COM Handler 的範例實作,功能為每五秒於事件記錄中寫入一筆資料,會寫入 12 次:

    [ComVisible(true), Guid("CE7D4428-8A77-4c5d-8A13-5CAB5D1EC734"), ClassInterface(ClassInterfaceType.None)]
    public sealed class MyCOMTask : ITaskHandler
    {
        private ITaskHandlerStatus handlerService;
        private Timer timer;
        private DateTime lastWriteTime = DateTime.MinValue;
        private byte writeCount = 0;
        private const string file = @"C:\TaskLog.txt";
     
        void ITaskHandler.Start(object pHandlerServices, string Data)
        {
            handlerService = pHandlerServices as ITaskHandlerStatus;
            lastWriteTime = DateTime.Now;
            timer_Elapsed(null, null);
            timer.Enabled = true;
        }
     
        void ITaskHandler.Stop(out int pRetCode)
        {
            timer.Enabled = false;
            pRetCode = 0;
        }
     
        void ITaskHandler.Pause()
        {
            timer.Enabled = false;
        }
     
        void ITaskHandler.Resume()
        {
            timer.Enabled = true;
        }
     
        public MyCOMTask()
        {
            timer = new Timer(5000) { AutoReset = true };
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
        }
     
        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (writeCount < 12)
            {
                try
                {
                    using (StreamWriter wri = File.AppendText(file))
                        wri.WriteLine("Log entry {0}", DateTime.Now);
     
                    handlerService.UpdateStatus((short)(++writeCount / 12), string.Format("Log file started at {0}", lastWriteTime));
                }
                catch { }
            }
     
            if (writeCount >= 12)
            {
                timer.Enabled = false;
                writeCount = 0;
                handlerService.TaskCompleted(0);
            }
        }
     
    }

    結語


    Task Scheduler Wrapper Library 是相容性高(可用在 1.0 和 2.0)的一組工具函式庫,並直接控制 Task Scheduler 的功能,以實現能利用程式碼去存取與控制工作排程的能力,不必再額外去撰寫命令列指令或是使用 GUI 工具去設定排程了,讀者可以善用它來開發自己的工具,像是 Web 化的排程管理員或集中的管理工具等。

    沒有留言:

    張貼留言