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 幾個基本概念
-
Task
物件。一個Task
物件就是一個計劃任務,Task
物件又包括多個元件,具體如下圖所示。Task
物件至少包含一個Trigger
物件和一個Actions
物件。
-
Trigger
物件定義的是計劃任務執行的觸發器,詳細描述了計劃任務的啟動時機。 -
Action
物件定義的是計劃任務需要執行的具體操作。 -
Principal
定義了執行計劃任務需要的安全上下文(Security Context) ,比如指定可執行計劃任務的使用者。 -
Setting
可以定義計劃任務執行時的程序優先順序、是否支援一個計劃任務有多個例項同時執行等。 -
Registration Infomation
儲存的時該計劃任務的相關管理資訊,例如計劃任務的建立者、建立時間等。 -
Data
計劃任務的建立者可以在這裡儲存計劃任務執行所需的額外資料,例如一個XML幫助文件。
1.2.2 Task API
windows提供兩個版本的API介面用於建立計劃任務,分別是Task Scheduler 1.0
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 的幾個注意點:
- 必須確保 Task Scheduler service 正在執行。
- 當通過介面獲取字串後,必須使用 CoTaskMemFree 進行釋放。
- 在Task Scheduler 1.0中,每個IScheduledWorkItem類的物件就是一個計劃任務;
Action
直接由IScheduledWorkItem物件的SetApplicationName、和SetParameters函式定義。
2.1 建立計劃任務
注1:建立計劃任務需要管理員許可權;
注2:同時需要為計劃任務指定一個唯一的名稱,如果指定的名稱已被使用,則會導致任務建立失敗。
注3:通過該方式建立的計劃任務會在C:\windows\Tasks目錄下建立一個同名的JOB檔案。
具體步驟如下:
-
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.)
-
Call ITaskScheduler::NewWorkItem to create a new task. (This method returns a pointer to an ITask interface.)
-
Save the new task to disk by calling IPersistFile::Save. (The IPersistFile interface is a standard COM interface supported by the ITask interface.)
-
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 列舉計劃任務
具體步驟:
- 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.)
- Call IEnumWorkItems::Next to retrieve the tasks. (This example tries to retrieve five tasks with each call.)
- Process the tasks returned. (This example simply prints the name of each task to the screen.
- 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使用一個結構體來描述觸發器,其結構如下圖所示。
其中,成員TriggerType是 TASK_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.
具體步驟如下
- 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.)
- Call ITaskScheduler::Activate to get the ITask interface of the task object. (Note that this example gets the “Test Task” task.)
- 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.
- 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.)
- 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.