Wix toolset Multiple Instances Installation - wix

Some months ago I posted this question about multiple installation, and I strictly followed the example suggested me.
It worked very fine, but I try to remove the default Instance.
When I type
msiexec /x MyInstaller.msi
my App is "logically" removed, but no folders and no files are deleted on my machine!
Here is the code:
<Directory Id="TARGETDIR" Name="SourceDir">
<Component Id="comp_67F76B3C_8D92_4DCF_8C51_42E51502C4A3" Guid="28C71156-F612-49ED-A4E9-0CB598AA84AB" MultiInstance="yes">
<CreateFolder/>
</Component>
<Component Id="comp_AA102B27_0657_498D_9CD5_683C4F33B5E2" Guid="0F601C97-CDFF-4614-A608-B42253240E2C">
<File Id="_C72F9A1F_AF4A_47A3_928C_238643ABA5D4" Name="CrashReportManager.exe" Source="..\workspace\Release\CrashReportManager.exe" KeyPath="yes" />
</Component>
<Component Id="comp_442142FD_D0B8_410C_8904_E73047757FAB" Guid="0A1AE820-0FF7-442C-8333-9FEFA2E3F33C">
<File Id="_CA463C5C_E397_40E6_9B7B_28CCA647D0CA" Name="BCGCBPRO2440d120.dll" Source="..\workspace\Debug\BCGCBPRO2440d120.dll" KeyPath="yes" />
</Component>
<Directory Id="dir_350BD3EA_2F6C_4AD4_A960_8AB2C40F4F36" Name="Docs">
<Component Id="DocFolderId" Guid="32DAE480-7C01-4BAA-B99D-9FE8D7D43369" MultiInstance="yes">
<CreateFolder />
</Component>
<Component Id="comp_FFFDE3FE_1205_4E74_82B1_E832501A096C" Guid="EECC223C-EBAD-43CA-9F3C-4A19FD9E7429">
<File Id="_D0FE1868_D0D7_4778_8BC6_D40FE2B21DB2" Name="ModuleList(1).txt" Source="..\ModuleList(1).txt" KeyPath="yes" />
</Component>
<Component Id="comp_07E32598_CA8D_46B6_A3D6_DA36FD308E1F" Guid="FCCC41AA-17BC-4ADA-925D-631A614C9F80">
<File Id="_894CFDFB_4514_4CAC_86C3_426CC6836B7C" Name="ModuleList(2).txt" Source="..\ModuleList(2).txt" KeyPath="yes" />
</Component>
<Component Id="comp_21465088_A65C_43D4_A038_93412404BA91" Guid="67D18D29-6466-4D36-A279-A9396A62019C">
<File Id="_C9362477_88D8_463C_B77D_7097255F5E13" Name="ModuleList.txt" Source="..\ModuleList.txt" KeyPath="yes" />
</Component>
<Component Id="comp_3C85BB37_5715_45E7_A135_C640D7348360" Guid="6DDB0F88-7346-4221-8FB1-106C5F707EE5">
<File Id="_BFE55263_BD18_427B_9F87_30403BB2540D" Name="ReadMe.txt" Source="..\ReadMe.txt" KeyPath="yes" />
</Component>
</Directory>
</Directory>
What's wrong?

You used KeyPath="yes" in all of your components. This means, that such a component is used as a checkpoint for the Windows installer, for example if you want to repair an installation. It means that it is a mandatory component required for the application to function.
Since you are using multiple instances, and you mentioned you installed more than just the default instance, the Windows installer does not remove key components until the last one of the instances is getting uninstalled (i.e. it keeps track of them internally with a reference counter).

Use MultiInstance="yes" for each and every component, and like Yan says, get rid of the <CreateFolder/> component

Related

Install component only during fresh install but not during upgrade

