Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bal:DisplayFilesInUseDialogCondition attribute to disable "Files In Use" #573

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ public interface IPackageInfo
/// </summary>
string DisplayInternalUICondition { get; }

/// <summary>
/// The authored bal:DisplayFilesInUseDialogCondition.
/// </summary>
string DisplayFilesInUseDialogCondition { get; }

/// <summary>
/// The package's display name.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ public class PackageInfo : IPackageInfo
/// <inheritdoc/>
public string DisplayInternalUICondition { get; internal set; }

/// <inheritdoc/>
public string DisplayFilesInUseDialogCondition { get; internal set; }

/// <inheritdoc/>
public string ProductCode { get; internal set; }

Expand Down Expand Up @@ -363,6 +366,7 @@ internal static void ParseBalPackageInfoFromXml(XPathNavigator root, XmlNamespac
var package = (PackageInfo)ipackage;

package.DisplayInternalUICondition = BootstrapperApplicationData.GetAttribute(node, "DisplayInternalUICondition");
package.DisplayFilesInUseDialogCondition = BootstrapperApplicationData.GetAttribute(node, "DisplayFilesInUseDialogCondition");
}

nodes = root.Select("/p:BootstrapperApplicationData/p:WixPrereqInformation", namespaceManager);
Expand Down
4 changes: 4 additions & 0 deletions src/api/burn/balutil/balinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ DAPI_(void) BalInfoUninitialize(
ReleaseStr(pBundle->packages.rgPackages[i].sczDescription);
ReleaseStr(pBundle->packages.rgPackages[i].sczId);
ReleaseStr(pBundle->packages.rgPackages[i].sczDisplayInternalUICondition);
ReleaseStr(pBundle->packages.rgPackages[i].sczDisplayFilesInUseDialogCondition);
ReleaseStr(pBundle->packages.rgPackages[i].sczProductCode);
ReleaseStr(pBundle->packages.rgPackages[i].sczUpgradeCode);
ReleaseStr(pBundle->packages.rgPackages[i].sczVersion);
Expand Down Expand Up @@ -517,6 +518,9 @@ static HRESULT ParseBalPackageInfoFromXml(
hr = XmlGetAttributeEx(pNode, L"DisplayInternalUICondition", &pPackage->sczDisplayInternalUICondition);
ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get DisplayInternalUICondition setting for package.");

hr = XmlGetAttributeEx(pNode, L"DisplayFilesInUseDialogCondition", &pPackage->sczDisplayFilesInUseDialogCondition);
ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get DisplayFilesInUseDialogCondition setting for package.");

hr = XmlGetAttributeEx(pNode, L"PrimaryPackageType", &scz);
ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get PrimaryPackageType setting for package.");

Expand Down
1 change: 1 addition & 0 deletions src/api/burn/balutil/inc/balinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ typedef struct _BAL_INFO_PACKAGE
BOOL fPermanent;
BOOL fVital;
LPWSTR sczDisplayInternalUICondition;
LPWSTR sczDisplayFilesInUseDialogCondition;
LPWSTR sczProductCode;
LPWSTR sczUpgradeCode;
LPWSTR sczVersion;
Expand Down
52 changes: 35 additions & 17 deletions src/ext/Bal/stdbas/WixStandardBootstrapperApplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1231,34 +1231,52 @@ class CWixStandardBootstrapperApplication : public CBootstrapperApplicationBase
__inout int* pResult
)
{
HRESULT hr = S_OK;
Copy link
Author

@charles-juicelabs charles-juicelabs Oct 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wondered if the DisplayFilesInUseDialogCondition should be evaluated in OnExecutePackageBegin or OnPlanPackageBegin instead. I left it here because that's closest to its only use and that seemed clearer. Happy to move it if either of those are more appropriate places.

BAL_INFO_PACKAGE* pPackage = NULL;
BOOL fShowFilesInUseDialog = TRUE;

if (!m_fShowingInternalUiThisPackage && wzPackageId && *wzPackageId)
{
BalLog(BOOTSTRAPPER_LOG_LEVEL_VERBOSE, "Package %ls has %d applications holding files in use.", wzPackageId, cFiles);

switch (source)
hr = BalInfoFindPackageById(&m_Bundle.packages, wzPackageId, &pPackage);
if (SUCCEEDED(hr) && pPackage->sczDisplayFilesInUseDialogCondition)
{
case BOOTSTRAPPER_FILES_IN_USE_TYPE_MSI:
if (m_fShowStandardFilesInUse)
{
return ShowMsiFilesInUse(cFiles, rgwzFiles, source, pResult);
}
break;
case BOOTSTRAPPER_FILES_IN_USE_TYPE_MSI_RM:
if (m_fShowRMFilesInUse)
{
return ShowMsiFilesInUse(cFiles, rgwzFiles, source, pResult);
}
break;
case BOOTSTRAPPER_FILES_IN_USE_TYPE_NETFX:
if (m_fShowNetfxFilesInUse)
hr = BalEvaluateCondition(pPackage->sczDisplayFilesInUseDialogCondition, &fShowFilesInUseDialog);
BalExitOnFailure(hr, "Failed to evaluate condition for package '%ls': %ls", wzPackageId, pPackage->sczDisplayFilesInUseDialogCondition);
}

if (fShowFilesInUseDialog)
{
switch (source)
{
return ShowNetfxFilesInUse(cFiles, rgwzFiles, pResult);
case BOOTSTRAPPER_FILES_IN_USE_TYPE_MSI:
if (m_fShowStandardFilesInUse)
{
return ShowMsiFilesInUse(cFiles, rgwzFiles, source, pResult);
}
break;
case BOOTSTRAPPER_FILES_IN_USE_TYPE_MSI_RM:
if (m_fShowRMFilesInUse)
{
return ShowMsiFilesInUse(cFiles, rgwzFiles, source, pResult);
}
break;
case BOOTSTRAPPER_FILES_IN_USE_TYPE_NETFX:
if (m_fShowNetfxFilesInUse)
{
return ShowNetfxFilesInUse(cFiles, rgwzFiles, pResult);
}
break;
}
break;
}
else
{
*pResult = IDIGNORE;
}
}

LExit:
return __super::OnExecuteFilesInUse(wzPackageId, cFiles, rgwzFiles, nRecommendation, source, pResult);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,44 @@ public void CanBuildUsingDisplayInternalUICondition()
}
}

