How to use VS Installer class in a Custom Action - installation

Dozens of Q&A entries (all but one in stackoverflow!) that I found got close to this question, but didn't teach me what I needed. I have what should be a nearly simple installation: a Windows service and an associated tray icon application. They install fine with the standard VS Setup project. After the files are installed, I need to present a dialog to the user to set some parameters in the service's exe.config file. In that dialog, the user should be able to abort the installation. I've tried two approaches to the Custom Action process and ran into a wall with each when it comes to making the installation roll back.
Approach 1: An exe for the Custom Action, run at Commit time.
This sort-of works. The application returns a non-zero exit code and the installation rollback occurs. What I don't like is that:
When the app exits (after the user selects to Cancel), the installation displays an error message saying that there was a problem with the installation and the user should contact the vendor. Since that's not the case, I'd prefer a more correct message ("Installation canceled by user") or no message at all.
Both of the project outputs (the service and the tray app) have to be listed under all four Custom Action sections or my dialog won't appear. Instead, an error appears about a missing InstallState file and the installation always fails. Intuitively, this seems wrong.
Approach 2: An Installer as the Custom Action, run at Install or Commit time.
This is cleaner to me (only the one item listed in the Custom Actions), but getting the process to roll back is worse than Approach 1. It seems that I have to throw an exception in the overridden method (Install/Commit), which then gives me several error dialogs before the rollback occurs, and then the rollback doesn't always uninstall the service.
What is the cleanest way to make this work without going to WiX or similar options?

The simple answer is don't use VS Installer Classes. They have a number of fundamental design flaws. I suggest you look at Windows Installer XML's ( WiX ) Deployment Tools Foundation ( DTF ) instead. DTF is a far superior hosting model / interop library for your managed code and outputs DLL's that are compatible ( from an MSI perspective ) with C/C++ custom actions. They can be consumed as Custom Actions by any MSI authoring tool, not just WiX installers.
Deployment Tools Foundation joins the WiX toolset.
Deployment Tools Foundation (DTF) Managed Custom Actions

I recommend this approach:
create a custom installation dialog which asks the user about your options
use the installer properties set by this dialog to modify your service configuration file (you can use a custom action or the XML support of another setup authoring tool)
This way the information is gathered before the install and the user can also abort the install without problems.
This approach is not supported by Visual Studio, but it can be done with free or commercial setup authoring tools.
If you want to stick with a custom action, you can try this:
make sure your custom action is deferred and doesn't run during commit (commit means that the installation was performed and there's no rollback)
use a Win32 DLL to show your custom dialog; this way you can return ERROR_INSTALL_USEREXIT (1602) so a friendlier user exit dialog is shown instead of the fatal error dialog

Related

How to get MSI Installer to run some code on uninstall of a service