I have a component say web.config, in this component I have included a web.config file.
<Component Directory="FeatureA" Guid="{692AA53D-4DFB-4FA0-A6FD-D30905383D1D}" Id="web.config" Permanent="yes">
<File KeyPath="yes" Source="Content\web.config" />
</Component>
During upgrades, I dont want to install this component. So, I have added a condition
<Component Directory="FeatureA" Guid="{692AA53D-4DFB-4FA0-A6FD-D30905383D1D}" Id="web.config" Permanent="yes">
<Condition>[WixBundleInstalled]=0</Condition>
<File KeyPath="yes" Source="Content\web.config" />
</Component>
The above condition not working during upgrades. Component is installing during upgrades. What should I add inside condition, so that the component should not install during upgrades?

How do I tell wix to install a file in a directory set in a property?

I want to do the following where XLSTART is defined as:
<CustomAction Id="AssignXLSTART" Return="check" Execute="firstSequence" Directory ='XLSTART' Value='[AppDataFolder]\Microsoft\Excel\XLSTART'>
</CustomAction>
And then I have a subsequent CustomAction that calls some C# code that may change this value.
And then in the list of files to install I have:
<Directory Id="XlStartFolderId" Name="[XLSTART]">
<Component Id="ExcelMacro_xla" Guid="26D21093-B617-4fb8-A5E7-016493D46055" DiskId="1">
<File Id="ExcelXLA" Name="AutoTagExcelMacro.xlam" ShortName="XLMacro.xla" Source="$(var.srcFolder)\AutoTagExcelMacro.xlam"/>
</Component>
</Directory>
But the above puts it in the INSTALLDIR[XLSTART]. How do I get it to read this as a property?
You should be able to install to the userprofile directory you refer to like this:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="LocalAppDataFolder">
<Directory Id="Microsoft" Name="Microsoft">
<Directory Id="Excel" Name="Excel">
<Directory Id="XLSTART" Name="XLSTART">
<Component Id="ExcelAddIn" Feature="MyFeature" Guid="{11111-1111-GUID-HERE-YOURGUIDHERE}">
<File Source="C:\SourceFiles\MyAddin.xla" />
<RemoveFolder Id="Microsoft" On="uninstall" Directory="Microsoft" />
<RemoveFolder Id="Excel" On="uninstall" Directory="Excel" />
<RemoveFolder Id="XLSTART" On="uninstall" Directory="XLSTART" />
<RegistryValue Root="HKCU" Key="Software\MySoftware" Name="installed" Type="integer" Value="1" KeyPath="yes" />
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
I would suggest you use the per-machine xlstart folder instead - if it still exists. I am not sure it does. The the addin is loaded for every user on the box on every launch. Generally I prefer this. It has been ages since I looked at this, so this could have changed in newer Office versions - in fact I am sure it has, but the details are unclear to me.
System Folder Properties: There are a number of System Folder Properties that can be used in MSI files to specify installation location - LocalAppDataFolder is just one of them: https://learn.microsoft.com/en-us/windows/win32/msi/property-reference#system-folder-properties
Figured it out. You need to install to the INSTALLDIR and then use CopyFile
<!-- place it in C:\Program Files (x86)\Microsoft Office\Root\Office16\XLSTART\ -->
<Component Id="ExcelMacro_xla" Guid="26D21093-B617-4fb8-A5E7-016493D46055" DiskId="1">
<File Id="ExcelXLA" Name="AutoTagExcelMacro.xlam" ShortName="XLMacro.xla" Source="$(var.srcFolder)\AutoTagExcelMacro.xlam">
<CopyFile Id='CopyXlMacro' DestinationProperty='XLPATH' DestinationName='AutoTagExcelMacro.xlam'/>
</File>
</Component>

Files not getting copied to install directory using WIX and WAX

