WiX CloseApplication for exe and dll - wix

I've created a WiX setup project based on the article WiX 3 Tutorial: Understanding main WXS and WXI file mainly because it gives the WiX needed to do an application shutdown.
However, I'm puzzled by the outcome. Here's the situation:
We have an executable which uses a dll and create a setup which installs the executable and the dll. We execute the setup.
CASE 1: Next, we change the executable and NOT the dll and create the setup again. Then we start the installed application and make sure also the dll is loaded. If we now execute the second setup, a dialog is shown asking the user to shutdown the executable just as we expected.
CASE 2: But if we do not change the application but only the dll and then execute the setup while the application is running and the dll is loaded, no dialog is shown. At the end of the setup a dialog appears asking if we want to restart the computer.
Is this expected behaviour and how can I force the application shutdown dialog of CASE 1 also when only a dll is changed as in CASE 2? I do not want the user having to restart the computer because the application is running on a server which cannot be restarted.

This is all determined by Windows Installer during the costing process. The installer decides which files need to be installed / updated and calculates how much disk space is needed and if there are any file locks. If there are file locks, it attempts to resolve the lock to a process with a window handle. If it can do this, you'll get the dialog. If it can't, you won't. This doesn't mean a reboot won't be needed, it just can't give you useful information on how to avoid it.
A few additional points:
Make sure you are versioning your EXE and DLL. If the old DLL is 1.0.0.0 and the new DLL is 1.0.0.0 costing will say "Nothing to do here".
How does the EXE use the DLL at runtime? It might simply not have a lock on it during the entire life of the process.
Understand that MSI's reboot behavior can be altered through the use of properties such as REBOOT=ReallySuppress
Here's some good articles to read:
InstallValidate
FileInUseDialog
System Reboots

I haven't checked the code but I think what is happening is the CloseApplication action is not running because it sees that the exe hasn't changed. As far as I am aware you cannot target a DLL with CloseApplication. If you run your install with logging you should be able to see if the action is triggered. I am assuming you have RemoveExistingProducts schedule late in the install, if you were to move it after InstallValidate it would remove the exe every time and therefore trigger the action.

Related

Windows per-machine install requires reference to original installer when second user runs application

I'm working on an MSI installer written in Wix. The installer works in both per-user, and per-machine contexts.
In a per-machine installation, everything goes smoothly; the product is installed and configured for the initial user. Upon switching to a test user, the application appears in the start menu correctly. Running it for the first time, a msiexec process starts with the message that the app is being configured. However, if the original .msi has been deleted, this process fails.
The failing setup action gives the following message in its log:
Error 1706. An installation package for the product myProduct cannot be found. Try the installation again using a valid copy of the installation package 'myInstaller.msi'.
=== Logging stopped: 3/16/2017 11:15:52 ===
I understand from reading a blog post by Rob Mensching (Lead of Wix) that it probably isn't possible to just edit the source list to point towards the windows cached .msi, a point backed up by another article I've found. Is that correct?
Is there a way to stop this entire action of calling the msi on first run by users from happening? Caching the msi or keeping the original is not ideal, I'd like to use the .msi in a custom bootstrapper that involves deleting the msi once installation is complete.
Microsoft recommends you keep the original MSI available, Rule 31:
https://blogs.msdn.microsoft.com/windows_installer_team/2006/05/24/tao-of-the-windows-installer-part-3/
and I won't repeat what it says about repair/resiliency, but you cannot guarantee the source MSI won't be needed sometime.
You're probably getting this "repair" because there is some resource (a file most likely) that is being installed to a user-profile location. When another user logs on and uses the application that file is missing, so potentially the application is broken. For example a file installed to User's Application Data needs to be available for all users of the system, not just the user that installed it.
So keeping the MSI might not be ideal but is strongly recommended, and in your case of product use by multiple users it's even more likely to required. There should be an Application Event log entry under MsiInstaller that says something about the missing resource.

Installer stopping service and giving file in use warning

