|
|
本帖最后由 515151 于 2026-3-4 16:49 编辑
极域电子教室 每1分钟检测学生端程序运行状态,崩溃时自动重启
分三部分
1、操作说明
2、源代码
3、编译程序下载
操作说明:
1. 确保已安装Python环境并配置好脚本运行环境。将本脚本保存为Python文件(如monitor.py),放置在任意目录。
2. 首次运行:
- 以管理员身份运行脚本。系统会弹出对话框询问是否禁用任务管理器及Win键组合。
- 选择"是"将限制用户通过Ctrl+Shift+Esc和任务管理器终止进程;选择"否"则保持原系统功能。
3. 进程监控功能:
- 脚本会自动监控StudentMain.exe进程(默认路径:C:\Program Files (x86)\Mythware\极域课堂管理系统软件v6.0 2021豪华版\StudentMain.exe)
- 每60秒检测一次进程状态,若检测到进程异常退出,将自动尝试重启
- 重启间隔设有60秒冷却期,避免高频异常重启
4. 日志记录:
- 所有操作记录保存在StudentMain.exe同级目录下的studentmain_monitor.log
- 包含进程状态、启动结果、异常信息等监控日志
5. 自动化设置:
- 脚本会自动添加到系统启动项,系统启动时自动运行
- 监控服务运行时会在后台持续守护进程
6. 特殊功能配置:
- 若选择禁用任务管理器,系统注册表将被修改(路径:Software\Microsoft\Windows\CurrentVersion\Policies\System)
- 此修改可通过组策略编辑器或手动修改注册表恢复
7. 路径修改(可选):
- 若极域学生端安装路径非默认,可通过设置环境变量STUDENTMAIN_PATH指向实际路径
- 或直接修改代码中PROCESS_PATH常量值后重新运行
8. 注意事项:
- 所有关键操作(注册表修改/进程控制)需要管理员权限
- 日志和配置文件与StudentMain.exe位于同一目录
- 若遇到权限问题,请检查运行环境是否以管理员身份启动
9. 故障排查:
- 检查studentmain_monitor.pid文件是否存在(位于StudentMain.exe目录)
- 查看日志文件获取详细错误信息
- 确保目标进程路径有效且具有可执行权限
该脚本适用于极域电子教室v6.0及以上版本,建议在教学终端部署前先进行测试环境验证。
源代码
import time
import psutil
import subprocess
from datetime import datetime
import os
import sys
import atexit
import ctypes
import winreg as wr
# 配置参数
PROCESS_NAME = "StudentMain.exe"
PROCESS_PATH = os.getenv("STUDENTMAIN_PATH", r"C:\Program Files (x86)\Mythware\极域课堂管理系统软件v6.0 2021豪华版\StudentMain.exe")
# 将日志、PID文件和标志文件都放在StudentMain.exe所在目录
BASE_DIR = os.path.dirname(PROCESS_PATH)
LOG_FILE = os.getenv("LOG_FILE", os.path.join(BASE_DIR, "studentmain_monitor.log"))
PID_FILE = os.getenv("PID_FILE", os.path.join(BASE_DIR, "studentmain_monitor.pid"))
DIALOG_FLAG_FILE = os.getenv("DIALOG_FLAG_FILE", os.path.join(BASE_DIR, "dialog_shown.flag"))
CHECK_INTERVAL = 60
RESTART_COOLDOWN = 60
def log_message(message):
try:
# 确保目录存在
log_dir = os.path.dirname(LOG_FILE)
if not os.path.exists(log_dir):
os.makedirs(log_dir, exist_ok=True)
with open(LOG_FILE, 'a', encoding='utf-8') as f:
f.write(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {message}\n")
except Exception as e:
print(f"日志写入失败: {e}")
def is_process_running():
for proc in psutil.process_iter(['pid', 'name', 'exe']):
try:
proc_info = proc.info
if proc_info['name'].lower() == PROCESS_NAME.lower():
if proc_info['exe'] == PROCESS_PATH:
return True
except:
pass
return False
def start_process():
if not os.path.exists(PROCESS_PATH):
log_message(f"错误:程序路径不存在 - {PROCESS_PATH}")
return False
try:
subprocess.Popen(
PROCESS_PATH,
creationflags=subprocess.CREATE_NO_WINDOW,
cwd=os.path.dirname(PROCESS_PATH),
shell=False
)
log_message(f"✓ 已成功启动 {PROCESS_NAME}")
return True
except Exception as e:
log_message(f"启动失败:{str(e)}")
return False
def is_already_running():
try:
if os.path.exists(PID_FILE):
with open(PID_FILE, 'r') as f:
old_pid = f.read().strip()
if old_pid and psutil.pid_exists(int(old_pid)):
log_message("检测到已有监控实例在运行,当前实例退出")
return True
else:
os.remove(PID_FILE)
except:
pass
try:
# 确保目录存在
pid_dir = os.path.dirname(PID_FILE)
if not os.path.exists(pid_dir):
os.makedirs(pid_dir, exist_ok=True)
with open(PID_FILE, 'w') as f:
f.write(str(os.getpid()))
except IOError as e:
log_message(f"警告:无法创建PID文件 - {e}")
return False
def cleanup():
try:
os.remove(PID_FILE)
except:
pass
log_message("监控服务已停止")
def add_to_startup():
key_path = r"Software\Microsoft\Windows\CurrentVersion\Run"
exe_path = os.path.abspath(sys.argv[0])
try:
with wr.OpenKey(wr.HKEY_CURRENT_USER, key_path, 0, wr.KEY_SET_VALUE) as key:
wr.SetValueEx(key, "StudentMainMonitor", 0, wr.REG_SZ, f'"{exe_path}"')
log_message("✓ 已添加到开机自启动")
except Exception as e:
log_message(f"添加自启动失败: {str(e)}")
def disable_taskmgr():
key_path = r"Software\Microsoft\Windows\CurrentVersion\Policies\System"
try:
with wr.CreateKey(wr.HKEY_CURRENT_USER, key_path) as key:
wr.SetValueEx(key, "DisableTaskMgr", 0, wr.REG_DWORD, 1)
log_message("已禁用任务管理器")
except Exception as e:
log_message(f"禁用任务管理器失败: {str(e)}")
def show_dialog():
result = ctypes.windll.user32.MessageBoxW(
None,
"是否禁用WIN键组合与任务管理器?\n\n选择「是」将限制用户操作\n选择「否」保持正常使用",
"StudentMain 监控服务配置",
4 | 0x40
)
return result == 6
def monitor_loop():
log_message("=" * 50)
log_message(f"监控服务启动 - 目标进程: {PROCESS_NAME}")
log_message(f"检测间隔: {CHECK_INTERVAL}秒")
log_message(f"目标路径: {PROCESS_PATH}")
log_message("=" * 50)
last_restart_time = 0
while True:
try:
if not is_process_running():
current_time = time.time()
if current_time - last_restart_time >= RESTART_COOLDOWN:
log_message(f"检测到 {PROCESS_NAME} 未运行,正在启动...")
if start_process():
last_restart_time = current_time
else:
log_message(f"冷却中,跳过本次启动尝试")
else:
log_message(f"✓ {PROCESS_NAME} 运行正常")
time.sleep(CHECK_INTERVAL)
except KeyboardInterrupt:
log_message("收到停止信号")
break
except Exception as e:
log_message(f"监控异常: {str(e)}")
time.sleep(CHECK_INTERVAL)
def main():
if is_already_running():
sys.exit(0)
atexit.register(cleanup)
# 检查是否已执行过对话框,仅首次运行显示
if not os.path.exists(DIALOG_FLAG_FILE):
result = show_dialog()
if result:
disable_taskmgr()
# 创建标志文件,表示已经显示过对话框
try:
# 确保目录存在
flag_dir = os.path.dirname(DIALOG_FLAG_FILE)
if not os.path.exists(flag_dir):
os.makedirs(flag_dir, exist_ok=True)
with open(DIALOG_FLAG_FILE, 'w') as f:
f.write('1')
log_message("✓ 已创建对话框标记文件,后续运行将不再显示")
except IOError as e:
log_message(f"创建标志文件失败: {e}")
add_to_startup()
monitor_loop()
if __name__ == "__main__":
main()
编译文件下载
studentmain_monitor.rar
(4.4 MB, 下载次数: 18)
|
|