Wix toolset: complete cleanup after "disallowing uninstallation of component since another client exists"
Asked Answered
D

4

14

today I found out that my installer does not uninstall correctly anymore. Meaning my app is not shown in control panel anymore after uninstalling from there but all files are still present. I looked at the log files and I see a lot of "disallowing uninstallation of component since another client exists" which afaik means I screwed up..

So what is the best way to cleanup my pc and to prevent it from happening in the future? What could have caused this? afaik a not completely uninstalled previous version of my app is the reason for this error?

Unfortunately, using VM is not possible for various reasons..

FYI: For developing and test purposes I usually test and create installer with 1.0.xxxxx where xxxxx often stays the same. My upgradecode is always the same. In addition I am using heat and wherever possible I am letting wix auto-generate GUIDs. Furthermore I have one CA to show my readme file after installation and one to execute a batch file (modifies registry entries using powercfg). Upon uninstall a executable is run to import an .reg file to restore modified registry entries (because they would be uninstalled by wix).

Duce answered 4/11, 2014 at 15:58 Comment(1)
No, that's not an error; It's informational. Since you are installing product after product that share a component, the component shouldn't be removed until all products have be uninstalled. You might want to just be sure to uninstall a product before installing the product produced by the next build.Goshawk
G
12

It sounds like you need to uninstall the features (or whole products) that have installed your unwanted components. Windows Installer has an API for querying components, features and products. The WiX Toolset has incorporated a wrapper around the API called DTF. You can use it to query features by component.

So, break out your favorite .NET script runner (mine is LINQPad) and run a query. For example, to find out how to remove "candle.exe":

// using System.Linq;
// using Microsoft.Deployment.WindowsInstaller;

// <ref>"C:\Program Files (x86)\WiX Toolset v3.8\SDK\
         Microsoft.Deployment.WindowsInstaller.dll"</ref>

ComponentInstallation.AllComponents
    .Where(c=>c.State == InstallState.Local)
    .Where(c => c.Path.ToLowerInvariant().EndsWith(@"\candle.exe"))
    .SelectMany(c => c.ClientProducts
        .SelectMany(p => p.Features.Where(f => f.Usage.UseCount > 0)
            .Select(f => new {
                c.Path, 
                f.FeatureName,
                p.LocalPackage,
                p.UserSid, 
                p.ProductCode})))

LINQPad Instant Share

LINQPad Output

Then, run msiexec /x <ProductCode> to remove all the features of the products

or msiexec /i <LocalPackage> REMOVE=<FeatureName> to remove just the features that installed the component.

Goshawk answered 5/11, 2014 at 4:35 Comment(0)
S
18

We recently had the case that one of our development machines couldn't remove all components on uninstallation. On other machines, however, the WiX setup worked as intended.

So, if you uninstalled incorrectly an earlier version of your product and getting the message Disallowing uninstallation of component: {GUID} since another client exists there is a high chance that you have orphan components lying around in your registry.

There is a much more elegant solution for deleting those hidden registry keys with PowerShell instead of using, as mentioned by others, a 3rd party application.

$productName = "Path\\YourProductName"  # this should basically match against your previous
# installation path. Make sure that you don't mess with other components used 
# by any other MSI package

$components = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\
$count = 0

foreach ($c in $components) 
{
    foreach($p in $c.Property)
    {
        $propValue = (Get-ItemProperty "Registry::$($c.Name)" -Name "$($p)")."$($p)"
        if ($propValue -match $productName) 
        {
            Write-Output $propValue
            $count++
            Remove-Item "Registry::$($c.Name)" -Recurse
        }
    }
}

Write-Host "$($count) key(s) removed"

If you want to get a more detailed explanation about the cause of the message disallowing uninstallation... take a look here.

Style answered 14/2, 2018 at 12:56 Comment(3)
Thanks for this! I was able to modify this and it corrected my uninstallation problems with the WixInstaller app I'm building.Bingo
This does what I need, but unfortunately it runs extremely slowly on my machine (around 8 hours). I also encounter non-fatal errors because there are components in my registry that exist but are not viewable even from regedit so possibly a machine issue.Deflected
I left my registry in a state after many installs iterating on my development machine while developing an msi installer using wix. The msi would run the uninstall but not remove any of the files. Definitely should have invested the time in setting up a virtual machine for testing. The script originally failed with an error malformed px character escape but solution is here #66780896 When I ran this script, it removed refs to my installation files 3x times and the problem went away.Balkin
G
12

It sounds like you need to uninstall the features (or whole products) that have installed your unwanted components. Windows Installer has an API for querying components, features and products. The WiX Toolset has incorporated a wrapper around the API called DTF. You can use it to query features by component.

So, break out your favorite .NET script runner (mine is LINQPad) and run a query. For example, to find out how to remove "candle.exe":

// using System.Linq;
// using Microsoft.Deployment.WindowsInstaller;

// <ref>"C:\Program Files (x86)\WiX Toolset v3.8\SDK\
         Microsoft.Deployment.WindowsInstaller.dll"</ref>

ComponentInstallation.AllComponents
    .Where(c=>c.State == InstallState.Local)
    .Where(c => c.Path.ToLowerInvariant().EndsWith(@"\candle.exe"))
    .SelectMany(c => c.ClientProducts
        .SelectMany(p => p.Features.Where(f => f.Usage.UseCount > 0)
            .Select(f => new {
                c.Path, 
                f.FeatureName,
                p.LocalPackage,
                p.UserSid, 
                p.ProductCode})))

LINQPad Instant Share

LINQPad Output

Then, run msiexec /x <ProductCode> to remove all the features of the products

or msiexec /i <LocalPackage> REMOVE=<FeatureName> to remove just the features that installed the component.

Goshawk answered 5/11, 2014 at 4:35 Comment(0)
T
10

Even though this is a bit old link, however posting my findings which can be helpful to others, who are facing such same situation.

If you have found "Disallowing uninstallation of component: {Some GUID} since another client exists" in your log files, then the reason could be that your previous installations might still be referring to this component/GUID.

Moreover if you take a risk that you will try to remove the registry keys manually, you might even not find the GUID in regedit.

But few of these registries might be there and they may be hidden. In such case use RegSeeker tool http://www.hoverdesk.net/ , which can help finding the hidden registries. Be alert and cautious as you going to deal with registries.

Based on the GUID, get the name of the component from your solution/project and find it using the "Find in registry" option of this tool. Verify and remove only those entries which you think are not needed.

Admittedly, I came to know about this tool using below link

http://www.daviddeley.com/solutions/msiexec/index.htm

Towline answered 9/5, 2016 at 11:3 Comment(1)
A bit of correction: the registry items are not hidden per se (they can be viewed normally by regedit or any other registry viewing/editing utility); but they don't contain the GUID of the component. Instead, the GUID value is converted to bytes, the bytes are converted to a hexadecimal string, and this is what appears as a part of the registry path.Incrassate
E
0

Following this workflow works perfect:

How to fix "disallowing uninstallation of component since another client exists"?

After the creation of the two files there, it is necessary to remove BOM for them before applying the next step. I've used Notepad++ (Encoding > Encode in UTF-8).

Adding the /f option for each line is easily possible with the Multi-Cursor of Notepad++ - activate it with SHIFT+ALT+Arrows

Enoch answered 10/5, 2019 at 9:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.