I have a WiX installer project which installs a client app and a windows service. It is set to stop the service during install. However it still shows the error window "The following applications are using files which the installer must update" with the "Try Again", "Continue" and "Cancel" options. If I choose continue and inspect the windows event logs for the installer it shows the service being stopped and started again. The StopServices element is in the recommended sequence position.
How can I avoid the error window?
[Edit] My understanding is that it doesn't matter what order the files are listed as windows installer stops the service before copying any of them. I had wondered whether the service exe needed to be listed first.
Best solution: Use the "ServiceInstall" and "ServiceControl" elements to ensure the service is stopped/started (and installed/uninstalled) correctly.
In fact in our installer the app and service were being stopped/started from within custom installer code. However the check for whether the files are in use occurs before the custom installer code is run. So the files are in use when the installer starts, but are not in use by the time the installer attempts to copy the files. So annoying to the user, but not actually an issue. And if installed using msiexec.exe in quiet mode then the install succeeds.
Furthermore we had another issue with the service returned from the shutdown call, prior to actually having shutdown. (As commented by #PhilDW).

VS Setup Project - Installing Assemblies to GAC and starting a service that uses them all in one installation

I've read every stackoverflow article on MSI installations, but I cannot find the solution to my problem:
I have a VS2010 solution with 5 projects, all targeting .NET 2.0:
DLL A, no project references
DLL B, references DLL
A Windows Forms App, references DLL B
Windows Service, references DLL B
Setup Project
DLL A and DLL B are set up as to be installed to the GAC at install time. I'd like to start the service once the installation has finished, but according to what I've read, the assemblies are not registered until the very last step. I have proven this by attempting to start the service on the AfterInstall event of my ServiceInstaller class and I get the following error:
Error 1001. Could not load file or
assembly 'DLL_B', version 1.0.0.1,
Culture=neutral,
PublicKeyToken=5e297270603814f4' or
one of its dependencies. The system
could not find the file specified.
But of course, once installation is complete, I can manually start the service and it runs fine. Also, in Windows XP, I can usually have the service started at application launch (I have a checkbox with Launch Application as the last step of the installer). But in Windows 7, permissions are no longer elevated at that time and starting the service throws an error.
How can I achieve the installation and starting of the service without forcing a reboot? To quote my client: "Its 2011 now and that shouldn't be necessary.", and I agree whole-heartedly.
Thanks ahead of time.
This is a well-known issue with the GAC. One option might be to use two separate installers and daisy-chain them. This is the way we have chosen to get around the problem of deploying Microsoft VC runtimes on Vista and later. If you use the merge modules, any services that depend on them won't start. So in effect you put your GAC-destined components in a pre-installer whose transaction will be completed and committed before you run a second install that installs and starts the services that depend on them. Ugly, I know, but better than a reboot.
A solution is to use a custom action which runs after InstallFinalize in InstallExecuteSequence table. This custom action should use the msidbCustomActionTypeAsync and msidbCustomActionTypeContinue flags so it runs in a separate process after the installation is finished.
This cannot be done with a Visual Studio setup project, but there are a lot of alternatives: Orca, WiX, a commercial setup authoring tool etc.
I worked around this issues slightly differently: I installed my assemblies not only in GAC, but also into the Application Folder. My GAC-bound assemblies were already found as dependencies, so I put those into GAC (and those indeed end up there only after all custom steps executed). I also added same assemblies as primary output to the Application Folder, where my InstallHelper DLL with custom actions also resides. This way during installation local copy from Application Folder is used.

How to tell MSI to upgrade locked dll's and avoid reboots

I have MSI installer which installs product and this product has several widely used API dll's.
These dll's may be loaded into processes that I cannot control during upgrade (for instance, I cannot ask user to close explorer.exe or svchost).
So, during MSI upgrade these dll's are locked and cannot be upgraded without reboot. I need to make it upgradeable without reboot.
These API dll's are very stable and it is acceptable to leave old copies working in old processes when new versions of these dll's will be loaded into new running processes.
So, when we didn't use MSI then we just used standard trick - rename file, mark it to delete on reboot, write new file.
What is the best way how to do it in MSI?
Should I create custom action which will do this standard trick?
Or maybe MSI has some better way to do it?
Thank you!
The processes are "locked" because they're in-use, and you can't change an executable file while it's running; there is no "unlock" but to stop using the file. So either you kill the processes now or use the PendingFileRename key to change the file after a reboot...
You could perhaps try to kill the handles/threads that explorer.exe et al have to hold onto your DLLs (using a custom action), which might work for a minute... but that would ensure that (a) your newly upgraded DLLs won't work until after a restart either, and (b) you've probably made the user's computer unstable and Explorer could crash at any moment. Either way, the end users would not be pleased with your software... must worse than they would be annoyed at having to reboot.

Wix / MSI : Unable to uninstall

I've developed a Wix installer for an internal project however entirely by accident I've found that I'm unable to uninstall the installer on my development machine as I get the following error message:
The feature you are trying to use is on a network resource that is unavailable
with a dialog pointing to the path of the .msi that I installed from feature from. (The .msi is there, however is has been rebuilt and so has changed since I installed it)
I'm concerned by this dialog as I had believed that Windows Installer kept track of installed .MSI files, however this dialog seems to suggest that I can break my uninstaller by deleting, moving or changing the installer.
Is this the case?
What do I need to do to make sure that I don't break my uninstaller in this way? (Do we need to keep copies of all versions of the installer ever installed on a machine?)
The easiest way to get out of this situation is to do a recache/reinstall. Build a new version of your MSI that isn't "broken" (in whatever way it is broken, in this case, it might not really be broken at all, you just need a new source). Then you use a command line like:
msiexec /fv path\to\your.msi /l*v i.txt
That will copy your.msi over the MSI that is cached and do a repair. Then you'll be in a better place.
One of the first painful lessons of writing installs is to never run your install on your own box. Certainly not until it reaches a point of maturity and has gone through several QA cycles. This is what we have integration labs and virtual machines for. (There is a saying about things you shouldn't do in your own back yard.)
That said, normally an MSI uninstall doesn't require the MSI but there are situations where it could be required. For example if one was to call the ResolveSource action during an uninstall, MSI would then look for the .MSI.
Now there are several ways out of this pickle:
Take an MSI you do have and edit it with ORCA to match to file name, UpgradeCode, ProductCode and PackageCode of the MSI that you installed. You should be able to get all of this information from looking at the stripped cached MSI that exists in %WINDIR%\Installer. CD to that directory and do a findstr -i -m SOMESTRING *.msi where SOMESTRING is something unique like your ProductName property. Once you know the name of the cached MSI, open it in Orca to get the required attributes. Then put these attributes in a copy of the MSI you have available and try to do an uninstall. No, it's not the exact MSI that you installed but usually it's close enough.
or
Use the front end windows installer cleanup utility (if you still have it) and/or the backend MSIZAP utility to wipe all knowledge of the application from MSI and Add/RemovePrograms. Note, this doesn't actually uninstall the program so you'll have to also write a script or otherwise manually uninstall all traces of the program.
or
Reimage your workstation
If you know exactly what is wrong (which is often the case during development), I prefer to open the MSI file that Windows will use for uninstallation and edit it directly with a tool like Orca to fix or remove the part that causes the failure.
For example:
Locate the MSI file in %WINDIR%\Installer. The MSI should be the last edited MSI file in that folder right after you did the failed uninstallation.
Open the msi file with Orca.
Remove the failing part - for example the InstallExecuteSequence action that fails which is atypical scenario.
Save the msi and close Orca to release the lock on the msi file.
1 - Have you experimented with "run from source" during installation?
This is an option in the feature tree which allows you to run some files from their installation source. This is generally combined with an admin image on the network. See image below. I haven't tried it, but I assume this could cause: "The feature you are trying to use is on a network resource that is unavailable" if the network is down and you are trying to uninstall. Just a theory, there are other ways this could happen.
2 - Are you running script custom actions? If so, do you extract to the tmp folder or run from installed files or the binary table? If so, is the custom action conditioned to run only on install?
3 - Are you perhaps running an EXE custom action that is pointing to an installed file? If so this file may be unreachable on the network.
4 - Are any of your userprofile folders redirected to a network share?
5 - Are you installing anything directly to a folder on the network?
There are plenty of other possibilities.