【发布时间】: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