65.9K
CodeProject 正在变化。 阅读更多。
Home

Windows 应用程序的 Restart Manager 支持

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (8投票s)

2014年5月16日

CPOL

4分钟阅读

viewsIcon

29410

downloadIcon

593

Windows 应用程序的 Restart Manager 支持

引言

我一直在网上查找关于如何为一个在 C#.NET 中为 Windows VISTA 及更高操作系统开发的 Windows 窗体应用程序添加 Restart Manager 支持的优秀文章,但我找不到任何好的文章,于是决定自己写一篇。

Restart Manager

这是 Microsoft 提供的一项功能,它允许用户安全地更新用户系统上正在运行的应用程序软件。 Restart Manager 随 Windows Vista 和 Windows Server 2008 操作系统一起引入。

Restart Manager 提供了一组 API,这些 API 可供 Windows Installer 4.0 或更高版本以及它打算安全升级的应用程序使用,而不会丢失其正在执行的任何关键工作。

在 Restart Manager 出现之前,如果用户需要更新正在运行的应用程序,他必须手动停止应用程序,运行更新安装程序,然后再次启动应用程序。这听起来很简单,但是如果安装程序更新了一套应用程序/服务,那么用户必须停止并启动其中的每一个。

Restart Manager 通过将责任从用户转移到应用程序本身来解决上述问题,使应用程序在更新时能够自动重启。使用 Restart Manager 还可以减少更新多个应用程序时所需的重启次数。

本文主要关注如何使 C#.NET Windows 窗体应用程序支持 Restart Manager,允许 Windows Installer 重启它。有关如何创建安装程序的更多详细信息,请参阅 MSDN 主题 使用 Restart Manager

使 WinForm 应用程序支持 Restart Manager

这是一个三步过程,下面将详细介绍

第一步:注册您的应用程序

为了让 Restart Manager 重启应用程序,它必须在操作系统中注册。这是通过调用 kernel32.dll 中提供的 RegisterApplicationRestart 方法来完成的。由于我们的代码是托管代码,我们需要导入本地方法。

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern uint RegisterApplicationRestart(string pszCommandline, int dwFlags);  

在上面附带的示例程序中,我已将本地方法封装在 RestartManagerWrapper 类中。

现在我们可以将我们的应用程序注册到操作系统,这通常在构造函数中完成。

public MainApplicationForm()
{
    InitializeComponent();

    //Regsiter your application for restart
    if (RestartManagerWrapper.IsRestartManagerSupported)
    {
        string commandLine = null;

        RestartManagerWrapper.RegisterApplicationRestart(commandLine, ApplicationRestartFlags.NONE);

    }//End-if (RestartManagerWrapper.IsRestartManagerSupported)        
} 

第二步:通过监听应用程序重启消息来保存应用程序状态

如果应用程序需要保存当前状态以便在不丢失任何关键工作的情况下重启,那么我们需要监听重启消息。这是通过重写 Form 类中的 WndProc 来完成的。

 protected override void WndProc(ref Message m)
 {
     base.WndProc(ref m);
 
     //Check for shutdown message from windows
     if (m.Msg == WindowsMessages.WM_QUERYENDSESSION ||
         m.Msg == WindowsMessages.WM_ENDSESSION)
     {
          if (m.LParam.ToInt32() == LParameter.ENDSESSION_CLOSEAPP)
          {
            //Save application state so it can be restored when its restarted.              
 
          }//End-if (m.LParam.ToInt32() == LParameter.ENDSESSION_CLOSEAPP)
 
     }//End-if (m.Msg == WindowsMessages.WM_QUERYENDSESSION ||
          //    m.Msg == WindowsMessages.WM_ENDSESSION)
  }

第三步:恢复应用程序状态(可选)

应用程序重启后,可能需要恢复到关闭前的状态。这可能需要根据第二步中保存的信息来完成,并且我们可以通过在注册应用程序时在第一步中传递所需参数来知道它是否通过 Restart Manager 重启。

测试支持 Restart Manager 的应用程序

要测试您的应用程序是否会按需重启,您可以使用 Microsoft 提供的 Windows 徽标测试工具,可以通过此 链接 下载。

安装测试工具后,您需要打开命令提示符并导航到 C:\Program Files\Microsoft Corporation\Logo Testing Tools for Windows\Restart Manager。然后,根据您的处理器架构,您需要选择 AMD64x86。我的机器是 x86。

Command Prompt

现在启动您的测试应用程序,并从任务管理器中获取 PID(进程标识符)。在上面的命令提示符中键入以下命令。

>RMTool.exe -p 682408 -S -R

命令参数说明如下
  • -p 接受 PID 以了解需要重启的应用程序实例。 -pPID 之间必须有一个空格。
  • -S 表示应用程序需要关闭。
  • -R 表示应用程序关闭后需要重启。

RMTool.exe 将启动到指定应用程序的关闭和重启序列,并显示每个步骤的结果,如下所示。


如果发生错误,将显示给用户,如下所示。根据关闭或重启错误的阶段,您可能需要修复您的应用程序。

关注点

遇到的问题

  1. 当我在一个 C#.NET 应用程序中添加 Restart Manager 支持时,我必须在主窗体的 FormClosed 事件中关闭我的应用程序创建的所有 BITS 作业,然后才能终止。当 Restart Manager 尝试关闭我的应用程序时,它抛出了一个异常,错误消息为:'由于应用程序正在分派输入同步调用,因此无法进行出站调用。(来自 HRESULT 的异常: 0x8001010D (RPC_E_CANTCALLOUT_ININPUTSYNCCALL))。'
    看起来我们在 Restart Manager 关闭过程中无法访问 COM 服务,因为当用户关闭应用程序时相同的代码可以正常工作。如果有人有解决此问题的方法,请与我联系。
© . All rights reserved.