1. 程式人生 > >VC++建立計劃任務的若干方式

VC++建立計劃任務的若干方式

1. 建立計劃任務的兩種方式

計劃任務是windows作業系統提供的定時執行程式的方式,可在指定時間、指定時機(開機或使用者登入)週期性執行指定程式或命令。

建立計劃任務需要管理員許可權(過UAC),同時計劃任務也將在管理員許可權下被執行。

1.1 利用CMD命令列建立計劃任務

CMD命令列下有兩個命令可以建立計劃任務,一個是at 另一個是schtasks

  • at 命令僅在Win7及以下系統有效,支援指定任務的執行時間,支援遠端建立計劃任務,但不能指定任務在系統啟動或使用者登入時啟動。與schtasks命令相比,其優勢是建立計劃任務所需的命令比較簡單。
  • schtasks支援Windows全系列系統,與at
    命令相比,可設定的選項更加豐富,能適應更多的應用場景,同時還允許指定任務在系統啟動、使用者登入甚至是系統閒置時間啟動。

1.2 利用COM元件的API程式設計建立計劃任務

: 通過COM元件建立的計劃任務會在C:\windows\Tasks目錄下生成一個.OBJ格式的檔案,且該計劃任務無法通過schtasks命令查詢。

1.2.1 幾個基本概念

  1. Task物件。一個Task物件就是一個計劃任務,Task物件又包括多個元件,具體如下圖所示。Task物件至少包含一個Trigger物件和一個Actions物件。
    在這裡插入圖片描述

  2. Trigger物件定義的是計劃任務執行的觸發器,詳細描述了計劃任務的啟動時機。

  3. Action物件定義的是計劃任務需要執行的具體操作。

  4. Principal定義了執行計劃任務需要的安全上下文(Security Context) ,比如指定可執行計劃任務的使用者。

  5. Setting可以定義計劃任務執行時的程序優先順序、是否支援一個計劃任務有多個例項同時執行等。

  6. Registration Infomation儲存的時該計劃任務的相關管理資訊,例如計劃任務的建立者、建立時間等。

  7. Data 計劃任務的建立者可以在這裡儲存計劃任務執行所需的額外資料,例如一個XML幫助文件。

1.2.2 Task API

windows提供兩個版本的API介面用於建立計劃任務,分別是Task Scheduler 1.0

Task Scheduler 2.0。以下是兩套API的區別。

API 版本 系統需求
Task Scheduler 1.0 Windows全系列
Task Scheduler 2.0 Windows Vista 及以上系統

:Task Scheduler 2.0 允許在遠端XP計算機上建立計劃任務,但需要將Compatibility屬性設定為TASK_COMPATIBILITY_V1。

2. 使用Task Scheduler 1.0 管理計劃任務

使用Task Scheduler 1.0 的幾個注意點:

  1. 必須確保 Task Scheduler service 正在執行。
  2. 當通過介面獲取字串後,必須使用 CoTaskMemFree 進行釋放。
  3. 在Task Scheduler 1.0中,每個IScheduledWorkItem類的物件就是一個計劃任務;Action直接由IScheduledWorkItem物件的SetApplicationName、和SetParameters函式定義。

2.1 建立計劃任務

注1:建立計劃任務需要管理員許可權;

注2:同時需要為計劃任務指定一個唯一的名稱,如果指定的名稱已被使用,則會導致任務建立失敗。

注3:通過該方式建立的計劃任務會在C:\windows\Tasks目錄下建立一個同名的JOB檔案。

