在某些情况下,可能需要重启应用程序以应用某些更改。例如,可能希望在下载了文件的新版本或更改了应用程序的用户界面语言后重启应用程序。对于用户来说,不必手动重启应用程序会非常方便。最佳方法是询问用户是否需要立即重启或稍后重启。
本文将介绍一种通过几行代码轻松完成此任务的方法。
使用重启代码非常简单。首先,将 "RestartAPI.h" 包含在 "stdafx.h" 中,并将 "RestartAPI.cpp" 添加到 VC 项目中。
第二步是修改 main 或 WinMain 函数,如下所示。另一种方法是将重启初始化代码添加到应用程序的起始点,并将重启完成代码添加到退出点,例如在 WTL 应用程序中的 PreMessageLoop/PostMessageLoop。以下是修改后的 WinMain 函数的示例。
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow) {
// 初始化重启代码
if (RA_CheckForRestartProcessStart()) {
RA_WaitForPreviousProcessFinish();
}
// WinMain 代码在这里
// 完成重启过程(如果需要)
RA_DoRestartProcessFinish();
return 0;
}
第三步是确定想要初始化应用程序重启的点。在附带的示例中,这个点是按钮 "Restart Me!" 的点击处理程序。要重启应用程序,必须调用 RA_ActivateRestartProcess 函数并终止应用程序。
LRESULT CMainDlg::OnBnClickedRestart(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
// 初始化重启过程
if (!RA_ActivateRestartProcess()) {
::MessageBox(NULL, _T("Something Wrong"), _T("Restart App"), MB_OK|MB_ICONEXCLAMATION);
return 0;
}
// 终止应用程序。
CloseDialog(IDC_RESTART);
return 0;
}
宏:
#define RA_CMDLINE_RESTART_PROCESS TEXT("--Restart")
可以重新定义命令行开关以满足需求。使用此开关启动的重启应用程序:
#define RA_MUTEX_OTHER_RESTARTING TEXT("YOUR_RESTART-MUTEX_NAME")
互斥体唯一名称:
命名互斥体用于等待第一个进程实例的终止。互斥体名称必须是唯一的。为此,可以使用 GUID 来定义互斥体名称,如下所示:
#define RA_MUTEX_OTHER_RESTARTING TEXT("APPRESTART-E476AE82-AA92-11DA-ACE4-006098EFC07C")
可以重新定义互斥体名称以满足需求。
函数:
BOOL RA_CheckProcessWasRestarted();
如果进程已重启,则返回 TRUE。
BOOL RA_CheckForRestartProcessStart();
检查进程命令行是否有重启开关。调用此函数以检查它是否是重启实例。
BOOL RA_WaitForPreviousProcessFinish();
等待进程的前一个实例完成。
BOOL RA_DoRestartProcessFinish();
当进程完成时调用它。
BOOL RA_ActivateRestartProcess();
当需要重启应用程序时调用此函数。使用命令行 RA_CMDLINE_RESTART_PROCESS 启动进程的另一个副本。调用 RA_ActivateRestartProcess 后,必须关闭应用程序的活跃实例。
演示项目:
演示项目包括一个示例 WTL 对话框应用程序,演示了如何使用重启 API。从屏幕截图中,可以看到应用程序工作的一些阶段。
第一屏显示应用程序正常启动。在第二屏中,用户点击了 "Restart Me!" 按钮,可以看到伪终止进度。如果在那一刻运行任务管理器,将看到两个实例的 RestartableApp.exe。在最后一屏中,应用程序在重启后处于正常状态。