I want to have the installer/uninstaller remove a folder that contains content generated by the application at run time. I figured a Custom Action would be the way to go.
We are using WiX 3.6.
(I want it in the installer sequence for a specific reason that is not important to this question.)
Here is my CustomAction definitions in the xml:
<Binary Id="CustomActionLib" SourceFile="$(var.CustomActionLibrary.TargetDir)$(var.CustomActionLibrary.TargetName).CA.dll" />
<CustomAction Id="DeleteLocalizedCA" Impersonate="yes" BinaryKey="CustomActionLib" DllEntry="DeleteLocalized" Return="check" />
<CustomAction Id="DeleteResourcesCA" Impersonate="yes" BinaryKey="CustomActionLib" DllEntry="DeleteResources" Return="check" />
Here are my references to them:
<InstallExecuteSequence>
<Custom Action="DeleteLocalizedCA" Before="InstallFiles"/>
<FindRelatedProducts Before="LaunchConditions" />
<RemoveExistingProducts After="InstallFinalize" />
<RemoveShortcuts>Installed AND NOT UPGRADINGPRODUCTCODE</RemoveShortcuts>
</InstallExecuteSequence>
<InstallUISequence>
<Custom Action="DeleteLocalizedCA" Before="InstallFiles"/>
<FindRelatedProducts Before="LaunchConditions" />
</InstallUISequence>
I added the CustomActionLibrary project to the solution and added a reference to it from the installer project but it never runs, I never see it in the logs, nothing!
And thus my question, Why Don't my WiX Custom Actions Run?
After several hours of googling and reading (Blog posts, documentation, Stackoverflow, etc.) and testing I finally found a solution that none of my reading pointed to.
I had to put an InstallExecuteSequence to contain my references in a fragment that contained a ComponentGroup:
<Fragment>
<InstallExecuteSequence>
<Custom Action="DeleteLocalizedCA" Before="InstallFiles">NOT Installed</Custom>
</InstallExecuteSequence>
<ComponentGroup Id='StringsComponents'>
...
</ComponentGroup>
</Fragment>
The Fragment that I had previously put the CustomAction reference in only had steps but no Component or ComponentGroup so apparently doesn't do anything. (I am not the original author of the installer, just taking over for a co-worker who wasn't able to help me on this).
Hopefully this helps others who are struggling with the same issue.
Related
Firstly I should clarify that I am a novice and have been struggling to understand the WIX formatting, but by cobbling together examples found on-line, I now have the files installing fine so I next need to register my DLL.
I used the example here as a starting point: How to deploy a SharpShell-based shell extension via WiX? but it seems that the SharpShell tool srm.exe may not be getting called at installation.
If I manually call srm.exe as follows, it works as hoped i.e. the DLL is registered and my shell extension works.
srm install MyExtension.dll -codebase
I can also see that the registration has been successful via the Server Manager application that comes with SharpShell.
I can also manually uninstall with the following - not that this is particularly relevant to my problem but it at least confirms that the manual methods work:
srm uninstall MyExtension.dll
Here is a fragment of my WXS file. When I run the resultant MSI, the files are installed but the DLL is not being registered; confirmed via SharpShell's Server Manager. Where am I going wrong?
</Component>
<Component Id="SRMexe" Guid="C17BB61F-6471-46F9-AA87-2D14D2456632">
<File Id='srm' Name='srm.exe' DiskId='1' Source='..\MyExtension\packages\SharpShellTools.2.2.0.0\lib\srm.exe' KeyPath='yes'>
</File>
</Component>
<!-- TODO: Insert files, registry keys, and other resources here. -->
<!-- </Component> -->
</ComponentGroup>
</Fragment>
<Fragment>
<CustomAction Id="InstallShell" FileKey="srm"
ExeCommand='install "[INSTALLFOLDER]\MyExtension.dll" -codebase'
Execute="deferred" Return="check" Impersonate="no" />
<CustomAction Id="UninstallShell" FileKey="srm"
ExeCommand='uninstall "[INSTALLFOLDER]\MyExtension.dll"'
Execute="deferred" Return="check" Impersonate="no" />
<InstallExecuteSequence>
<Custom Action="InstallShell"
After="InstallFiles">
NOT Installed
</Custom>
<Custom Action="UninstallShell"
Before="RemoveFiles">
(NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
</Custom>
</InstallExecuteSequence>
</Fragment>
It doesn't look like you have any references to the Fragment with the CustomAction definitions so they are not linked into your final output MSI.
Add a CustomActionRef from your Product element to create the reference.
I'm working on a setup that validate many user inputs by a custom action. The event "DoAction" of publish control are doing very good job, but I figured out that no one custom validation are triggered if I execute the setup in silence mode.
I tried InstallExecuteSequence like the Yen Tran's blog (http://yentran.org/blog/2013/09/27/wix-executing-custom-action-before-starting-windows-service/) but still not working.
<Frament>
<Binary Id="CALibrary" SourceFile="$(var.Project.Installer.CustomAction.TargetDir)CustomAction.CA.dll" />
<CustomAction Id ="ProxyCheck" BinaryKey="CALibrary" DllEntry="Proxy" Execute="immediate" Return="check" />
<CustomAction Id ="ActivationCheck" BinaryKey="CALibrary" DllEntry="Activation" Execute="immediate" Return="check" />
</Frament>
...
<Fragment>
<InstallExecuteSequence>
<Custom Action="ActivationCheck" Before="InstallInitialize" Overridable="yes">PROXYSERVER</Custom>
</InstallExecuteSequence>
With Orca.exe I found that the action was not configured in InstallExecuteSequence no matter what I do. Reviewing all the files for the thousandth time, I found that I was putting the instruction of InstallExecuteSequence in a wrong place, moved into the <Product> </Product> and then everything works well.
I need to forcefully kill a process that is running in the background before attempting to delete any files, when running an Uninstall from an MSI created with Wix. The main application consist of a trayicon which reflects the status of the bg-process monitoring local windows services (made on C#, though this may not be so relevant going further).
I first tried the following:
<File Id='FooEXE' Name='Foo.exe' Source='..\Source\bin\Release\Foo.exe' Vital='yes' />
...
<InstallExecuteSequence>
<Custom Action="CloseTray" Before="InstallValidate" />
</InstallExecuteSequence>
...
<CustomAction Id="CloseTray" ExeCommand="-exit" FileKey="FooEXE" Execute="immediate" Return="asyncWait" />
The tray icon is immediately closed after confirming application-close dialog, but the Foo.Exe task still appears on the taskmgr after the uninstall completed. Also,the following error message was given:
Thats why, then I tried this:
<InstallExecuteSequence>
<Custom Action="Foo.TaskKill" Before="InstallValidate" />
</InstallExecuteSequence>
...
<CustomAction Id="Foo.TaskKill" Impersonate="yes" Return="asyncWait" Directory="WinDir" ExeCommand="\System32\taskkill.exe /F /IM Foo.exe /T" />
After obtaining the same result, tried:
<Property Id="QtExecCmdLine" Value='"[WinDir]\System32\taskkill.exe" /F /IM Foo.exe'/>
...
<InstallExecuteSequence>
<Custom Action="MyProcess.TaskKill" Before="InstallValidate" />
</InstallExecuteSequence>
...
<CustomAction Id="MyProcess.TaskKill" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="immediate" Return="ignore"/>
Sample which I took from here: How to kill a process from WiX
lately when all else failed, I also tried this without any success:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
...
<InstallExecuteSequence>
<Custom Action="WixCloseApplications" Before="InstallValidate" />
</InstallExecuteSequence>
...
<util:CloseApplication Id="CloseFoo" CloseMessage="yes" Description="Foo is still running!" ElevatedCloseMessage="yes" RebootPrompt="yes" Target="Foo.exe" />
This one gave me a different error:
I'm thinking on building a statue in honor to this process that just refuses to die!!! ... either that or think a problem on the application side exists, where I should add something like Application.Exit(); or Environment.Exit(0); at some line inside Program.cs.
Is there any other thing I could do at either Wix or my application to attempt closing it successfully at Uninstall?
Thanks!
Personally I think the best option for you to go with is the in-built CloseApplication method rather than your previous options.
The error you are getting for that (Error code 2762) is because you are trying to schedule the action in the immediate sequence but have the ElevatedCloseMessage="yes" set which triggers it as a deferred action. Either remove this attribute or schedule it in the deferred sequence.
I have a custom action to execute a custom action DLL but it is failing and I believe it's because it does not know how to read the strong name assembly
so I have this:
<Binary Id="StrongName" SourceFile="$(var.MyProject.TargetDir)MyProject.CA.dll"/>
<CustomAction Id="CreateIt"
BinaryKey="StrongName"
DllEntry="Create"
Execute="deferred"
Return="check"
HideTarget="no"
Impersonate="no" />
<CustomAction Id="RemoveIt"
BinaryKey="StrongName"
DllEntry="Remove"
Execute="deferred"
Return="check"
HideTarget="no"
Impersonate="no" />
<InstallExecuteSequence>
<Custom Action="CreateIt" Before="InstallFinalize">(NOT REMOVE = "ALL")</Custom>
<Custom Action="RemoveIt" Before='InstallFinalize'>(NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")</Custom>
</InstallExecuteSequence>
So how do I reference the signature as I execute this DLL?
I assume from the *.CA.DLL nomenclature that you are using that this is a DTF custom action. This is a native encapsulated DLL that hosts your managed DLL. Being native, it can't be strong named.
Log the install and look through the log for the reason it is failing.
The solution to my problem was a security issue caused by an obsolete library which is not supported in .NET 4 and it is a different topic so I will not go into detail on it unless someone is curious.
Is it possible to sequence a custom action before "LaunchConditions"?
This is my custom action:
<CustomAction
Id="CA_vcAppRunning"
BinaryKey="vcShowMsg"
DllEntry="IsAppRunning"
Return="check"
Execute="immediate"/>
Sequenced in <InstallExecuteSequence/>
<Custom Action="CA_vcAppRunning" Before="LaunchConditions" />
I tried this, opened the MSI file in Orca and found that my custom action is sequenced at "99".
But when I tried to install, it never got called.
I want to schedule this before LaunchConditions as this custom action is supposed to set a property which is used in the LaunchCondition (if the application is running, exit the installer/updater).
Don't schedule it in before LaunchConditions, schedule it after FindRelatedProducts and then add a second custom action that blocks install based on the results from your first CA.
This is the same method used to prevent downgrading in many tutorials, e.g.
<CustomAction Id="CA_BlockOlderVersionInstall" Error="!(loc.LaunchCondition_LaterVersion)" />
<InstallExecuteSequence>
<LaunchConditions After="AppSearch" />
<Custom Action="CA_BlockOlderVersionInstall" After="FindRelatedProducts">
<![CDATA[NEWERVERSIONDETECTED]]>
</Custom>
</InstallExecuteSequence>
<InstallUISequence>
<LaunchConditions After="AppSearch" />
<Custom Action="CA_BlockOlderVersionInstall" After="FindRelatedProducts">
<![CDATA[NEWERVERSIONDETECTED]]>
</Custom>
</InstallUISequence>