Dealing with orphaned components while linking wixlib - wix

I am tasked to build 2 installers based on the same wixlib supplied by 3rd party. Full installer includes all Components, Lite only the core stuff. I assume the wixlib has the following structure:
<Fragment>
<ComponentGroup Id="CoreStuff">
<!-- List of components for this bit, roughly 5MB -->
</ComponentGroup>
</Fragment>
<Fragment>
<ComponentGroup Id="ExtraStuff">
<!-- List of components for this bit, roughly 45MB -->
<ComponentRef Id="BigFile1"/>
</ComponentGroup>
<Component Id="BigFile1">
<File Id="BigFile1_bin" Name="BigFile1.bin"/>
</Component>
</Fragment>
The installer is build in msbuild. The components are included in to the project the following way:
<Feature Id="ThirdPartyStuff">
<ComponentGroupRef Id="CoreStuff"/>
<?if $(var.Configuration) = "Full"?>
<ComponentGroupRef Id="ExtraStuff"/>
<?endif?>
</Feature>
In the end, as expected, I get LGHT0267 error:
error LGHT0267: Found orphaned Component 'BigFile1'. If this is a Product, every Component must have at least one parent Feature. To include a Component in a Module, you must include it directly as a Component element of the Module element or indirectly via ComponentRef, ComponentGroup, or ComponentGroupRef elements.
Have anyone come up with workaround on how to selectively use components provided in wixlib? I could include ExtraStuff as separate Feature for user, but the goal here is to shrink the installer. I could ask politely ThirdParty to provide two separate wixlib's, but I'd like to avoid it.

I don't think that wix has the ability to consume only part of a wixlib package. Think of wixlibs as merge modules (without viewable tables). You can't consume only half of a merge module, and you can't consume only half of a wixlib.
I'm afraid you'll have to ask the third party to break up their wixlib into two packages.

After a struggle I have got the workaround, nasty workaround:
Create dummy wixproject and include wixlib as you would normally do.
Add dummy project as your dependency for final project
In post-build event of dummy project set powershell script to run, which will:
De-compile dummy.msi with binaries output (switch -x) using dark.exe
Craft new.wxs file based on dummy.wxs with inclusion of tags to make the components conditional
Include new.wxs in the final project

Related

Wix Toolset install optional component

I am trying to use Wix Toolset 3.10 to install a small app. The thing I am having trouble with it getting it to launch a third-party .exe that is an optional feature.
Here is the related code in my Product.wxs file:
<Feature Id="iCalSetup" Title="Automation" Level="2">
<ComponentRef Id="icalsetup"/>
</Feature>
<Component Id="icalsetup" Guid="*" Directory="PRODUCTFOLDER">
<File Id="icalsetup" Name="foo.exe" Source="$(var.*****.TargetDir)foo.exe" KeyPath="yes"/>
</Component>
I am wrapping the ending msi in a bootstrapper application. to generate a .exe. The feature/selection tree shows the optional components correctly, but the .exe is never executed when it is selected. Please help!
I found a way to accomplish what I was looking to do. The .exe I was using was a self-extracting executable. I extracted it and created component groups for the extracted files. then I put an MsiPackage in the Bootstrapper app. if the component groups are not copied over, then the msi does not run.

Creating an installer bundle using Wix Toolset

I've been asked to jump on a project and help build an installer. I'm normally a hardware guy so my coding experience is limited, especially when it comes to this particular instance.
Essentially I have a bunch of components: exe's, dll's, drivers, etc. that I would like to bundle together into one installer to deliver to the client. A coworker suggested using the Wix toolset to do this.
Most of the material I have found has only covered the very basics and it seems like I'm being asked to do something custom and a bit more nuanced. Any help in the form of some guidance on the most efficient/easiest way to do this would be a huge help. A rough outline of what I'll need to do and/or any examples would go a long way.
Thanks!
If you want to send a bundle of files, you can simply mention those specific files in Product.wxs file of wix setup project .
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="abc.exe" Guid="de34d0c6-3b9e-439c-a254-c9f695e2e389">
<File Id="abc.exe" Name="abc.exe" Source="$(var.abc_TargetDir)abc.exe" />
</Component>
<Component Id="abc.exe.config" Guid="3a38ad30-51ce-42fd-b262-1249c7087111">
<File Id="abc.exe.config" Name="abc.exe.config" Source="$(var.abc_TargetDir)abc.exe.config" />
</Component>
</Fragment>
Like the above abc.exe and the .config file, any other file can be sent using the component tag inside the ComponentGroup tag.

