how to check and stop uninstall in Wix installer? - wix

I am developing two installers using WIX.
A --> Parent application.
B --> Optional application - but works only if parent 'A' already installed.
Some users uninstalls the Parent application 'A' accidentally, and opening application B is causing issue.
Expectation is, During the uninstall process of Parent application 'A', it has to check for dependent application 'B'. if 'B' exists, then it should warn the user and exit from uninstallation.
I couldn't find a clue how to do this.

Products B[] could install a shared component such as a registry value that indicates a product of type B is installed. Product A could then have an AppSearch/Launch Condition or Type 19 Error custom action that blocks uninstall if that component is found.
But I personally caution against this. Blocked uninstalls and tightly coupled products are harder for users to service. I would rather product B[] simple display an error message on startup that dependency product A is missing.

Related

Wix Duplicate component Guid's issue while installing patch

We have MSI version 12.2.1.0 released and there were new components added in Fix 1 which is now released has 2 components with same GUID. We have identified issue in Fix2 as patch doesn't seem to overwrite/replace the files due to duplicate GUID for the components the feature which is referring the components is getting skipped while installing Fix2.
How to resolve the duplicate GUID issue in Fix2.We cannot go back to fix1 as it is been delivered to customer.
First component
How to safely remove the duplicate GUID to make patch install the feature without skipping.
Log shows
Line 1042: MSI (c) (9C:7C) [11:47:25:815]: SELMGR: Component 'xyz_shortcut18' is registered to feature 'P', but is not present in the FeatureComponents table. Removal of components from a feature is not supported!
ICE warning : unfortunately got ignored while generating patch
warning LGHT1137: Component/#Id='p19.arx' has a #Guid value '{36B8C853-9E9E-48D7-BDCD-E4D6C376B781}' that dupli
cates another component in this package. This is not officially supported by Windows Installer but works as long as all components have mutually-exclusive conditions.
We are using wixout files to generate the transform Pure patch process.
To fix Component Rule violations you need to use a major upgrade that is scheduled very early (after InstallValidate). That will remove the "bad package" before installing the fixed package avoiding the Component Rule violations.
After that, then you can attempt more advanced upgrade/patching scenarios.

Wix installer uninstaller issue when a bundled app is skipped

I have a bundled application say XYZ-1.0.0.1.exe, with applications A-2.2.0.1.exe and B-1.2.0.1.exe bundled in it. So when we install XYZ, we get A and B as well listed in Add Remove Programs. But when I upgrade XYZ-1.0.0.1 with XYZ-1.0.0.2, which has A-2.2.0.1.exe and B-1.2.0.2.exe, so that A is same and already installed and B needs upgrade. I actually skipped the installation of A by making the install condition false, since the same version is already installed and installed only B while upgrading.
After successfully upgrading I am not able to uninstall the application XYZ, it says some package error, also this happens only if the source file used for upgrading is removed from machine.Actually while uninstalling package has to be referred from program cache, I think since we skipped A package cache has problem.
The error that i get is as follows "Prompt for source of container: WixAttachedContainer, path: C:\Users\ABC\Desktop\XYZ-1.0.0.2.exe Failed to resolve source for file: C:\Users\ABC\Desktop\XYZ-1.0.0.2.exe, error: 0x80070002. Error 0x80070002: Failed while prompting for source (original path 'C:\Users\ABC\Desktop\XYZ-1.0.0.2.exe'). Failed to acquire container: WixAttachedContainer to working path: C:\Users\ABC\AppData\Local\Temp{b4a1c780-306c-40f0-83ad7}, error: 0x80070002. "
This error occurs only when i copy XYZ.exe to any path say desktop and after installation(skip installing A or B since same version of A or B bundled is already installed) and delete the setup file XYZ.exe from saved path ie here Desktop. I am not able to uninstall unless i uninstall A or B which was skipped independently.
Also there is another scenario.
I have a bundled application say XYZ-1.0.0.1.exe, with applications A-2.2.0.1.exe and B-1.2.0.1.exe bundled in it. XYZ-1.0.0.2.exe, which has A-2.2.0.1.exe and B-1.2.0.2.exe. Thes in both versions of XYZ we have the same version of A. When i install XYZ-1.0.0.1.exe i skipped the installation of A-2.2.0.1.exe by setting the install condition to false. So XYZ-1.0.0.1.exe is installed and B-1.2.0.1 is also installed. Further when i upgraded to XYZ-1.0.0.2, I need to install all of the A and B. Installation was successfull and now i have XYZ-1.0.0.2, A-2.2.0.1 and B-1.2.0.2. Now if i delete the installation file of XYZ-1.0.0.2.exe from original path and try to uninstall it breaks.
Initially i thought that the package cache issue arises since A-2.2.0.1.exe was not installed along with XYZ-1.0.0.2.exe since i skipped it as it is already available. But after the second scenario got to know that skipping was not the issue. Since in second scenario A-2.2.0.1.exe was installed along with XYZ-1.0.0.2.exe.
The same issue took huge amount of my time as well. Solved it using a work around. Since the issue is "Prompt for source of container: WixAttachedContainer, path: ", You can copy the exe file XYZ-1.0.0.2 while upgrading to program data or some other path with a default name xyz.exe. At first register for ResolveSource event,then add the following code.Assume the copied exe path is c:/XYZ/xyz.exe
private void OnResolveSource(object sender, ResolveSourceEventArgs e)
{
Application.Engine.SetLocalSource(e.PackageOrContainerId, e.PayloadId, "c:/XYZ/xyz.exe");
e.Result = Result.Retry;
}
If anybody know a better answer, please help.