[Fact]
public void CanBuildUsingDisplayFilesInUseDialogCondition()
{
using (var fs = new DisposableFileSystem())
{
var baseFolder = fs.GetFolder();
var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
var bundleSourceFolder = TestData.Get(@"TestData\WixStdBa");
var intermediateFolder = Path.Combine(baseFolder, "obj");
var baFolderPath = Path.Combine(baseFolder, "ba");
var extractFolderPath = Path.Combine(baseFolder, "extract");

var compileResult = WixRunner.Execute(new[]
{
"build",
Path.Combine(bundleSourceFolder, "DisplayFilesInUseDialogConditionBundle.wxs"),
"-ext", TestData.Get(@"WixToolset.BootstrapperApplications.wixext.dll"),
"-intermediateFolder", intermediateFolder,
"-bindpath", Path.Combine(bundleSourceFolder, "data"),
"-o", bundleFile,
});
compileResult.AssertSuccess();

Assert.True(File.Exists(bundleFile));

var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath);
extractResult.AssertSuccess();

var balPackageInfos = extractResult.GetBADataTestXmlLines("/ba:BootstrapperApplicationData/ba:WixBalPackageInfo");
WixAssert.CompareLineByLine(new string[]
{
"<WixBalPackageInfo PackageId='test.msi' DisplayFilesInUseDialogCondition='1' />",
}, balPackageInfos);

Assert.True(File.Exists(Path.Combine(baFolderPath, "thm.wxl")));
}
}

[Fact]
public void CanBuildUsingOverridable()
{
Expand Down Expand Up @@ -253,6 +291,7 @@ public void CannotBuildUsingOverridableWrongCase()
{
"bal:Condition/@Condition contains the built-in Variable 'WixBundleAction', which is not available when it is evaluated. (Unavailable Variables are: 'WixBundleAction'.). Rewrite the condition to avoid Variables that are never valid during its evaluation.",
"Overridable variable 'TEST1' collides with 'Test1' with Bundle/@CommandLineVariables value 'caseInsensitive'.",
"The *Package/@bal:DisplayFilesInUseDialogCondition attribute's value '=' is not a valid bundle condition.",
"The *Package/@bal:DisplayInternalUICondition attribute's value '=' is not a valid bundle condition.",
"The location of the Variable related to the previous error.",
}, messages.ToArray());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ public void CanBuildUsingWixIuiBaWithWarnings()
"WixInternalUIBootstrapperApplication does not support the value of 'force' for Cache on prereq packages. Prereq packages are only cached when they need to be installed.",
"WixInternalUIBootstrapperApplication ignores InstallCondition for the primary package so that the MSI UI is always shown.",
"WixInternalUIBootstrapperApplication ignores DisplayInternalUICondition for the primary package so that the MSI UI is always shown.",
"WixInternalUIBootstrapperApplication ignores DisplayFilesInUseDialogCondition for the primary package so that the MSI UI is always shown.",
"When using WixInternalUIBootstrapperApplication, all prereq packages should be before the primary package in the chain. The prereq packages are always installed before the primary package.",
}, compileResult.Messages.Select(m => m.ToString()).ToArray());