I have some additional unmanaged dll's that need to be copied to the install folder. I am using WAX as well as it is supposed to make Wix easier to use. I have added the following markup to Product.wxs:
<Component Id="DataModel1.csdl" Guid="f8fb154d-f0c9-40f5-9bcf-593ed9540bda" Directory="INSTALLFOLDER">
<File Id="DataModel1.csdl" Name="DataModel1.csdl" Source="$(var.FLIR_TargetDir)DataModel1.csdl" />
</Component>
<Component Id="DataModel1.ssdl" Guid="a13c3c3b-e6a6-40ea-b9d8-84fd093ca0d5" Directory="INSTALLFOLDER">
<File Id="DataModel1.ssdl" Name="DataModel1.ssdl" Source="$(var.FLIR_TargetDir)DataModel1.ssdl" />
</Component>
<Component Id="DataModel1.msl" Guid="e308d75b-1f0b-4234-843d-6b44af2e80a9" Directory="INSTALLFOLDER">
<File Id="DataModel1.msl" Name="DataModel1.msl" Source="$(var.FLIR_TargetDir)" />
</Component>
<Component Id="Devart.Data.dll" Guid="a95a3053-7d4a-4030-b8c9-9d860a81a221" Directory="INSTALLFOLDER">
<File Id="Devart.Data.dll" Name="Devart.Data.dll" Assembly=".net" KeyPath="yes" Source="C:\Program Files (x86)\Devart\dotConnect\SQLite\Devart.Data.dll" />
</Component>
<Component Id="Devart.Data.SQLite.dll" Guid="16d0ca3c-425d-49e9-a754-043b0b9e4ada" Directory="INSTALLFOLDER">
<File Id="Devart.Data.SQLite.dll" Name="Devart.Data.SQLite.dll" Assembly=".net" KeyPath="yes" Source="C:\Program Files (x86)\Devart\dotConnect\SQLite\Devart.Data.SQLite.dll" />
</Component>
The files shows up as an unmapped file in the unmapped files area of the UI:
When the install happens the files do not get installed into the installation folder. What am I doing wrong?
The Assembly=".NET" tell's MSI to install the files in the Global Assembly Cache. The parent directory element is ignored/overridden. See:
http://wixtoolset.org/documentation/manual/v3/xsd/wix/file.html
If your looking for a tool to make WiX easier to learn/use then I'd suggest my own open source project:
https://github.com/iswix-llc/iswix-tutorials

Add resource files in wix installer

I have created a multi lingual app that uses 2 diferent resource files to manage the UI language, so when I build and execute my program, in my bin directory I have my app files and two folders, en-GB and pt-PT.
I am now trying to create a installer with Wix, for that I am defining the following directories:
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="App" >
<Directory Id="LOCALEEN" Name="en-GB"/>
<Directory Id="LOCALEPT" Name="pt-PT"/>
</Directory>
</Directory>
</Directory>
</Fragment>
And then, I define the following components:
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="App.resources.en.GB.dll" Guid="...">
<CreateFolder />
<File Id="App.resources.en.GB.dll" Name="App.resources.dll" Source="$(var.App.App_TargetDir)en-GB\App.resources.dll" />
</Component>
<Component Id="App.resources.pt.PT.dll" Guid="...">
<CreateFolder />
<File Id="App.resources.pt.PT.dll" Name="App.resources.dll" Source="$(var.App.App_TargetDir)pt-PT\App.resources.dll" />
</Component>
... Other components...
</ComponentGroup>
</Fragment>
When I rebuild my solution I get the following error:
'App.resources.dll' is installed in '[ProgramFilesFolder]\App\' by two
different components on an LFN system: 'App.resources.en.GB.dll' and
'App.resources.pt.PT.dll'. This breaks component reference counting.
I understand the problem, both resources dll are being copied to the installation folder, and not to the specific resources file... But I don't know how to solve it. Anyone can give any hints on how to solve this?
Just reference the directory where you want your components eg. Directory="LOCALEEN". There is no need to specify <CreateFolder />
I also recomend to maintain some kind of naming convention. Your Components and Fils have the same id. See https://stackoverflow.com/a/1801464/4634044. So this should do what you expect:
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="C_EnglishLocale" Guid="..." Directory="LOCALEEN">
<File Id="Fi_EnglishLocale" Name="App.resources.dll" Source="$(var.App.App_TargetDir)en-GB\App.resources.dll" />
</Component>
<Component Id="C_PolnishLocale" Guid="..." Directory="LOCALEPT">
<File Id="Fi_PolnishLocale" Name="App.resources.dll" Source="$(var.App.App_TargetDir)pt-PT\App.resources.dll" />
</Component>
</ComponentGroup>
</Fragment>

