在使用 wix 卸载之前关闭系统托盘应用程序

Posted

技术标签:

【中文标题】在使用 wix 卸载之前关闭系统托盘应用程序【英文标题】:Close a systemtray app before uninstalling using wix 【发布时间】:2014-10-09 14:56:37 【问题描述】:

我知道过去有人问过类似的问题,但我至今仍未找到解决问题的方法。

我有一个正在运行的系统托盘应用程序,我想在卸载开始之前关闭它并显示“FileInUse”对话框,但无论我在做什么似乎都不起作用。为了关闭我的系统托盘应用程序,我需要在安装它的文件夹中创建一个文件。然后应用程序会删除该文件并自行关闭。

根据我的尝试,我遇到了以下问题:

1) 显示“FileInUse”对话框。不好

2) 未能调用我的自定义操作,该操作创建一个文件来通知我的系统托盘应用程序它应该关闭。

Error   1   ICE77: CloseAgentMonitor is a in-script custom action.  It must be 
sequenced in between the InstallInitialize action and the InstallFinalize action in 
the InstallExecuteSequence table

3) 如果我将应用程序文件夹设置为 Immediate 而不是 Immediate,则无法将我的应用程序文件夹作为 CustomData 参数传递给 CustomAction,但如果我将其设置为 Deferred,则会收到中提到的错误2)

4) 我尝试了在 RemoveFilesInstallValidateInstallFinalize 之前调用自定义操作的不同场景。

由于我不确定什么是正确的序列,有人可以告诉我如何以及何时调用我的 CustomAction 以便触发“删除”按钮关闭或文件开始被删除之前。

我想在卸载文件时以及在显示FileInUse 对话框之前执行此操作。

请注意,我可以在静默卸载或可视卸载中处理此问题,这一点非常重要。

谢谢。

更新:

我可能应该发布我的 wix 代码:

<!-- Set variables required by the CloseAgentMonitor CustomAction -->
<CustomAction Id="CloseAgentMonitorSetProp"
      Return="check"
      Property="CloseAgentMonitor"
      Execute="immediate"
      Value="APPLICATIONFOLDER=[APPLICATIONFOLDER]" />

<!-- Define CustomAction to close the Agent on uninstall -->
<CustomAction Id="CloseAgentMonitor"
      Return="check"
      Execute="immediate"
      BinaryKey="CustomActions.CA"
      DllEntry="CloseAgentMonitor" />


<InstallExecuteSequence>
  <!- Make sure to set the props before the CloseAgentMonitor custom action -->
  <Custom Action="CloseAgentMonitorSetProp" Before="CloseAgentMonitor">
    <![CDATA[(Installed AND NOT UPGRADINGPRODUCTCODE)]]>
  </Custom>

  <Custom Action="CloseAgentMonitor" Before="InstallValidate">
    <![CDATA[(Installed AND NOT UPGRADINGPRODUCTCODE)]]>
  </Custom>
  ...

CustomAction 更改为立即并将其设置为在InstallValidate 解决2 中提到的问题之前调用它,但它带回了第3 点中提到的错误,似乎我的CustomActionData 不是设置,甚至认为它应该是因为它在CustomAction之前被调用。

你可以从我的日志中清楚地看到它是:

MSI (s) (30:08) [16:22:47:148]: Doing action: CloseAgentMonitorSetProp
MSI (s) (30:08) [16:22:47:148]: Note: 1: 2205 2:  3: ActionText 
Action 16:22:47: CloseAgentMonitorSetProp. 
Action start 16:22:47: CloseAgentMonitorSetProp.
MSI (s) (30:08) [16:22:47:148]: PROPERTY CHANGE: Adding CloseAgentMonitor property. 
Its value is 'APPLICATIONFOLDER=C:\Program Files (x86)\Company\Client\'.
Action ended 16:22:47: CloseAgentMonitorSetProp. Return value 1.

但是正如你所看到的,当我的CustomAction 被调用时,它会在尝试访问APPLICATIONFOLDER 时触发错误。