I'm having troubles with some could I would like to execute when the service will be uninstalled. I've added the code to both the System.ServiceProcess.ServiceProcessInstaller BeforeUninstall event, and
to the override method OnBeforeUninstall, but that did not work too.
When using my InstallShield msi to uninstall the service this code does not get executed.
How can I force the service to launch some code during uninstall? Do I need to use a different event in my C# service? Do I need to change something in my MSI?
Note:
My problem is identical to the following
https://community.flexerasoftware.com/showthread.php?149176-MSI-Uninstall-NET-Service-does-not-launch-BeforeUninstall-event
Thanks,
sagar
You'll need to be more explicit about everything you've done. For example there is no automatic calling of installer class methods unless they are explicitly added to your setup as custom actions (in your case an uninstall custom action). You should also explain exactly how the service was installed.
Note that installer classes were invented by Visual Studio setups, and there is typically no need to use them because tools like InstallShield usually support the standard ServiceInstall and ServiceControl functionality in Windows Installer. Installer classes are unnecessary. Also, those events are Visual Studio specials, and it's not clear to me if InstallShield supports them. If you are using an Uninstall method to uninstall a service then just add your "before" code to before the Base.Uninstall() call.
If you want code to run when the service is uninstalled, the more usual way is to have a custom action that calls your code, and condition the call on REMOVE="ALL" (for an uninstall) or other conditions depending on your exact requirement. For example, if you do an upgrade MSI to upgrade your existing product do you still want to run that uninstall code?
.NET Installer Class: PhilDW has already said it all, but I just want to add a couple of things. I assume you are using System.Configuration.Install.Installer and the ServiceProcessInstaller Class (there is a sample in the Installshield help file). There used to be (and I think there still is) a flag for each Installshield component called .NET Installer Class. You can set this flag to Yes, and then I believe Installshield itself will take care of running your installer class methods (Install, Commit, Rollback, Uninstall - whichever one is implemented I think, but I have never tested all scenarios. I don't use this feature).
InstallUtil.exe: Running InstallUtil.exe would indeed call these methods. I am not sure how Installshield calls the methods under the hood (during setup execution) - they may actually be calling InstallUtil.exe for all I know, or some more low-level API call.
Conclusion: Just go to the components view and click on the component containing your service.exe file - and set the flag mentioned above. The exe must be a key-file for the component in question - and it must be a .NET assembly. Like PhilDW wrote, I wouldn't use these methods since they are intended to be used during service development only - not during deployment. For one thing you could run into runtime errors when the methods try to run faulting your whole setup (and often unnecessarily so), and there are also likely issues with rollback and potentially other problems. Can we ask what the methods are actually doing? Perhaps you are just deleting some log files? There are other ways to do that - most significantly using the RemoveFile table.

VS or WIX MSI installer - show serial number from first install

I'd like to show the serial number in the CustomerInfo form (which was captured from the first install and installed in the registry) within the second, third, etc installs when the upgrade is simply a minor version change (or patch). Is this something that can be done within VS deployment project and/or WIX via a custom action (I have a C++ method to fetch the SerialNumber from the registry), MSI config (thru editing a table(s) via say Orca), or otherwise
Regards
Travis
Personally I always do PerMachine installs and don't bother to show the customer information dialog. If an application wants to have licensing it's best to do it in the application on first run.
If you really want to do it in the MSI, you've got a lot of work ahead of you. MSI doesn't persist properties across transactions so you'll have to do it yourself. See:
The WiX toolset's "Remember Property" pattern
I have an open source project called IsWiX. It includes a Visual Studio project template that creates an installer project framework. Part of that framework shows how to insert a custom dialog and then authors a component to handle the remember property for the control on that dialog. You can find the source here.
I'll skip the WiX part that Chris covered.
To do this in a VS project you're supposed to use the Customer Information dialog, added from the list of extra canned dialogs, and use the SerialNumberTemplate stuff. That sets the ProductID property which is the way you're supposed to do serial numbers. So then you could create a registry item in the Visual Studio IDE that has the value [ProductID] to save it somewhere personal. The "official" way to get hold of it for an installed product is MsiGetProductInfo() or equivalent passing the ProductCode and asking for "ProductID" as documented here:
http://msdn.microsoft.com/en-us/library/aa370130(v=vs.85).aspx
To summarize, if the package uses the official PIDKEY /ProductID mechanism (like VS and maybe WiX) you don't need to save it yourself and you can get it via MsiGetProductInfo() or a scipt/managed code equivalent.
If you want to show that previous SerialNumber in a VS setup in the standard customer information form on an upgrade, I don't believe you can do that. There's no mechanism for getting into those forms. If you save the SerialNumber privately, you could try a registry search for your saved serialnumber and store it in the PIDKEY property to see if it shows up there, that might work because the PIDKEY property is the source for that value.

Windows installer is too clever, tries to repair when tester deletes config file

Our application is deployed to the target machine with an msi file. All works nicely. Our tester has gone through his plan, and one of the tests requires deleting the application's configuration file. The application is designed to alert the user with a dialog on startup saying "missing config". However, what happens is that - somehow! - the software starts the installer again and retrieves the missing file from the msi! Which is nice, but not what we want. How do we disable that behaviour?
without going into much depth of the windows installer mechanics (if you interested in that there a plenty of articles about this), the shortcut of the software is probably advertised, which means the windows installer checks if everything is in its place before the software is started.
if you can edit the msi, make the shortcut non advertised.
if you can't, install it with DISABLEADVTSHORTCUTS
e.g. msiexec /i myMsi.msi DISABLEADVTSHORTCUTS=1
please note that this is only a quick (and dirty) workaround,
to fix this proper you need to understand the whole windows installer advertising (also called repair or self resiliency) mechanism.
but explaining all the causes and the mechanism of the repair is far beyond this answer and there are quite some articles and posts about that on the internet (and especially on MSDN and stackoverflow)
There is a more correct answer to this, and it is NOT DISABLEADVTSHORTCUTS. You set the component id to null in the MSI file to prevent repair of that individual file. See ComponentId comments here:
http://msdn.microsoft.com/en-us/library/aa368007(v=vs.85).aspx
Edit the MSI file with Orca to delete the Componenty ID, and write an uninstall custom action to delete the file at uninstall if it's there.
In addition, that's a redundant test. Windows will restore that file for you if it's missing, so the idea that you need a test to notify that it's missing is pointless. The true test should be that Windows will restore the file if it's lost, and your app needs to do potentially nothing about the missing file.
You don't mention what tool you are using to make your MSI but I'm going to go out on a limb and guess Visual Studio Deployment Projects (.VDRPOJ).
One of the (many) horrible things about this tool was that it fails to expose the foundational concept of components. Instead it makes every file a key file of it's own component and hides the existence of the component from you. I say 'was' because Microsoft killed this project type in VS. There are around 50k people complaining on UserVoice to bring this tool back and I'm guessing that 49,990 of them don't know what a key path is.
Windows Installer has a concept called the component rules and each component has a keypath. The keypath teaches MSI how to handle repair scenarios. But your tool has to allow you to be able to control this to make it work.
Windows Installer is functioning exactly the way it's supposed to function. You just aren't up to speed on what that is.
However, if you want to ignore Windows Installer best practices and continue using the tool you use today, the trick is to install the app.config file as a different file. Then have the application copy the file to the real file name on run. Windows Installer won't service what it didn't install.
Several answers have been provided that can work:
You can install the file with a blank guid. Then you need to remove it on uninstall using the RemoveFile feature. You will also run into issues if you want to replace it during an upgrade. Could be tricky at times.
You can disable the advertised shortcut(s), but this affects too much in my opinion.
Finally you can use my suggestion to install a separate non-advertised shortcut to use to launch the application. Such a shortcut bypasses the self-repair check. It may still be invoked by other means such as missing file associations, COM registration or similar, but those are exception states.
However, my preference is that an application can start without a config file present, if at all possible. I always suggest a good startup routine with "internal defaults" available. The startup routine should also degrade gracefully if faced with any file system access denied conditions.
Most importantly you should place this config file in the userprofile so you can generate the file on first launch for the user in question. It can even be copied from a read-only copy in the main installation directory.
When you generate a file from internal defaults and put it in a userprofile location, the file will have no interference with Windows Installer at all. The issues that results is how to clean up user data on uninstall. I discussed this with Stefan Kruger (MSI MVP) at one point, and I agree with his notion that user data is indeed user data and should not be automatically dealt with by your installer at all. Leave it installed, and clean it up via system administrator tools if necessary - for example logon scripts.

Creating Basic MSI that invokes another msi installation

I have asked this exact question on the Flexara forum, but got no response up to today, so I want to ask it here.
We currently have a InstallScript project which runs fine. The resulting setup can be made unattended/silent fine.
In this setup we have some features and invoke a number of third-party installations (that are a prerequisite for running our software).
However, we have customers that want an MSI file and therefore we resorted to the Basic MSI project type.
The setup is made without too much hassle (I'm fairly new to InstallShield) and I can generate a .exe and .msi from this project.
However the only issue I have left is invoking one of the third-party installers.
That third-party installer (made with NSIS) on its turn invokes another installer which is MSI based.
This results in having error 1500 - the fact that you cannot run a msi type installation while another is running.
I've tried scheduling the CA (that are used to invoke the third-party installers) as the first action and as last, but no success.
Before resorting on the more unorthodox scenarios (like creating a task on Windows Task manager that runs after our installer finishes, or at the next reboot and forcing a reboot - which our customers don't like) or a scenario that we don't bundle the 'faulting' installer (we really like to be able to hand over a single intaller and not multiple), I'd thought I ask your input.
I've tried searching for solutions everywhere on the internet, but either I'm failing due to wrong keywords or I just didn't stumble on the right post yet.
Are there any options left for us to create a single MSI installer that is able to invoke this third-party installer (which invokes a msi installer on its turn)?
Since an EXE bootstrapper is not acceptable, there is only one solution:
store the prerequisite installers in Binary table of your MSI
create some custom actions which extract them from this table and launch them
schedule them in InstallUISequence, for example right before Progress dialog
use searches to detect if the prerequisites are installed or not
condition your custom actions with the search results
Basically, you need to launch them during the installation UI. It won't work if you launch them during InstallExecuteSequence.
I don't think the basic MSI project supports this, but it may be supported by more advanced project types. Other setup authoring tools offer direct support for this.
You can try InstallShield's "Chained .msi Package" feature.

UI During Custom Installer Action

What is the correct way to display UI during a custom installer action?
I would like my UI to be modal on the install dialog, or alternatively, I'd like a way to display text/progress from my custom action in the installer dislog.
The installer is a VS2005 setup project and the custom action is a C# Installer-derived class.
Displaying any kind of non-standard UI would require changes to the UI handler object. This isn't trivial, and the implementation depends on the toolkit you use to author your MSIs: I'm not sure it's even possible with VS setup projects.
Displaying simple status/progress messages and logging to the MSI log isn't too hard to do from a custom action, though, at least not using the Windows Installer XML (WiX) toolset, which is what I use myself for this purpose.
When authoring your custom actions with WiX, you get access to the active installer session through the Microsoft.Deployment.WindowsInstaller.Session object, which has 'Log' (writes a message to the log, if logging is enabled) and 'Message' (performs any enabled logging operations and defers execution to the UI handler object associated with the engine) functions, amongst many other goodies.
If you're currently already creating your custom actions in C#, you may be able to find something similar in your current environment (I've never worked with VS.net installer projects, so I'm not exactly sure how they work -- I'm quite surprised actually that these allow you to create managed custom actions...). Otherwise, I'd definitely recommend looking into WiX for custom actions: these work with any MSI authoring environment, and are quite flexible.

Resources