计划任务是windows操作系统提供的定时执行程序的方式,可在指定时间、指定时机(开机或用户登录)周期性执行指定程序或命令。
创建计划任务需要管理员权限(过UAC),同时计划任务也将在管理员权限下被执行。
CMD命令行下有两个命令可以创建计划任务,一个是at
另一个是schtasks
。
at
命令仅在Win7及以下系统有效,支持指定任务的执行时间,支持远程创建计划任务,但不能指定任务在系统启动或用户登录时启动。与schtasks
命令相比,其优势是创建计划任务所需的命令比较简单。schtasks
支持Windows全系列系统,与at
命令相比,可设置的选项更加丰富,能适应更多的应用场景,同时还允许指定任务在系统启动、用户登录甚至是系统闲置时间启动。本小节内容来自于 https://docs.microsoft.com/en-us/windows/desktop/TaskSchd/tasks
注: 通过COM组件创建的计划任务会在C:\windows\Tasks目录下生成一个.OBJ格式的文件,且该计划任务无法通过schtasks命令查询。
Task
对象。一个Task
对象就是一个计划任务,Task
对象又包括多个组件,具体如下图所示。Task
对象至少包含一个Trigger
对象和一个Actions
对象。
Trigger
对象定义的是计划任务执行的触发器,详细描述了计划任务的启动时机。
Action
对象定义的是计划任务需要执行的具体操作。
Principal
定义了执行计划任务需要的安全上下文(Security Context) ,比如指定可执行计划任务的用户。
Setting
可以定义计划任务执行时的进程优先级、是否支持一个计划任务有多个实例同时运行等。
Registration Infomation
保存的时该计划任务的相关管理信息,例如计划任务的创建者、创建时间等。
Data
计划任务的创建者可以在这里保存计划任务执行所需的额外数据,例如一个XML帮助文档。
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。
Task Scheduler 1.0 需要使用ITaskScheduler接口,相关示例代码参见:https://docs.microsoft.com/en-us/windows/desktop/TaskSchd/task-scheduler-1-0-examples
使用Task Scheduler 1.0 的几个注意点:
Action
直接由IScheduledWorkItem对象的SetApplicationName、和SetParameters函数定义。本小节内容来自于:https://docs.microsoft.com/en-us/windows/desktop/TaskSchd/creating-a-task-using-newworkitem-example
注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
#include
#include
#include
#include
#include
#include
#include
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;
}
具体步骤:
示例代码:
#include
#include
#include
#include
#include
#include
#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;
}
通过调用接口ITaskScheduler::Delete可以删除指定名称的任务。
本小节内容来自于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 所取的结构体类型之间的对应关系图。
本小节内容来自于 https://docs.microsoft.com/en-us/windows/desktop/TaskSchd/creating-a-new-trigger
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.
具体步骤如下
示例代码如下
#include
#include
#include
#include
#include
#include
#include
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;
}
参见 https://docs.microsoft.com/en-us/windows/desktop/TaskSchd/task-scheduler-1-0-examples
Be coming soon.