在我的WiX安装程序中,我想优雅地关闭即将运行的即将更新的应用程序。我不想提示用户关闭,我不想杀死进程。在关闭申请之前,我需要有机会进行一些清理等工作。
该应用是一个在系统托盘中运行的WinForms应用。主窗体有一个标题,比方说“mainwindow”,但是隐藏了并且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#Custom Action 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.
答案 0 :(得分:2)
如果正确理解Wix中的CloseApp CustomAction,您应该枚举进程中的所有窗口。
所以你需要实现一个EnumWindows(EnumCallBack,HANDLE processToClose) 在EnumCallBack中,实际上每个窗口都有PostMessage WM_CLOSE。