Expand All @@ -180,7 +181,7 @@ public void CanBuildUsingWixIuiBaWithWarnings()
var balPackageInfos = extractResult.GetBADataTestXmlLines("/ba:BootstrapperApplicationData/ba:WixBalPackageInfo");
WixAssert.CompareLineByLine(new string[]
{
"<WixBalPackageInfo PackageId='test.msi' DisplayInternalUICondition='DISPLAYTEST' PrimaryPackageType='default' />",
"<WixBalPackageInfo PackageId='test.msi' DisplayInternalUICondition='DISPLAYTEST' DisplayFilesInUseDialogCondition='DISPLAYTEST' PrimaryPackageType='default' />",
}, balPackageInfos);

var mbaPrereqInfos = extractResult.GetBADataTestXmlLines("/ba:BootstrapperApplicationData/ba:WixPrereqInformation");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<Variable Name="TEST1" bal:Overridable="yes" />
<Chain>
<ExePackage Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" />
<MsiPackage SourceFile="test.msi" bal:DisplayInternalUICondition="!(loc.NonsensePlanCondition)" />
<MsiPackage SourceFile="test.msi" bal:DisplayInternalUICondition="!(loc.NonsensePlanCondition)" bal:DisplayFilesInUseDialogCondition="!(loc.NonsensePlanCondition)" />
</Chain>
<bal:Condition Condition="!(loc.NonsenseDetectCondition)" Message="Unsupported" />
</Bundle>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<bal:WixInternalUIBootstrapperApplication />
</BootstrapperApplication>
<Chain>
<MsiPackage SourceFile="test.msi" InstallCondition="INSTALLTEST" bal:DisplayInternalUICondition="DISPLAYTEST" />
<MsiPackage SourceFile="test.msi" InstallCondition="INSTALLTEST" bal:DisplayInternalUICondition="DISPLAYTEST" bal:DisplayFilesInUseDialogCondition="DISPLAYTEST" />
<ExePackage Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" Cache="force" />
</Chain>
</Bundle>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
<Bundle Name="WixStdBa" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="75D5D534-E177-4689-AAE9-CAC1C39002C2">
<BootstrapperApplication>
<bal:WixStandardBootstrapperApplication LicenseUrl="http://wixtoolset.org/about/license/" Theme="hyperlinkLicense" />
</BootstrapperApplication>
<Chain>
<MsiPackage SourceFile="test.msi" bal:DisplayFilesInUseDialogCondition="1" />
</Chain>
</Bundle>
</Wix>
22 changes: 22 additions & 0 deletions src/ext/Bal/wixext/BalBurnBackendExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ public override bool TryProcessSymbol(IntermediateSection section, IntermediateS
writer.WriteAttributeString("DisplayInternalUICondition", balPackageInfoSymbol.DisplayInternalUICondition);
}

if (balPackageInfoSymbol.DisplayFilesInUseDialogCondition != null)
{
writer.WriteAttributeString("DisplayFilesInUseDialogCondition", balPackageInfoSymbol.DisplayFilesInUseDialogCondition);
}

if (balPackageInfoSymbol.PrimaryPackageType != BalPrimaryPackageType.None)
{
writer.WriteAttributeString("PrimaryPackageType", balPackageInfoSymbol.PrimaryPackageType.ToString().ToLower());
Expand Down Expand Up @@ -104,6 +109,7 @@ public override void SymbolsFinalized(IntermediateSection section)

this.VerifyBalConditions(section);
this.VerifyDisplayInternalUICondition(section);
this.VerifyDisplayFilesInUseDialogCondition(section);
this.VerifyOverridableVariables(section);

var balBaSymbol = section.Symbols.OfType<WixBalBootstrapperApplicationSymbol>().SingleOrDefault();
Expand Down Expand Up @@ -195,6 +201,17 @@ private void VerifyDisplayInternalUICondition(IntermediateSection section)
}
}

private void VerifyDisplayFilesInUseDialogCondition(IntermediateSection section)
{
foreach (var balPackageInfoSymbol in section.Symbols.OfType<WixBalPackageInfoSymbol>().ToList())
{
if (balPackageInfoSymbol.DisplayFilesInUseDialogCondition != null)
{
this.BackendHelper.ValidateBundleCondition(balPackageInfoSymbol.SourceLineNumbers, "*Package", "bal:DisplayFilesInUseDialogCondition", balPackageInfoSymbol.DisplayFilesInUseDialogCondition, BundleConditionPhase.Plan);
}
}
}