pyro (WiX) delta patches are too big (when compared to bdiff)

I added the -delta switch when building patches with pyro (WiX) recently which seems to improve sizes somewhat. However when comparing diff sizes to those of our old bdiff-based patcher some files still come out much larger than expected. I delved into the source and it seems to be using mspatchc.dll
It appears to be one file in particular that's causing problems: The original and new versions of the file are both around the 100MB mark. Using bdiff generates a diff of 15KB, but pyro -delta uses 18MB!!
Why is this? Is it a bug in WiX? Is there a way i can improve (reduce the size of) the diffs generated by pyro?
candle patch.wxs
light patch.wixobj
melt ..\old\project.msi -out old.wixpdb -pdb old\project.wixpdb -x old_bin
melt ..\new\project.msi -out new.wixpdb -pdb new\project.wixpdb -x new_bin
torch -p -xi old.wixpdb new.wixpdb -out diff.wixmst
pyro -delta patch.wixmsp -out patch.msp -t proj1 diff.wixmst
I don't know if this should be an answer really, this is just an educated guess.
I'm guessing bdiff creates diff files of only the differences of files and has special logic to apply those diffs to the installed files. Alternatively, pyro -delta includes whole file if they are different.
You could test this by including a gigantic text file and then using bdiff after changing one word to get a tiny diff and then using pyro -delta will probably get you a diff basically the size of the text file.
This is more of a work-around, but by using more fragments this issue can be mitigated (at least until you need to patch the file in question). For example:
<Fragment>
<DirectoryRef Id="MyApp" DiskId="1">
<Component Id="MyApp.exe" Guid="*">
<File Id="MyApp.exe" KeyPath="yes" Source="$(var.OutputDir)\MyApp.exe" />
</Component>
<Component Id="Library.dll" Guid="*">
<File Id="Library.dll" KeyPath="yes" Source="$(var.OutputDir)\Library.dll"/>
</Component>
<Component Id="HugeLibrary.dll" Guid="*">
<File Id="HugeLibrary.dll" KeyPath="yes" Source="$(var.OutputDir)\HugeLibrary.dll" />
</Component>
</DirectoryRef>
</Fragment>
If HugeLibrary.dll always creates big deltas, we can move it to it's own fragment which means that it will only be in the patch if it's explicitly coded in:
<Fragment>
<DirectoryRef Id="MyApp" DiskId="1">
<Component Id="MyApp.exe" Guid="*">
<File Id="MyApp.exe" KeyPath="yes" Source="$(var.OutputDir)\MyApp.exe" />
</Component>
<Component Id="Library.dll" Guid="*">
<File Id="Library.dll" KeyPath="yes" Source="$(var.OutputDir)\Library.dll"/>
</Component>
</DirectoryRef>
</Fragment>
<Fragment>
<DirectoryRef Id="MyApp" DiskId="1">
<Component Id="HugeLibrary.dll" Guid="*">
<File Id="HugeLibrary.dll" KeyPath="yes" Source="$(var.OutputDir)\HugeLibrary.dll" />
</Component>
</DirectoryRef>
</Fragment>
All files will still be in the installer, and the component group(s) will remain the same.
<Fragment>
<ComponentGroup Id ="myapp">
<ComponentRef Id="MyApp.exe"/>
<ComponentRef Id="Library.dll"/>
<ComponentRef Id="HugeLibrary.dll"/>
</ComponentGroup>
</Fragment>