Wix XmlFile is keeping SqlDatabase from creating databases - wix

I've got a Wix project made up of several fragments. One of those fragments has the database components, another has a component that manipulates xml files.
When I include the XmlFile element to manipulate a file, the databases defined by the SqlDatabase do not get created. If I comment out the XmlFile, then the databases do get created.
Here are the two wix files with fragments that are being used:
Database:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:sql="http://schemas.microsoft.com/wix/SqlExtension">
<Fragment>
<DirectoryRef Id="TARGETDIR">
<Component Id="Database1Creation" Guid="GUID_HERE">
<sql:SqlDatabase Id="Database1"
Server="[DATABASE_SERVER]" Database="[DATABASE_NAME]"
CreateOnInstall="yes" ConfirmOverwrite="no"
DropOnUninstall="yes">
</sql:SqlDatabase>
</Component>
</DirectoryRef>
</Fragment>
</Wix>
Xml Manipulation:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:sql="http://schemas.microsoft.com/wix/SqlExtension"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="MyDirectory">
<Component Id="ServiceExecutables" Guid="GUID_HERE">
<File Id="File1" Name="File1.xml" Source="Source/File1.xml" />
<util:XmlFile Id="UpdateFile1" File="[INSTALLDIR]File1.xml" Action="setValue" ElementPath="//SomeContainer/SomeElement" Value="[SOME_VALUE]" />
</Component>
</Directory>
</Directory>
</Directory>
</Fragment>
</Wix>
There are other things that are also installed, but they don't appear to have any influence on the issue (I've removed everything else and tested the install).
When looking at the install logs when using XmlFile and when not, they are almost exact copies of each other, except that the SqlDatabase calls would be completely missing, and the XmlFile calls would be in their place.
Is there a known bug here? Or am I doing something I shouldn't be? This isn't a killer for our app, since I can move the things I'm putting in the xml file into the registry, but I'd rather not do that.
I am using Wix 3.5.

Good news, build 1616 fixes this. Update Wix ASAP.

Related

Can I use auto-generated GUIDS with a merge module?

I use auto-guids in my <Product> but can't figure out how to use them with <Module>. I only get this error:
The component X has a key file with path 'TARGETDIR\company...'.
Since this path is not rooted in one of the standard directories (like
ProgramFiles Folder), the component does not meet the criteria for
having an automatically generated guid.
Above, company is the value mapped to !(loc.ProductManufacturerFolderName).
The only problem is that's not true. My directories are rooted in ProgramFiles just like my product is and my product works fine:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="MODULEINSTALLLOCATION" Name="!(loc.ProductManufacturerFolderName)">
<Directory Id="Data" Name="Data">
All my component declarations look roughly like this:
<Component Id="DocumentationParty_Business_TestCases_v1xlsx.component" Guid="{YOURGUID-1234-1234-84B3-C595A63428AD}" MultiInstance="yes">
<File Source="../../Development/Integration/SSIS/Documentation/Party_Business_Test Cases_v1.xlsx" KeyPath="yes" Id="DocumentationParty_Business_TestCases_v1xlsx.file" />
</Component>
Breaking it is easy, you only have to change the GUID to * and the above error results. This is broken:
<Component Id="DocumentationParty_Business_TestCases_v1xlsx.component" Guid="*" MultiInstance="yes">
<File Source="../../Development/ClaimsIntegration/SSIS/Documentation/Party_Business_Test Cases_v1.xlsx" KeyPath="yes" Id="DocumentationParty_Business_TestCases_v1xlsx.file" />
</Component>
I have a .wxs file for each directory to which components will be installed. All my component-holding .wxs files have the following structure:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<ComponentGroup Id="DatabasePolicy_Files">
<ComponentRef Id="DatabasePolicyCreateDatabasecmdtemplate.component" />
</ComponentGroup>
<DirectoryRef Id="DataPolicy">
<Component Id="DatabasePolicyCreateDatabasecmdtemplate.component" Guid="*" MultiInstance="yes">
<File Source="../../Development/Database/Policy/CreateDatabase.cmd.template" KeyPath="yes" Id="DatabasePolicyCreateDatabasecmdtemplate.file" />
</Component>
</DirectoryRef>
</Fragment>
</Wix>
Each <ComponentGroup> is included in my master .wxs file through a <ComponentGroupRef>. This works in all my MSI projects and breaks only now that I've started working with merge modules. Also, I've tried commenting out all components except for which matches the above definition and it still breaks on the same error.
What is the problem?
I've had this similar issue myself and based on your error message it's probably the same.
Try adding a ComponentGuidGenerationSeed, that should solve your issue. The ComponentGuidGenerationSeed acts on all subfolders as well so a single one at the top-level is sufficient for all folders.
Example:
<Directory Id="DOCUMENTATIONFOLDER" Name="Documentation" ComponentGuidGenerationSeed="a9f690d3-22b3-488f-bdac-bb665c25933c"/>
http://wixtoolset.org/documentation/manual/v3/xsd/wix/directory.html
The Component Guid Generation Seed is a guid that must be used when a
Component with the generate guid directive ("*") is not rooted in a
standard Windows Installer directory (for example, ProgramFilesFolder
or CommonFilesFolder).

