Wix installer minor upgrade exe leaving licence untouched - wix

About 18 months ago I built a Wix installer for my program. It only has to install 3 files, an exe, a chm and a licence file. The exe and chm are the same for each user, but the licence file is different. I build a new msi, with the appropriate licence, for each user. This is OK for me because I only get new users about once a week (if I'm lucky!), so it's not a big deal to spend 10 minutes on the build. The installer works well.
A few months ago, I released an update that needed a new exe and chm. I ended up rebuilding a new msi for each user as a major upgrade, and sending it indivdually to each user (by then about 50). It was a pain, but it worked OK. However, it seems obvious that there must be a way to have just a single patch, that replaces the exe and chm (which are identical for all users), but leaves their existing licence untouched. Then I could just send a single file to each user, which would be a lot less work.
I have been reading the tutorials, and the Ramirez book, and they all talk about building a patch by comparing the original msi with the new one. However, in my case the original msi's are different for each user. I have got into rather a tangle trying to figure it all out (I am obviously NOT an experienced install builder), so any advice, or better still example code or tutorial, would be really welcome.
Thanks.

OK, so my problem was that I had put the licence and the exe/chm in the same fragment in the original installer. I had missed the bit in the patch documentation that said that a ComponentRef in the patch wxs will pull in "all neighboring components from the same fragment".
I think I am screwed regarding the individual msi's I have already sent out to users, they'll have to get an individual major upgrade msi for the next upgrade. But I will change my primary msi installer, and hopefully after that (and for new users from now on) I'll just be able to supply a single msp file to upgrade all users.
Sorry if anyone has wasted any time on my question. It would obviously have been better if I had planned properly for upgrades from the start, but as always, it's the "unknown unknowns" that bite you.

Related

Accidentally changed Wix Installer UpgradeCode. Is there a way to repair post-install?

We changed the UpgradeCode component to a different GUID. Is there a way to change an installed product's UpgradeCode without redoing the install?
Live?: Is the product live yet? If not, just uninstall all instances and revert to the original upgrade code? (Especially the case if you are in a corporate environment with proper control of deployment via a distribution system - then there are no constructs needed to add to the package itself for eternity).
Hotfix: Some would suggest hotfixing the cached installation database. I wouldn't even try. I find it very hacky, even when using the MSI API (Win32 functions / COM API to manipulate MSI files).
Upgrade Table: I haven't done so in ages, but you should be able to author the erronous upgrade code into your MSI file's Upgrade Table in addition to your main one. In other words, you can detect multiple related products (or even unrelated products), each with different upgrade codes by authoring the Upgrade Table. You would generally need to leave that legacy entry in there for the foreseeable future though, to ensure smooth upgrades for as long as that particular product line is relevant. You could keep using the new upgrade code, or revert to the old one (but you need both entries in there for as long as this product line updates - if you are live with all versions).
Sample: I am doing something along the lines of what is described above here: Adding entries to MSI UpgradeTable to remove related products

Optionally leave old version of component on upgrade

I've been trying to set up a WiX component such that the user can specify that the installer should not upgrade that component on a MajorUpgrade. I had the following code, but this means that if the condition is met then the new version is not installed, but the old version is also removed.
<Component Id="ExampleComponent" GUID="{GUID here}">
<Condition>NOT(KEEPOLDFILE="TRUE")</Condition>
<File Id="ExampleFile" Name="File.txt" KeyPath="yes" Source="File.txt"/>
</Component>
Ideally, if the user specifies "KEEPOLDFILE=TRUE", then the existing version of "File.txt" should be kept. I've looked into using the Permanent attribute, but this doesn't look relevant.
Is this possible to achieve without using CustomActions?
A bit more background information would be useful, however:
If your major upgrade is sequenced early (e.g. afterInstallInitialize) the upgrade is an uninstall followed by a fresh install, so saving the file is a tricky proposition because you'd save it, then do the new install, then restore it.
If the upgrade is late, then file overwrite rules apply during the upgrade, therefore it won't be replaced anyway. You'd need to do something such as make the creation and modify timestamps identical so that Windows will overwrite it with the new one. The solution in this case would be to run a custom action conditioned on "keep old file", so you'd do the reverse of this:
https://blogs.msdn.microsoft.com/astebner/2013/05/23/updating-the-last-modified-time-to-prevent-windows-installer-from-updating-an-unversioned-file/
And it's also not clear if that file is ALWAYS updated, so if in fact it has not been updated then why bother to ask the client whether to keep it?
It might be simpler to ignore the Windows Installer behavior by setting its component id to null, as documented here:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa368007(v=vs.85).aspx
Then you can do what you want with the file. If you've already installed it with a component guid it's too late for this solution.
There are better solutions that require the app to get involved where you install a template version of this file. The app makes a copy of it that it always uses. At upgrade time that template file is always replaced, and when the app first runs after the upgrade it asks whether to use the new file (so it copies and overwrites the one it was using) or continue to use the existing file. In my opinion delegating these issues to the install is not often an optimal solution.
Setting attributes like Permanent is typically not a good idea because they are not project attributes you can turn on and off on a whim - they apply to that component id on the system, and permanent means permanent.
I tried to make this a comment, it became to long. I prefer option 4 that Phil describes. Data files should not be meddled with by the setup, but managed by your application exe (if there is one) during its launch sequence. I don't know about others, but I feel like a broken record repeating this advice, but hear us out...
There is a description of a way to manage your data file's overwriting or preservation here. Essentially you update your exe to be "aware" of how your data file should be managed - if it should be preserved or overwritten, and you can change this behavior per version of your application exe if you like. The linked thread describes registry keys, but the concept can be used for files as well.
So essentially:
Template: Install your file per-machine as a read-only template
Launch Sequence: Copy it in place with application.exe launch sequence magic
Complex File Revision: Update the logic for file overwrite or preservation for every release as you see fit along the lines as the linked thread proposes
Your setup will "never know" about your data file, only the template file. It will leave your data file alone in all cases. Only the template file it will deal with.
Liberating your data files from the setup has many advantages:
Setup.exe bugs: No unintended accidental file overwrites or file reset problems from problematic major upgrade etc... this is a very common problem with MSI.
Setup bugs are hard to reproduce and debug since the conditions found on the target systems can generally not be replicated and debugging involves a lot of unusual technical complexity.
This is not great - it is messy - but here is a list of common MSI problems: How do I avoid common design flaws in my WiX / MSI deployment solution? - "a best effort in the interest of helping sort of thing". Let's be honest, it is a mess, but maybe it is helpful.
Application.exe Bugs: Keep in mind that you can make new bugs in your application.exe file, so you can still see errors - obviously. Bad ones too - if you are not careful - but you can easily implement a backup feature as well - one that always runs in a predictable context.
You avoid the complicated sequencing, conditioning and impersonation concerns that make custom actions and modern setups so complicated to do right and make reliable.
Following from that and other, technical and practical reasons: it is much easier to debug problems in the application launch sequence than bugs in your setup.
You can easily set up test conditions and test them interactively. In other words you can re-create problem conditions easily and test them in seconds. It could take you hours to do so with a setup.
Error messages can be interactive and meaningful and be shown to the user.
QA people are more familiar with testing application functionality than setup functionality.
And I repeat it: you are always in the same impersonation context (user context) and you have no installation sequence to worry about.

Create a Patch without 2nd MSI

I believe Patch works by creating a transform by comparing the existing MSI (1st one) and the new one (2nd MSI). I have a customer requirement (don't ask me why) not to create the 2nd MSI and still have another option to create a patch. Is this possible? If so, can you please provide the details? If not, can you please provide links / proofs substantiating this?
Since all files are just a collection of bytes, it's hard to prove the impossibility. However the only Microsoft-documented way to create a patch (.msp file) involves invoking patchwiz.dll (perhaps through msimsp.exe) to process the differences between two or more installation databases (.msi files). Creating a Patch Package describes this process in more detail.
If you got past this, skipping msimsp.exe/patchwiz.dll and thus avoiding creating the upgraded .msi file here, you would still have to create the transforms that go in the transform substorage. The only documented way to generate a transform (.mst file) still requires two installation databases, so you'd need your second .msi file for this step.
If you figure out how to generate .mst files without a pair of .msi files, then in theory it may also be possible to package it all up into a .msp file. I have yet to see enough documentation on how to do this, however.
(Pointers to that documentation would be gratefully accepted, whether as comments, edits, or alternate answers.)

Can I generate a patch(.msp) without the upgrade image(.msi)

I've googled a lot, but there's little information about my question.
The question for short is "Suppose you have the target image(.msi), the list of changed binaries, but you don't have the upgrade image. How to make a patch based on those inputs?".
The detailed description is:
Currently, We use TFS as the source control. And each time when making a new MSI, we will increment the AssemblyFileVersion of all projects whether the project is really changed or not firstly. This is fine when there's no requirement to make a patch.But, actually, we DO have the requirement to make a patch now. I have tried to create a patch using Purely WiX or Patch Creation Properties, but almost all projects will be considered as changed when we use these MSIs directly.So if I have three inputs:
Target Image(.msi)
A list of really changed binaries
Upgrade Image(all binaries' file version is incremented) <--- this input may be useless
How Can I make use of above inputs to create a patch?
Thanks in advance.
Alternative to Phils answer, you could add an ignore switch for the only incremented files in your Patch Creative Properties File.
<UpgradeFile File="YourFileID" Ignore="yes" />
see
http://wixtoolset.org/documentation/manual/v3/xsd/wix/upgradefile.html
Depending on how many files there are to ignore might make Phils method easier. Although if you get the file table id list (export the table in orca and edit in excel, copy A3 down) and remove all the ids from you're really changed list, then add the xml around each id..it shouldn't take long.
You can still use the upgraded MSI build when you make a patch. I don't know all the WiX things you may need to do, but I've done exactly what you want to do by setting IgnoreMissingSrcFiles in the TargetImages table:
http://msdn.microsoft.com/en-us/library/aa372066(v=vs.85).aspx
and just delete all the files you don't want to be patched. You use admin images anyway to create the patch, so all you'll have are two admin images wiyth MSI files and only the files you want to patch.

How to diagnose/manage DLL hell with InstallShield?

We use InstallShield to build installers for a number of very similar products, each of which has shared files parked in fixed directories underneath our vendor directory. We have a DLL hell problem that I thought installers should handle.
Imagine products A and B both have file FOO, installed in directory D. FOO isn't necessarily a DLL; it can be any file.
In an ideal world, both copies of FOO are identical and when both products are installed FOO gets (overwritten) in D and everything is fine. And that's how it seems to work when everything is identical.
In practice, A and B may be from different generations, so in fact A has FOO variant A (FOO_a) and B has variant FOO_b. Now only one of FOO_a or FOO_b will end up in D if both products are installed, and consequently one of A or B will be confused because the wrong file is there.
What I would have expected from installers (and InstallShield) is that for each product P installed on a system, that a reference counter would be kept somewhere (the registry?) regarding each installed file. So when A is installed and FOO(_a) is placed, FOO is marked as belonging to A, and has reference count set to 1. If B is now installed with an FOO_b identical to FOO_a, FOO should be marked as belonging also to B, and the reference count incremented. If B is installed, and FOO_b is different than FOO_a, I'd expect the installer to complain that incompatible files FOO were being proposed for installation and the install should abort. When a product is de-installed, I'd expect reference counters for each installed file to be decremented, and the installed file only removed when the reference count goes to zero.
That's not what InstallShield appears to do. It simply smashes FOO into its target directory during an install. This is in effect the same thing as DLL hell. Is this the intended behavior of installers? Of InstallShield? Of Windows?
We thought we looked for a way to ask InstallShield to manage this, but can't find anything. I'd be pleased to have somebody tell where to look to configure this correctly. Or is it that InstallShield can't/won't do this? [If so, why am I giving them money?]
If variants of FOO are versioned and properly cumulative (this is key to all installation technologies that operate on shared locations), and if your component is shared, shares the same GUID in both products (if MSI), and shares the same installation location, then everything will work. As parts of that list of conditions are made untrue, various bad things can and will happen; some have workarounds, some are unrecoverable.
If the installation location differs, little or none of this matters, unless both products end up searching in the same location for some other reason.
If MSI, and the GUID differs (or the contents of the component differ), you've broken component rules. This may result in files not uninstalling at the final uninstall, unexpected changes in a repair, or other hard to predict results.
If the file is not properly versioned, it is not possible to know when to replace it with the other one. It is likely in some ordering, a new install will end up running with an old version. This can be mitigated in an MSI with companion files, if another file has properly increasing versions.
If the file is not cumulative with respect to versions, it is likely that a new version of the file will break the other consumer of it. In this scenario, you should not install it to a shared location.
One size fits all does get a little messy sometimes, so generally the problem space is simplified to one that can be addressed. In this case the cost is that all installation authors have to follow some rules if they want well-defined behavior.
If you are truly looking for a solution, use separate DLLs. This is simple and reliable, and in fact it's easier to talk about (as you have demonstrated when you mention FOO_a and FOO_b). It also avoids the error message, which is not helpful for your users.
Windows did have a reference counting scheme for shared DLLs, but it was by convention, so it was unreliable. If you've ever had an uninstaller ask if you really want to delete a shared component, now you know why.
No one can possibly begin to answer your question without knowing what installation technology you are using. InstallShield is a product that supports many different frameworks.
Windows only keeps track of shared references on DLL files. ( SharedDllCount ). Windows Installer ( assuming you are even using it ) also keeps track of Compoent reference counts.
However, it should be noted (again IF you are using Windows Installer ) that the file costing process that decides to overwrite a file really has nothing to do with reference counts. Reference counts come into play on uninstall.
Assuming you are using Windows Installer, take a look at:
File Versioning Rules
Also look at:
What happens if the component rules are broken?
This *is something Windows Installer and InstallShield know how to handle it assuming that you implement it correctly. Any programming language can be misused and abused intentionally or not.
if you don't want the files to be common, why in the world are you placing them in the same directory? I would rather put them in different location. Now suppose your FOO_a is being used by many programs at the same version, then for FOO_b which is required by your new program and others that might be added later, add another similar common directory and name them using generation names or something.
I believe you are correct in how the reference counting works if you are dealing with a pure MSI-based installer (it would help to know if A and B are Basic MSI or InstallScript projects). In any case, I would verify the components that contains FOO in the A and B install projects have it set as the key file, and have the Shared property set to Yes. That should cause the reference counting to be managed correctly.
Regarding what should happen when you run the installer and it has a newer version of a shared file, to my knowledge that depends mostly on whether the file has a version or not, whether it's a newer version, and properties like its last changed timestamp. If you are building an installer for B that contains FOO_b that is different from FOO_a, I'm not sure how InstallShield could know that it will break A (I could be wrong, maybe it can). One possible workaround is to use custom actions to check if FOO_b is different and if it is, make a copy of the existing one early in the install, then copy it back at the end of the process.