How to rewrite an element's attribute value using the current attribute value? - xslt-1.0

I've got an almost working XSLT sample, but for some reason it adds the attribute to the parent instead of rewriting the node I am trying to rewrite.
Input XML
<Include xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<DirectoryRef Id="WEBFOLDER">
<Directory Id="dirA82847423D2E0E6780E69FEDB5941AC0" Name="web">
<Component Id="cmpADE52C2B19915F5AFB7C41166996B6C5" Guid="*">
<File Id="fil83688EC53AE556DE24B5F5444F16F6BE" KeyPath="yes" Source="$(var.SolutionDir)\Company.PCR.Blazor.dll" />
</Component>
</Directory>
</DirectoryRef>
</Fragment>
</Include>
My XSL (transformation)
<!-- patch relative paths -->
<xsl:template match="wix:File">
<xsl:attribute name="Source">
<xsl:value-of select="concat(substring(self::node()/#Source,0,19), '..\artifacts\msi\web\', substring(self::node()/#Source, 20))"/>
</xsl:attribute>
</xsl:template>
Actual output (currently transformed)
<Include xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<DirectoryRef Id="WEBFOLDER">
<Directory Id="dirA82847423D2E0E6780E69FEDB5941AC0" Name="web">
<Component Id="cmpADE52C2B19915F5AFB7C41166996B6C5" Guid="*" Source="$(var.SolutionDir)..\artifacts\msi\web\Company.PCR.Blazor.dll"/>
</Directory>
</DirectoryRef>
</Fragment>
</Include>
Expected XML output (transformed):
<Include xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<DirectoryRef Id="WEBFOLDER">
<Directory Id="dirA82847423D2E0E6780E69FEDB5941AC0" Name="web">
<Component Id="cmpADE52C2B19915F5AFB7C41166996B6C5" Guid="*">
<File Id="fil83688EC53AE556DE24B5F5444F16F6BE" KeyPath="yes" Source="$(var.SolutionDir)..\artifacts\msi\web\Company.PCR.Blazor.dll" />
</Component>
</Directory>
</DirectoryRef>
</Fragment>
</Include>
Can you explain why my match="wix:File" applies its attribute change to its parent?

If you want to modify the Source attribute, then why not make the template match the Source attribute?
<xsl:template match="wix:File/#Source">
<xsl:attribute name="Source">
<xsl:value-of select="concat(substring(., 1, 18), '..\artifacts\msi\web\', substring(., 20))"/>
</xsl:attribute>
</xsl:template>

Related

Wix XML Error - The Component/#Directory attribute cannot be specified when the Component element is nested underneath a Directory element

First time doing some Wix practice, so im completely new to it.
Here is my short script:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="SampleMSI" Language="1033" Version="1.0.0.0" Manufacturer="Nunya" UpgradeCode="b2c39f9b-1de1-433e-bc59-a3548cc531b9">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" Description="Installs Signout Utility" Keywords="Practice,Signout,Utility,MSI,Installer" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate />
<Feature Id="ProductFeature" Title="SampleMSI" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="SampleMSI" />
<Directory Id="APPFOLDER" Name="APPDir" >
</Directory>
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="CMP_ADispOCX"
Guid="5E23B839-35CA-480E-8AFC-2E914BA8E32A"
Directory="INSTALLLOCATION">
<File Id="FILE_ADispocx"
Source="ADisp.ocx"
KeyPath="yes" />
</Component>
<Component Id="CMP_Abtn32ocx"
Guid="98B357F2-C295-4019-A878-885E56AA3BF3"
Directory="INSTALLLOCATION">
<File Id="FILE_Abtn32a20ocx"
Source="btn32a20.ocx"
KeyPath="yes" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>
I just wanted to make sure they are going to the same folder, basic installation check. (it is my first time)
I get this error however:
Error 2 The Component/#Directory attribute cannot be specified when the Component element is nested underneath a Directory element.
I get it twice for each component id I have.
Am I missing something? Im using Wix 3.6 A Developers Guide for reference.
edit: Side question......how do I specify an exact path? like C:\Herp\Derp
You don't need to specify the directory of a Component if you did so already in the ComponentGroup element. Remove the Directory attribute in both Components elements in your fragment.
Change your code to this
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="CMP_ADispOCX"
Guid="5E23B839-35CA-480E-8AFC-2E914BA8E32A">
<File Id="FILE_ADispocx"
Source="ADisp.ocx"
KeyPath="yes" />
</Component>
<Component Id="CMP_Abtn32ocx"
Guid="98B357F2-C295-4019-A878-885E56AA3BF3">
<File Id="FILE_Abtn32a20ocx"
Source="btn32a20.ocx"
KeyPath="yes" />
</Component>
</ComponentGroup>
</Fragment>