How do I conditionally uninstall files in WiX?

I have a WiX package that should always deliver files, but should only uninstall the files when a condition is met. The condition is that common files should not be uninstalled if another version of the product is installed (we are not supporting true upgrades, our upgrade is installing the files to a new folder that has the version of the package and installing new versions of the common files).
I realize this can be achieved by using the same GUIDs across components or using merge modules, but I also have to account for the fact that I have legacy packages from InstallShield that could be installed. Unfortunately, the designers of those packages had no idea of what was going on with installers, and they installed files to a temp directory, then copied them to a new location, so Windows Installer has no knowledge that the files are installed.
I have tried a couple different things.
Approach #1:
<Component Id="myfile.dll" Guid="{YOUR-GUID-HERE}" Transitive="yes" >
<Condition>OTHER_VERSIONS_PRESENT ~= "FALSE"</Condition>
<File Id="myfile.dll" KeyPath="yes" Source="$(var.PATH_TO_BIN_FILES)myfile.dll" />
</Component>
Approach #2:
<Component Id="myfile.dll" Guid="{YOUR_GUID_HERE}" Permanent="yes" >
<File Id="myfile.dll" KeyPath="yes" Source="$(var.PATH_TO_BIN_FILES)myfile.dll" />
</Component>
<Component Id="myfile.dll_remove" Guid="{YOUR_GUID_HERE}" Transitive="yes" >
<RemoveFile Id="myfile.dll_remove" Name="myfile.dll" On="uninstall" />
<Condition>OTHER_VERSIONS_PRESENT ~= "FALSE"></Condition>
</Component>
Additional Info
Here is my property that I am using with the custom actions and the condition:
<Property Id="OTHER_VERSIONS_PRESENT" Value="FALSE" />
Here is my scheduling of the custom action that sets the OTHER_VERSIONS_PRESENT property. I have verified that it is correctly set to true or false, based on whether another version of the product is present.
<Custom Action="FindOtherVersionsOfProduct" After="CostFinalize" />
I have also tried the above approaches with CDATA wrapped around the condition, but this also failed. Additionally, I tried changing the install sequence of when I set the property. I've tried different conditions. But nothing has worked.
Thank you in advance for any support you can give me.
Edit: Approach 1 is working, but once I change it to be
<Condition>NOT Installed OR ((REMOVE ~= "ALL") AND (OTHER_VERSIONS_PRESENT ~= "FALSE"))</Condition>
it no longer works.
My suggestion is that both of those approaches are probably incorrect. The general solution used in all cases I can think of that both packages need to install the same files to same common location. A common merge module containing those components ensures that the Windows Installer sharing works, so uninstalling one product leaves the files behind for the remaining product (because ref counting is based on component ids and just decrements the count when a product is uninstalled). In other words it all just works without transitive components or conditions.

WiX 3.7 UI not linking correctly

Newbie to WiX here... I have created my WiX installer package, and it installs all features correctly. Then I try adding a UI to it with the following:
<UIRef Id="WixUI_Minimal" />
<UIRef Id="WixUI_ErrorProgressText" />
and I link with "light -ext WixUIExtension -cultures:en-us". It finds this extension because it will give an error if I try it with a non-existent name, but the resulting msi package is only 30kb. I assume this should be slightly larger if the UI extension is correctly linked?
When I run the msi, it just gives the normal progress bar and no additional UI that I am expecting from WixUI_Minimal.
All the references seem to claim that a simple UIRef is all you need to get a UI when the package is linked correctly... Is there a known way for the linking to not happen correctly with no errors being thrown (even when I link with -pedantic)?
The MSI may not be significantly larger when you add the UI. There are not many graphics provided by default. However, if you are not seeing UI during the install, that does mean the UI is not being linked in.
The UIRef needs to be in a referenced section. The first section the linker starts with is the Product element. If your UIRef is a child of Product then it will definitely get linked in. The linker then walks through all the references in the Product element (anything that ends in a Ref is a reference as are many other attributes) looking for needed elements in other Fragment elements. The linker then pulls in everything in those Fragment elements. For example:
<Product>
<DirectoryRef Id='TARGETDIR' />
</Product>
<Fragment>
<Directory Id='TARGETDIR' Source='SourceDir' />
<BinaryRef Id='icon' />
<Fragment>
<Fragment>
<Binary Id='icon' Source='path\to\my.ico' />
</Fragment>
<Fragment>
<UIRef Id='WixUI_Minimal' />
</Fragment>
In the above example, the first three sections will be included by the linker. The section with UIRef='WixUI_Minimal' however is left out because nothing references it. To fix it, the UIRef could be moved to any of the other Fragment elements.
To test, try moving your UIRef to your Product element. If that doesn't work, provide more details in your question about where your UIRef is for us to help further.