WIX deploy two assemblies to GAC

Using WIX, and trying to install two of the same assemblies, one for .Net35 and the other .Net40. I am using two separate components, however WIX is preventing the project from compiling.
<Directory Id="GAC40" Name="GAC">
<Component Id="MyDllServicesModuleGac40Component" Guid="307675AA-8AEC-473B-A78A-FB362CCEDE2A" Win64="yes">
<File Id="MyDllNet40DllGac" Name="MyDll.dll" KeyPath="yes" Assembly=".net" Source="..\MyDll\bin\Net40\MyDll.dll" />
</Component>
</Directory>
<Directory Id="GAC35" Name="GAC">
<Component Id="MyDllServicesModuleGac35Component" Guid="47E6BD1B-25CD-466D-945E-06DCF0F2A269" Win64="yes">
<File Id="MyDllNet35DllGac" Name="MyDll.dll" KeyPath="yes" Assembly=".net" Source="..\MyDll\bin\Net35\MyDll.dll" />
</Component>
</Directory>
The error I receive is:
Error 29 ICE30: The target file 'MyDll.dll' is installed in '[TARGETDIR]\GAC\' by two different components on an SFN system: 'MyDllServicesModuleGac40Component.DDD7D974_FE9C_4BA3_BDD3_A1A3A23F8057' and 'MyDllServicesModuleGac35Component.DDD7D974_FE9C_4BA3_BDD3_A1A3A23F8057'. This breaks component reference counting. D:\PROJECTS\MyDll.Experimental.3.0.0\Project\MyDll\MyDll.Wix.Services\MergeModule.wxs 34 1 MyDll.Wix.Services
The installer should be able to detect that the .Net35 dll gets installed to the GAC at C:\Windows\assembly, while the .Net40 dll gets installed to the GAC at C:\Windows\Microsoft.NET\assembly.
Renaming the DLLs is not an option.
Thanks!
UPDATE
Naturally I came up with a solution just after posting, seem wrapping the components in additional elements allowed me to get this to work. Later I read Tom Blodget's post so that is correct.
<Directory Id="GAC1" Name="GAC">
<Directory Id="GAC40" Name="GAC">
<Component Id="MyDllServicesModuleGac40Component" Guid="307675AA-8AEC-473B-A78A-FB362CCEDE2A" Win64="yes">
<File Id="MyDllNet40DllGac" Name="MyDll.dll" KeyPath="yes" Assembly=".net" Source="..\MyDll\bin\Net40\MyDll.dll" />
</Component>
</Directory>
</Directory>
<Directory Id="GAC2">
<Directory Id="GAC35" Name="GAC">
<Component Id="MyDllServicesModuleGac35Component" Guid="FD74504A-6FE9-488E-9086-9DAD3024B35D" Win64="yes">
<File Id="MyDllNet35DllGac" Name="MyDll.dll" KeyPath="yes" Assembly=".net" Source="..\MyDll\bin\Net35\MyDll.dll" />
</Component>
</Directory>
</Directory>
Well, hope it helps someone!
As explained by Aaron Stebner,
When you use the attribute Assembly=".net" for a file in WiX, it will
create entries in the MsiAssembly and MsiAssemblyName table for this
component and mark it as a GAC component. That means that the file
will only be installed to the GAC by this component, and it will not
install to the directory that the component is a child of. That
directory will only be used by Windows Installer to stage a copy of
that file when creating an administrative install point.
So the directories for your two components must be different since the file names are the same. If nothing else is targeted for those directories, they won't even be created. I put my GAC components under a subdirectory of my install folder:
<Directory Id="tmp_to_GAC" Name="tmp_to_GAC">
You'd need one for each GAC.