How do I set ProgramFilesFolder subfolder permissions in Wix?

I am installing an application to the Program Files folder using WiX. I am using util:XmlFile to update the connectionStrings element but I am getting an error "Failed to open XML file C:\Program Files (x86)\developMENTALmadness\MainApp.exe.config system error -2147024786". I am trying to elevate permissions and set the permissions on the target file and parent folder, but the permissions aren't getting set.
Product.wxs:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Product Id="{7A04DDDD-F423-4E81-A42F-6831479ECF15}" Name="Installer"
Language="1033" Version="1.0.0.0"
Manufacturer="developMENTALmadness"
UpgradeCode="a65f51b5-8bf8-4490-8fab-899cc23a8e1b">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine"
InstallPrivileges="elevated" />
<MajorUpgrade DowngradeErrorMessage="A newer version is already installed." />
<MediaTemplate EmbedCab="yes" />
<Property Id="SQLSERVER" Value="(local)" />
<Property Id="SQLDATABASE" Value="OMDatabase" />
<Property Id="SQLINSTALLUSER" Value="sa" />
<Property Id="SQLINSTALLPWD" />
<Property Id="SQLUSER" />
<Property Id="SQLPWD" />
<Feature Id="ProductFeature" Title="Installer" Level="1">
<ComponentGroupRef Id="main_output"/>
</Feature>
<!--<UIRef Id="WixUI_Minimal"/>-->
<UIRef Id="CustomWizard"/>
<Binary Id="WixUI_Bmp_Banner"
SourceFile="$(var.MainApp.ProjectDir)info.png" />
<Binary Id="WixUI_Ico_Info"
SourceFile="$(var.MainApp.ProjectDir)favicon.ico"/>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="developMENTALmadness">
<Directory Id="target_root" Name="HelloWiX" >
</Directory>
</Directory>
</Directory>
</Directory>
</Fragment>
I've generated the component list by using heat.exe and modified it (MainOutput.wxs):
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Fragment>
<DirectoryRef Id="target_root">
<Component Id="root_permissions" Guid="{87E634CC-8F0E-4610-961A-9B6C1BBDAEFE}">
<CreateFolder Directory="target_root">
<util:PermissionEx User="Users" GenericAll="yes" ChangePermission="yes" />
</CreateFolder>
</Component>
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup Id="main_output">
<Component Id="cmp2D913B775A49E24FBD0E4DB1A96F05A7" Directory="target_root" Guid="{6284BD47-6181-4220-8DF8-D76F43A608F4}">
<File Id="fil115E0DBDE48A315B4A1DABD091FE0184" KeyPath="yes" Source="$(var.MainApp.TargetPath)" />
</Component>
<Component Id="cmp1A2EDC339002636FAD729B028E1D726A" Directory="target_root" Guid="{45D6B30C-4C74-4260-B53F-855E5F4681FA}">
<File Id="filB9D96E3BAC71662F051EA888708285DA" KeyPath="yes" Source="$(var.MainApp.TargetPath).config" Vital="yes">
<util:PermissionEx User="Users" GenericAll="yes" ChangePermission="yes" />
</File>
<util:XmlFile Id="SetSqlConnection" Action="setValue"
ElementPath="/configuration/connectionStrings/add[\[]#name='database'[\]]"
File="[INSTALLFOLDER]$(var.MainApp.TargetFileName).config"
Value="Server=[SQLSERVER];Database=[SQLDATABASE];uid=[SQLUSER];pwd=[SQLPWD];"
Sequence="1"
SelectionLanguage="XPath" Name="connectionString" />
</Component>
</ComponentGroup>
</Fragment>
You can try the PermissionEx element.
Some similar questions:
WIX: Giving Permissions to a folder
Wix: How to set permissions for folder and all sub folders
Okay, so it would seem that it is better (recommended?) to store my config file in the CommonAppDataFolder (C:\ProgramData). This means I'll need to use the ConfigurationManager.OpenMappedExeConfiguration method to load my config now, like this:
ExeConfigurationFileMap map = new ExeConfigurationFileMap();
map.ExeConfigFilename = Path.Combine(#"C:\ProgramData\developMENTALmadness",
Path.GetFileName(Assembly.GetExecutingAssembly().Location) + ".config");
var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
var name = config.AppSettings.Settings["FullName"].Value;
And a much more simplified version of what I'm trying to do is this:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Product Id="{F15C9D98-5296-417C-847F-1DC1E67C3498}" Name="HelloWiXInstaller" Manufacturer="developMENTALmadness" Language="1033" Version="1.0.0.0" UpgradeCode="a3be08fb-680d-425a-a471-4ab16e4aa805">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MediaTemplate EmbedCab="yes" />
<Property Id="FULL_NAME" Value="Mark J. Miller (installed)" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="developMENTALmadness">
<Component Id="CMP_HelloWiX.exe" Guid="{38FC6E96-37D6-4A2D-A584-F7D84705AC34}">
<File Id="EXE_HelloWiX.exe" Source="$(var.HelloWiX.TargetPath)" />
</Component>
</Directory>
</Directory>
<Directory Id="CommonAppDataFolder">
<Directory Id="CONFIGFOLDER" Name="developMENTALmadness">
<Component Id="CMP_HelloWiX.exe.config" Guid="{6D470FDB-BF36-4648-BDBD-63D168F8D085}">
<File Id="CONFIG_HelloWiX.exe.config" Source="$(var.HelloWiX.TargetPath).config" />
<util:XmlFile Id="SetConfigValue" Action="setValue"
File="[CONFIGFOLDER]$(var.HelloWiX.TargetFileName).config"
ElementPath="/configuration/appSettings/add[\[]#key='FullName'[\]]"
Value="[FULL_NAME]"
SelectionLanguage="XPath"
Name="value"/>
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id="HelloWiXProduct" Title="Hello, WiX" Level="1">
<ComponentRef Id="CMP_HelloWiX.exe" />
<ComponentRef Id="CMP_HelloWiX.exe.config" />
</Feature>
</Product>
And that works without any issues, so unless someone knows how to fix the other problem I'll go with this solution.
Here's a link to the full source for this sample on github: https://github.com/developmentalmadness/HelloWiX

