Windows 작업 스케줄러 (기본)
C ++. COM 프로그래밍의 악몽. 모든 도전 요구 사항을 충족합니다.
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <taskschd.h>
#include <comutil.h>
#pragma comment(lib, "taskschd.lib")
#pragma comment(lib, "comsuppw.lib")
static void timeplus (int seconds, char timestr[30]);
int main () {
CoInitializeEx(NULL, COINIT_MULTITHREADED);
CoInitializeSecurity(NULL, -1, NULL, NULL,
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL);
const char *name = "Restarter";
char path[MAX_PATH + 1];
GetModuleFileNameA(NULL, path, sizeof(path));
path[sizeof(path) - 1] = 0; // workaround for xp
ITaskService *taskman;
CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER,
IID_ITaskService, (void **)&taskman);
taskman->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
ITaskFolder *root;
taskman->GetFolder(_bstr_t("\\"), &root);
// Delete the task.
root->DeleteTask(_bstr_t(name), 0);
// pause for 5 seconds to give user a chance to kill the cycle
fprintf(stderr, "If you want to kill the program, close this window now.\n");
Sleep(5000);
fprintf(stderr, "Sorry, time's up, maybe next time.\n");
// Create the task for 5 seconds from now.
ITaskDefinition *task;
taskman->NewTask(0, &task);
IPrincipal *principal;
task->get_Principal(&principal);
principal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN);
ITaskSettings *settings;
task->get_Settings(&settings);
settings->put_StartWhenAvailable(VARIANT_TRUE);
settings->put_DisallowStartIfOnBatteries(VARIANT_FALSE);
settings->put_StopIfGoingOnBatteries(VARIANT_FALSE);
ITriggerCollection *triggers;
task->get_Triggers(&triggers);
ITrigger *trigger;
triggers->Create(TASK_TRIGGER_TIME, &trigger);
char when[30];
ITimeTrigger *trigger_time;
trigger->QueryInterface(IID_ITimeTrigger, (void **)&trigger_time);
trigger_time->put_Id(_bstr_t("TimeTrigger"));
timeplus(10, when);
trigger_time->put_StartBoundary(_bstr_t(when));
timeplus(300, when);
trigger_time->put_EndBoundary(_bstr_t(when));
IActionCollection *actions;
task->get_Actions(&actions);
IAction *action;
actions->Create(TASK_ACTION_EXEC, &action);
IExecAction *action_exec;
action->QueryInterface(IID_IExecAction, (void **)&action_exec);
action_exec->put_Path(_bstr_t(path));
IRegisteredTask *regtask;
root->RegisterTaskDefinition(_bstr_t(name), task,
TASK_CREATE_OR_UPDATE, _variant_t(), _variant_t(),
TASK_LOGON_INTERACTIVE_TOKEN, _variant_t(""),
®task);
regtask->Release();
action_exec->Release();
actions->Release();
trigger_time->Release();
trigger->Release();
triggers->Release();
settings->Release();
principal->Release();
task->Release();
root->Release();
taskman->Release();
CoUninitialize();
}
// outputs current utc time + given number of seconds as
// a string of the form YYYY-MM-DDTHH:MM:SSZ
static void timeplus (int seconds, char timestr[30]) {
SYSTEMTIME when;
FILETIME whenf;
LARGE_INTEGER tempval;
GetSystemTimeAsFileTime(&whenf);
tempval.HighPart = whenf.dwHighDateTime;
tempval.LowPart = whenf.dwLowDateTime;
tempval.QuadPart += seconds * 10000000LL; // 100 nanosecond units
whenf.dwHighDateTime = tempval.HighPart;
whenf.dwLowDateTime = tempval.LowPart;
FileTimeToSystemTime(&whenf, &when);
sprintf(timestr, "%04hu-%02hu-%02huT%02hu:%02hu:%02huZ",
when.wYear, when.wMonth, when.wDay,
when.wHour, when.wMinute, when.wSecond);
}
MSVC (또는 모든 종속성이있는 경우 MinGW GCC)로 컴파일하십시오.
프로그램은 Windows 작업 스케줄러를 사용하여 일회성 작업을 시작하고 5 초 후에 시작되도록 등록합니다 (제어판-> 관리 도구-> 작업 스케줄러를 보려면 작업 이름이 "다시 시작"). 프로그램은 작업을 생성하기 전에 프로그램을 종료 할 수있는 5 초 동안 일시 중지됩니다.
도전 과제 :
완료되면 다시 시작됩니다.
예. 작업은 프로그램 종료 직전에 예약됩니다.
동시에 실행되는 프로그램의 인스턴스는 두 개 이상입니다.
예. 프로그램이 완전히 종료되고 5 초 동안 실행되지 않습니다. 스케줄러에 의해 시작됩니다.
주기 동안 사용자가 수동으로 시작한 인스턴스는 무시해도됩니다.
예, 일정한 작업 이름을 사용하는 부작용으로 그렇습니다.
다시 시작하는 것이 보장되는 한.
예, 작업 스케줄러가 실행중인 경우 (표준 Windows 구성에 있음).
주기를 중지하는 유일한 방법은 프로세스를 종료하는 것입니다.
예, 5 초 동안 프로세스가 종료되는 동안 프로세스가 종료 될 수 있습니다. 프로그램은 5 초 지연 이전에 작업을 삭제하며이 시점에서 작업을 종료하면 스케줄러에 흩어진 작업이 남지 않습니다.
솔루션을 다시 시작하면 안됩니다
. 예.
그건 그렇고, Windows 응용 프로그램이 왜 그렇게 불안정한 지 궁금해하는 사람이 있다면 (.NET 및 C #이 출현하기 전에) 이것이 이유 중 하나입니다. 프로그래머가 조금이라도 조금 게으른 경우 (위의 코드는 매우 게으름) 필요한 오류 처리량 (내가 포함 했음), 리소스 관리 및 자세한 정보는 오류가 발생하기 쉬운 상황을 설정합니다.
훨씬 쉽고 짧은 대안은 schtasks.exe를 호출하는 것입니다. .BAT 스크립트 로 버전을 제출 했습니다 .
exec
리눅스에서하는 것 아닌가요?