Close a systemtray app before uninstalling using w

2019-09-07 12:05发布

问题:

I know similar questions have been asked in the past but I still haven't managed to find a solution to my problem as of yet.

I've got a system tray app that's running and I want to close it before uninstall begins and displays the "FileInUse" dialog but whatever I'm doing doesn't appear to work. In order to close my system tray app, I need to create a file in the folder where it is installed. The app then deletes the file and closes itself.

I'm getting the following issues depending on what I've tried:

1) The "FileInUse" dialog gets displayed. No good

2) Failing to call my custom action which create a file to notify my system tray app that it should close.

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) Fails to pass my application folder as a CustomData parameter to the CustomAction if I set it to Immediate instead of Immediate but if I set any it to Deferred, I get the error mentioned in 2)

4) I've tried different scenarios from calling the custom action before RemoveFiles, InstallValidate, InstallFinalize.

As I'm not sure what are the correct sequences, can someone tell me how and when to call my CustomAction so that it is triggered the "Remove" button is closed or before the files starts to get removed.

I want to do this when uninstalling the files and before the FileInUse dialog is displayed.

Note that it's really important that I can handle this in both silent or visual uninstall.

Thanks.

UPDATE:

I probably should have posted my wix code:

<!-- 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>
  ...

Changing the CustomAction to immediate and set it to be called before InstallValidate sorts out the problem mentioned in 2, but it brings back the error mentioned in point 3, where it appears that my CustomActionData is not being set, even thought it should be since it is called before the CustomAction.

You can clearly see from my logs that it is:

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.

But as you can see when my CustomAction is called, it triggers an error when trying to access the 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:

I figured it out!!

I can't believe it was that simple! Spend hours looking into it when all I had to do, was change the session.CustomActionData["APPLICATIONFOLDER"] to session["APPLICATIONFOLDER"].

I originally started using the session variables but hit various problems so I ended up using CustomActionData but I've just checked and all my custom action were deferred up to now.

So if I get Wix correctly, you should use CustomActionData in deferred CustomAction and you should use the session's variables in immediate CustomAction.

So code in your custom action should be:

string applicationFolder = session["APPLICATIONFOLDER"];

instead of

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

Hope this helps someone else!



回答2:

The files in use detection is performed by the InstallValidate action, which is before InstallInitialize. Assuming your code works ok, run it as an immediate custom action, and before InstallValidate should be ok.

Why do you need to create a file in that same folder? It doesn't seem related to your files-in-use problem. The usual method of closing a running app is to send it a close down message. WiX has a CloseApp custom action that will do that.

And there's this, which says similar things:

WiX close application before uninstall - close open applications message