具體步驟如下:

  1. Call CoInitialize to initialize the COM library and CoCreateInstance to get a Task Scheduler object. (This example assumes that the Task Scheduler service is running.)

  2. Call ITaskScheduler::NewWorkItem to create a new task. (This method returns a pointer to an ITask interface.)

  3. Save the new task to disk by calling IPersistFile::Save. (The IPersistFile interface is a standard COM interface supported by the ITask interface.)

  4. Call ITask::Release to release all resources. (Note that Release is an IUnknown method inherited by ITask.

示例程式碼:

#include <windows.h>
#include <initguid.h>
#include <ole2.h>
#include <mstask.h>
#include <msterr.h>
#include <objidl.h>
#include <wchar.h>
#include <stdio.h>


int main(int argc, char **argv)
{
  HRESULT hr = S_OK;
  ITaskScheduler *pITS;
  
  
  /////////////////////////////////////////////////////////////////
  // Call CoInitialize to initialize the COM library and then 
  // call CoCreateInstance to get the Task Scheduler object. 
  /////////////////////////////////////////////////////////////////
  hr = CoInitialize(NULL);
  if (SUCCEEDED(hr))
  {
     hr = CoCreateInstance(CLSID_CTaskScheduler,
                           NULL,
                           CLSCTX_INPROC_SERVER,
                           IID_ITaskScheduler,
                           (void **) &pITS);
     if (FAILED(hr))
     {
        CoUninitialize();
        return 1;
     }
  }
  else
  {
     return 1;
  }
  
  
  /////////////////////////////////////////////////////////////////
  // Call ITaskScheduler::NewWorkItem to create new task.
  /////////////////////////////////////////////////////////////////
  LPCWSTR pwszTaskName;
  ITask *pITask;
  IPersistFile *pIPersistFile;
  pwszTaskName = L"Test Task";
  
  hr = pITS->NewWorkItem(pwszTaskName,         // Name of task
                         CLSID_CTask,          // Class identifier 
                         IID_ITask,            // Interface identifier
                         (IUnknown**)&pITask); // Address of task 
                                                                                                                                                                                            //  interface
  
  
  pITS->Release();                               // Release object
  if (FAILED(hr))
  {
     CoUninitialize();
     fprintf(stderr, "Failed calling NewWorkItem, error = 0x%x\n",hr);
     return 1;
  }
  
  
  /////////////////////////////////////////////////////////////////
  // Call IUnknown::QueryInterface to get a pointer to 
  // IPersistFile and IPersistFile::Save to save 
  // the new task to disk.
  /////////////////////////////////////////////////////////////////
  
  hr = pITask->QueryInterface(IID_IPersistFile,
                              (void **)&pIPersistFile);
  
  pITask->Release();
  if (FAILED(hr))
  {
     CoUninitialize();
     fprintf(stderr, "Failed calling QueryInterface, error = 0x%x\n",hr);
     return 1;
  }
  
  
  hr = pIPersistFile->Save(NULL,
                           TRUE);
  pIPersistFile->Release();
  if (FAILED(hr))
  {
     CoUninitialize();
     fprintf(stderr, "Failed calling Save, error = 0x%x\n",hr);
     return 1;
  }
  
  
  CoUninitialize();
  printf("Created task.\n");
  return 0;
}

2.2 列舉計劃任務

具體步驟:

  1. Call CoInitialize to initialize the COM library and CoCreateInstance to get a Task Scheduler object. (This example assumes that the Task Scheduler service is running.)
  2. Call IEnumWorkItems::Next to retrieve the tasks. (This example tries to retrieve five tasks with each call.)
  3. Process the tasks returned. (This example simply prints the name of each task to the screen.
  4. Release resources. Call CoTaskMemFree to free the memory used for names.

示例程式碼:

#include <windows.h>
#include <initguid.h>
#include <ole2.h>
#include <mstask.h>
#include <msterr.h>
#include <wchar.h>

#define TASKS_TO_RETRIEVE          5


int main(int argc, char **argv)
{
  HRESULT hr = S_OK;
  ITaskScheduler *pITS;
  
  
  /////////////////////////////////////////////////////////////////
  // Call CoInitialize to initialize the COM library and 
  // then call CoCreateInstance to get the Task Scheduler object. 
  /////////////////////////////////////////////////////////////////
  hr = CoInitialize(NULL);
  if (SUCCEEDED(hr))
  {
    hr = CoCreateInstance(CLSID_CTaskScheduler,
                          NULL,
                          CLSCTX_INPROC_SERVER,
                          IID_ITaskScheduler,
                          (void **) &pITS);
    if (FAILED(hr))
    {
      CoUninitialize();
      return hr;
    }
  }
  else
  {
    return hr;
  }
  
  /////////////////////////////////////////////////////////////////
  // Call ITaskScheduler::Enum to get an enumeration object.
  /////////////////////////////////////////////////////////////////
  IEnumWorkItems *pIEnum;
  hr = pITS->Enum(&pIEnum);
  pITS->Release();
  if (FAILED(hr))
  {
    CoUninitialize();
    return hr;
  }
  
  /////////////////////////////////////////////////////////////////
  // Call IEnumWorkItems::Next to retrieve tasks. Note that 
  // this example tries to retrieve five tasks for each call.
  /////////////////////////////////////////////////////////////////
  LPWSTR *lpwszNames;
  DWORD dwFetchedTasks = 0;
  while (SUCCEEDED(pIEnum->Next(TASKS_TO_RETRIEVE,
                                &lpwszNames,
                                &dwFetchedTasks))
                  && (dwFetchedTasks != 0))
  {
    ///////////////////////////////////////////////////////////////
    // Process each task. Note that this example prints the 
    // name of each task to the screen.
    //////////////////////////////////////////////////////////////
    while (dwFetchedTasks)
    {
       wprintf(L"%s\n", lpwszNames[--dwFetchedTasks]);
       CoTaskMemFree(lpwszNames[dwFetchedTasks]);
    }
    CoTaskMemFree(lpwszNames);
  }
  
  pIEnum->Release();
  CoUninitialize();
  return S_OK;
}

2.3 刪除計劃任務

2.4 觸發器結構體 TASK_TRIGGER

本小節內容來自於https://docs.microsoft.com/en-us/windows/desktop/TaskSchd/trigger-structures

Task Scheduler 1.0使用一個結構體來描述觸發器,其結構如下圖所示。

在這裡插入圖片描述

其中,成員TriggerTypeTASK_TRIGGER_TYPE 的列舉型別,而成員Type則是一個TASK_TRIGGER_UNION 型別的結構體。列舉型別TASK_TRIGGER_TYPE用於指定觸發器的型別,而根據TriggerType取值的不同,Type的取值可以是 DAILY, WEEKLY, MONTHLYDATE (day of month), and MONTHLYDOW (day of week) 這幾種型別之一,Type用於指定觸發器何時被觸發。

如果TriggerType定義的觸發器型別為one-time time-based trigger 或 event-based trigger,那麼Type的取值將被忽略。

以下是Type取值與 TRIGGER_TYPE_UNION 所取的結構體型別之間的對應關係圖。

在這裡插入圖片描述

2.5 建立觸發器

To create a trigger you must use three interfaces. IScheduledWorkItem provides the IScheduledWorkItem::CreateTrigger method for creating the trigger object, ITaskTrigger provides the ITaskTrigger::SetTrigger method for setting the criteria for the trigger, and the COM interface IPersistFile provides a Save method for saving the new trigger to disk.

具體步驟如下

  1. Call CoInitialize to initialize the COM library and CoCreateInstance to get a Task Scheduler object. (This example assumes that the Task Scheduler service is running.)
  2. Call ITaskScheduler::Activate to get the ITask interface of the task object. (Note that this example gets the “Test Task” task.)
  3. Define a TASK_TRIGGER structure. Note that wBeginDay, wBeginMonth, and wBeginYear members of TASK_TRIGGER must be set to a valid day, month, and year respectively.
  4. Save the task with the new trigger to disk using IPersistFile::Save. (The IPersistFile interface is a standard COM interface supported by the ITask interface.)
  5. Call Release to release all resources. (Note that Release is an IUnknown method inherited by ITask.)

示例程式碼如下

#include <windows.h>
#include <winbase.h>
#include <initguid.h>
#include <ole2.h>
#include <mstask.h>
#include <msterr.h>
#include <wchar.h>


int main(int argc, char **argv)
{
  HRESULT hr = S_OK;
  ITaskScheduler *pITS;
  
  
  ///////////////////////////////////////////////////////////////////
  // Call CoInitialize to initialize the COM library and then
  // call CoCreateInstance to get the Task Scheduler object.
  ///////////////////////////////////////////////////////////////////
  hr = CoInitialize(NULL);
  if (SUCCEEDED(hr))
  {
    hr = CoCreateInstance(CLSID_CTaskScheduler,
                          NULL,
                          CLSCTX_INPROC_SERVER,
                          IID_ITaskScheduler,
                          (void **) &pITS);
    if (FAILED(hr))
    {
      CoUninitialize();
      return 1;
    }
  }
  else
  {
     return 1;
  }
  
  
  ///////////////////////////////////////////////////////////////////
  // Call ITaskScheduler::Activate to get the Task object.
  ///////////////////////////////////////////////////////////////////
  
  ITask *pITask;
  LPCWSTR lpcwszTaskName;
  lpcwszTaskName = L"Test Task";
  hr = pITS->Activate(lpcwszTaskName,
                      IID_ITask,
                      (IUnknown**) &pITask);
  pITS->Release();

  if (FAILED(hr))
  {
     wprintf(L"Failed calling ITaskScheduler::Activate: ");
     wprintf(L"error = 0x%x\n",hr);
     CoUninitialize();
     return 1;
  }
    
  
  
  ///////////////////////////////////////////////////////////////////
  // Call ITask::CreateTrigger to create new trigger.
  ///////////////////////////////////////////////////////////////////
  
  ITaskTrigger *pITaskTrigger;
  WORD piNewTrigger;
  hr = pITask->CreateTrigger(&piNewTrigger,
                             &pITaskTrigger);
  if (FAILED(hr))
  {
    wprintf(L"Failed calling ITask::CreatTrigger: ");
    wprintf(L"error = 0x%x\n",hr);
    pITask->Release();
    CoUninitialize();
    return 1;
  }
  
  
  //////////////////////////////////////////////////////
  // Define TASK_TRIGGER structure. Note that wBeginDay,
  // wBeginMonth, and wBeginYear must be set to a valid 
  // day, month, and year respectively.
  //////////////////////////////////////////////////////
  
  TASK_TRIGGER pTrigger;
  ZeroMemory(&pTrigger, sizeof (TASK_TRIGGER));
  
  // Add code to set trigger structure?
  pTrigger.wBeginDay =1;                  // Required
  pTrigger.wBeginMonth =1;                // Required
  pTrigger.wBeginYear =1999;              // Required
  pTrigger.cbTriggerSize = sizeof (TASK_TRIGGER); 
  pTrigger.wStartHour = 13;
  pTrigger.TriggerType = TASK_TIME_TRIGGER_DAILY;
  pTrigger.Type.Daily.DaysInterval = 1;
  
  
  ///////////////////////////////////////////////////////////////////
  // Call ITaskTrigger::SetTrigger to set trigger criteria.
  ///////////////////////////////////////////////////////////////////
  
  hr = pITaskTrigger->SetTrigger (&pTrigger);
  if (FAILED(hr))
  {
    wprintf(L"Failed calling ITaskTrigger::SetTrigger: ");
    wprintf(L"error = 0x%x\n",hr);
    pITask->Release();
    pITaskTrigger->Release();
    CoUninitialize();
    return 1;
  }
  
  
  ///////////////////////////////////////////////////////////////////
  // Call IPersistFile::Save to save trigger to disk.
  ///////////////////////////////////////////////////////////////////
  
  IPersistFile *pIPersistFile;
  hr = pITask->QueryInterface(IID_IPersistFile,
                              (void **)&pIPersistFile);
  hr = pIPersistFile->Save(NULL,
                           TRUE);

  if (FAILED(hr))
  {
    wprintf(L"Failed calling IPersistFile::Save: ");
    wprintf(L"error = 0x%x\n",hr);
    pITask->Release();
    pITaskTrigger->Release();
    pIPersistFile->Release();
    CoUninitialize();
    return 1;
  }
  
  wprintf(L"The trigger was created and IPersistFile::Save was \n");
  wprintf(L"called to save the new trigger to disk.\n"); 
  
  
  ///////////////////////////////////////////////////////////////////
  // Release resources.
  ///////////////////////////////////////////////////////////////////
  
  pITask->Release();
  pITaskTrigger->Release();
  pIPersistFile->Release();
  CoUninitialize();
  return 0;
}

2.6 立刻執行計劃任務、中止計劃任務執行

3. 使用Task Scheduler 2.0 管理計劃任務

Be coming soon.