WiX - How to change name of a directory after installation

Pretty simple question, suppose my app will be installed as
myApp
+-- bin
+-- lib
I'd like to rename "lib" to "plugins" after installation, how can i do that?
There is a MoveFiles Element that might help, but no idea how to use it.
EDIT:
The problem here is, in my case, source files could be installed into different paths, this scenario described in here.
The only way I can figure out is to create two component groups and install them conditionally. However, using heat to harvest same subdir twice will cause ID conflicting, so I'm thinking to use different paths(e.g. lib and another-lib), and then rename one of the path back after installation, so this question arised...
Don't. Install the files correctly up front. The way that the Windows Installer tracks things will fight you every step of the way. Just install the files in the correct folder from the beginning. Probably not the answer you wanted.
I finally wrote a C++ program to extend heat generated wxs with another directory structure. So we can decide which path to install under different situations. It worked just like changing name during installation.
Here is the wxs file patched by my program. Basically it creates another directory WEBIDR and different subdirs, then adds another component group webGroup for later reference by condition element.
You can do the same thing manually, but if there are thousands of files awaiting, and if they are frequently updating, maybe a program(or script) is a better choice.
<Fragment>
<DirectoryRef Id="INSTALLDIR">
<Directory Id="dirA5528701EE26FFBF346CCE20EE8ACE99" Name="bin">
<Component Id="cmpEBA9C2A32D81BA8646BD1A64DBB39DB1" Guid="{142C531A-C71C-4890-9318-0FC42026C8FC}">
<File Id="filDB56E052EC783676CEF361C0C5AA71F3" KeyPath="yes" Source="$(var.runDir)\bin\boost_date_time-vc100-mt-1_47.dll" />
</Component>
</Directory>
<Directory Id="dir3279BEF4E08D9A00D2F205F325F00A81" Name="modules">
<Component Id="cmpDECCAE13F8937500E4AC367A8EAC95F4" Guid="{85CC0C94-1BFB-4062-BC4E-FBF143921301}">
<File Id="filDD3B40D68D0437B18B1108FBA49ABC1B" KeyPath="yes" Source="$(var.runDir)\modules\HelloAPI.dll" />
</Component>
</Directory>
</DirectoryRef>
<DirectoryRef Id="WEBDIR">
<Component Id="webcmpEBA9C2A32D81BA8646BD1A64DBB39DB1" Guid="{fec110c5-a1a0-4b07-8a35-50f1af84001a}">
<File Id="webfilDB56E052EC783676CEF361C0C5AA71F3" KeyPath="yes" Source="$(var.runDir)\bin\boost_date_time-vc100-mt-1_47.dll" />
</Component>
<Directory Id="webdirpluginF4E08D9A00D2F205F325F00A81" Name="plugins">
<Component Id="webcmpDECCAE13F8937500E4AC367A8EAC95F4" Guid="{3ef79a47-7681-4991-9726-02db38c22f6d}">
<File Id="webfilDD3B40D68D0437B18B1108FBA49ABC1B" KeyPath="yes" Source="$(var.runDir)\modules\HelloAPI.dll" />
</Component>
</Directory>
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup Id="runGroup">
<ComponentRef Id="cmpEBA9C2A32D81BA8646BD1A64DBB39DB1" />
<ComponentRef Id="cmpDECCAE13F8937500E4AC367A8EAC95F4" />
</ComponentGroup>
<ComponentGroup Id="webGroup">
<ComponentRef Id="webcmpEBA9C2A32D81BA8646BD1A64DBB39DB1" />
<ComponentRef Id="webcmpDECCAE13F8937500E4AC367A8EAC95F4" />
</ComponentGroup>
</Fragment>

