I am trying to create a custom UI for WiX and Burn. I have followed some of the guides I've found, and so far I have a project that has the following, which inherits from BootstrapperApplication.
namespace MyBA
{
public class TestBA : BootstrapperApplication
{
protected override void Run()
{
MessageBox.Show("My BA is running");
this.Engine.Quit(0);
}
}
}
And in the AssemblyInfo.cs:
[assembly: BootstrapperApplication(typeof(TestBA))]
Then in my Bootstrapper project I have the following.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Bundle Name="MyApplication"
Version="1.0.0"
Manufacturer="Acme Ltd"
UpgradeCode="F84A4058-FDF6-4218-BCB5-12C811DA3C99"
Condition="NOT ((VersionNT = 600 AND ServicePackLevel >=2) OR (VersionNT >= 601))"
IconSourceFile="$(var.MyApplicationInstallerRequiredFiles.ProjectDir)logo.ico"
SplashScreenSourceFile="$(var.MyApplicationInstallerRequiredFiles.ProjectDir)Splashscreen.bmp"
DisableRepair="no"
DisableRemove="no"
DisableModify="no">
<WixVariable Id="WixMbaPrereqPackageId"
Value="Netfx4Full" />
<WixVariable Id="WixMbaPrereqLicenseUrl"
Value="NetfxLicense.rtf" />
<WixVariable Id="WixStdbaLicenseRtf"
Value="$(var.MyApplicationInstallerRequiredFiles.ProjectDir)Licence.en-gb.rtf" />
<WixVariable Id="WixStdbaLogo"
Value="$(var.MyApplicationInstallerRequiredFiles.ProjectDir)logoInstallSmall.bmp" />
<BootstrapperApplicationRef Id='ManagedBootstrapperApplicationHost'>
<Payload Name='BootstrapperCore.config'
SourceFile='$(var.MyApplicationInstallerRequiredFiles.ProjectDir)Bootstrapper\MyBA.BootstrapperCore.config' />
<Payload SourceFile='$(var.MyApplicationInstallerRequiredFiles.ProjectDir)Bootstrapper\MyBA.dll' />
</BootstrapperApplicationRef>
<Chain>
<PackageGroupRef Id="MyApplicationPackage" />
</Chain>
</Bundle>
</Wix>
and I have added MyBA.BootstrapperCore.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="wix.bootstrapper"
type="Microsoft.Tools.WindowsInstallerXml.Bootstrapper.BootstrapperSectionGroup, BootstrapperCore">
<section name="host"
type="Microsoft.Tools.WindowsInstallerXml.Bootstrapper.HostSection, BootstrapperCore" />
</sectionGroup>
</configSections>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" />
</startup>
<wix.bootstrapper>
<host assemblyName="MyBA">
<supportedFramework version="v4\Full" />
<supportedFramework version="v4\Client" />
</host>
</wix.bootstrapper>
</configuration>
However, whenever I run the Setup.exe for the bootstrapper, I get the splashscreen appear briefly, but nothing else. If I look in the %TEMP% at the logs there is the following
[0A00:0424][2011-11-02T15:52:08]: Burn v3.6.2221.0, path: C:\MyApplication\dev\source\Bootstrapper1\bin\Debug\Setup.exe, cmdline: ''
[0A00:0424][2011-11-02T15:52:08]: Setting string variable 'WixBundleName' to value 'MyApplication'
[0A00:0424][2011-11-02T15:52:08]: Setting string variable 'WixBundleLog' to value 'C:\Users\AppData\Local\Temp\MyApplication_20111102155208.log'
[0A00:0424][2011-11-02T15:52:08]: Condition 'NOT ((VersionNT = 600 AND ServicePackLevel >=2) OR (VersionNT >= 601))' evaluates to true.
[0A00:0424][2011-11-02T15:52:08]: Setting string variable 'WixBundleOriginalSource' to value 'C:\MyApplication\dev\source\Bootstrapper1\bin\Debug\Setup.exe'
[0A00:0424][2011-11-02T15:52:08]: Loading managed bootstrapper application.
[0A00:0424][2011-11-02T15:52:08]: Error 0x80131040: Failed to create the managed bootstrapper application.
[0A00:0424][2011-11-02T15:52:08]: Error 0x80131040: Failed to create UX.
[0A00:0424][2011-11-02T15:52:08]: Error 0x80131040: Failed to load UX.
[0A00:0424][2011-11-02T15:52:08]: Error 0x80131040: Failed while running
[0A00:0424][2011-11-02T15:52:08]: Error 0x80131040: Failed to run per-user mode.
Why is this happening and why are the above errors occurring?
If you look at the source code for the WixBA, they declare a global Threading.Dispatcher, and then in the overridden Run() method, there is the following line:
Threading.Dispatcher.Run();
I had similar issues, and similarly adding the Threading.Dispatcher to my bootstrapper application fixed them.
Also, if your Bootstrapper Application depends on any other dlls, you need to include them as a <Payload/> under your <BootstrapperApplicationRef/>.
Related
I am trying to use customAction method in a Bootstrapper project to determined specific version of .net core is installed or not, but it not work
here is my wsx file code
<Fragment>
<WixVariable Id="TargetFileName" Value="[WixBundleSourceProcessPath]" Overridable="yes" />
<Binary Id="CustomAction.dll" SourceFile="$(var.CustomAction.TargetDir)CustomAction.CA.dll" />
<CustomAction Id="CheckASPNETCore" Return="check" Execute="immediate" Impersonate="no" BinaryKey=".CustomAction.dll" DllEntry="TestMethod" />
<WixVariable Id="ASPDOTNETCORE60" Value="[ASPDOTNETCORE60]" Overridable="yes" />
<PackageGroup Id="NetRuntime6Web">
<ExePackage
Name="dotnet-hosting-6.0.8-win.exe"
InstallCommand="/install /quiet /norestart /log "[AspNetCoreRuntime6Log]""
RepairCommand="/repair /quiet /norestart /log "[AspNetCoreRuntime6Log]""
UninstallCommand="/uninstall /quiet /norestart /log "[AspNetCoreRuntime6Log]""
PerMachine="yes"
DetectCondition="[ASPDOTNETCORE60] = 1"
Vital="yes"
Permanent="yes"
Protocol="burn"
DownloadUrl="https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-aspnetcore-6.0.8-windows-hosting-bundle-installer"
LogPathVariable="AspNetCoreRuntime6Log"
SourceFile="C:\Net\dotnet-hosting-6.0.8-win.exe"
Compressed="yes">
</ExePackage>
</PackageGroup>
</Fragment>
[CustomAction]
public static ActionResult TestMethod(Session session)
{
session.Log($"Test Method Run");
session["ASPDOTNETCORE60"] = "1";
return ActionResult.Success;
}
and here is my customAction
and this is the error I'm getting where run exe file
[26A0:E8C4][2022-12-01T12:17:46]e000: Error 0x8007000d: Failed to parse condition "[ASPDOTNETCORE60] = 1". Unexpected character at position 0.
how can I use that customAction ???
Each version of the .NET Runtime will create a directory in Program Files\dotnet\shared\Microsoft.NETCore.App\
The existance of the directory Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.5 confirms the existance of .NET Runtime version 6.0.5. Using this knowledge, you can do a simple DirectorySearch in Wix to check whether a specific version of the runtime is installed like so:
<!-- Check if NET 6.0 Runtime already installed -->
<util:DirectorySearch
Path="[ProgramFiles6432Folder]dotnet\shared\Microsoft.NETCore.App\6.0.5"
Result="exists"
Variable="Net6RuntimeExists"/>
Here's the (almost) full file for clarity:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Bundle ...>
... code removed for brevity
<!-- Check if NET 6.0 Runtime already installed -->
<util:DirectorySearch
Path="[ProgramFiles6432Folder]dotnet\shared\Microsoft.NETCore.App\6.0.5"
Result="exists"
Variable="Net6RuntimeExists" />
<Chain>
<!--This will only be installed when the .NET 6 Runtime is not already installed-->
<ExePackage
Id="TheNet6Runtime"
DisplayName=".NET 6 Desktop Runtime"
Vital="no"
Cache="no"
Permanent="yes"
InstallCommand="/install /quiet /norestart"
SourceFile="windowsdesktop-runtime-6.0.5-win-x64.exe"
DetectCondition="Net6RuntimeExists" />
... code removed for brevity
</Chain>
</Bundle>
</Wix>
We have an (old) build definition is using the UpgradeTemplate.xaml on TFS 2015 (and an underlying TFSBuild.proj which has a heap of custom actions). As such, the task of properly modernising the build is going to take time.
I'd like to hack the UpgradeTemplate to add in C#6/VB14 support without requiring a full re-write of the build definition, in order to keep the devs happy.
I attempted to edit the UpgradeTemplate.xaml to add a ToolPath property on the TfsBuild. However, now that I have done this, I get the following error on nearly all my projects:
ArgumentOutOfRangeException: Index and length must refer to a location within the string. Parameter name: length
On investigation, the lines of code in these projects all look like this:
<MSBuild.ExtensionPack.VisualStudio.TfsVersion TaskAction="GetVersion"
BuildName="$(BuildDefinition)" TfsBuildNumber="$(BuildNumber)"
VersionFormat="DateTime" DateFormat="MMdd" Major="$(MajorVersion)"
Minor="$(MinorVersion)">
The values of these variables as set printed out by Message tasks on the vbproj:
BuildDefinition: MyBuild-Testing
BuildNumber: 57902
MajorVersion: 43
MinorVersion: 2
The Build server has version 3.5.10 on the MSBuild ExtensionPack installed.
How do I resolve this issue? I'm testing this with a new build definition to allow devs to continue working while I get this set up, so I don't want to replace the ExtensionPack with the latest release (if possible) if it is likely to break the existing build.
Upgrade Template
<Activity mc:Ignorable="sad" x:Class="TfsBuild.Process" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mtbc="clr-namespace:Microsoft.TeamFoundation.Build.Client;assembly=Microsoft.TeamFoundation.Build.Client" xmlns:mtbw="clr-namespace:Microsoft.TeamFoundation.Build.Workflow;assembly=Microsoft.TeamFoundation.Build.Workflow" xmlns:mtbwa="clr-namespace:Microsoft.TeamFoundation.Build.Workflow.Activities;assembly=Microsoft.TeamFoundation.Build.Workflow" xmlns:mtbwt="clr-namespace:Microsoft.TeamFoundation.Build.Workflow.Tracking;assembly=Microsoft.TeamFoundation.Build.Workflow" xmlns:mtvc="clr-namespace:Microsoft.TeamFoundation.VersionControl.Client;assembly=Microsoft.TeamFoundation.VersionControl.Client" xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:sad="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation" xmlns:sad1="clr-namespace:System.Activities.Debugger;assembly=System.Activities" xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:this="clr-namespace:TfsBuild;" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:Members>
<x:Property Name="ConfigurationFolderPath" Type="InArgument(x:String)" />
<x:Property Name="AgentSettings" Type="InArgument(mtbwa:AgentSettings)" />
<x:Property Name="MSBuildArguments" Type="InArgument(x:String)" />
<x:Property Name="MSBuildPlatform" Type="InArgument(mtbwa:ToolPlatform)" />
<x:Property Name="DoNotDownloadBuildType" Type="InArgument(x:Boolean)" />
<x:Property Name="LogFilePerProject" Type="InArgument(x:Boolean)" />
<x:Property Name="SourcesSubdirectory" Type="InArgument(x:String)" />
<x:Property Name="BinariesSubdirectory" Type="InArgument(x:String)" />
<x:Property Name="TestResultsSubdirectory" Type="InArgument(x:String)" />
<x:Property Name="RecursionType" Type="InArgument(mtvc:RecursionType)" />
<x:Property Name="Verbosity" Type="InArgument(mtbw:BuildVerbosity)" />
<x:Property Name="Metadata" Type="mtbw:ProcessParameterMetadataCollection" />
<x:Property Name="SupportedReasons" Type="mtbc:BuildReason" />
</x:Members>
<this:Process.ConfigurationFolderPath>
<InArgument x:TypeArguments="x:String" />
</this:Process.ConfigurationFolderPath>
<this:Process.AgentSettings>[New Microsoft.TeamFoundation.Build.Workflow.Activities.AgentSettings() With {.MaxWaitTime = New System.TimeSpan(4, 0, 0), .MaxExecutionTime = New System.TimeSpan(0, 0, 0), .TagComparison = Microsoft.TeamFoundation.Build.Workflow.Activities.TagComparison.MatchExactly }]</this:Process.AgentSettings>
<this:Process.MSBuildArguments>
<InArgument x:TypeArguments="x:String" />
</this:Process.MSBuildArguments>
<this:Process.MSBuildPlatform>[Microsoft.TeamFoundation.Build.Workflow.Activities.ToolPlatform.Auto]</this:Process.MSBuildPlatform>
<this:Process.DoNotDownloadBuildType>[False]</this:Process.DoNotDownloadBuildType>
<this:Process.LogFilePerProject>[False]</this:Process.LogFilePerProject>
<this:Process.SourcesSubdirectory>
<InArgument x:TypeArguments="x:String" />
</this:Process.SourcesSubdirectory>
<this:Process.BinariesSubdirectory>
<InArgument x:TypeArguments="x:String" />
</this:Process.BinariesSubdirectory>
<this:Process.TestResultsSubdirectory>
<InArgument x:TypeArguments="x:String" />
</this:Process.TestResultsSubdirectory>
<this:Process.RecursionType>[Microsoft.TeamFoundation.VersionControl.Client.RecursionType.OneLevel]</this:Process.RecursionType>
<this:Process.Verbosity>[Microsoft.TeamFoundation.Build.Workflow.BuildVerbosity.Normal]</this:Process.Verbosity>
<this:Process.Metadata>
<mtbw:ProcessParameterMetadataCollection />
</this:Process.Metadata>
<this:Process.SupportedReasons>All</this:Process.SupportedReasons>
<mva:VisualBasic.Settings>Assembly references and imported namespaces serialized as XML namespaces</mva:VisualBasic.Settings>
<Sequence mtbwt:BuildTrackingParticipant.Importance="None">
<Sequence.Variables>
<Variable x:TypeArguments="mtbc:IBuildDetail" Name="BuildDetail" />
</Sequence.Variables>
<mtbwa:GetBuildDetail DisplayName="Get the Build" Result="[BuildDetail]" />
<mtbwa:InvokeForReason DisplayName="Update Build Number for Triggered Builds" Reason="Triggered">
<mtbwa:UpdateBuildNumber BuildNumberFormat="["$(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.r)"]" DisplayName="Update Build Number" />
</mtbwa:InvokeForReason>
<mtbwa:AgentScope DisplayName="Run On Agent" MaxExecutionTime="[AgentSettings.MaxExecutionTime]" MaxWaitTime="[AgentSettings.MaxWaitTime]" ReservationSpec="[AgentSettings.GetAgentReservationSpec()]">
<mtbwa:AgentScope.Variables>
<Variable x:TypeArguments="x:String" Name="buildDirectory" />
</mtbwa:AgentScope.Variables>
<mtbwa:GetBuildDirectory DisplayName="Get the Build Directory" Result="[buildDirectory]" />
<If Condition="[Not String.IsNullOrEmpty(ConfigurationFolderPath)]" DisplayName="If Not String.IsNullOrEmpty(ConfigurationFolderPath)">
<If.Then>
<mtbwa:TfsBuild BinariesSubdirectory="[BinariesSubdirectory]" BuildDirectory="[buildDirectory]" CommandLineArguments="[MSBuildArguments]" ConfigurationFolderPath="[ConfigurationFolderPath]" DisplayName="Run TfsBuild for Configuration Folder" DoNotDownloadBuildType="[DoNotDownloadBuildType]" LogFilePerProject="[LogFilePerProject]" RecursionType="[RecursionType]" SourcesSubdirectory="[SourcesSubdirectory]" TestResultsSubdirectory="[TestResultsSubdirectory]" ToolPath="C:\Program Files (x86)\MSBuild\12.0\Bin\" ToolPlatform="[MSBuildPlatform]" Verbosity="[Verbosity]" />
</If.Then>
</If>
<If Condition="[BuildDetail.CompilationStatus = Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Unknown]" DisplayName="If CompilationStatus = Unknown">
<If.Then>
<mtbwa:SetBuildProperties CompilationStatus="[Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Succeeded]" DisplayName="Set CompilationStatus to Succeeded" PropertiesToSet="CompilationStatus" />
</If.Then>
</If>
<If Condition="[BuildDetail.TestStatus = Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Unknown]" DisplayName="If TestStatus = Unknown">
<If.Then>
<mtbwa:SetBuildProperties DisplayName="Set TestStatus to Succeeded" PropertiesToSet="TestStatus" TestStatus="[Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Succeeded]" />
</If.Then>
</If>
</mtbwa:AgentScope>
<mtbwa:InvokeForReason Reason="CheckInShelveset">
<mtbwa:CheckInGatedChanges DisplayName="Check In Gated Changes" />
</mtbwa:InvokeForReason>
</Sequence>
</Activity>
In Particular, I added ToolPath="C:\Program Files (x86)\MSBuild\12.0\Bin\" to line 58.
TFSBuild.proj
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="DesktopBuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\SDC\Microsoft.Sdc.Common.tasks" />
<Import Project="$(MSBuildExtensionsPath)\ExtensionPack\MSBuild.ExtensionPack.tasks"/>
<ProjectExtensions>
<!-- Team Foundation Build Version - DO NOT CHANGE -->
<ProjectFileVersion>2</ProjectFileVersion>
</ProjectExtensions>
<PropertyGroup>
<RunCodeAnalysis>Never</RunCodeAnalysis>
<UpdateAssociatedWorkItems>false</UpdateAssociatedWorkItems>
<AdditionalVCOverrides></AdditionalVCOverrides>
<CustomPropertiesForClean></CustomPropertiesForClean>
<CustomPropertiesForBuild></CustomPropertiesForBuild>
<SkipGetChangesetsAndUpdateWorkItems>False</SkipGetChangesetsAndUpdateWorkItems>
<SkipWorkItemCreation>true</SkipWorkItemCreation>
<BuildConfigurationsInParallel>true</BuildConfigurationsInParallel>
<SkipDropBuild>false</SkipDropBuild>
</PropertyGroup>
<ItemGroup>
<SolutionToBuild Include="$(BuildProjectFolderPath)/SolutionsToBuild/Common.sln">
<Targets></Targets>
<Properties></Properties>
</SolutionToBuild>
</ItemGroup>
<ItemGroup>
<ConfigurationToBuild Include="Release|Any CPU">
<FlavorToBuild>Release</FlavorToBuild>
<PlatformToBuild>Any CPU</PlatformToBuild>
</ConfigurationToBuild>
</ItemGroup>
<PropertyGroup>
<SkipClean>false</SkipClean>
<SkipInitializeWorkspace>true</SkipInitializeWorkspace>
<ForceGet>true</ForceGet>
<IncrementalBuild>false</IncrementalBuild>
</PropertyGroup>
</Project>
Update
I think it might be something to do with running a private build (Latest + Shelveset). When I run a normal build, the BuildNumber variable is MyBuild-Testing_20170328.1. This appears to be working fine.
This issue is due to a difference between Private and Public builds. With Public Builds, the build is immediately numbered as BuildName_DateFormat.BuildNumber. Private builds however, are just numeric (e.g. 57902 above).
The Code in the extension does the following:
string buildstring = this.TfsBuildNumber.Replace(string.Concat(this.BuildName, "_"),
string.Empty);
char[] chrArray = new char[] { '.' };
string[] buildParts = buildstring.Split(chrArray, StringSplitOptions.RemoveEmptyEntries);
DateTime t = new DateTime(Convert.ToInt32(buildParts[0].Substring(0, 4),
CultureInfo.CurrentCulture),
Convert.ToInt32(buildParts[0].Substring(4, 2),
CultureInfo.CurrentCulture),
Convert.ToInt32(buildParts[0].Substring(6, 2),
CultureInfo.InvariantCulture));
Are you can see, its substringing on the build name, assuming it's been stripped down to the date component (20170328). Private builds aren't this long, and so fail.
This build works fine when running as a public build - basically it means that private builds on this definition are not available until an upgrade takes place.
I have create an installer by using WiXBaStd and customize the UI by edit the theme.xml. Besides, I have apply localization in bootstrapper and set the thm.wxl(en-us) Build Action to EmbeddedResource and thm.wxl(ja-jp) to None.
Then when I run the bootstrapper.exe in JP OS, the !(loc.ProductManufacturer) and !(loc.TransformsCode) always be EN-US but the UI display Japanese !.
If I reserve Build Action setting, set the thm.wxl(ja-jp) Build Action to EmbeddedResource and thm.wxl(en-us) to None.
Then when I run the bootstrapper.exe in JP OS, the !(loc.ProductManufacturer) and !(loc.TransformsCode) always be JA-JP ! and UI display Japanese also !.
How come the !(loc.ProductManufacturer) and !(loc.TransformsCode) not being change correctly in localization ? How to solve this problem ? Thanks.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
<?define ProductName = "Product A" ?>
<?define ProductManufacturer = "!(loc.ProductManufacturer)" ?>
<?define ProductUpgradeCode = "AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA" ?>
<Bundle Name="$(var.ProductName)" Version="$(var.BuildVersion)" Manufacturer="$(var.ProductManufacturer)" UpgradeCode="$(var.ProductUpgradeCode)">
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense">
<bal:WixStandardBootstrapperApplication SuppressOptionsUI="yes" LicenseFile="Localization\1033\LICENSE.rtf" ThemeFile="Custom\CustomRtfTheme.xml" />
<Payload Name="1033\thm.wxl" SourceFile="Localization\1033\thm.wxl" />
<Payload Name="1041\thm.wxl" SourceFile="Localization\1041\thm.wxl" />
<Payload Name="1041\LICENSE.rtf" SourceFile="Localization\1041\LICENSE.rtf" />
</BootstrapperApplicationRef>
<Chain>
<MsiPackage Id="MSI_A" SourceFile="A.msi">
<MsiProperty Name="TRANSFORMS" Value="!(loc.TransformsCode)" />
</MsiPackage>
<MsiPackage Id="MSI_B" SourceFile="B.msi">
<MsiProperty Name="TRANSFORMS" Value="!(loc.TransformsCode)" />
</MsiPackage>
</Chain>
</Bundle>
</Wix>
<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="ja-jp" Language="1041" xmlns="http://schemas.microsoft.com/wix/2006/localization">
<String Id="TransformsCode">:ja-jp.mst</String>
<String Id="ProductManufacturer">XXXXXX</String>
<String Id="Caption">[WixBundleName] Setup</String>
<String Id="Title">[WixBundleName]</String>
</WixLocalization>
Localisation strings !(loc.whatever), and !(wix.variables) are applied by the binder at the end of the overall build process, after light.exe has completed linking the compiled objects.
This statement is a pre-processor statement so the payload is not available to be resolved at the pre-compile stage:
<?define ProductManufacturer = "!(loc.ProductManufacturer)" ?>
I have a wix project that installs a web site. One of the steps adds several xml tags to web.config file. Whenever adding xml tags WIX adds xmlns="" attribute which I don't want.
PluginSettings.wxi
<?xml version="1.0" encoding="utf-8"?>
<Include>
...
<?define PluginProbingPath="<probing privatePath="IntegrityChecker\bin\" />" ?>
</Include>
ConfigFiles.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">
<?include PluginSettings.wxi ?>
<Fragment>
<!-- WEB.CONFIG -->
<Component Id="Web.ConfigPortal" Guid="3ED81B77-F153-4003-9006-4770D789D4B7" Directory ="INSTALLDIR">
<CreateFolder/>
...
<util:XmlConfig Id = "AppConfigAddPlugin1" ElementPath = "//configuration/runtime/assemblyBinding" Action = "create" Node = "document"
On = "install" File = "[INSTALLDIR]web.config" Value = "$(var.PluginProbingPath)" Sequence = "1"/>
</Component>
</Fragment>
</Wix>
Which results in web.config having this after install:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
...
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0"/>
</dependentAssembly>
<probing xmlns="" privatePath="IntegrityChecker\bin\"/></assemblyBinding>
</runtime>
As you can see nowhere did I specify xmlns tag (which I DON"T want).
I've tried removing that attribute with additional tag but it doesn't work:
<util:XmlFile Id="AppConfigAddPlugin8" Action="deleteValue" Permanent="yes" File="[INSTALLDIR]web.config"
ElementPath="//configuration/runtime/assemblyBinding/probing" Name="xmlns" Sequence = "2"/>
what am I doing wrong?
The WIX XmlConfig extension uses MSXML to modify the XML file on the target computer. Specifically the attributes action="create" and node="document", results in this simplified sequence of MSXML calls:
selectSingleNode("//configuration/runtime/assemblyBinding")
Create new xml document from: <probing privatePath=\"IntegrityChecker\bin\" />
Get the top level document element
call appendChild() to append the new document element
The problem is the probing element has no name space, but the parent assemblyBinding element has the namespace "urn:schemas-microsoft-com:asm.v1". When MSXML adds the probing element, xmlns="" is added to reset the default namespace. Without xmlns="", the probing element inherits the "urn:schemas-microsoft-com:asm.v1" namespace.
The article, MSXML inserted blank namespaces, describes this behaviour. Unfortunately this article (and others) recommend changing the call sequence to specify a default namespace when adding the probing element. Since this is WIX we can't easily change how WIX uses MSXML.
You could try adding a namespace to the probing element:
<?define PluginProbingPath="<probing xmlns="urn:schemas-microsoft-com:asm.v1" privatePath="IntegrityChecker\bin\" />" ?>
This will result in:
<probing xmlns="urn:schemas-microsoft-com:asm.v1" privatePath="IntegrityChecker\bin\" />
I'm not an expert on xml namespaces, but the effect of the explicit xmlns="urn:schemas-microsoft-com:asm.v1" should be benign in that the probing element will now have the same default namespace as its parent assemblyBinding. Whether this is a suitable work around depends on what is consuming the xml.
I have following .wxs-file:
<?xml version="1.0" encoding="UTF-8"?>
<?define ProductVersion="x.x.x.x" ?>
<?define UpgradeCode="{**MYGUID**}" ?>
<?define Manufacturer="My Company" ?>
<?define ProductName="My Product" ?>
<?define SkuName="MyProduct" ?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*"
Name="$(var.ProductName)"
Language="1033"
Version="$(var.ProductVersion)"
Manufacturer="$(var.Manufacturer)"
UpgradeCode="$(var.UpgradeCode)">
<Package InstallerVersion="301"
Compressed="yes"
InstallPrivileges="elevated"
InstallScope="perMachine"
Platform="x86" />
<Media Id="1"
Cabinet="$(var.SkuName).cab"
EmbedCab="yes" />
<Directory Id="TARGETDIR"
Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="ManufacturereDirectory"
Name="$(var.Manufacturer)">
<Directory Id="ProductDirectory"
Name="$(var.ProductName)" />
</Directory>
</Directory>
</Directory>
<ComponentGroup Id="MainComponentGroup">
<Component Directory="ProductDirectory">
<File Name="$(var.MyProject.TargetFileName)"
Source="$(var.MyProject.TargetPath)"
KeyPath="yes"
Vital="yes" />
<ServiceInstall Id="SeviceInstall"
Name="$(var.ProductName)"
DisplayName="$(var.ProductName)"
Type="ownProcess"
Interactive="no"
Start="auto"
Vital="yes"
ErrorControl="normal"
Account="LOCALSYSTEM">
</ServiceInstall>
<ServiceControl Id="ServiceControl_Start"
Name="$(var.ProductName)"
Start="install"
Wait="no" />
<ServiceControl Id="ServiceControl_Stop"
Name="$(var.ProductName)"
Stop="both"
Remove="uninstall"
Wait="yes" />
</Component>
</ComponentGroup>
<Feature Id="MainFeature"
Level="1">
<ComponentGroupRef Id="MainComponentGroup" />
</Feature>
<Upgrade Id="$(var.UpgradeCode)">
<UpgradeVersion Property="UPGRADEFOUND"
Minimum="0.0.0.1" IncludeMinimum="yes"
Maximum="$(var.ProductVersion)" IncludeMaximum="yes"
OnlyDetect="no"
IgnoreRemoveFailure="yes"
MigrateFeatures="yes"/>
</Upgrade>
<CustomAction Id="ServiceRestarter"
Directory="ProductDirectory"
ExeCommand=""[SystemFolder]sc.exe" failure "$(var.ProductName)" reset= 60 actions= restart/0"
Impersonate="no" />
<InstallExecuteSequence>
<InstallExecute Before="RemoveExistingProducts" />
<RemoveExistingProducts Before="InstallFinalize" />
<Custom Action="ServiceRestarter" After="InstallFinalize"><![CDATA[NOT Installed]]></Custom>
</InstallExecuteSequence>
</Product>
</Wix>
Before that, I've tried:
<CustomAction Id="ServiceRestarter"
Property="QtExecCmdLine"
Value='"[SystemFolder]sc.exe" failure "$(var.ProductName)" reset= 60 actions= restart/0' />
which apparently called sc.exe - but changed nothing ...
Before that I've tried:
<ServiceInstall Id="SeviceInstall"
Name="$(var.ProductName)"
DisplayName="$(var.ProductName)"
Type="ownProcess"
Interactive="no"
Start="auto"
Vital="yes"
ErrorControl="normal"
Account="LOCALSYSTEM">
<ServiceConfig Id="ServiceConfig"
DelayedAutoStart="yes"
OnInstall="yes"
OnReinstall="yes"
OnUninstall="no"
FailureActionsWhen="failedToStopOrReturnedError" />
<ServiceConfigFailureActions Id="ServiceRestarter"
OnInstall="yes"
OnReinstall="yes"
OnUninstall="no"
ResetPeriod="0">
<Failure Action="restartService" Delay="0" />
<Failure Action="restartService" Delay="0" />
<Failure Action="restartService" Delay="0" />
</ServiceConfigFailureActions>
</ServiceInstall>
which did not work, as the MsiServiceConfigFailureActions table does not work if using an installer < 5.0, and even if using InstallerVersion="500" the only thing I get is an error:
Serivce 'My Product' (My Product) could not be configured. This could
be a problem with the package or your permissions. Verify that you
have sufficient privileges to configure system services.
(and yes, ... I've tried InstallPrivilges="elevated" also - but ... the real issue is Action="restartService" according to this)
So ... using a CustomAction is the way to go (or not?).
I have following output of the log
MSI (s) (34:28) [13:56:46:914]: Note: 1: 1722 2: ServiceRestarter 3: C:\Program Files (x86)\My Company\My Product\ 4: "C:\Windows\SysWOW64\sc.exe" failure "My Product" reset= 60 actions= restart/0
MSI (s) (34:28) [13:56:46:914]: Note: 1: 2205 2: 3: Error
MSI (s) (34:28) [13:56:46:914]: Note: 1: 2228 2: 3: Error 4: SELECT Message FROM Error WHERE Error = 1722
MSI (c) (2C:0C) [13:56:46:914]: Font created. Charset: Req=0, Ret=0, Font: Req=MS Shell Dlg, Ret=MS Shell Dlg
Error 1722. There is a problem with this Windows Installer package. A program run as part of the setup did not finish as expected. Contact your support personnel or package vendor. Action ServiceRestarter, location: C:\Program Files (x86)\My Company\My Product\, command: "C:\Windows\SysWOW64\sc.exe" failure "My Product" reset= 60 actions= restart/0
MSI (s) (34:28) [13:56:48:849]: Note: 1: 2205 2: 3: Error
MSI (s) (34:28) [13:56:48:849]: Note: 1: 2228 2: 3: Error 4: SELECT Message FROM Error WHERE Error = 1709
MSI (s) (34:28) [13:56:48:849]: Product: My Product -- Error 1722. There is a problem with this Windows Installer package. A program run as part of the setup did not finish as expected. Contact your support personnel or package vendor. Action ServiceRestarter, location: C:\Program Files (x86)\My Company\My Product\, command: "C:\Windows\SysWOW64\sc.exe" failure "My Product" reset= 60 actions= restart/0
Action ended 13:56:48: ServiceRestarter. Return value 3.
Action ended 13:56:48: INSTALL. Return value 3.
Can anybody help me out?
edit
I've used the old ServiceConfig-extension:
<util:ServiceConfig xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
FirstFailureActionType="restart"
SecondFailureActionType="restart"
ThirdFailureActionType="restart"
ResetPeriodInDays="1"
RestartServiceDelayInSeconds="20" />
which gives me a following build-error:
error CNDL0200: The ServiceInstall element contains an unhandled
extension element 'util:ServiceConfig'. Please ensure that the
extension for elements in the
'http://schemas.microsoft.com/wix/UtilExtension' namespace has been
provided.
I know that I can resolve this error by using -ext WixUtilExtension via commandline - but I want to use Visual Studio for building ... So how can I adapt the build-command?
Only chance is to add a reference to WixUtilExtension.dll to my project.
I can see that you've only tried the ServiceConfig element, which came with MSI 5.0. However, there's another ServiceConfig element in UtilExtension, which has been there for a long time and it seems that the thread you mention in your question confirms that it works.
The util:ServiceConfig element contains 3 parameters you'd like to use: FirstFailureActionType, SecondFailureActionType and ThirdFailureActionType, all accepting the same enumeration of values - none, reboot, restart and runCommand.
Try it out and if it works, it is far better choice than a custom action.
For WIX V 4.0, building with VS2015, the following works:
1: Ensure that WixUtilExtension.dll assembly is referenced by WIX project.
2: Add http://wixtoolset.org/schemas/v4/wxs/util ns to root Wix element. Note that this is the correct NS for WIX 4.0 (NOT http://schemas.microsoft.com/wix/UtilExtension as for previous versions).
<Wix
xmlns="http://wixtoolset.org/schemas/v4/wxs"
xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"
>
3: Ensure that ServiceConfig element is prefixed with correct namespace reference.
<ServiceInstall
Id="MyService"
Type="ownProcess"
Name="MyService"
DisplayName="MyService"
Description="My Service"
Start="auto"
Account="[SERVICEACCOUNT]"
Password="[SERVICEPASSWORD]"
ErrorControl="normal"
>
<util:ServiceConfig
FirstFailureActionType='restart'
SecondFailureActionType='restart'
ThirdFailureActionType='restart'
RestartServiceDelayInSeconds='30'
ResetPeriodInDays='1'/>
</ServiceInstall>
In Visual Studio, to avoid using -ext in CLI you may do the following:
Of course, you add a resource: <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
then, in Solution Explorer -> References -> Add..
WixUtilExtension.dll
After that everything works like a charm.
(wix 3.10)
Of course, if you do use the second ServiceConfig from utils. Like <util:ServiceConfig blablabla