【问题标题】:Gracefully close application before installing through Wix managed custom action在通过 Wix 托管的自定义操作安装之前优雅地关闭应用程序
【发布时间】:2011-02-08 23:27:28
【问题描述】:

在我的 WiX 安装程序中,如果它仍在运行,我想优雅地关闭即将更新的应用程序。我不想提示用户关闭,也不想终止进程。在关闭应用程序之前,我需要有机会进行一些清理等。

该应用是在系统托盘中运行的 WinForms 应用。主窗体有一个标题,例如“主窗口”,但它是隐藏的,并且 ShowInTaskbar = false。

通过尝试使用Process.Kill() Process.CloseMainWindow() FindWindow, SendMessage, PostMessage 等一些不同的测试应用程序,我发现对我来说最好的方法是使用PostMessage

var hWnd = FindWindow(null, "mainwindowtitle");
PostMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);

这样我可以覆盖 OnFormClosing 并执行我需要的任何清理。这在我放在一起的测试器应用程序中运行良好。问题是它在 WiX 安装程序中运行时不起作用。我有一个 c# 自定义操作 CA.dll,安装程序肯定会调用自定义操作 - 我可以从 msiexec 日志中看到,如果我将自定义操作代码更改为 Process.Kill(),它确实会正确停止应用程序。但是,当它使用PostMessage 代码运行时,应用程序不会关闭,并且永远不会调用 OnFormClosing。

这是我的 CustomAction 代码

        private const int WM_CLOSE = 0x0010;

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll", SetLastError = true)]
    static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    [CustomAction]
    public static ActionResult CloseApplicationGracefully(Session session)
    {
        session.Log("Starting the CloseApplicationGracefully Custom Action - attempting to stop DUC.");

        var hWnd = FindWindow(null, "mainwindowtitle");

        session.Log("Window handle found: " + hWnd);

        bool result = PostMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);

        session.Log("Result of calling app to close: " + result);

        if (result)
        {
            return ActionResult.Success;
        }
        return ActionResult.Failure;
    }

这里是 wx 设置代码

<Binary Id="WixCustomAction.dll"
        SourceFile="$(var.WixCustomAction.TargetDir)$(var.WixCustomAction.TargetName).CA.dll" />
<CustomAction Id="WixCustomAction"
              BinaryKey="WixCustomAction.dll"
              DllEntry="CloseDeploymentUpdater" />
<InstallExecuteSequence>
  <Custom Action="WixCustomAction" After="FindRelatedProducts"></Custom>
</InstallExecuteSequence>

我尝试过以不同的顺序调用此自定义操作,但没有成功... 当我使用 Process.Kill 时,代码在测试应用程序中工作,自定义操作有效,但在自定义操作中代码不起作用 - 必须是事件序列?

编辑

使用如下建议的 WixCloseApplications CA 在答案中产生以下日志条目

WixCloseApplications:  App: DUC.exe found running, 1 processes, attempting to send close message.
WixCloseApplications:  Sending close message to process id 0x1978
WixCloseApplications:  Result 0x12
WixCloseApplications:  Sending close message to process id 0x1978
WixCloseApplications:  Result 0x0
WixCloseApplications:  Sending close message to process id 0x1978
WixCloseApplications:  Result 0x578
WixCloseApplications:  Sending close message to process id 0x1978
WixCloseApplications:  Result 0x0
.
.
.
MSI (s) (C8!D4) [15:00:47:985]: PROPERTY CHANGE: Adding WixCloseApplicationsDeferred property. Its value is 'DUC.exe5'.
MSI (s) (C8!D4) [15:00:48:000]: Doing action: WixCloseApplicationsDeferred
.
.
Action 15:00:48: WixCloseApplicationsDeferred. 
Action start 15:00:48: WixCloseApplicationsDeferred.
.
.
Action ended 15:00:48: WixCloseApplicationsDeferred. Return value 1.
Action ended 15:00:48: WixCloseApplications. Return value 1.

【问题讨论】:

  • 您是否尝试过在自定义操作中调用 SendMessage 而不是 PostMessage?
  • @Vijay Sirigiri 是的 - 我尝试了 SendMessage(使用 SC_CLOSE),这再次在我的测试应用程序中工作,但不是来自 WiX 安装程序。有趣的是,OnFormClosing 的 EventArgs 有一个 CloseReason 枚举,而 PostMessage 使用 WM_CLOSE 使它看起来原因是任务管理器请求关闭,而带有 SC_CLOSE 的 SendMessage 使它看起来像用户请求关闭。
  • @rene 我可以得到一个有效的句柄,但 PostMessage 的结果是假的,所以由于某种原因它不能正常工作。 MSDN 建议不要将 WM_QUIT 与 PostMessage 一起使用。无论如何我都会尝试看看会发生什么,但我怀疑在这种情况下 OnFormClosing 事件不会触发。
  • @Peter Kelly 你能添加对 GetLastError 的调用并记录结果吗?
  • @rene GetLastError 返回 997 正在查找...

标签: c# wix pinvoke wix3 custom-action


【解决方案1】:

如果正确理解来自 Wix 的 CloseApp CustomAction,您应该枚举进程中的所有窗口。

http://wix.codeplex.com/SourceControl/changeset/view/175af30efe78#src%2fca%2fwixca%2fdll%2fCloseApps.cpp

所以你需要实现一个 EnumWindows(EnumCallBack, HANDLE processToClose) 而在 EnumCallBack 你实际上 PostMessage WM_CLOSE 为每个窗口。

【讨论】:

  • 有助于指向 CloseApp 的源代码,但这不是内置 CA WixCloseApplications 使用的吗?我已经尝试过了,它关闭了应用程序,但没有优雅地关闭,即 OnFormClosing 事件没有被触发。
  • @Peter Kelly 我在想 MSI 是否在提升或 CA 是否被推迟。能发个日志吗? msiexec /i [你的 msi] /l*vx logfile.log
  • @rene 我在使用 util:CloseApplication 后发布了一些日志条目。延期有什么影响?
  • Util:CloseApplication 向您指定的应用程序窗口发送 WM_CLOSE 消息。该应用程序如何对该消息进行子类化是该应用程序问题而不是 WiX 的问题。
  • @Christoper Painter 我不确定您所说的“子类化该消息”是什么意思,但如果您认为问题与 WiX 无关,那么为什么自定义操作可以在简单的测试应用程序中完美运行,但是不是从 WiX 调用时?你能建议另一种方式来做我想要实现的目标吗?从 WiX 优雅地关闭 WinForms 系统托盘应用程序?谢谢!
猜你喜欢
  • 2019-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多