Copy file from setup location to another location in wix on install

I have created an msi setup file which includes some files in a "Sample" folder which should be copied to a temp folder. Anybody suggest how to do this?
Something like this:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="MyVendor" Name="MyVendor">
<Directory Id="INSTALLDIR" Name="MyDir">
<Component Id="MyFileId" Guid="...G1...">
<File Id="MyFileId" Name="MyFile" Source="...blabla...\MyFile" KeyPath="yes" >
</File>
</Component>
<DirectoryRef Id="TARGETDIR">
<Component Id="MyFileCopyId" Guid="...G2...">
<RemoveFile Id="MyFileRemoveId" Name="MyFile" On="install" Directory="MyCopyDir" />
<CopyFile Id="MyFileCopyId" FileId="MyFileId" DestinationDirectory="MyCopyDir" />
</Component>
<Feature Id="MyFeature" ... >
<ComponentRef Id="MyFileId" />
<ComponentRef Id="MyFileCopyId" />
The important Xml element is CopyFile. You need to create a new component that is a copy of the first one (with different ids, guids, ... of course). Both components needs to be declared in a feature.
CopyFile element is your friend. You can nest it under the original File element a number of times, depending on how many times you need to copy it. Put the correct destination folder(s) and let Windows Installer do the rest.

Upgrade individual feature in WIX feature-tree without uninstalling/upgrading other feature(s)

