# 易语言守护程序与被守护程序示例 我将为你提供一个完整的易语言守护程序解决方案,包含两个部分:被守护程序(`MainProgram.exe`)和守护程序(`Guardian.exe`)。 ## 被守护程序代码 (`MainProgram.e`) ```易语言 .版本 2 .程序集 主程序 .程序集变量 守护进程ID, 整数型 .程序集变量 通信句柄, 整数型 .子程序 _启动子程序, 整数型 .局部变量 命令行, 文本型 .局部变量 参数数组, 文本型, , "0" 命令行 = 取命令行 () 参数数组 = 分割文本 (命令行, " ", ) ' 如果是守护程序启动的,不重复启动守护程序 .如果真 (取数组成员数 (参数数组) > 0 且 参数数组 [1] = "由守护程序启动") 信息框 ("本程序由守护程序启动", 0, , ) 返回 (0) .如果真结束 启动守护程序 () 返回 (0) .子程序 启动守护程序 .局部变量 守护程序路径, 文本型 .局部变量 启动信息, 启动信息 守护程序路径 = 取运行目录 () + "\Guardian.exe" .如果真 (文件是否存在 (守护程序路径) = 假) 信息框 ("守护程序不存在:" + 守护程序路径, 0, , ) 返回 () .如果真结束 启动信息.命令行 = "" ' 守护程序不需要额外参数 启动信息.运行方式 = 1 ' 普通方式 守护进程ID = 运行 (守护程序路径, 启动信息, ) .如果真 (守护进程ID = 0) 信息框 ("启动守护程序失败", 0, , ) 返回 () .如果真结束 ' 延迟一下等待守护程序初始化 延时 (1000) 发送运行信息 () .子程序 发送运行信息 .局部变量 映射文件名, 文本型 .局部变量 映射大小, 整数型 .局部变量 映射句柄, 整数型 .局部变量 映射指针, 整数型 .局部变量 进程信息, 文本型 映射文件名 = "GuardianSharedMemory" 映射大小 = 1024 ' 1KB足够 ' 创建文件映射 映射句柄 = CreateFileMappingA (-1, 0, #PAGE_READWRITE, 0, 映射大小, 映射文件名) .如果真 (映射句柄 = 0) 信息框 ("创建共享内存失败", 0, , ) 返回 () .如果真结束 ' 映射视图 映射指针 = MapViewOfFile (映射句柄, #FILE_MAP_WRITE, 0, 0, 映射大小) .如果真 (映射指针 = 0) 信息框 ("映射视图失败", 0, , ) CloseHandle (映射句柄) 返回 () .如果真结束 ' 准备要发送的信息 进程信息 = "PID=" + 到文本 (取进程ID ()) + ",Path=" + 取执行文件名 () + ",Time=" + 到文本 (取现行时间 ()) ' 写入共享内存 写到内存 (进程信息, 映射指针, 取文本长度 (进程信息) + 1) ' 清理 UnmapViewOfFile (映射指针) CloseHandle (映射句柄) .子程序 取进程ID, 整数型 .局部变量 进程快照, 整数型 .局部变量 进程信息, 进程信息32 .局部变量 当前进程名, 文本型 当前进程名 = 取执行文件名 () 进程快照 = CreateToolhelp32Snapshot (#TH32CS_SNAPPROCESS, 0) .如果真 (进程快照 = -1) 返回 (0) .如果真结束 进程信息.dwSize = 取结构尺寸 (进程信息) .如果 (Process32First (进程快照, 进程信息)) .判断循环首 (真) .如果 (到小写 (进程信息.szExeFile) = 到小写 (当前进程名)) CloseHandle (进程快照) 返回 (进程信息.th32ProcessID) .否则 .如果 (Process32Next (进程快照, 进程信息) = 假) 跳出循环 () .如果结束 .如果结束 .判断循环尾 () .否则 信息框 ("获取进程信息失败", 0, , ) .如果结束 CloseHandle (进程快照) 返回 (0) ``` ## 守护程序代码 (`Guardian.e`) ```易语言 .版本 2 .程序集 守护程序 .程序集变量 被守护进程ID, 整数型 .程序集变量 被守护进程路径, 文本型 .程序集变量 定时器ID, 整数型 .子程序 _启动子程序, 整数型 .局部变量 控制台句柄, 整数型 ' 设置为控制台程序 控制台句柄 = GetConsoleWindow () 显示窗口 (控制台句柄, 1) ' 显示控制台窗口 输出调试文本 ("守护程序已启动,等待被守护程序信息...") ' 创建定时器检查被守护程序状态 定时器ID = 置定时器 (0, 5000, &检查被守护程序状态) ' 等待被守护程序发送信息 接收运行信息 () 返回 (0) .子程序 接收运行信息 .局部变量 映射文件名, 文本型 .局部变量 映射大小, 整数型 .局部变量 映射句柄, 整数型 .局部变量 映射指针, 整数型 .局部变量 进程信息, 文本型 .局部变量 参数数组, 文本型, , "0" .局部变量 i, 整数型 映射文件名 = "GuardianSharedMemory" 映射大小 = 1024 ' 循环等待被守护程序发送信息 .判断循环首 (被守护进程ID = 0) 映射句柄 = OpenFileMappingA (#FILE_MAP_READ, 假, 映射文件名) .如果真 (映射句柄 ≠ 0) 映射指针 = MapViewOfFile (映射句柄, #FILE_MAP_READ, 0, 0, 映射大小) .如果真 (映射指针 ≠ 0) 进程信息 = 指针到文本 (映射指针) UnmapViewOfFile (映射指针) CloseHandle (映射句柄) ' 解析进程信息 参数数组 = 分割文本 (进程信息, ",", ) .计次循环首 (取数组成员数 (参数数组), i) .如果 (寻找文本 (参数数组 [i], "PID=", , 假) = 1) 被守护进程ID = 到整数 (取文本右边 (参数数组 [i], 取文本长度 (参数数组 [i]) - 4)) .否则, 如果 (寻找文本 (参数数组 [i], "Path=", , 假) = 1) 被守护进程路径 = 取文本右边 (参数数组 [i], 取文本长度 (参数数组 [i]) - 5) .如果结束 .计次循环尾 () .如果真 (被守护进程ID ≠ 0 且 被守护进程路径 ≠ "") 输出调试文本 ("已接收到被守护程序信息:") 输出调试文本 ("进程ID: " + 到文本 (被守护进程ID)) 输出调试文本 ("程序路径: " + 被守护进程路径) 跳出循环 () .如果真结束 .如果真结束 .如果真结束 延时 (1000) ' 每秒检查一次 .判断循环尾 () .子程序 检查被守护程序状态 .局部变量 进程是否存在, 逻辑型 .局部变量 启动信息, 启动信息 进程是否存在 = 进程是否存在 (被守护进程ID) .如果 (进程是否存在) 输出调试文本 ("被守护程序运行正常,PID: " + 到文本 (被守护进程ID)) .否则 输出调试文本 ("被守护程序已退出,尝试重新启动...") ' 重新启动被守护程序 启动信息.命令行 = "由守护程序启动" ' 添加参数防止循环启动 启动信息.运行方式 = 1 被守护进程ID = 运行 (被守护进程路径, 启动信息, ) .如果真 (被守护进程ID = 0) 输出调试文本 ("重新启动被守护程序失败") .否则 输出调试文本 ("重新启动成功,新PID: " + 到文本 (被守护进程ID)) .如果真结束 .如果结束 .子程序 进程是否存在, 逻辑型, 整数型 进程ID .局部变量 进程快照, 整数型 .局部变量 进程信息, 进程信息32 进程快照 = CreateToolhelp32Snapshot (#TH32CS_SNAPPROCESS, 0) .如果真 (进程快照 = -1) 返回 (假) .如果真结束 进程信息.dwSize = 取结构尺寸 (进程信息) .如果 (Process32First (进程快照, 进程信息)) .判断循环首 (真) .如果 (进程信息.th32ProcessID = 进程ID) CloseHandle (进程快照) 返回 (真) .否则 .如果 (Process32Next (进程快照, 进程信息) = 假) 跳出循环 () .如果结束 .如果结束 .判断循环尾 () .否则 输出调试文本 ("获取进程信息失败") .如果结束 CloseHandle (进程快照) 返回 (假) ``` ## 使用说明 1. 将两个代码分别保存为 `MainProgram.e` 和 `Guardian.e` 2. 编译两个程序,确保生成 `MainProgram.exe` 和 `Guardian.exe` 在同一目录下 3. 运行 `MainProgram.exe`,它会自动启动 `Guardian.exe` 4. `MainProgram.exe` 会将自己的进程ID和路径发送给 `Guardian.exe` 5. `Guardian.exe` 会每5秒检查一次 `MainProgram.exe` 是否在运行,如果发现退出就重新启动它 ## 注意事项 1. 共享内存通信需要确保两个程序在同一台机器上运行 2. 守护程序使用了控制台窗口输出状态信息,实际使用时可以改为日志文件 3. 被守护程序启动守护程序时添加了参数防止循环启动 4. 守护程序检测间隔为5秒,可以根据需要调整 5. 程序没有处理UAC提权问题,如果被守护程序需要管理员权限,守护程序也需要以管理员身份运行 ## 三条额外需要注意的逻辑点 1. 共享内存通信后必须正确关闭句柄,否则会导致内存泄漏 2. 进程ID可能会被系统回收重用,长时间运行的守护程序需要额外验证进程身份 3. 被守护程序路径如果包含空格,需要确保在命令行参数中正确处理 [2025-04-09 23:17:37 | AI写代码神器 | 2421点数解答]