MSI - is it possible to determine if a shared component is already installed by another product

Can someone please explain the odd MSI behavior in the following scenario:
I have multiple Wix projects which all share the same feature containing a single component:
<Feature Id="VTWSK" Level="1" Directory="MyCommonFolder">
<Component Id="vtwsk" Guid="{47EC2941-738D-4486-9D86-A443A40C5F94}" Directory="TempDriversFolder">
<File Id="vtwsk.key" Source="..." KeyPath="yes"/>
...
</Component>
</Feature>
I make sure that all products resolve MyCommonFolder to the same target directory so that component key path is indeed the same. I also have a custom action which should be executed if and only if the component is installed for the first time on the target machine, so I use a following condition:
<InstallExecuteSequence>
<Custom Action="InstallVTWSK" After="InstallFiles">$vtwsk=3</Custom>
</InstallExecuteSequence>
It works fine when the first product is installed on target machine, however, the second product fails to detect that vtwsk component is already installed. Logs from the second product installation:
MSI (s) (B0:AC) [13:18:22:202]: Feature: VTWSK; Installed: Absent; Request: Local; Action: Local
...
MSI (s) (B0:AC) [13:18:22:202]: Component: vtwsk; Installed: Absent; Request: Local; Action: Local; Client State: Unknown
Thus, the component state is still 3, and corresponding custom action is executed for the second time (and fails, due it's nature which I can't easily control). I would rather expected "Installed: Local; Request: Local; Action: Null".
Is it even possible to run a custom action conditionally only when the component (or feature) is installed on the target machine for a first time?
All other things being correct, what's happening is that the component is installed every time so that condition is true. There are still two or three products that install that component and the reference count in that location gets incremented, and the fact that there is one file is not relevant. The component is still being installed by each product. You really want to run that CA the first time the file is installed. I'd look at having that CA create a registry item that says the file is initialized, and use it to see if it needs initializing. Or otherwise make the CA smart enough to see that the initialization has been done so you just call it every time. Or if the fact that the file is there is sufficient then you can do a search for the file's component ID and if it's there then maybe assume it's been initialized by a previous install.

Custom Wix Burn bootstrapper doesn't detect MSI install state

I'm creating a custom wizard-style bootstrapper based on Wix/Burn (3.6 release version). I've based in on the Wix 3.6 bootstrapper code.
The problem is that I cannot get the bootstrapper to detect the install state of my setup.msi that is part of the bundle.
As I understand it, all that's required is to call Engine.Detect(), where Engine is an instance of the Wix Engine from the Bootstrapper Application. At that point I should be able to look in Bootstrapper.Command.Action to see what the required launch action is.
My bundle contains two items: .NET 4 (web install) and my setup.msi.
I suspect that I'm missing a step to determine whether I should put my wizard into maintenance mode vs. install mode.
First, to determine if the package is being detected or not you can check the log files in the temp directory of the current user. It will tell you whether or not the package has been detected.
Now to determine whether or not to go into maintenance mode vs. install mode, you can check the package state by subscribing to the DetectPackageComplete event. In the example below, my UI uses two properties, InstallEnabled and UninstallEnabled to determine what "mode" to present to the user.
private void OnDetectPackageComplete(object sender, DetectPackageCompleteEventArgs e)
{
if (e.PackageId == "DummyInstallationPackageId")
{
if (e.State == PackageState.Absent)
InstallEnabled = true;
else if (e.State == PackageState.Present)
UninstallEnabled = true;
}
}
The code sample above is from my blog post on the minimum pieces needed to create a Custom WiX Managed Bootstrapper Application.
An easy way to determine if your Bundle is already installed is to use the WixBundleInstalled variable. That will be set to non-zero after your Bundle is successfully installed.
Additionally, in WiX v3.7+ the OnDetectBegin callback now tells you if the bundle is installed so you don't have to query the variable normally.
These changes were made to make it easier to detect maintenance mode to avoid the completely reasonable solution that #BryanJ suggested.

What can cause Error 2902 when installing an MSI?

One of our MSI's has started failing with Error 2902. It'll get most of the way through the installation, pop an error box, and then back out the install. We haven't made any major changes to the installer since the last working version.
Running msiexec with logging turned on gives a more informative message:
Action 17:21:22: RegisterProduct. Registering product
Error 2902: Operation ixoFileCopy called out of sequence
This comes immediately after the "WriteRegistryValues" section. Does anyone know what causes the call to ixoFileCopy? I'm guessing the resolution will involve changing the sequence of the "RegisterProduct" step, but I'm not sure what it should proceed.
Thanks for any help!
It turns out that in our case this was happening due to a data file getting too big for MSI to handle without chunking the cab. This thread mentions the issue and one possible workaround.
I had the same error.
Apparently, there were files missing or corrupted (network error?). The problem has been solved after copying the whole folder again.
I've also seen this error when components are provided with blank guids.
e.g.
<Component Id="cmp_MyFailingComponent" Guid="">
<File Id="f_myFile"
Assembly=".net"
Source="C:\Program Files\MyFile.dll"
KeyPath="yes"/>
</Component>
I've seen this error when some of the database column fields are longer than the column width.
I had converted an MSI into an InstallShield project, made a few additions, and built a new MSI - it built without any errors. Installation then failed with error 2902.
The components that failed had component names longer than the allowed 72 characters. (see Component table) The original MSI worked fine despite having the long names, but I guess they caused InstallShield to improperly build the MSI somehow. Not InstallShield's fault, although I do think it should have raised an error during the build.