如何测试RegisterApplicationRestart()以应对更新导致的程序关闭?
MFC托盘程序更新关闭后的重启解决方案及测试方法
一、集成RegisterApplicationRestart()实现自动重启
在程序初始化阶段(比如CWinApp::InitInstance())调用RegisterApplicationRestart(),指定合适的重启条件,确保只有系统更新导致的关闭才触发重启:
#include <windows.h> #include <restartmanager.h> BOOL CYourTrayApp::InitInstance() { // 常规初始化代码... // 注册重启逻辑:仅在系统更新/补丁安装导致关闭时重启,忽略崩溃、挂起场景 HRESULT hr = RegisterApplicationRestart(NULL, RESTART_NO_CRASH | RESTART_NO_HANG | RESTART_NO_PATCH); if (FAILED(hr)) { TRACE(_T("RegisterApplicationRestart 调用失败,错误码: 0x%X\n"), hr); // 可写入日志记录失败信息 } return TRUE; }
参数说明:
RESTART_NO_CRASH:程序崩溃时不重启RESTART_NO_HANG:程序挂起时不重启RESTART_NO_PATCH:仅当系统安装更新/补丁触发关闭时才重启,完全匹配你的场景
二、测试RegisterApplicationRestart()的有效性
1. 模拟系统更新的关闭消息
编写工具程序,向你的托盘程序发送WM_QUERYENDSESSION和WM_ENDSESSION消息(带ENDSESSION_CLOSEAPP标记,对应更新场景):
#include <windows.h> #include <tlhelp32.h> HWND FindTrayAppMainWindow(const TCHAR* exeName) { HWND targetWnd = NULL; HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) return NULL; PROCESSENTRY32 pe32{sizeof(PROCESSENTRY32)}; if (Process32First(hProcessSnap, &pe32)) { do { if (_tcscmp(pe32.szExeFile, exeName) == 0) { EnumWindows([](HWND hWnd, LPARAM lParam) -> BOOL { DWORD procId; GetWindowThreadProcessId(hWnd, &procId); if (procId == (DWORD)lParam && IsWindowVisible(hWnd)) { *(HWND*)lParam = hWnd; return FALSE; } return TRUE; }, (LPARAM)&targetWnd); break; } } while (Process32Next(hProcessSnap, &pe32)); } CloseHandle(hProcessSnap); return targetWnd; } int _tmain(int argc, TCHAR* argv[]) { HWND trayWnd = FindTrayAppMainWindow(_T("YourTrayApp.exe")); if (!trayWnd) return 1; // 发送WM_QUERYENDSESSION,告知程序系统即将因更新关闭 BOOL canClose = SendMessage(trayWnd, WM_QUERYENDSESSION, 0, ENDSESSION_CLOSEAPP); if (canClose) { // 发送WM_ENDSESSION,确认关闭 SendMessage(trayWnd, WM_ENDSESSION, TRUE, ENDSESSION_CLOSEAPP); } return 0; }
编译运行该工具后,观察托盘程序是否关闭并自动重启,可通过日志记录启动/关闭时间、进程ID来验证。
2. 使用shutdown命令模拟重启提示
以管理员身份打开命令提示符,执行:
shutdown /r /t 30 /c "模拟系统更新重启" /d p:4:1
该命令会触发系统重启流程,发送WM_QUERYENDSESSION和WM_ENDSESSION消息给所有程序。此时点击重启提示的“取消”,但程序已收到关闭消息,若注册生效,程序会被关闭并重启。
三、模拟真实更新场景
1. 安装Windows可选预览更新
手动安装Windows可选预览更新(部分更新无需重启,但会关闭占用系统资源的程序),观察托盘程序是否被关闭后自动重启。
2. 用Restart Manager API模拟更新流程
直接调用Restart Manager的API,模拟系统更新时关闭程序并重启的逻辑:
#include <windows.h> #include <restartmanager.h> int _tmain() { DWORD sessionHandle; WCHAR sessionKey[CCH_RM_SESSION_KEY + 1]; HRESULT hr = RmStartSession(&sessionHandle, 0, sessionKey); if (FAILED(hr)) return 1; // 替换为你的托盘程序进程ID DWORD targetProcId = 1234; RM_PROCESS_INFO procInfo{0}; procInfo.dwProcessId = targetProcId; hr = RmRegisterResources(sessionHandle, 0, NULL, 1, &procInfo, 0, NULL); if (SUCCEEDED(hr)) { DWORD rebootReasons; // 关闭注册的程序 hr = RmShutdown(sessionHandle, RM_SHUTDOWN_REASON_INSTALLATION, &rebootReasons); if (SUCCEEDED(hr)) { // 重启程序 RmRestart(sessionHandle, 0, NULL); } } RmEndSession(sessionHandle); return 0; }
此方法完全复刻Windows更新时的处理逻辑,测试结果最贴近真实场景。
关键注意事项
- 程序需以对应权限运行:若托盘程序是管理员权限启动,Restart Manager会以相同权限重启它。
- 处理关闭逻辑:在
WM_QUERYENDSESSION消息中返回TRUE,表示程序可以安全关闭;若返回FALSE,Restart Manager可能会强制终止程序,但仍会触发重启。 - 系统版本限制:
RegisterApplicationRestart()仅支持Windows Vista及以上系统,XP及以下无法使用。
内容的提问来源于stack exchange,提问作者KokoCa
相关产品推荐
相关产品推荐