I'm trying to create a setup project using WIX that will allow me to install multiple features of a single product. How can I update one of the installed features (which is independent of the other installed features) without having to reinstall the other features in the feature-tree?
For example, I want to be able to have a project (going back to HelloWolrd) called HelloWolrd, which (surprise) prints "Hello world!" on the screen. Let's say that I have three of these hello world applications, Hello World 1, Hello World 2, and Hello World 3. Each of which prints on the screen Hello World 1, 2, or 3, respectfully. What I would like is to create an MSI which by default installs all three of these "features" but also allows upgrading of each feature individually at a later time.
Here is my layout of my solution:
Solution Explorer http://img12.imageshack.us/img12/5671/solutionexplorerm.jpg
My WIX Product.wxs file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="ca484210-c719-4b2e-b960-45212d407c11" Name="HelloWorldInstaller" Language="1033" Version="1.0.0.0" Manufacturer="HelloWorldInstaller" UpgradeCode="68eeb8cb-9ef3-443c-870c-9b406129f7ff">
<Package InstallerVersion="200" Compressed="yes" />
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />
<!-- Create Directory Structure -->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLLOCATION" Name="Hello World" />
</Directory>
<Directory Id="DesktopFolder" Name="Desktop"/>
</Directory>
<DirectoryRef Id="INSTALLLOCATION">
<Component Id="HelloWorld1" Guid="6D1D9D33-DA17-4db3-8132-C39F32200C3A">
<RegistryKey Root="HKCU" Key="Software\HelloWorldInstaller\HelloWorld1\Install" Action="createAndRemoveOnUninstall">
<RegistryValue Name="DTSC" Value="1" Type="integer" KeyPath="yes" />
</RegistryKey>
<File Id="HelloWorld1.exe" Name="$(var.HelloWorld1.TargetFileName)" Source="$(var.HelloWorld1.TargetPath)" DiskId="1" Checksum="yes">
<Shortcut Id="HelloWorld1ApplicationDesktopShortcut" Name="Hello World 1" Description="Hello World Application 1" Directory="DesktopFolder" WorkingDirectory="INSTALLLOCATION" />
</File>
</Component>
<Component Id="HelloWorld2" Guid="B2D51F85-358B-41a7-8C45-B4BB341158F8">
<RegistryKey Root="HKCU" Key="Software\HelloWorldInstaller\HelloWorld2\Install" Action="createAndRemoveOnUninstall">
<RegistryValue Name="DTSC" Value="1" Type="integer" KeyPath="yes" />
</RegistryKey>
<File Id="HelloWorld2.exe" Name="$(var.HelloWorld2.TargetFileName)" Source="$(var.HelloWorld2.TargetPath)" DiskId="1" Checksum="yes">
<Shortcut Id="HelloWorld2ApplicationDesktopShortcut" Name="Hello World 2" Description="Hello World Application 2" Directory="DesktopFolder" WorkingDirectory="INSTALLLOCATION" />
</File>
</Component>
<Component Id="HelloWorld3" Guid="A550223E-792F-4169-90A3-574D4240F3C4">
<RegistryKey Root="HKCU" Key="Software\HelloWorldInstaller\HelloWorld3\Install" Action="createAndRemoveOnUninstall">
<RegistryValue Name="DTSC" Value="1" Type="integer" KeyPath="yes" />
</RegistryKey>
<File Id="HelloWorld3.exe" Name="$(var.HelloWorld3.TargetFileName)" Source="$(var.HelloWorld3.TargetPath)" DiskId="1" Checksum="yes">
<Shortcut Id="HelloWorld3ApplicationDesktopShortcut" Name="Hello World 3" Description="Hello World Application 3" Directory="DesktopFolder" WorkingDirectory="INSTALLLOCATION" />
</File>
</Component>
</DirectoryRef>
<Feature Id="HelloWorld1Feature" Title="Hello World 1" Level="1">
<ComponentRef Id="HelloWorld1"/>
</Feature>
<Feature Id="HelloWorld2Feature" Title="Hello World 2" Level="1">
<ComponentRef Id="HelloWorld2"/>
</Feature>
<Feature Id="HelloWorld3Feature" Title="Hello World 3" Level="1">
<ComponentRef Id="HelloWorld3"/>
</Feature>
</Product>
</Wix>
Now, when this is built, it installs the features as you would expect. However, when you make a modification to HelloWorld1.vb and recompile, I would like it to be able to reinstall (upgrade) only that feature, not all of them.
When I update one file, and rebuild the solution, then try to install the msi, i get this error:
MSI Error http://img696.imageshack.us/img696/849/anotherversionisinstall.jpg
I updated my code to allow for uninstalling of the features and allow the use of upgrade codes, but that un-installed all of the features, and re-installed all of them.
-- Real world application --
The real world application to this is a large software package that needs multiple support applications that run as services/scheduled tasks on a regular basis. I would like to get the install of these supporting apps into one MSI allowing us to not have such a nightmare of rolling out each exe individually. I know that if we have an update to one of the exe's that we could just manually compile that exe and roll it out, but I'd like to do this in a completely reproducible manner.
Any help would be appriciated,
Thank you!
EDIT:
I added the source for download from Google Code. Thanks again!
I got this figured out and thought I would post the answer here for future reference for others. So I have fully explained the problem, I will go in to more depth of the real world scenario.
We have a moderately large piece of software that requires us to have multiple supporting applications that run on a number of different servers. Our current progression of upgrades makes it moderately difficult to upgrade code in a reliable fashion. Currently we use self extracting exe's to rollout our code to the different servers. The problem arises when we have such a large number of supporting applications that it becomes hard to make sure that the applications got installed correctly with the correct configuration settings, etc. To solve this problem we are looking into the ability to instead of compressing each of the supporting applications, we create a single installer (MSI) that will allow the infrastructure team to install a specific set of supporting applications to each given machine. When we have a major change (for example from 1.0 to 2.0) we will do a full upgrade install (meaning all services/processes will need to be stopped, un-installed, installed, and started.) When we have a minor change, we would like to only have to stop and reinstall the affected services/processes, without touching other applications. Now, enough of me rambling, lets get to the solution:
I modified the WIX Product.wxs to remove the shortcuts as we don't really need them in our scenario. Here is the updated wxs file:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="13C373D3-5C27-487e-A020-C2C89E4607B1" Name="HelloWorldInstaller" Language="1033" Version="1.0.0.0"
Manufacturer="HelloWorldInstaller" UpgradeCode="E7CB3C76-4D51-48a8-BFB4-6D11B2E2E65B">
<Package InstallerVersion="200" Compressed="yes" />
<Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
<FeatureRef Id="HelloWorld1Feature" />
<FeatureRef Id="HelloWorld2Feature" />
<FeatureRef Id="HelloWorld3Feature" />
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLLOCATION" Name="Hello World" />
</Directory>
<Directory Id="DesktopFolder" Name="Desktop"/>
</Directory>
</Fragment>
<Fragment>
<DirectoryRef Id="INSTALLLOCATION">
<Directory Id="HelloWorld1Directory" Name="Hello World 1">
<Component Id="HelloWorld1Component" Guid="6D1D9D33-DA17-4db3-8132-C39F32200C3A">
<File Id="HelloWorld1.exe" Name="HelloWorld1.exe" Source="HelloWorld1.exe" DiskId="1" Checksum="yes" />
</Component>
</Directory>
<Directory Id="HelloWorld2Directory" Name="Hello World 2">
<Component Id="HelloWorld2Component" Guid="B2D51F85-358B-41a7-8C45-B4BB341158F8">
<File Id="HelloWorld2.exe" Name="HelloWorld2.exe" Source="HelloWorld2.exe" DiskId="1" Checksum="yes" />
</Component>
</Directory>
<Directory Id="HelloWorld3Directory" Name="Hello World 3">
<Component Id="HelloWorld3Component" Guid="A550223E-792F-4169-90A3-574D4240F3C4">
<File Id="HelloWorld3.exe" Name="HelloWorld3.exe" Source="HelloWorld3.exe" DiskId="1" Checksum="yes" />
</Component>
</Directory>
</DirectoryRef>
</Fragment>
<Fragment>
<Feature Id="HelloWorld1Feature" Title="Hello World 1" Level="1">
<ComponentRef Id="HelloWorld1Component"/>
</Feature>
</Fragment>
<Fragment>
<Feature Id="HelloWorld2Feature" Title="Hello World 2" Level="1">
<ComponentRef Id="HelloWorld2Component"/>
</Feature>
</Fragment>
<Fragment>
<Feature Id="HelloWorld3Feature" Title="Hello World 3" Level="1">
<ComponentRef Id="HelloWorld3Component"/>
</Feature>
</Fragment>
</Wix>
Now along with this, for our minor upgrades, we will be looking at releasing patches for our components.
For example, let's say we have a ProductA, which has three components - 1,2, and 3. These three components must run either as services, or scheduled tasks. The nature of our product, we cannot shut down all of our services to update or fix one of our components. So, if after we've installed version 1.0, we find a bug in component 2, but we don't want 1 or 3 to be affected by the fix being applied to this bug, we will be releasing a patch for component 2, thus only component 2 will be affected.
For our quick example above, we are using HelloWorld1, HelloWorld2, and HelloWorld3 as our 3 components in our software application. The thought is that we should be able to install all three with one MSI, but then update each one independently without it affecting any of the other installed components.
So, to demonstrate this, I have created the three console applications above that will display "Hello World 1!", "Hello World 2!", and "Hello World 3!". Then after we release the initial MSI, lets say we find a "bug" that requires us to have HelloWorld1 say "Hello World 1! Updated." instead. Here is what we will do to simulate this:
Create the Product.wixobj by executing this command at the command prompt:candle.exe Product.wxsPlease remember that in order to call the candle.exe or any of the WIX commands, the Wix install directory should be in your PATH variable. (Short tutorial on updating PATH environment variable) Also, please perform the commands in the same directory as your Product.wxs file.
Create the first version of your product (lets say 1.0): light.exe Product.wixobj -out ProductA-1.0.msi
Now find a bug (change the output of HelloWorld1 to say "Hello World 1! Updated.") then update the assembly version and file version. This is important as this is how WIX can tell the exe's are different.
Run the same command as step one (for good measure): candle.exe Product.wxs
Run nearly the same command as step two: light.exe Product.wixobj -out ProductA-1.1.msi Notice that this is version 1.1 instead of 1.0 (this is the msi with our updated code). However, we don't want to just install this, keep reading.
Here is the fun part, we get the difference in the two MSIs with the following command: torch.exe -p -xi ProductA-1.0.wixpdb ProductA-1.1.wixpdb -out Diff.WixMst
Now we create the patch file from this (Patch.wxs will be explained below): candle.exe Patch.wxs
We will now create the WixMsp file with this command: light.exe Patch.wixobj -out Patch.WixMsp
And now, the fun part. Create the MSP file with this command: pyro.exe Patch.WixMsp -out Patch.msp -t RTM Diff.Wixmst
Now, if everything went according to plan, you should have two msi's and one msp file. If you install the first msi (ProductA-1.0.msi) and run HelloWorld1.exe, you should see the message, "Hello World 1!". Just for fun (and example), run both the other applications and leave them running (I built in a stop to keep them open). Close HelloWorld1.exe as we are now going to apply the update for that exe, but in doing so we will not affect HelloWorld2.exe or HelloWorld3.exe. If you now install the msp (Patch.msp) file, and then run HelloWorld1.exe, you will see the updated message, "Hello World 1! Updated."
Now, for the magical Patch.wxs file:
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Patch
AllowRemoval="yes"
Manufacturer="Dynamo Corp"
MoreInfoURL="http://www.dynamocorp.com/"
DisplayName="Sample Patch"
Description="Small Update Patch"
Classification="Update"
>
<Media Id="5000" Cabinet="RTM.cab">
<PatchBaseline Id="RTM"/>
</Media>
<PatchFamilyRef Id="SamplePatchFamily"/>
</Patch>
<Fragment>
<PatchFamily Id='SamplePatchFamily' Version='1.0.0' Supersede='yes'>
<ComponentRef Id="HelloWorld1Component"/>
</PatchFamily>
</Fragment>
</Wix>
Doesn't look like much, does it? Well, the most interesting parts are these:
<PatchBaseline Id="RTM"/> - This if you recall is used in our creation of the patch msi. The "RTM" is referred to in the last step above: -t RTM - These have to match.
<ComponentRef Id="HelloWorld1Component"/> - This points the patch to the correct component to update, in our case HelloWorld1Component.
If you've been doing any searching around, the above code may seem familiar because it came from Peter Marcu's Blog: WiX: Building a Patch using the new Patch Building System - Part 3
I also relied heavily on Alex Shevchuk's Blog: From MSI to WiX, Part 8 - Major Upgrade
If you're wondering, "Wow, that's a lot of steps, why would anyone do this many steps?", please remember that once the hard work (above) is done, you need to move this into your integration routine. Thats right, integrate, integrate, integrate! How do you do this? Well, thats a bit more research, and maybe a blog post? - Probably. To get you off on the right foot, here is an awesome article on Automate Releases With MSBuild And Windows Installer XML.
Wow, I hope you read all of this (all two of you), and learned a lot. I hope this helps someone other than myself.
Thank you!
Sounds like you figured out the upgrade scenario, now you just need to figure out Where to place RemoveExistingProducts in a major MSI upgrade so that features aren't reinstalled if they haven't changed :)