MSI (s) (30:08) [16:22:47:148]: Doing action: CloseAgentMonitor
MSI (s) (30:08) [16:22:47:148]: Note: 1: 2205 2:  3: ActionText 
Action 16:22:47: CloseAgentMonitor. 
Action start 16:22:47: CloseAgentMonitor.
MSI (s) (30:1C) [16:22:47:148]: Invoking remote custom action. DLL: 
C:\Windows\Installer\MSI57B2.tmp, Entrypoint: CloseAgentMonitor
MSI (s) (30:C0) [16:22:47:148]: Generating random cookie.
MSI (s) (30:C0) [16:22:47:148]: Created Custom Action Server with PID 2528 (0x9E0).
MSI (s) (30:F4) [16:22:47:195]: Running as a service.
MSI (s) (30:F4) [16:22:47:195]: Hello, I'm your 32bit Impersonated custom action server.
SFXCA: Extracting custom action to temporary directory: C:\Windows\Installer\MSI57B2.tmp-\
SFXCA: Binding to CLR version v4.0.30319
Calling custom action CustomActions!CustomActions.CustomActions.CloseAgentMonitor
CloseAgentMonitor - Start
IsAgentMonitorRunning - Start
Checking if  Agent Monitor is running.
Agent Monitor running: True
IsAgentMonitorRunning - End
Checking CustomActionData - Start
Checking CustomActionData - End
Exception thrown by custom action:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of 
an invocation. ---> System.Collections.Generic.KeyNotFoundException: The given key was 
not present in the dictionary. at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at Microsoft.Deployment.WindowsInstaller.CustomActionData.get_Item(String key)
at CustomActions.CustomActions.CloseAgentMonitor(Session session)
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object arguments, Signature sig,
Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object parameters, 
Object arguments)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder 
binder, Object parameters, CultureInfo culture)
at Microsoft.Deployment.WindowsInstaller.CustomActionProxy.InvokeCustomAction(Int32
sessionHandle, String entryPoint, IntPtr remotingDelegatePtr)
CustomAction CloseAgentMonitor returned actual error code 1603 (note this may not be 100%
accurate if translation happened inside sandbox)
Action ended 16:22:47: CloseAgentMonitor. Return value 3.
Action ended 16:22:47: INSTALL. Return value 3.

【问题讨论】:

【参考方案1】:

我想通了!!

我不敢相信事情就这么简单!当我所要做的就是将session.CustomActionData["APPLICATIONFOLDER"] 更改为session["APPLICATIONFOLDER"] 时,花几个小时研究它。

我最初开始使用会话变量,但遇到了各种问题,所以我最终使用了CustomActionData,但我刚刚检查了一下,我的所有自定义操作都被推迟到现在。

因此,如果我正确获取 Wix,您应该在延迟 CustomAction 中使用 CustomActionData,并且您应该在即时 CustomAction 中使用会话变量。

所以自定义操作中的代码应该是:

string applicationFolder = session["APPLICATIONFOLDER"];

而不是

string applicationFolder = session.CustomActionData["APPLICATIONFOLDER"];

希望这对其他人有帮助!

【讨论】:

【参考方案2】:

使用中的文件检测由 InstallValidate 操作执行,该操作在 InstallInitialize 之前。假设您的代码可以正常工作,请将其作为即时自定义操作运行,并且在 InstallValidate 之前应该可以。

为什么需要在同一个文件夹中创建文件?它似乎与您的文件使用问题无关。关闭正在运行的应用程序的常用方法是向其发送关闭消息。 WiX 有一个 CloseApp 自定义操作可以做到这一点。

还有这个,它说了类似的话:

WiX close application before uninstall - close open applications message

【讨论】:

我会试试看的。我创建 .exit 文件的原因是关闭我的应用程序,因为发送 WM_CLOSE 消息似乎对我不起作用,CloseApp 也不起作用。我认为这是一种快速简便的解决方法,看起来效果很好,所以我想我会这样做。无论如何,我会尝试你的建议并恢复。谢谢。 如果托盘应用程序对关闭没有很好的响应,那会很痛苦工作。 我同意,但是这个系统托盘应用程序并没有被很多客户使用,并且是可选的,它的优先级很低。我正在尝试将其包含在内,因此最终会更频繁地使用它,但不幸的是,这不会改变我的优先级。最终我会调查它并尝试使用适当的 WM_CLOSE 消息来关闭它。 我刚刚更新了我的答案。如您所见,问题 2 消失了,但问题 3 发生在我的变量没有被设置/传递给自定义操作的地方。如果您查看我的脚本,我已经记录了一个`Checking CustomActionData - Start` 消息,然后,有一个Checking CustomActionData - End,但两者之间没有任何内容。这包含一个应该输出正在传递的变量的循环,但没有一个甚至认为 CloseAgentMonitorSetProp 设置为在 CustomAction 之前调用 您需要立即执行自定义操作,但他们不使用 CustomActionData。

以上是关于在使用 wix 卸载之前关闭系统托盘应用程序的主要内容,如果未能解决你的问题,请参考以下文章

如何从另一个应用程序关闭 WPF 系统托盘应用程序?

如何在卸载时立即生成WIX执行命令

Wix 自定义卸载操作 - 如何在 msi 删除文件之前运行

卸载 WiX 时删除文件

WIX安装项目未完全卸载应用程序

开发一个简单的Windows系统托盘桌面应用程序来使用.NET Web服务