private void VerifyPrimaryPackages(IntermediateSection section, SourceLineNumber baSourceLineNumbers)
{
WixBalPackageInfoSymbol defaultPrimaryPackage = null;
Expand Down Expand Up @@ -420,6 +437,11 @@ private void VerifyIuibaPrimaryPackage(WixBundlePackageSymbol packageSymbol, Wix
{
this.Messaging.Write(BalWarnings.IuibaPrimaryPackageDisplayInternalUICondition(packageSymbol.SourceLineNumbers));
}

if (balPackageInfoSymbol.DisplayFilesInUseDialogCondition != null)
{
this.Messaging.Write(BalWarnings.IuibaPrimaryPackageDisplayFilesInUseDialogCondition(packageSymbol.SourceLineNumbers));
}
}

private void VerifyOverridableVariables(IntermediateSection section)
Expand Down
14 changes: 14 additions & 0 deletions src/ext/Bal/wixext/BalCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,20 @@ public override void ParseAttribute(Intermediate intermediate, IntermediateSecti
break;
}
break;
case "DisplayFilesInUseDialogCondition":
switch (parentElement.Name.LocalName)
{
case "MsiPackage":
case "MspPackage":
var displayFilesInUseDialogCondition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attribute);
var packageInfo = this.GetBalPackageInfoSymbol(section, sourceLineNumbers, packageId);
packageInfo.DisplayFilesInUseDialogCondition = displayFilesInUseDialogCondition;
break;
default:
this.ParseHelper.UnexpectedAttribute(parentElement, attribute);
break;
}
break;
case "PrimaryPackageType":
{
var primaryPackageType = BalPrimaryPackageType.None;
Expand Down
6 changes: 6 additions & 0 deletions src/ext/Bal/wixext/BalWarnings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public static Message IuibaPrimaryPackageDisplayInternalUICondition(SourceLineNu
return Message(sourceLineNumbers, Ids.IuibaPrimaryPackageDisplayInternalUICondition, "WixInternalUIBootstrapperApplication ignores DisplayInternalUICondition for the primary package so that the MSI UI is always shown.");
}

public static Message IuibaPrimaryPackageDisplayFilesInUseDialogCondition(SourceLineNumber sourceLineNumbers)
{
return Message(sourceLineNumbers, Ids.IuibaPrimaryPackageDisplayFilesInUseDialogCondition, "WixInternalUIBootstrapperApplication ignores DisplayFilesInUseDialogCondition for the primary package so that the MSI UI is always shown.");
}

public static Message IuibaPrimaryPackageInstallCondition(SourceLineNumber sourceLineNumbers)
{
return Message(sourceLineNumbers, Ids.IuibaPrimaryPackageInstallCondition, "WixInternalUIBootstrapperApplication ignores InstallCondition for the primary package so that the MSI UI is always shown.");
Expand Down Expand Up @@ -56,6 +61,7 @@ public enum Ids
IuibaPrimaryPackageDisplayInternalUICondition = 6504,
IuibaPrereqPackageAfterPrimaryPackage = 6505,
DeprecatedBAFactoryAssemblyAttribute = 6506,
IuibaPrimaryPackageDisplayFilesInUseDialogCondition = 6507,
}
}
}
8 changes: 8 additions & 0 deletions src/ext/Bal/wixext/Symbols/WixBalPackageInfoSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public static partial class BalSymbolDefinitions
{
new IntermediateFieldDefinition(nameof(WixBalPackageInfoSymbolFields.PackageId), IntermediateFieldType.String),
new IntermediateFieldDefinition(nameof(WixBalPackageInfoSymbolFields.DisplayInternalUICondition), IntermediateFieldType.String),
new IntermediateFieldDefinition(nameof(WixBalPackageInfoSymbolFields.DisplayFilesInUseDialogCondition), IntermediateFieldType.String),
new IntermediateFieldDefinition(nameof(WixBalPackageInfoSymbolFields.PrimaryPackageType), IntermediateFieldType.Number),
},
typeof(WixBalPackageInfoSymbol));
Expand All @@ -27,6 +28,7 @@ public enum WixBalPackageInfoSymbolFields
{
PackageId,
DisplayInternalUICondition,
DisplayFilesInUseDialogCondition,
PrimaryPackageType,
}

Expand Down Expand Up @@ -63,6 +65,12 @@ public string DisplayInternalUICondition
set => this.Set((int)WixBalPackageInfoSymbolFields.DisplayInternalUICondition, value);
}

public string DisplayFilesInUseDialogCondition
{
get => this.Fields[(int)WixBalPackageInfoSymbolFields.DisplayFilesInUseDialogCondition].AsString();
set => this.Set((int)WixBalPackageInfoSymbolFields.DisplayFilesInUseDialogCondition, value);
}

public BalPrimaryPackageType PrimaryPackageType
{
get => (BalPrimaryPackageType)this.Fields[(int)WixBalPackageInfoSymbolFields.PrimaryPackageType].AsNumber();
Expand Down
Loading