wix HeatDirectory ServiceInstall

I'm using HeatDirectory to create source .wxs file. In the pickup directory there is an exe which should be installed as service. Actually I know how to install service if I create component myself, but I don't know how to include ServiceInstall in auto generated component. Is there any suggestion?
<HeatDirectory DirectoryRefId="Guardian" OutputFile="Source\GuardianSource.wxs" Transforms="Filter.xsl" Directory="..\Setup\C24.Guardian\bin\Debug" PreprocessorVariable="var.GuardianPath" ComponentGroupName="GuardianGroup" ToolPath="$(WixToolPath)" SuppressCom="true" SuppressFragments="true" SuppressRegistry="true" SuppressRootDirectory="true" AutoGenerateGuids="true" GenerateGuidsNow="false">
</HeatDirectory>
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<DirectoryRef Id="Guardian">
<Component Id="cmp70BEDA00F3161F3FB5E847EB1136B1D5" Guid="*">
<File Id="fil26DCBF1E4218C7363018FBA2CD456633" KeyPath="yes" Source="$(var.GuardianPath)\C24.Guardian.exe" />
</Component>
<Component Id="cmp2EE8126A193FA022ED35FAD8F182E65A" Guid="*">
<File Id="fil785CD681C496EDDAB457E8314C49D686" KeyPath="yes" Source="$(var.GuardianPath)\C24.Guardian.exe.config" />
</Component>
<Component Id="cmp0CC91B457FBC44F978A2AD6B24043DCF" Guid="*">
<File Id="fil2D304D0395599AAAAAF975A2DBFD530F" KeyPath="yes" Source="$(var.GuardianPath)\C24.Guardian.pdb" />
</Component>
<Component Id="cmpFB799FA015274DDBE2C337C60667D2C5" Guid="*">
<File Id="filB9C39B394CAD03F5A1BC3262C61EDDEB" KeyPath="yes" Source="$(var.GuardianPath)\C24.Guardian.vshost.exe" />
</Component>
<Component Id="cmp28C29865AE85B067BCEEBD70EFDB19D5" Guid="*">
<File Id="fil0A756B711769AAD657F306B3A6EA7134" KeyPath="yes" Source="$(var.GuardianPath)\C24.Guardian.vshost.exe.config" />
</Component>
<Component Id="cmp92A715A4BD4B580A6E70362230170428" Guid="*">
<File Id="filBD9D504F303A6EEC9E340E3872BBB0AE" KeyPath="yes" Source="$(var.GuardianPath)\C24.Guardian.vshost.exe.manifest" />
</Component>
<Component Id="cmp8AB6A241FA2D13F296CBD946C9711579" Guid="*">
<File Id="fil8EF8CC607CB82B32F84FC9EC2F1636B9" KeyPath="yes" Source="$(var.GuardianPath)\com.Contact24.Tools.dll" />
</Component>
<Component Id="cmpC0DBB85C89E8AEA9BAC6E32B85913A2C" Guid="*">
<File Id="fil917CD649C5C318C6717D8EA9FFDF911A" KeyPath="yes" Source="$(var.GuardianPath)\com.Contact24.Tools.pdb" />
</Component>
<Component Id="cmp8AFB0FC7CCF571B61196D9166DEEBA24" Guid="*">
<File Id="fil32C12DF0163D5BAD7D0495F2CA2C8DA1" KeyPath="yes" Source="$(var.GuardianPath)\ICSharpCode.SharpZipLib.dll" />
</Component>
<Component Id="cmpF5DE5EB2B4C6E33F0C32CFF5F464432C" Guid="*">
<File Id="fil3C8C6F29095A04034E72FBB187F8B841" KeyPath="yes" Source="$(var.GuardianPath)\log4net.dll" />
</Component>
<Component Id="cmp27A7791E229DDDBC065069B26138FC2F" Guid="*">
<File Id="fil8DED592D9F63E708FEF848D2980A5186" KeyPath="yes" Source="$(var.GuardianPath)\log4net.xml" />
</Component>
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup Id="GuardianGroup">
<ComponentRef Id="cmp70BEDA00F3161F3FB5E847EB1136B1D5" />
<ComponentRef Id="cmp2EE8126A193FA022ED35FAD8F182E65A" />
<ComponentRef Id="cmp0CC91B457FBC44F978A2AD6B24043DCF" />
<ComponentRef Id="cmpFB799FA015274DDBE2C337C60667D2C5" />
<ComponentRef Id="cmp28C29865AE85B067BCEEBD70EFDB19D5" />
<ComponentRef Id="cmp92A715A4BD4B580A6E70362230170428" />
<ComponentRef Id="cmp8AB6A241FA2D13F296CBD946C9711579" />
<ComponentRef Id="cmpC0DBB85C89E8AEA9BAC6E32B85913A2C" />
<ComponentRef Id="cmp8AFB0FC7CCF571B61196D9166DEEBA24" />
<ComponentRef Id="cmpF5DE5EB2B4C6E33F0C32CFF5F464432C" />
<ComponentRef Id="cmp27A7791E229DDDBC065069B26138FC2F" />
</ComponentGroup>
</Fragment>
</Wix>
It'll be good to get something like the following code auto generated:
<ComponentRef Id="cmp70BEDA00F3161F3FB5E847EB1136B1D5">
<ServiceInstall
Id="ServiceAdminGuardianInstaller"
Type="ownProcess"
Vital="yes"
Name="C24.Guardian"
DisplayName="C24.Guardian"
Description="Служба контроля работы сервера администрирования"
Start="auto"
Account="[SERVICEACCOUNT]"
Password="[SERVICEPASSWORD]"
ErrorControl="ignore"
Interactive="no">
<util:PermissionEx
User="Everyone"
GenericAll="yes"
ServiceChangeConfig="yes"
ServiceEnumerateDependents="yes"
ChangePermission="yes"
ServiceInterrogate="yes"
ServicePauseContinue="yes"
ServiceQueryConfig="yes"
ServiceQueryStatus="yes"
ServiceStart="yes"
ServiceStop="yes"/>
</ServiceInstall>
<ServiceControl Id="StopGuardianService" Name="C24.Guardian" Stop="both" Wait="yes" Remove="uninstall" />
</ComponentRef>
As an alternative to the method described by #sttaq, what I usually do is filter out the .exe files and manage them manually. You're already filtering your heat output with an xsl file (Filter.xsl), so it should be easy to add a rule to filter out any *.exe file.
<!--Match and ignore .exe files-->
<xsl:key name="exe-search" match="wix:Component[contains(wix:File/#Source, '.exe')]" use="#Id"/>
<xsl:template match="wix:Component[key('exe-search', #Id)]"/>
<xsl:template match="wix:ComponentRef[key('exe-search', #Id)]"/>
And then, in your .wxs file, you can manually author the .exe file component including your service installer, icons, or anything you may need. Just remember to put it inside the right Directory:
<Fragment>
<DirectoryRef Id="dirA9BC717C5B7BCAAF2B4C1161965AD894">
<Component Id="ExecFileComponent" Guid="YOUR-GUID-HERE">
<RemoveFile Id="RemoveLogFiles" Name="*.svclog" On="both"/>
<File Id="ExecFile" Source="$(exefile)" KeyPath="yes" />
<ServiceInstall Id="ServiceInstallation" DisplayName="displayname" Name="name" ErrorControl="normal" Start="auto" Type="ownProcess" Vital="yes">
<util:PermissionEx
User="Everyone"
GenericAll="yes"
ServiceChangeConfig="yes"
ServiceEnumerateDependents="yes"
ChangePermission="yes"
ServiceInterrogate="yes"
ServicePauseContinue="yes"
ServiceQueryConfig="yes"
ServiceQueryStatus="yes"
ServiceStart="yes"
ServiceStop="yes" />
</ServiceInstall>
<ServiceControl Id="ServiceControl" Name="name" Stop="both" Remove="uninstall" />
</Component>
</DirectoryRef>
</Fragment>
I assume that you already know the name of your file that needs to be wrapped in a ServiceInstall element.
This can be achieved using xsl transformation. The process can be automated using the XslTransformation MSBuild task. Here is what I have done recently:
In the wixproj file in the BeforeBuild target add some parameters to pass on to the xsl, if you like you can hard code these in your xsl and skip this step:
<PropertyGroup>
<WixServiceParams>
<Parameter Name="InstallFolder" Value="INSTALLFOLDER" />
<!-- INSTALLFOLDER is Guardian in your case -->
<Parameter Name="DisplayName" Value="Service Display Name" />
<Parameter Name="Name" Value="ServiceName" />
<Parameter Name="Description" Value="Service Description." />
</WixServiceParams>
<DefineConstants>...</DefineConstants>
</PropertyGroup>
Then after your HeatDirectory task call the XslTransformation task like this:
<XslTransformation XslInputPath="WixService.xsl" XmlInputPaths="Input.wxs" OutputPaths="Final.wxs" Parameters="$(WixServiceParams)" />
Add the WixService.xsl transformation file to your project. The file is as below:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:wix="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="InstallFolder"/>
<xsl:param name="DisplayName"/>
<xsl:param name="Name"/>
<xsl:param name="Description"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- Set Directory Reference to INSTALLFOLDER (set if required) -->
<xsl:template match="wix:DirectoryRef/#Id">
<xsl:attribute name="Id">
<xsl:value-of select="$InstallFolder"/>
</xsl:attribute>
</xsl:template>
<!-- XSL Template to inject WiX service installation elements to a .wxs generated from Heat Project task -->
<!-- There may be other ways to look for your file -->
<xsl:template match='wix:Wix/wix:Fragment/wix:DirectoryRef/wix:Component[wix:File[#Source="PATH-TO\YourService.exe"]]'>
<xsl:element name="wix:Component">
<xsl:attribute name="Id">
<xsl:value-of select="#Id"/>
</xsl:attribute>
<xsl:attribute name="Guid">
<xsl:value-of select="#Guid"/>
</xsl:attribute>
<xsl:element name="wix:File">
<xsl:attribute name="Id">
<xsl:value-of select="wix:File/#Id"/>
</xsl:attribute>
<xsl:attribute name="Source">
<xsl:value-of select="wix:File/#Source"/>
</xsl:attribute>
<xsl:attribute name="KeyPath">yes</xsl:attribute>
</xsl:element>
<xsl:element name="wix:ServiceInstall">
<!-- Service Install -->
<xsl:attribute name="Id">SERVICEINSTALLER</xsl:attribute>
<xsl:attribute name="DisplayName">
<xsl:value-of select="$DisplayName"/>
</xsl:attribute>
<xsl:attribute name="Name">
<xsl:value-of select="$Name"/>
</xsl:attribute>
<xsl:attribute name="Description">
<xsl:value-of select="$Description"/>
</xsl:attribute>
<xsl:attribute name="Start">auto</xsl:attribute>
<xsl:attribute name="Type">ownProcess</xsl:attribute>
<xsl:attribute name="Account">[USERNAME]</xsl:attribute>
<xsl:attribute name="Password">[PASSWORD]</xsl:attribute>
<xsl:attribute name="ErrorControl">normal</xsl:attribute>
<xsl:attribute name="Vital">yes</xsl:attribute>
<!-- Service Dependencies, if required -->
<xsl:element name="wix:ServiceDependency">
<xsl:attribute name="Id">DEPENDENCY</xsl:attribute>
</xsl:element>
<!-- Service Configuration, set as required -->
<xsl:element name="util:ServiceConfig">
<xsl:attribute name="FirstFailureActionType">restart</xsl:attribute>
<xsl:attribute name="SecondFailureActionType">restart</xsl:attribute>
<xsl:attribute name="ThirdFailureActionType">none</xsl:attribute>
<xsl:attribute name="RestartServiceDelayInSeconds">60</xsl:attribute>
</xsl:element>
</xsl:element>
<!-- Service Control, set as required -->
<xsl:element name="wix:ServiceControl">
<xsl:attribute name="Id">SERVICECONTROLLER</xsl:attribute>
<xsl:attribute name="Name">
<xsl:value-of select="$Name"/>
</xsl:attribute>
<xsl:attribute name="Remove">uninstall</xsl:attribute>
<xsl:attribute name="Stop">uninstall</xsl:attribute>
<xsl:attribute name="Wait">no</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
once done wish for a better way of doing this...
I was able to come up with a .xsl file that snips the Windows Service executable file from the list of files and components generated by the <HeatDirectory>:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
xmlns:wix="http://schemas.microsoft.com/wix/2006/wi">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<!-- Deep copy everything else that is not the Windows Service .exe file -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()" />
</xsl:copy>
</xsl:template>
<!-- Remove the Windows Service .exe file from the list of auto-generated components -->
<xsl:template match="wix:Component[wix:File/#Source='$(var.PublishDir)\MyWindowsService.exe']"></xsl:template>
<xsl:template match="wix:ComponentRef[#Id=//wix:Component[wix:File/#Source='$(var.PublishDir)\MyWindowsService.exe']/#Id]">
<xsl:apply-templates />
</xsl:template>
</xsl:stylesheet>
The var.PublishDir was specified as the PreprocessorVariable attribute of the <HeatDirectory>. I also added the PublishDir in the <DefineConstants>,
<PropertyGroup>
<DefineConstants>BuildVersion=%(AssemblyVersion.Version);PublishDir=$(PublishDir)</DefineConstants>
</PropertyGroup>
The <PublishDir> has the path to the folder to where the Windows Service is being published,
<PropertyGroup>
<PublishDir>$(ProjectDir)Publish</PublishDir>
</PropertyGroup>

