ตัวกำหนดเวลางาน 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 task scheduler เพื่อเริ่มต้นเอง 5 วินาทีต่อมา (แผงควบคุม -> เครื่องมือการดูแลระบบ -> Task Scheduler เพื่อดูงานจะมีชื่อว่า "Restarter") โปรแกรมจะหยุดเป็นเวลา 5 วินาทีเพื่อให้คุณมีโอกาสฆ่ามันก่อนที่จะสร้างงาน
ข้อกำหนดในการท้าทาย:
เริ่มต้นตัวเองอีกครั้งเมื่อเสร็จสิ้น
ใช่. งานถูกกำหนดไว้ก่อนที่โปรแกรมจะออก
ไม่มีมากกว่าหนึ่งอินสแตนซ์ของโปรแกรมที่ทำงานในเวลาเดียวกัน
ใช่. ออกจากโปรแกรมอย่างสมบูรณ์และไม่ทำงานเป็นเวลา 5 วินาที มันเริ่มจากตัวกำหนดตารางเวลา
คุณสามารถละเว้นอินสแตนซ์ใด ๆ ที่เริ่มต้นโดยผู้ใช้ด้วยตนเองในระหว่างรอบของคุณ
ใช่เป็นผลข้างเคียงของการใช้ชื่อภารกิจคงที่
ตราบใดที่มันรับประกันว่ามันจะเริ่มขึ้นอีกครั้ง
ใช่โดยที่ Task Scheduler กำลังทำงาน (อยู่ในการกำหนดค่า Windows มาตรฐาน)
วิธีเดียวที่จะหยุดวงจรคือการฆ่ากระบวนการ
ใช่กระบวนการสามารถถูกฆ่าได้ในช่วง 5 วินาทีขณะที่มันกำลังทำงาน โปรแกรมจะลบงานก่อนที่จะมีการหน่วงเวลา 5 วินาทีการฆ่ามันในเวลานี้จะไม่ปล่อยให้งานหลงทางอยู่ในตัวกำหนดตารางเวลา
โซลูชันของคุณไม่ควรเกี่ยวข้องกับการรีสตาร์ทสภาพแวดล้อม
ใช่
อย่างไรก็ตามถ้าใครเคยสงสัยว่าทำไมแอปพลิเคชัน Windows ที่เคยมีความไม่เสถียร (ก่อนการกำเนิดของ. NET และ C #) นี่เป็นเหตุผลหนึ่งที่ทำไม จำนวนของการจัดการข้อผิดพลาดที่จำเป็น (ถ้าฉันรวมไว้) การจัดการทรัพยากรและการใช้คำฟุ่มเฟื่อยตั้งสถานการณ์ที่เกิดข้อผิดพลาดได้ง่ายมากหากโปรแกรมเมอร์นั้นแม้แต่คนที่ขี้เกียจนิดหน่อย
ทางเลือกที่ง่ายและสั้นกว่ามากคือการเรียกใช้ schtasks.exe ฉันได้ส่งเวอร์ชันที่มีในสคริปต์. BATเช่นกัน
exec
ลินุกซ์หรือเปล่า?