本帖最后由 dimo 于 2022-5-8 19:02 编辑
灵光乍现,来写一篇(原创)
如果使用多个批处理守护的话,有个缺陷就是它们都是调用cmd.exe,这样只要结束cmd.exe进程树或者快速连续发送结束cmd.exe,程序还是会关闭。
最近读刘慈欣的白垩纪往事,这里面讲到终极核威慑武器(这里不重要),这种武器的倒计时引爆系统使用了“负计时”,即计时器每时每刻都在倒计时,到达计时就会引爆。但是控制中心每隔一段时间就向武器发送指令,增加计时的时间。
举个例子,比如在每天计时还剩一个小时引爆的时候,控制中心会发送指令增加计时时间24小时,此时距离引爆的时间变成了25小时。如果每天都这样发指令,就不会引爆,而只要某天到了应该发送指令的时间未接受到指令,则计时时间仍为一小时,此后一小时炸弹即引爆。这样即使控制中心被摧毁,核弹也会引爆。
从这里我就想到了系统自带的任务计划程序。(可以通过命令行或在批处理文件里用命令调用,不算第三方吧。)
实现方法我简单说一下。最近没空写出代码,有空我会补上,也欢迎各位帮忙用代码实现或者改进提高:
1.批处理文件启动后,创建一个临时批处理(比如放在%TEMP%文件夹下,命名为temp.bat)并将其启动,启动时传递一个参数,内容是自身的路径和进程PID。之后这个批处理开始执行本来需要的命令(echo批处理测试)。
2.Temp.bat启动时接受原批处理传的参数,即原批处理的路径和进程PID,之后新建一个临时文件存放这两个参数。
3.temp.bat使用任务计划程序新建任务(命令用法在最后提及),第一个任务为在当前时间5秒后启动自己并跳到下面讲的4步中命令的位置;第二个任务为在10秒后启动源批处理(用到2步中临时文件存放的源批处理路径,预防万一)。之后temp.bat暂时退出。源批处理继续运行或被关闭都没关系。
4.5秒后temp.bat启动,首先重新覆盖上次创建的任务,任务其他配置不变,只将自己的任务执行时间设置为当前时间的5秒后,将启动原文件任务的时间设为当前时间的10秒后(即两个任务时间都晚了5秒,这样5秒后还能重新执行temp.bat自身)。之后检查原批处理的进程PID是否存在,存在则temp.bat直接退出,不存在则运行原批处理文件并跳到显示“哈哈我又运行了”的语句,之后temp.bat退出。
5.5秒后,temp.bat重复4步中的几个操作。循环往复。这里可以实现记录关闭的时间,即检测到PID不存在时便可以锁定关闭的时间在上一个5秒内。此时temp.bat可以利用2步中临时文件中原批处理所在路径,将关闭的日期时间保存在原批处理上一级目录的一个文件里,精确度5秒左右。
6.一旦好巧不巧,用户用了taskkill命令的时机正好就是在temp.bat启动的时候,这时候temp.bat和原批处理一起被kill了,就不能通过temp来启动原批处理,但是十秒之后(此时用户应该已经觉得完事大吉了),任务计划程序还会启动原批处理,大不了从头再来一遍;如果第三步中设置任务的时候多加上几个参数,还能实现更多的功能。
7.主程序可以留下一个set/p一直等待输入,事先确定好一个结束码,将输入与结束码进行比对,一旦正确则执行退出操作:删除所有创建的任务计划,删除所有的临时文件,最后一条命令taskkill自己(防止temp.bat还在运行),完美退出。(还有一种情况是执行删除的时候temp还在运行,解决这个问题可以再新建一个任务计划,任务为启动cmd,加一个delete参数删除temp,设置大约15秒后启动。任务计划程序里本来就有不少废弃的计划任务,这一个不删除也没什么吧,反正以后不会再自动启动了)
这样,最开始提出的4个要求大致都解决了。
附上命令行计划任务的命令schtasks格式:- schtasks/create /tn TaskName /tr TaskRun /sc schedule [/mo modifier ]
- [/d day][/m month[,month...][/i IdleTime][/st StartTime]
- [/sd StartDate][/ed EndDate][/scomputer[/u [domain\]user /p password]]
- [/ru {[Domain\]User|"System"} [/rp Password]]
复制代码 详见https://blog.csdn.net/d1240673769/article/details/121087720 |