Wix toolset: create directory in root disk (system disk or c:\) and copy files inside

I'm aware of similar questions inside stackoverflow:
WIX:default directory in WixUI_InstallDir,
WIX installer root directory and versioning,
Is it possible to have two root directories in WIX,
copy file to custom dir in another partition,
How to create a directory in wix?
however none of them shows a simple and immediate code to create a folder inside the C:\ folder (not hard coded but should be the root disk or system disk or whatever you would call the disk which contains the Windows folder) and to copy files inside it.
In other words how can Wix create a C:\MynewDir\example.jar folder?
Here's what I tried:
<?xml version="1.0" encoding="UTF-8"?>
<!-- WiX installer MyProgram by Mark Seuffert -->
<?define ProductVersion = "13.1.2.3"?>
<?define ProductUpgradeCode = "12345678-1234-1234-1234-111111111112"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" UpgradeCode="$(var.ProductUpgradeCode)" Name="MyProgram" Version="$(var.ProductVersion)" Manufacturer="COMPANY" Language="1033">
<Package InstallerVersion="200" Compressed="yes" Comments="Windows Installer Package" />
<Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="MyProgram">
<Component Id="ApplicationFiles" Guid="12345678-1234-1234-1234-222222222222">
<File Id="ApplicationFile1" Source="C:\Users\user\Desktop\myprogram.exe" />
</Component>
</Directory>
</Directory>
<Directory Id="ANOTHERLOCATION" FileSource="C:\MynewDir">
</Directory>
</Directory>
<DirectoryRef Id="ANOTHERLOCATION" FileSource="C:\MynewDir">
<Component Id="ApplicationFiles2" Guid="12345678-1234-1234-1235-111111111111">
<File Id="ApplicationFile2" Source="C:\Users\user\Desktop\InstallerFiles_13_4_9_3\myprogramLauncher.jar" />
<CreateFolder />
</Component>
</DirectoryRef>
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallValidate" />
</InstallExecuteSequence>
<Feature Id="DefaultFeature" Level="1">
<ComponentRef Id="ApplicationFiles2" />
<ComponentRef Id="ApplicationFiles" />
</Feature>
</Product>
</Wix>
EDIT 1:
Yan Sklyarenko just found what I was looking for, that's the WindowsVolume (I don't know how I missed it inside http://msdn.microsoft.com/en-us/library/windows/desktop/aa370905%28v=vs.85%29.aspx#system_folder_properties microsoft document).
However how do I replace FileSource="C:\MynewDir" with FileSource="[WindowsVolume]MynewDir" ??? because apparently even with WINDOWSVOLUME the resulting volume chosen is always D:\ in my computer which has more available space :(
EDIT 2 I updated my code using Yan Sklyarenko's second sample ( ####newpart#### identifies parts where code differs), however behaviour is still the same, the installer chooses the disk with more free space (D:\ in my case) and not C:\ where windows is..
<?xml version="1.0" encoding="UTF-8"?>
<!-- WiX installer MyProgram by Mark Seuffert -->
<?define ProductVersion = "13.1.2.3"?>
<?define ProductUpgradeCode = "12345678-1234-1234-1234-111111111112"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" UpgradeCode="$(var.ProductUpgradeCode)" Name="MyProgram" Version="$(var.ProductVersion)" Manufacturer="COMPANY" Language="1033">
<Package InstallerVersion="200" Compressed="yes" Comments="Windows Installer Package" />
<Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="MyProgram">
<Component Id="ApplicationFiles" Guid="12345678-1234-1234-1234-222222222222">
<File Id="ApplicationFile1" Source="C:\Users\user\Desktop\myprogram.exe" />
</Component>
</Directory>
</Directory>
<Directory Id="ANOTHERLOCATION" FileSource="C:\MynewDir">
####newpart####<Component Id="ApplicationFiles2" Guid="12345678-1234-1234-1235-111111111111">
<File Id="ApplicationFile2" Source="C:\Users\user\Desktop\InstallerFiles_13_4_9_3\myprogramLauncher.jar" />
<CreateFolder />
</Component>
</Directory>
</Directory>
####newpart####<SetDirectory Id="ANOTHERLOCATION" Value="[WINDOWSVOLUME]" />
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallValidate" />
</InstallExecuteSequence>
<Feature Id="DefaultFeature" Level="1">
<ComponentRef Id="ApplicationFiles2" />
<ComponentRef Id="ApplicationFiles" />
</Feature>
</Product>
</Wix>
EDIT 3 The last code snippet above should work however change the casing of WINDOWSVOLUME to WindowsVolume as suggested.
Here is a complete working solution based on your code simplified (notice the comment in the code):
<?define ProductVersion = "13.1.2.3"?>
<?define ProductUpgradeCode = "12345678-1234-1234-1234-111111111112"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" UpgradeCode="$(var.ProductUpgradeCode)" Name="MyProgram"
Version="$(var.ProductVersion)" Manufacturer="COMPANY" Language="1033">
<Package InstallerVersion="200" Compressed="yes" />
<Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="MyProgram" />
<Directory Id="ANOTHERLOCATION" />
</Directory>
</Directory>
<!-- The casing of 'ANOTHERLOCATION' and 'WindowsVolume' is very important here.
Replace 'MyNewDir' with the correct name of the folder you want on
WindowsVolume.
-->
<SetDirectory Id="ANOTHERLOCATION" Value="[WindowsVolume]MyNewDir" />
<Feature Id="DefaultFeature" Level="1">
<Component Directory="INSTALLDIR">
<File Id="ApplicationFile1" Source="C:\Users\user\Desktop\myprogram.exe" />
</Component>
<Component Directory="ANOTHERLOCATION">
<File Id="ApplicationFile2" Source="C:\Users\user\Desktop\InstallerFiles_13_4_9_3\myprogramLauncher.jar" />
</Component>
</Feature>
</Product>
</Wix>
Ok, you can do something like this:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="WindowsVolume">
<Directory Id="MyNewDirId" Name="MyNewDir">
<Component Id="SampleComponent" Guid="...">
<File Id="SampleFile" Source="..." KeyPath="yes" />
</Component>
</Directory>
</Directory>
</Directory>
This will install the file to the MyNewDir folder on Windows drive (C: in my case).
However, it will complain that using WindowsVolume in this fashion might have unexpected side effects.
To satisfy that validation, you can change the sample to:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="MyNewDirId" Name="MyNewDir">
<Component Id="SampleComponent" Guid="...">
<File Id="SampleFile" Source="..." KeyPath="yes" />
</Component>
</Directory>
</Directory>
<SetDirectory Id="MyNewDirId" Value="[WindowsVolume]MyNewDir" />
This looks more like a hack, but the result is the same.
To be honest, I don't understand what those "unexpected side effects" could be. Maybe, Windows Installer gurus can shed some light on this.
Hope this helps.

WIX : Merge Module Issue

When I try to use merge module feature in VS2010, I am getting an issue "Multiple Section entery"
Why i am getting this error?
I have done googling but I did not get any thread where i got my answer.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Module Id="ModuleTest" Language="1033" Version="1.0.0.0">
<Package Id='94290AA7-50E3-414E-A1BD-FC3C2B0C47D8' Description='My first Merge Module'
Comments='This is my first attempt at creating a Windows Installer Merge Module'
Manufacturer='TravelPort Private Limited' InstallerVersion='200' />
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='MyModuleDirectory' Name='.'>
<Component Id='MyModuleComponent' Guid='93F36B4B-B6E0-4000-8174-2660C0AE9D6A'>
<File Id='readme' Name='ReadMeModule' Source='ReadMergeModule.txt' DiskId='1' KeyPath='yes' Checksum='yes'></File>
</Component>
</Directory>
</Directory>
</Module>
</Wix>
product.wxs file
<Product Id="ec20ec5e-bb50-45d0-9190-156cf146c8f3" Name="WinDemoApp" Language="1033" Version="1.0.0.0" Manufacturer="WinDemoApp" UpgradeCode="979e03f4-3b50-43c1-9dde-dd675f726fde">
<Package InstallerVersion="200" Compressed="yes" />
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="WinDemoApp">
<!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
</Directory>
<Directory Id ="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="WinDemoApp"></Directory>
</Directory>
<!--<Merge Id='MyModule' Language='1033' SourceFile='Module.msm' DiskId='1' />-->
</Directory>
</Directory>
<DirectoryRef Id="APPLICATIONROOTDIRECTORY">
<Component Id="MyApp.exe" Guid="36AA7C63-ED57-40C6-8B14-843B9355C265">
<File Id="MyApp.exe" Source="D:\WIXDemo\WinDemoApp\MyApp\bin\Debug\MyApp.exe" KeyPath="yes" Checksum="yes"></File>
</Component>
</DirectoryRef>
<DirectoryRef Id="ApplicationProgramsFolder">
<Component Id="ApplicationShortcut" Guid="EA549460-4D98-4B09-B621-D4F1AA12A617">
<Shortcut Id="ApplicationStartMenuShortcut" Name="WinDemoApp"
Description="My Win Installer sample"
Target="[APPLICATIONROOTDIRECTORY]MyApp.exe"
WorkingDirectory="APPLICATIONROOTDIRECTORY"/>
<RemoveFolder Id ="ApplicationProgramsFolder" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\Microsoft\WinDemoApp" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
</DirectoryRef>
<!--<Icon Id="bug.ico" SourceFile="bug.ico"/>
<Property Id="ARPPRODUCTICON" Value="bug.ico" />-->
<Feature Id="MyApplication" Title="WinDemoApp" Level="1">
<!-- TODO: Remove the comments around this ComponentRef element and the Component above in order to add resources to this installer. -->
<ComponentRef Id="MyApp.exe"/>
<ComponentRef Id="ApplicationShortcut"/>
<!--<MergeRef Id="MyModule"/>-->
<!-- Note: The following ComponentGroupRef is required to pull in generated authoring from project references. -->
</Feature>
</Product>
The MyModuleDirectory directory element shouldn't have a name attribute. Also your Merge element should probably be nested underneath the ApplicationProgramsFolder directory. Where it's now it'll go to [ProgramFilesFolder].
Take a look at Industrial Strength Windows Installer XML.
Even if you don't want to use the tool, it's own installer is setup exactly the way you are setting up yours with merge modules consumed by a product.