Using Wix how can I deploy one of several web.config files while installing an ASP.net web application

I'm using Wix 3.6 beta from the command line, not as VS projects. I have a web application that is harvested with heat as a directory. This works. I'm using web.config transforms to manage each of the target environment web.config files. These are output with msbuild, this works and keeps things visible in Visual Studio and source control.
I've hit a problem deploying one of the several web.config files which I am manually including in product.wxs as components with conditions. I was expecting to include all components as deployable features and let the conditions select just one as active. For example:
<DirectoryRef Id="wwwroot">
<Component Id="setup_a" Guid="some_guid" >
<File Source="$(var.ConfigSourceDir)\setup_a\web.config" />
<Condition>ENVIRON = setup_a</Condition>
</Component>
<Component Id="setup_b" Guid="some_guid" >
<File Source="$(var.ConfigSourceDir)\setup_b\web.config" />
<Condition>ENVIRON = setup_b</Condition>
</Component>
This didn't create any file renaming, moving or deleting issues, but has the very fundamental problem that multiple web.config files are mapped to the same destination and this gives me a light error of "Product.wxs(xxx) : error LGHT0091 : Duplicate symbol 'File:web.config' found. This typically means that an Id is duplicated. Check to make sure all your identifiers of a given type (File, Component, Feature) are unique."
An alternative approach was to use different named .config files and rename/move one to be the web.config, so something like:
<DirectoryRef Id="wwwroot">
<Component Id="setup_a" Guid="some_guid" >
<File Id="setup_a.config" Source="$(var.ConfigSourceDir)\setup_a.config" />
<CopyFile Id="moveit" SourceDirectory="wwwroot" SourceName="setup_a.config" DestinationDirectory="wwwroot" DestinationName="web.config" />
</Component>
This doesn't throw an error, bot the CopyFile command does nothing at all. I just get setup_a.config in the wwwroot folder.
If I nest the CopyFile inside the File, the copy action then works:
<DirectoryRef Id="wwwroot">
<Component Id="setup_a" Guid="some_guid" >
<File Id="setup_a.config" Source="$(var.ConfigSourceDir)\setup_a.config" >
<CopyFile Id="moveit" DestinationName="web.config"/>
</File>
</Component>
...but nested CopyFile means I can't add (it's disallowed) the Delete="yes" attribute to create a 'move' action. Instead I'm left with both setup_a.config and web.config in the wwwroot folder. Alternatively, if I add a seperate removefile within the same component element it also does nothing:
<RemoveFile Id="removefile" On="install" Directory="wwwroot" Name="setup_a.config"/>
</Component>
So, I'm hoping for a working example of how handle multiple web.config files in a conditional deployment, that doesn't leave files behind. the destination filename of web.config is fixed by the framework and can't be changed. The different configs are also pre-generated outside of wix using config transforms, this also can't be changed but the generated filenames could be anything.
cheers!
You complicate it too much. This should work:
<Component Id="setup_a" Guid="some_guid" >
<File Name="web.config" Id="config_a" Source="$(var.ConfigSourceDir)\setup_a\web.config" />
<Condition>ENVIRON = setup_a</Condition>
</Component>
<Component Id="setup_b" Guid="some_guid" >
<File Name="web.config" Id="config_b" Source="$(var.ConfigSourceDir)\setup_b\web.config" />
<Condition>ENVIRON = setup_b</Condition>
</Component>
Pay attention to a couple of things here:
the File/#Name is the same - that's the target file name you'd like to have (web.config)
the File/#Id is different for each File in order to avoid the light error you mentioned first
the File/#Source can be anything - it just describes what file to take as a source
In this sample light will still complain with warning LGHT1076, but that's just a warning - it pays your attention that conditions MUST be mutually exclusive to avoid problems.
I usually take a different approach. Rather then placing multiple mutually exclusive files into an installer that are tightly coupled to specific instances I put a generic file in the installer and use XML changes to transform the XML with the variation point data such as connection string and what not.
This allows me to make installers that can be deployed anywhere silently just by passing a few properties and the command line.