// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Util
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using WixToolset.Data;
using WixToolset.Data.Symbols;
using WixToolset.Extensibility;
using WixToolset.Extensibility.Data;
using WixToolset.Util.Symbols;
///
/// The compiler for the WiX Toolset Utility Extension.
///
internal sealed class UtilCompiler : BaseCompilerExtension
{
// user creation attributes definitions (from sca.h)
internal const int UserDontExpirePasswrd = 0x00000001;
internal const int UserPasswdCantChange = 0x00000002;
internal const int UserPasswdChangeReqdOnLogin = 0x00000004;
internal const int UserDisableAccount = 0x00000008;
internal const int UserFailIfExists = 0x00000010;
internal const int UserUpdateIfExists = 0x00000020;
internal const int UserLogonAsService = 0x00000040;
internal const int UserLogonAsBatchJob = 0x00000080;
internal const int UserDontRemoveOnUninstall = 0x00000100;
internal const int UserDontCreateUser = 0x00000200;
internal const int UserNonVital = 0x00000400;
internal const int UserRemoveComment = 0x00000800;
private static readonly Regex FindPropertyBrackets = new Regex(@"\[(?!\\|\])|(? UtilConstants.Namespace;
///
/// Types of Internet shortcuts.
///
public enum InternetShortcutType
{
/// Create a .lnk file.
Link = 0,
/// Create a .url file.
Url,
}
///
/// Types of permission setting methods.
///
private enum PermissionType
{
/// LockPermissions (normal) type permission setting.
LockPermissions,
/// FileSharePermissions type permission setting.
FileSharePermissions,
/// SecureObjects type permission setting.
SecureObjects,
}
///
/// Processes an element for the Compiler.
///
/// Parent element of element to process.
/// Element to process.
/// Extra information about the context in which this element is being parsed.
public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary context)
{
this.ParsePossibleKeyPathElement(intermediate, section, parentElement, element, context);
}
///
/// Processes an element for the Compiler.
///
/// Source line number for the parent element.
/// Parent element of element to process.
/// Element to process.
/// Extra information about the context in which this element is being parsed.
public override IComponentKeyPath ParsePossibleKeyPathElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary context)
{
IComponentKeyPath possibleKeyPath = null;
switch (parentElement.Name.LocalName)
{
case "CreateFolder":
var createFolderId = context["DirectoryId"];
var createFolderComponentId = context["ComponentId"];
switch (element.Name.LocalName)
{
case "PermissionEx":
this.ParsePermissionExElement(intermediate, section, element, createFolderId, createFolderComponentId, "CreateFolder");
break;
default:
this.ParseHelper.UnexpectedElement(parentElement, element);
break;
}
break;
case "Component":
var componentId = context["ComponentId"];
var directoryId = context["DirectoryId"];
var componentWin64 = Boolean.Parse(context["Win64"]);
switch (element.Name.LocalName)
{
case "EventSource":
possibleKeyPath = this.ParseEventSourceElement(intermediate, section, element, componentId);
break;
case "FileShare":
this.ParseFileShareElement(intermediate, section, element, componentId, directoryId);
break;
case "InternetShortcut":
this.ParseInternetShortcutElement(intermediate, section, element, componentId, directoryId);
break;
case "PerformanceCategory":
this.ParsePerformanceCategoryElement(intermediate, section, element, componentId);
break;
case "RemoveFolderEx":
this.ParseRemoveFolderExElement(intermediate, section, element, componentId);
break;
case "RemoveRegistryKey":
this.ParseRemoveRegistryKeyExElement(intermediate, section, element, componentId);
break;
case "RestartResource":
this.ParseRestartResourceElement(intermediate, section, element, componentId);
break;
case "ServiceConfig":
this.ParseServiceConfigElement(intermediate, section, element, componentId, "Component", null);
break;
case "TouchFile":
this.ParseTouchFileElement(intermediate, section, element, componentId, componentWin64);
break;
case "Group":
this.ParseGroupElement(intermediate, section, element, componentId);
break;
case "User":
this.ParseUserElement(intermediate, section, element, componentId);
break;
case "XmlFile":
this.ParseXmlFileElement(intermediate, section, element, componentId);
break;
case "XmlConfig":
this.ParseXmlConfigElement(intermediate, section, element, componentId, false);
break;
default:
this.ParseHelper.UnexpectedElement(parentElement, element);
break;
}
break;
case "File":
var fileId = context["FileId"];
var fileComponentId = context["ComponentId"];
switch (element.Name.LocalName)
{
case "PerfCounter":
this.ParsePerfCounterElement(intermediate, section, element, fileComponentId, fileId);
break;
case "PermissionEx":
this.ParsePermissionExElement(intermediate, section, element, fileId, fileComponentId, "File");
break;
case "PerfCounterManifest":
this.ParsePerfCounterManifestElement(intermediate, section, element, fileComponentId, fileId);
break;
case "EventManifest":
this.ParseEventManifestElement(intermediate, section, element, fileComponentId, fileId);
break;
case "FormatFile":
this.ParseFormatFileElement(intermediate, section, element, fileId);
break;
default:
this.ParseHelper.UnexpectedElement(parentElement, element);
break;
}
break;
case "Bundle":
case "Fragment":
case "Module":
case "Package":
switch (element.Name.LocalName)
{
case "CloseApplication":
this.ParseCloseApplicationElement(intermediate, section, element);
break;
case "Group":
this.ParseGroupElement(intermediate, section, element, null);
break;
case "RestartResource":
// Currently not supported for Bundles.
if (parentElement.Name.LocalName != "Bundle")
{
this.ParseRestartResourceElement(intermediate, section, element, null);
}
else
{
this.ParseHelper.UnexpectedElement(parentElement, element);
}
break;
case "User":
this.ParseUserElement(intermediate, section, element, null);
break;
case "BroadcastEnvironmentChange":
case "BroadcastSettingChange":
case "CheckRebootRequired":
case "ExitEarlyWithSuccess":
case "FailWhenDeferred":
case "QueryNativeMachine":
case "QueryWindowsDirectories":
case "QueryWindowsDriverInfo":
case "QueryWindowsSuiteInfo":
case "QueryWindowsWellKnownSIDs":
case "WaitForEvent":
case "WaitForEventDeferred":
this.AddCustomActionReference(intermediate, section, element, parentElement);
break;
case "ComponentSearch":
case "ComponentSearchRef":
case "DirectorySearch":
case "DirectorySearchRef":
case "FileSearch":
case "FileSearchRef":
case "ProductSearch":
case "ProductSearchRef":
case "RegistrySearch":
case "RegistrySearchRef":
case "WindowsFeatureSearch":
case "WindowsFeatureSearchRef":
// These will eventually be supported under Module/Product, but are not yet.
if (parentElement.Name.LocalName == "Bundle" || parentElement.Name.LocalName == "Fragment")
{
// TODO: When these are supported by all section types, move
// these out of the nested switch and back into the surrounding one.
switch (element.Name.LocalName)
{
case "ComponentSearch":
this.ParseComponentSearchElement(intermediate, section, element);
break;
case "ComponentSearchRef":
this.ParseComponentSearchRefElement(intermediate, section, element);
break;
case "DirectorySearch":
this.ParseDirectorySearchElement(intermediate, section, element);
break;
case "DirectorySearchRef":
this.ParseWixSearchRefElement(intermediate, section, element);
break;
case "FileSearch":
this.ParseFileSearchElement(intermediate, section, element);
break;
case "FileSearchRef":
this.ParseWixSearchRefElement(intermediate, section, element);
break;
case "ProductSearch":
this.ParseProductSearchElement(intermediate, section, element);
break;
case "ProductSearchRef":
this.ParseWixSearchRefElement(intermediate, section, element);
break;
case "RegistrySearch":
this.ParseRegistrySearchElement(intermediate, section, element);
break;
case "RegistrySearchRef":
this.ParseWixSearchRefElement(intermediate, section, element);
break;
case "WindowsFeatureSearch":
this.ParseWindowsFeatureSearchElement(intermediate, section, element);
break;
case "WindowsFeatureSearchRef":
this.ParseWindowsFeatureSearchRefElement(intermediate, section, element);
break;
}
}
else
{
this.ParseHelper.UnexpectedElement(parentElement, element);
}
break;
default:
this.ParseHelper.UnexpectedElement(parentElement, element);
break;
}
break;
case "Registry":
case "RegistryKey":
case "RegistryValue":
var registryId = context["RegistryId"];
var registryComponentId = context["ComponentId"];
switch (element.Name.LocalName)
{
case "PermissionEx":
this.ParsePermissionExElement(intermediate, section, element, registryId, registryComponentId, "Registry");
break;
default:
this.ParseHelper.UnexpectedElement(parentElement, element);
break;
}
break;
case "ServiceInstall":
var serviceInstallId = context["ServiceInstallId"];
var serviceInstallName = context["ServiceInstallName"];
var serviceInstallComponentId = context["ServiceInstallComponentId"];
switch (element.Name.LocalName)
{
case "PermissionEx":
this.ParsePermissionExElement(intermediate, section, element, serviceInstallId, serviceInstallComponentId, "ServiceInstall");
break;
case "ServiceConfig":
this.ParseServiceConfigElement(intermediate, section, element, serviceInstallComponentId, "ServiceInstall", serviceInstallName);
break;
default:
this.ParseHelper.UnexpectedElement(parentElement, element);
break;
}
break;
case "UI":
switch (element.Name.LocalName)
{
case "BroadcastEnvironmentChange":
case "BroadcastSettingChange":
case "CheckRebootRequired":
case "ExitEarlyWithSuccess":
case "FailWhenDeferred":
case "QueryWindowsDirectories":
case "QueryWindowsDriverInfo":
case "QueryWindowsSuiteInfo":
case "QueryWindowsWellKnownSIDs":
case "WaitForEvent":
case "WaitForEventDeferred":
this.AddCustomActionReference(intermediate, section, element, parentElement);
break;
}
break;
default:
this.ParseHelper.UnexpectedElement(parentElement, element);
break;
}
return possibleKeyPath;
}
private void AddCustomActionReference(Intermediate intermediate, IntermediateSection section, XElement element, XElement parentElement)
{
// These elements are not supported for bundles.
if (parentElement.Name.LocalName == "Bundle")
{
this.ParseHelper.UnexpectedElement(parentElement, element);
return;
}
var customAction = element.Name.LocalName;
switch (element.Name.LocalName)
{
case "BroadcastEnvironmentChange":
case "BroadcastSettingChange":
case "CheckRebootRequired":
case "ExitEarlyWithSuccess":
case "FailWhenDeferred":
case "WaitForEvent":
case "WaitForEventDeferred":
//default: customAction = element.Name.LocalName;
break;
case "QueryWindowsDirectories":
customAction = "QueryOsDirs";
break;
case "QueryWindowsDriverInfo":
customAction = "QueryOsDriverInfo";
break;
case "QueryWindowsSuiteInfo":
customAction = "QueryOsInfo";
break;
case "QueryWindowsWellKnownSIDs":
customAction = "QueryOsWellKnownSID";
break;
}
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
// no attributes today
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4" + customAction, this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
}
///
/// Parses the common search attributes shared across all searches.
///
/// Source line number for the parent element.
/// Attribute to parse.
/// Value of the Id attribute.
/// Value of the Variable attribute.
/// Value of the Condition attribute.
/// Value of the After attribute.
private void ParseCommonSearchAttributes(SourceLineNumber sourceLineNumbers, XAttribute attrib, ref Identifier id, ref string variable, ref string condition, ref string after)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Variable":
variable = this.ParseHelper.GetAttributeBundleVariableNameValue(sourceLineNumbers, attrib);
break;
case "Condition":
condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "After":
after = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
System.Diagnostics.Debug.Assert(false);
break;
}
}
///
/// Parses a ComponentSearch element.
///
/// Element to parse.
private void ParseComponentSearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string variable = null;
string condition = null;
string after = null;
string guid = null;
string productCode = null;
var attributes = WixComponentSearchAttributes.None;
var type = WixComponentSearchType.KeyPath;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
case "Variable":
case "Condition":
case "After":
this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
break;
case "Guid":
guid = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib);
break;
case "ProductCode":
productCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib);
break;
case "Result":
var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
switch (result)
{
case "directory":
type = WixComponentSearchType.WantDirectory;
break;
case "keyPath":
type = WixComponentSearchType.KeyPath;
break;
case "state":
type = WixComponentSearchType.State;
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "directory", "keyPath", "state"));
break;
}
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == guid)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Guid"));
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("wcs", variable, condition, after, guid, productCode, attributes.ToString(), type.ToString());
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
section.AddSymbol(new WixComponentSearchSymbol(sourceLineNumbers, id)
{
Guid = guid,
ProductCode = productCode,
Attributes = attributes,
Type = type,
});
}
}
///
/// Parses a ComponentSearchRef element
///
/// Element to parse.
private void ParseComponentSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement element)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
var refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixComponentSearch, refId);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
}
///
/// Parses a WindowsFeatureSearch element.
///
/// Element to parse.
private void ParseWindowsFeatureSearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string variable = null;
string condition = null;
string after = null;
string feature = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
case "Variable":
case "Condition":
case "After":
this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
break;
case "Feature":
feature = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
switch (feature)
{
case "sha2CodeSigning":
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Feature", feature, "sha2CodeSigning"));
break;
}
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (id == null)
{
id = this.ParseHelper.CreateIdentifier("wwfs", variable, condition, after);
}
if (feature == null)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Feature"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
var bootstrapperExtensionId = this.ParseHelper.CreateIdentifierValueFromPlatform("Wix4UtilBootstrapperExtension", this.Context.Platform, BurnPlatforms.X86 | BurnPlatforms.X64 | BurnPlatforms.ARM64);
if (bootstrapperExtensionId == null)
{
this.Messaging.Write(ErrorMessages.UnsupportedPlatformForElement(sourceLineNumbers, this.Context.Platform.ToString(), element.Name.LocalName));
}
if (!this.Messaging.EncounteredError)
{
this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, bootstrapperExtensionId);
section.AddSymbol(new WixWindowsFeatureSearchSymbol(sourceLineNumbers, id)
{
Type = feature,
});
}
}
///
/// Parses a WindowsFeatureSearchRef element
///
/// Element to parse.
private void ParseWindowsFeatureSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement element)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
var refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.WixWindowsFeatureSearch, refId);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
}
///
/// Parses an event source element.
///
/// Element to parse.
/// Identifier of parent component.
private IComponentKeyPath ParseEventSourceElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
string sourceName = null;
string logName = null;
string categoryMessageFile = null;
var categoryCount = CompilerConstants.IntegerNotSet;
string eventMessageFile = null;
string parameterMessageFile = null;
var typesSupported = 0;
var isKeyPath = false;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "CategoryCount":
categoryCount = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
break;
case "CategoryMessageFile":
categoryMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "EventMessageFile":
eventMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "KeyPath":
isKeyPath = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "Log":
logName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
if ("Security" == logName)
{
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, logName, "Application", "System", ""));
}
break;
case "Name":
sourceName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "ParameterMessageFile":
parameterMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "SupportsErrors":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
typesSupported |= 0x01; // EVENTLOG_ERROR_TYPE
}
break;
case "SupportsFailureAudits":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
typesSupported |= 0x10; // EVENTLOG_AUDIT_FAILURE
}
break;
case "SupportsInformationals":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
typesSupported |= 0x04; // EVENTLOG_INFORMATION_TYPE
}
break;
case "SupportsSuccessAudits":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
typesSupported |= 0x08; // EVENTLOG_AUDIT_SUCCESS
}
break;
case "SupportsWarnings":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
typesSupported |= 0x02; // EVENTLOG_WARNING_TYPE
}
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == sourceName)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
}
if (null == logName)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "EventLog"));
}
if (null == eventMessageFile)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "EventMessageFile"));
}
if (null == categoryMessageFile && 0 < categoryCount)
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "CategoryCount", "CategoryMessageFile"));
}
if (null != categoryMessageFile && CompilerConstants.IntegerNotSet == categoryCount)
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "CategoryMessageFile", "CategoryCount"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
string eventSourceKey = $@"SYSTEM\CurrentControlSet\Services\EventLog\{logName}\{sourceName}";
var id = this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "EventMessageFile", eventMessageFile, componentId, RegistryValueType.Expandable);
if (null != categoryMessageFile)
{
this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "CategoryMessageFile", categoryMessageFile, componentId, RegistryValueType.Expandable);
}
if (CompilerConstants.IntegerNotSet != categoryCount)
{
this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "CategoryCount", categoryCount, componentId);
}
if (null != parameterMessageFile)
{
this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "ParameterMessageFile", parameterMessageFile, componentId, RegistryValueType.Expandable);
}
if (0 != typesSupported)
{
this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, eventSourceKey, "TypesSupported", typesSupported, componentId);
}
var componentKeyPath = this.CreateComponentKeyPath();
componentKeyPath.Id = id;
componentKeyPath.Explicit = isKeyPath;
componentKeyPath.Type = PossibleKeyPathType.Registry;
return componentKeyPath;
}
///
/// Parses a close application element.
///
/// Element to parse.
private void ParseCloseApplicationElement(Intermediate intermediate, IntermediateSection section, XElement element)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
string condition = null;
string description = null;
string target = null;
string property = null;
Identifier id = null;
int attributes = 2; // default to CLOSEAPP_ATTRIBUTE_REBOOTPROMPT enabled
var sequence = CompilerConstants.IntegerNotSet;
var terminateExitCode = CompilerConstants.IntegerNotSet;
var timeout = CompilerConstants.IntegerNotSet;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Condition":
condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Description":
description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Property":
property = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
break;
case "Sequence":
sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
break;
case "Timeout":
timeout = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
break;
case "Target":
target = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "CloseMessage":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= 1; // CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE
}
else
{
attributes &= ~1; // CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE
}
break;
case "EndSessionMessage":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= 8; // CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE
}
else
{
attributes &= ~8; // CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE
}
break;
case "PromptToContinue":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= 0x40; // CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE
}
else
{
attributes &= ~0x40; // CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE
}
break;
case "RebootPrompt":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= 2; // CLOSEAPP_ATTRIBUTE_REBOOTPROMPT
}
else
{
attributes &= ~2; // CLOSEAPP_ATTRIBUTE_REBOOTPROMPT
}
break;
case "ElevatedCloseMessage":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= 4; // CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE
}
else
{
attributes &= ~4; // CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE
}
break;
case "ElevatedEndSessionMessage":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= 0x10; // CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE
}
else
{
attributes &= ~0x10; // CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE
}
break;
case "TerminateProcess":
terminateExitCode = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
attributes |= 0x20; // CLOSEAPP_ATTRIBUTE_TERMINATEPROCESS
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == target)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Target"));
}
else if (null == id)
{
id = this.ParseHelper.CreateIdentifier("ca", target);
}
if (String.IsNullOrEmpty(description) && 0x40 == (attributes & 0x40))
{
this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, element.Name.LocalName, "PromptToContinue", "yes", "Description"));
}
if (0x22 == (attributes & 0x22))
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "TerminateProcess", "RebootPrompt", "yes"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4CloseApplications", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
if (!this.Messaging.EncounteredError)
{
var symbol = section.AddSymbol(new WixCloseApplicationSymbol(sourceLineNumbers, id)
{
Target = target,
Description = description,
Condition = condition,
Attributes = attributes,
Property = property,
});
if (CompilerConstants.IntegerNotSet != sequence)
{
symbol.Sequence = sequence;
}
if (CompilerConstants.IntegerNotSet != terminateExitCode)
{
symbol.TerminateExitCode = terminateExitCode;
}
if (CompilerConstants.IntegerNotSet != timeout)
{
symbol.Timeout = timeout * 1000; // make the timeout milliseconds in the table.
}
}
}
///
/// Parses a DirectorySearch element.
///
/// Element to parse.
private void ParseDirectorySearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string variable = null;
string condition = null;
string after = null;
string path = null;
var attributes = WixFileSearchAttributes.IsDirectory;
var type = WixFileSearchType.Path;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
case "Variable":
case "Condition":
case "After":
this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
break;
case "DisableFileRedirection":
if (this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.Yes)
{
attributes |= WixFileSearchAttributes.DisableFileRedirection;
}
break;
case "Path":
path = this.ParseHelper.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true);
break;
case "Result":
var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
switch (result)
{
case "exists":
type = WixFileSearchType.Exists;
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "exists"));
break;
}
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == path)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path"));
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("wds", variable, condition, after, path, attributes.ToString(), type.ToString());
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
this.CreateWixFileSearchRow(section, sourceLineNumbers, id, path, attributes, type);
}
}
///
/// Parses a DirectorySearchRef, FileSearchRef, ProductSearchRef, and RegistrySearchRef elements
///
/// Element to parse.
private void ParseWixSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement node)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
foreach (XAttribute attrib in node.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
var refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixSearch, refId);
break;
default:
this.ParseHelper.UnexpectedAttribute(node, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
}
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
}
///
/// Parses a FileSearch element.
///
/// Element to parse.
private void ParseFileSearchElement(Intermediate intermediate, IntermediateSection section, XElement node)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
Identifier id = null;
string variable = null;
string condition = null;
string after = null;
string path = null;
var attributes = WixFileSearchAttributes.None;
var type = WixFileSearchType.Path;
foreach (var attrib in node.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
case "Variable":
case "Condition":
case "After":
this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
break;
case "DisableFileRedirection":
if (this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.Yes)
{
attributes |= WixFileSearchAttributes.DisableFileRedirection;
}
break;
case "Path":
path = this.ParseHelper.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true);
break;
case "Result":
string result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
switch (result)
{
case "exists":
type = WixFileSearchType.Exists;
break;
case "version":
type = WixFileSearchType.Version;
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "exists", "version"));
break;
}
break;
default:
this.ParseHelper.UnexpectedAttribute(node, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
}
}
if (null == path)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Path"));
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("wfs", variable, condition, after, path, attributes.ToString(), type.ToString());
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
if (!this.Messaging.EncounteredError)
{
this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, node.Name.LocalName, id, variable, condition, after, null);
this.CreateWixFileSearchRow(section, sourceLineNumbers, id, path, attributes, type);
}
}
///
/// Creates a row in the WixFileSearch table.
///
/// Source line number for the parent element.
/// Identifier of the search (key into the WixSearch table)
/// File/directory path to search for.
///
///
private void CreateWixFileSearchRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string path, WixFileSearchAttributes attributes, WixFileSearchType type)
{
section.AddSymbol(new WixFileSearchSymbol(sourceLineNumbers, id)
{
Path = path,
Attributes = attributes,
Type = type,
});
}
///
/// Parses a file share element.
///
/// Element to parse.
/// Identifier of parent component.
/// Identifier of referred to directory.
private void ParseFileShareElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string directoryId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
string description = null;
string name = null;
Identifier id = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Name":
name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Description":
description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("ufs", componentId, name);
}
if (null == name)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
}
var fileSharePermissionCount = 0;
foreach (var child in element.Elements())
{
if (this.Namespace == child.Name.Namespace)
{
switch (child.Name.LocalName)
{
case "FileSharePermission":
this.ParseFileSharePermissionElement(intermediate, section, child, id);
++fileSharePermissionCount;
break;
default:
this.ParseHelper.UnexpectedElement(element, child);
break;
}
}
else
{
this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
}
}
if (fileSharePermissionCount == 0)
{
this.Messaging.Write(ErrorMessages.ExpectedElement(sourceLineNumbers, element.Name.LocalName, "FileSharePermission"));
}
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureSmbInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureSmbUninstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new FileShareSymbol(sourceLineNumbers, id)
{
ShareName = name,
ComponentRef = componentId,
Description = description,
DirectoryRef = directoryId,
});
}
}
///
/// Parses a FileSharePermission element.
///
/// Element to parse.
/// The identifier of the parent FileShare element.
private void ParseFileSharePermissionElement(Intermediate intermediate, IntermediateSection section, XElement element, Identifier fileShareId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
var bits = new BitArray(32);
string user = null;
var validBitNames = new HashSet(UtilConstants.StandardPermissions.Concat(UtilConstants.GenericPermissions).Concat(UtilConstants.FolderPermissions));
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "User":
user = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.User, user);
break;
default:
if (validBitNames.Contains(attrib.Name.LocalName))
{
var attribValue = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
if (this.TrySetBitFromName(UtilConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16) ||
this.TrySetBitFromName(UtilConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28) ||
this.TrySetBitFromName(UtilConstants.FolderPermissions, attrib.Name.LocalName, attribValue, bits, 0))
{
break;
}
}
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
var permission = this.CreateIntegerFromBitArray(bits);
if (null == user)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "User"));
}
if (Int32.MinValue == permission) // just GENERIC_READ, which is MSI_NULL
{
this.Messaging.Write(ErrorMessages.GenericReadNotAllowed(sourceLineNumbers));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new FileSharePermissionsSymbol(sourceLineNumbers)
{
FileShareRef = fileShareId.Id,
UserRef = user,
Permissions = permission,
});
}
}
///
/// Parses a group element.
///
/// Node to be parsed.
/// Component Id of the parent component of this element.
private void ParseGroupElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string domain = null;
string name = null;
string comment = null;
Group6SymbolAttributes attributes = Group6SymbolAttributes.None;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Name":
name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Domain":
domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Comment":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
comment = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "CreateGroup":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= Group6SymbolAttributes.DontCreateGroup;
}
break;
case "FailIfExists":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= Group6SymbolAttributes.FailIfExists;
}
break;
case "UpdateIfExists":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= Group6SymbolAttributes.UpdateIfExists;
}
break;
case "RemoveComment":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= Group6SymbolAttributes.RemoveComment;
}
break;
case "RemoveOnUninstall":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= Group6SymbolAttributes.DontRemoveOnUninstall;
}
break;
case "Vital":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= Group6SymbolAttributes.NonVital;
}
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("ugr", componentId, domain, name);
}
if (null == name)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
}
if (null != comment && (Group6SymbolAttributes.RemoveComment & attributes) != 0)
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Comment", "RemoveComment"));
}
if (null != componentId)
{
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix6ConfigureGroups", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
}
foreach (var child in element.Elements())
{
if (this.Namespace == child.Name.Namespace)
{
switch (child.Name.LocalName)
{
case "GroupRef":
this.ParseGroupRefElement(intermediate, section, child, id.Id, groupType: true);
break;
default:
this.ParseHelper.UnexpectedElement(element, child);
break;
}
}
else
{
this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
}
}
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new GroupSymbol(sourceLineNumbers, id)
{
ComponentRef = componentId,
Name = name,
Domain = domain,
});
section.AddSymbol(new Group6Symbol(sourceLineNumbers, id)
{
GroupRef = id.Id,
Comment = comment,
Attributes = attributes,
});
}
}
///
/// Parses a GroupRef element
///
/// Element to parse.
/// Required child id to be joined to the group.
/// whether the child is a group (true) or a user (false)
private void ParseGroupRefElement(Intermediate intermediate, IntermediateSection section, XElement element, string childId, bool groupType)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
string groupId = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
groupId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.Group, groupId);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
if (!groupType)
{
section.AddSymbol(new UserGroupSymbol(sourceLineNumbers)
{
UserRef = childId,
GroupRef = groupId,
});
}
else
{
// Add reference to bring in fragment
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix6AddGroupMembership", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
section.AddSymbol(new GroupGroupSymbol(sourceLineNumbers)
{
ChildGroupRef = childId,
ParentGroupRef = groupId,
});
}
}
}
///
/// Parses an InternetShortcut element.
///
/// Element to parse.
/// Identifier of parent component.
/// Default directory if none is specified on the InternetShortcut element.
private void ParseInternetShortcutElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string defaultTarget)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string name = null;
string target = null;
string directoryId = null;
string type = null;
string iconFile = null;
int iconIndex = 0;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Directory":
directoryId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
break;
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Name":
name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Target":
target = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Type":
type = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "IconFile":
iconFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "IconIndex":
iconIndex = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
// If there was no directoryId specified on the InternetShortcut element, default to the one on
// the parent component.
if (null == directoryId)
{
directoryId = defaultTarget;
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("uis", componentId, directoryId, name, target);
}
// In theory this can never be the case, since InternetShortcut can only be under
// a component element, and if the Directory wasn't specified the default will come
// from the component. However, better safe than sorry, so here's a check to make sure
// it didn't wind up being null after setting it to the defaultTarget.
if (null == directoryId)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Directory"));
}
if (null == name)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
}
if (null == target)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Target"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
var shortcutType = InternetShortcutType.Link;
if (String.Equals(type, "url", StringComparison.OrdinalIgnoreCase))
{
shortcutType = InternetShortcutType.Url;
}
if (!this.Messaging.EncounteredError)
{
this.CreateWixInternetShortcut(section, sourceLineNumbers, componentId, directoryId, id, name, target, shortcutType, iconFile, iconIndex);
}
}
///
/// Creates the rows needed for WixInternetShortcut to work.
///
/// The CompilerCore object used to create rows.
/// Source line information about the owner element.
/// Identifier of parent component.
/// Identifier of directory containing shortcut.
/// Identifier of shortcut.
/// Name of shortcut without extension.
/// Target URL of shortcut.
private void CreateWixInternetShortcut(IntermediateSection section, SourceLineNumber sourceLineNumbers, string componentId, string directoryId, Identifier shortcutId, string name, string target, InternetShortcutType type, string iconFile, int iconIndex)
{
// add the appropriate extension based on type of shortcut
name = String.Concat(name, InternetShortcutType.Url == type ? ".url" : ".lnk");
section.AddSymbol(new WixInternetShortcutSymbol(sourceLineNumbers, shortcutId)
{
ComponentRef = componentId,
DirectoryRef = directoryId,
Name = name,
Target = target,
Attributes = (int)type,
IconFile = iconFile,
IconIndex = iconIndex,
});
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedInternetShortcuts", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
// make sure we have a CreateFolder table so that the immediate CA can add temporary rows to handle installation and uninstallation
this.ParseHelper.EnsureTable(section, sourceLineNumbers, "CreateFolder");
// use built-in MSI functionality to remove the shortcuts rather than doing so via CA
section.AddSymbol(new RemoveFileSymbol(sourceLineNumbers, shortcutId)
{
ComponentRef = componentId,
DirPropertyRef = directoryId,
OnUninstall = true,
FileName = name,
});
}
///
/// Parses a performance category element.
///
/// Element to parse.
/// Identifier of parent component.
private void ParsePerformanceCategoryElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string name = null;
string help = null;
var multiInstance = YesNoType.No;
int defaultLanguage = 0x09; // default to "english"
var parsedPerformanceCounters = new List();
// default to managed performance counter
var library = "netfxperf.dll";
var openEntryPoint = "OpenPerformanceData";
var collectEntryPoint = "CollectPerformanceData";
var closeEntryPoint = "ClosePerformanceData";
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Close":
closeEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Collect":
collectEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "DefaultLanguage":
defaultLanguage = this.GetPerformanceCounterLanguage(sourceLineNumbers, attrib);
break;
case "Help":
help = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Library":
library = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "MultiInstance":
multiInstance = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "Name":
name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Open":
openEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id && null == name)
{
this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "Id", "Name"));
}
else if (null == id)
{
id = this.ParseHelper.CreateIdentifier("upc", componentId, name);
}
else if (null == name)
{
name = id.Id;
}
// Process the child counter elements.
foreach (var child in element.Elements())
{
if (this.Namespace == child.Name.Namespace)
{
switch (child.Name.LocalName)
{
case "PerformanceCounter":
var counter = this.ParsePerformanceCounterElement(intermediate, section, child, defaultLanguage);
if (null != counter)
{
parsedPerformanceCounters.Add(counter);
}
break;
default:
this.ParseHelper.UnexpectedElement(element, child);
break;
}
}
else
{
this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
}
}
if (!this.Messaging.EncounteredError)
{
// Calculate the ini and h file content.
var objectName = "OBJECT_1";
var objectLanguage = defaultLanguage.ToString("D3", CultureInfo.InvariantCulture);
var sbIniData = new StringBuilder();
sbIniData.AppendFormat("[info]\r\ndrivername={0}\r\nsymbolfile=wixperf.h\r\n\r\n[objects]\r\n{1}_{2}_NAME=\r\n\r\n[languages]\r\n{2}=LANG{2}\r\n\r\n", name, objectName, objectLanguage);
sbIniData.AppendFormat("[text]\r\n{0}_{1}_NAME={2}\r\n", objectName, objectLanguage, name);
if (null != help)
{
sbIniData.AppendFormat("{0}_{1}_HELP={2}\r\n", objectName, objectLanguage, help);
}
int symbolConstantsCounter = 0;
var sbSymbolicConstants = new StringBuilder();
sbSymbolicConstants.AppendFormat("#define {0} {1}\r\n", objectName, symbolConstantsCounter);
var sbCounterNames = new StringBuilder("[~]");
var sbCounterTypes = new StringBuilder("[~]");
for (int i = 0; i < parsedPerformanceCounters.Count; ++i)
{
var counter = parsedPerformanceCounters[i];
var counterName = String.Concat("DEVICE_COUNTER_", i + 1);
sbIniData.AppendFormat("{0}_{1}_NAME={2}\r\n", counterName, counter.Language, counter.Name);
if (null != counter.Help)
{
sbIniData.AppendFormat("{0}_{1}_HELP={2}\r\n", counterName, counter.Language, counter.Help);
}
symbolConstantsCounter += 2;
sbSymbolicConstants.AppendFormat("#define {0} {1}\r\n", counterName, symbolConstantsCounter);
sbCounterNames.Append(UtilCompiler.FindPropertyBrackets.Replace(counter.Name, this.EscapeProperties));
sbCounterNames.Append("[~]");
sbCounterTypes.Append(counter.Type);
sbCounterTypes.Append("[~]");
}
sbSymbolicConstants.AppendFormat("#define LAST_{0}_COUNTER_OFFSET {1}\r\n", objectName, symbolConstantsCounter);
// Add the calculated INI and H strings to the PerformanceCategory table.
section.AddSymbol(new PerformanceCategorySymbol(sourceLineNumbers, id)
{
ComponentRef = componentId,
Name = name,
IniData = sbIniData.ToString(),
ConstantData = sbSymbolicConstants.ToString(),
});
// Set up the application's performance key.
var escapedName = UtilCompiler.FindPropertyBrackets.Replace(name, this.EscapeProperties);
var linkageKey = String.Format(@"SYSTEM\CurrentControlSet\Services\{0}\Linkage", escapedName);
var performanceKey = String.Format(@"SYSTEM\CurrentControlSet\Services\{0}\Performance", escapedName);
this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, linkageKey, "Export", escapedName, componentId);
this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "-", null, componentId);
this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Library", library, componentId);
this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Open", openEntryPoint, componentId);
this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Collect", collectEntryPoint, componentId);
this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Close", closeEntryPoint, componentId);
this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "IsMultiInstance", YesNoType.Yes == multiInstance ? 1 : 0, componentId);
this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Counter Names", sbCounterNames.ToString(), componentId, RegistryValueType.MultiString);
this.ParseHelper.CreateRegistrySymbol(section, sourceLineNumbers, RegistryRootType.LocalMachine, performanceKey, "Counter Types", sbCounterTypes.ToString(), componentId, RegistryValueType.MultiString);
}
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4InstallPerfCounterData", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4UninstallPerfCounterData", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
}
///
/// Gets the performance counter language as a decimal number.
///
/// Source line information about the owner element.
/// The attribute containing the value to get.
/// Numeric representation of the language as per WinNT.h.
private int GetPerformanceCounterLanguage(SourceLineNumber sourceLineNumbers, XAttribute attribute)
{
int language = 0;
if (String.Empty == attribute.Value)
{
this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
}
else
{
switch (attribute.Value)
{
case "afrikaans":
language = 0x36;
break;
case "albanian":
language = 0x1c;
break;
case "arabic":
language = 0x01;
break;
case "armenian":
language = 0x2b;
break;
case "assamese":
language = 0x4d;
break;
case "azeri":
language = 0x2c;
break;
case "basque":
language = 0x2d;
break;
case "belarusian":
language = 0x23;
break;
case "bengali":
language = 0x45;
break;
case "bulgarian":
language = 0x02;
break;
case "catalan":
language = 0x03;
break;
case "chinese":
language = 0x04;
break;
case "croatian":
language = 0x1a;
break;
case "czech":
language = 0x05;
break;
case "danish":
language = 0x06;
break;
case "divehi":
language = 0x65;
break;
case "dutch":
language = 0x13;
break;
case "piglatin":
case "english":
language = 0x09;
break;
case "estonian":
language = 0x25;
break;
case "faeroese":
language = 0x38;
break;
case "farsi":
language = 0x29;
break;
case "finnish":
language = 0x0b;
break;
case "french":
language = 0x0c;
break;
case "galician":
language = 0x56;
break;
case "georgian":
language = 0x37;
break;
case "german":
language = 0x07;
break;
case "greek":
language = 0x08;
break;
case "gujarati":
language = 0x47;
break;
case "hebrew":
language = 0x0d;
break;
case "hindi":
language = 0x39;
break;
case "hungarian":
language = 0x0e;
break;
case "icelandic":
language = 0x0f;
break;
case "indonesian":
language = 0x21;
break;
case "italian":
language = 0x10;
break;
case "japanese":
language = 0x11;
break;
case "kannada":
language = 0x4b;
break;
case "kashmiri":
language = 0x60;
break;
case "kazak":
language = 0x3f;
break;
case "konkani":
language = 0x57;
break;
case "korean":
language = 0x12;
break;
case "kyrgyz":
language = 0x40;
break;
case "latvian":
language = 0x26;
break;
case "lithuanian":
language = 0x27;
break;
case "macedonian":
language = 0x2f;
break;
case "malay":
language = 0x3e;
break;
case "malayalam":
language = 0x4c;
break;
case "manipuri":
language = 0x58;
break;
case "marathi":
language = 0x4e;
break;
case "mongolian":
language = 0x50;
break;
case "nepali":
language = 0x61;
break;
case "norwegian":
language = 0x14;
break;
case "oriya":
language = 0x48;
break;
case "polish":
language = 0x15;
break;
case "portuguese":
language = 0x16;
break;
case "punjabi":
language = 0x46;
break;
case "romanian":
language = 0x18;
break;
case "russian":
language = 0x19;
break;
case "sanskrit":
language = 0x4f;
break;
case "serbian":
language = 0x1a;
break;
case "sindhi":
language = 0x59;
break;
case "slovak":
language = 0x1b;
break;
case "slovenian":
language = 0x24;
break;
case "spanish":
language = 0x0a;
break;
case "swahili":
language = 0x41;
break;
case "swedish":
language = 0x1d;
break;
case "syriac":
language = 0x5a;
break;
case "tamil":
language = 0x49;
break;
case "tatar":
language = 0x44;
break;
case "telugu":
language = 0x4a;
break;
case "thai":
language = 0x1e;
break;
case "turkish":
language = 0x1f;
break;
case "ukrainian":
language = 0x22;
break;
case "urdu":
language = 0x20;
break;
case "uzbek":
language = 0x43;
break;
case "vietnamese":
language = 0x2a;
break;
default:
this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
break;
}
}
return language;
}
///
/// Parses a performance counter element.
///
/// Element to parse.
/// Default language for the performance counter.
private ParsedPerformanceCounter ParsePerformanceCounterElement(Intermediate intermediate, IntermediateSection section, XElement element, int defaultLanguage)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
ParsedPerformanceCounter parsedPerformanceCounter = null;
string name = null;
string help = null;
var type = System.Diagnostics.PerformanceCounterType.NumberOfItems32;
int language = defaultLanguage;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Help":
help = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Name":
name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Type":
type = this.GetPerformanceCounterType(sourceLineNumbers, attrib);
break;
case "Language":
language = this.GetPerformanceCounterLanguage(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == name)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
}
if (null == help)
{
this.Messaging.Write(UtilWarnings.RequiredAttributeForWindowsXP(sourceLineNumbers, element.Name.LocalName, "Help"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
parsedPerformanceCounter = new ParsedPerformanceCounter(name, help, type, language);
}
return parsedPerformanceCounter;
}
///
/// Gets the performance counter type.
///
/// Source line information about the owner element.
/// The attribute containing the value to get.
/// Numeric representation of the language as per WinNT.h.
private System.Diagnostics.PerformanceCounterType GetPerformanceCounterType(SourceLineNumber sourceLineNumbers, XAttribute attribute)
{
var type = System.Diagnostics.PerformanceCounterType.NumberOfItems32;
if (String.Empty == attribute.Value)
{
this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
}
else
{
switch (attribute.Value)
{
case "averageBase":
type = System.Diagnostics.PerformanceCounterType.AverageBase;
break;
case "averageCount64":
type = System.Diagnostics.PerformanceCounterType.AverageCount64;
break;
case "averageTimer32":
type = System.Diagnostics.PerformanceCounterType.AverageTimer32;
break;
case "counterDelta32":
type = System.Diagnostics.PerformanceCounterType.CounterDelta32;
break;
case "counterTimerInverse":
type = System.Diagnostics.PerformanceCounterType.CounterTimerInverse;
break;
case "sampleFraction":
type = System.Diagnostics.PerformanceCounterType.SampleFraction;
break;
case "timer100Ns":
type = System.Diagnostics.PerformanceCounterType.Timer100Ns;
break;
case "counterTimer":
type = System.Diagnostics.PerformanceCounterType.CounterTimer;
break;
case "rawFraction":
type = System.Diagnostics.PerformanceCounterType.RawFraction;
break;
case "timer100NsInverse":
type = System.Diagnostics.PerformanceCounterType.Timer100NsInverse;
break;
case "counterMultiTimer":
type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer;
break;
case "counterMultiTimer100Ns":
type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer100Ns;
break;
case "counterMultiTimerInverse":
type = System.Diagnostics.PerformanceCounterType.CounterMultiTimerInverse;
break;
case "counterMultiTimer100NsInverse":
type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer100NsInverse;
break;
case "elapsedTime":
type = System.Diagnostics.PerformanceCounterType.ElapsedTime;
break;
case "sampleBase":
type = System.Diagnostics.PerformanceCounterType.SampleBase;
break;
case "rawBase":
type = System.Diagnostics.PerformanceCounterType.RawBase;
break;
case "counterMultiBase":
type = System.Diagnostics.PerformanceCounterType.CounterMultiBase;
break;
case "rateOfCountsPerSecond64":
type = System.Diagnostics.PerformanceCounterType.RateOfCountsPerSecond64;
break;
case "rateOfCountsPerSecond32":
type = System.Diagnostics.PerformanceCounterType.RateOfCountsPerSecond32;
break;
case "countPerTimeInterval64":
type = System.Diagnostics.PerformanceCounterType.CountPerTimeInterval64;
break;
case "countPerTimeInterval32":
type = System.Diagnostics.PerformanceCounterType.CountPerTimeInterval32;
break;
case "sampleCounter":
type = System.Diagnostics.PerformanceCounterType.SampleCounter;
break;
case "counterDelta64":
type = System.Diagnostics.PerformanceCounterType.CounterDelta64;
break;
case "numberOfItems64":
type = System.Diagnostics.PerformanceCounterType.NumberOfItems64;
break;
case "numberOfItems32":
type = System.Diagnostics.PerformanceCounterType.NumberOfItems32;
break;
case "numberOfItemsHEX64":
type = System.Diagnostics.PerformanceCounterType.NumberOfItemsHEX64;
break;
case "numberOfItemsHEX32":
type = System.Diagnostics.PerformanceCounterType.NumberOfItemsHEX32;
break;
default:
this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
break;
}
}
return type;
}
///
/// Parses a perf counter element.
///
/// Element to parse.
/// Identifier of parent component.
/// Identifier of referenced file.
private void ParsePerfCounterElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
string name = null;
this.Messaging.Write(UtilWarnings.DeprecatedPerfCounterElement(sourceLineNumbers));
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Name":
name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == name)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new PerfmonSymbol(sourceLineNumbers)
{
ComponentRef = componentId,
File = $"[#{fileId}]",
Name = name,
});
}
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonUninstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
}
///
/// Parses a perf manifest element.
///
/// Element to parse.
/// Identifier of parent component.
/// Identifier of referenced file.
private void ParsePerfCounterManifestElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
string resourceFileDirectory = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "ResourceFileDirectory":
resourceFileDirectory = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new PerfmonManifestSymbol(sourceLineNumbers)
{
ComponentRef = componentId,
File = $"[#{fileId}]",
ResourceFileDirectory = resourceFileDirectory,
});
}
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonManifestRegister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigurePerfmonManifestUnregister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
}
///
/// Parses a format files element.
///
/// Element to parse.
/// Identifier of referenced file.
/// Flag to determine whether the component is 64-bit.
private void ParseFormatFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string fileId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
string binaryId = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "BinaryRef":
binaryId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (null == binaryId)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "BinaryRef"));
}
if (!this.Messaging.EncounteredError)
{
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedFormatFiles", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
section.AddSymbol(new WixFormatFilesSymbol(sourceLineNumbers)
{
BinaryRef = binaryId,
FileRef = fileId,
});
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Binary, binaryId);
}
}
///
/// Parses a event manifest element.
///
/// Element to parse.
/// Identifier of parent component.
/// Identifier of referenced file.
private void ParseEventManifestElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
string messageFile = null;
string resourceFile = null;
string parameterFile = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "MessageFile":
messageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "ResourceFile":
resourceFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "ParameterFile":
parameterFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new EventManifestSymbol(sourceLineNumbers)
{
ComponentRef = componentId,
File = $"[#{fileId}]",
});
if (null != messageFile)
{
section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, $"Config_{fileId}MessageFile"))
{
File = $"[#{fileId}]",
ElementPath = "/*/*/*/*[\\[]@messageFileName[\\]]",
Name = "messageFileName",
Value = messageFile,
Flags = 4 | 0x00001000, //bulk write | preserve modified date
ComponentRef = componentId,
});
}
if (null != parameterFile)
{
section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, $"Config_{fileId}ParameterFile"))
{
File = $"[#{fileId}]",
ElementPath = "/*/*/*/*[\\[]@parameterFileName[\\]]",
Name = "parameterFileName",
Value = parameterFile,
Flags = 4 | 0x00001000, //bulk write | preserve modified date
ComponentRef = componentId,
});
}
if (null != resourceFile)
{
section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, $"Config_{fileId}ResourceFile"))
{
File = $"[#{fileId}]",
ElementPath = "/*/*/*/*[\\[]@resourceFileName[\\]]",
Name = "resourceFileName",
Value = resourceFile,
Flags = 4 | 0x00001000, //bulk write | preserve modified date
ComponentRef = componentId,
});
}
}
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureEventManifestRegister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureEventManifestUnregister", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
if (null != messageFile || null != parameterFile || null != resourceFile)
{
this.AddReferenceToSchedXmlFile(sourceLineNumbers, section);
}
}
///
/// Parses a PermissionEx element.
///
/// Element to parse.
/// Identifier of object to be secured.
/// Identifier of component, used to determine install state.
/// Flag to determine whether the component is 64-bit.
/// Name of table that contains objectId.
private void ParsePermissionExElement(Intermediate intermediate, IntermediateSection section, XElement element, string objectId, string componentId, string tableName)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
var bits = new BitArray(32);
string domain = null;
string[] specialPermissions = null;
string user = null;
var attributes = WixPermissionExAttributes.Inheritable; // default to inheritable.
var permissionType = PermissionType.SecureObjects;
switch (tableName)
{
case "CreateFolder":
specialPermissions = UtilConstants.FolderPermissions;
break;
case "File":
specialPermissions = UtilConstants.FilePermissions;
break;
case "Registry":
specialPermissions = UtilConstants.RegistryPermissions;
if (String.IsNullOrEmpty(objectId))
{
this.Messaging.Write(UtilErrors.InvalidRegistryObject(sourceLineNumbers, element.Parent.Name.LocalName));
}
break;
case "ServiceInstall":
specialPermissions = UtilConstants.ServicePermissions;
permissionType = PermissionType.SecureObjects;
break;
default:
this.ParseHelper.UnexpectedElement(element.Parent, element);
break;
}
var validBitNames = new HashSet(UtilConstants.StandardPermissions.Concat(UtilConstants.GenericPermissions).Concat(specialPermissions));
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Domain":
if (PermissionType.FileSharePermissions == permissionType)
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
}
domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Inheritable":
if (this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.No)
{
attributes &= ~WixPermissionExAttributes.Inheritable;
}
break;
case "User":
user = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
if (validBitNames.Contains(attrib.Name.LocalName))
{
var attribValue = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
if (this.TrySetBitFromName(UtilConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16) ||
this.TrySetBitFromName(UtilConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28) ||
this.TrySetBitFromName(specialPermissions, attrib.Name.LocalName, attribValue, bits, 0))
{
break;
}
}
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
var permission = this.CreateIntegerFromBitArray(bits);
if (null == user)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "User"));
}
if (Int32.MinValue == permission) // just GENERIC_READ, which is MSI_NULL
{
this.Messaging.Write(ErrorMessages.GenericReadNotAllowed(sourceLineNumbers));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedSecureObjects", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
var id = this.ParseHelper.CreateIdentifier("sec", objectId, tableName, domain, user);
section.AddSymbol(new SecureObjectsSymbol(sourceLineNumbers, id)
{
SecureObject = objectId,
Table = tableName,
Domain = domain,
User = user,
Attributes = attributes,
Permission = permission,
ComponentRef = componentId,
});
}
}
///
/// Parses a ProductSearch element.
///
/// Element to parse.
private void ParseProductSearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string variable = null;
string condition = null;
string after = null;
string productCode = null;
string upgradeCode = null;
var attributes = WixProductSearchAttributes.None;
var type = WixProductSearchType.Version;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
case "Variable":
case "Condition":
case "After":
this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
break;
case "ProductCode":
productCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib, false);
break;
case "UpgradeCode":
upgradeCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib, false);
break;
case "Result":
var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
switch (result)
{
case "version":
type = WixProductSearchType.Version;
break;
case "language":
type = WixProductSearchType.Language;
break;
case "state":
type = WixProductSearchType.State;
break;
case "assignment":
type = WixProductSearchType.Assignment;
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "version", "language", "state", "assignment"));
break;
}
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == upgradeCode && null == productCode)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ProductCode", "UpgradeCode", true));
}
if (null != upgradeCode && null != productCode)
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "UpgradeCode", "ProductCode"));
}
string guid;
if (upgradeCode != null)
{
// set an additional flag if this is an upgrade code
attributes |= WixProductSearchAttributes.UpgradeCode;
guid = upgradeCode;
}
else
{
guid = productCode;
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("wps", variable, condition, after, guid, attributes.ToString(), type.ToString());
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
section.AddSymbol(new WixProductSearchSymbol(sourceLineNumbers, id)
{
Guid = guid,
Attributes = attributes,
Type = type,
});
}
}
///
/// Parses a RegistrySearch element.
///
/// Element to parse.
private void ParseRegistrySearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string variable = null;
string condition = null;
string after = null;
RegistryRootType? root = null;
string key = null;
string value = null;
var expand = YesNoType.NotSet;
var win64 = this.Context.IsCurrentPlatform64Bit;
var attributes = WixRegistrySearchAttributes.None;
var type = WixRegistrySearchType.Value;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
case "Variable":
case "Condition":
case "After":
this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
break;
case "Bitness":
var bitnessValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
switch (bitnessValue)
{
case "always32":
win64 = false;
break;
case "always64":
win64 = true;
break;
case "default":
case "":
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Name.LocalName, attrib.Name.LocalName, bitnessValue, "default", "always32", "always64"));
break;
}
break;
case "Root":
root = this.ParseHelper.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, false);
break;
case "Key":
key = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Value":
value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "ExpandEnvironmentVariables":
expand = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "Result":
var result = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
switch (result)
{
case "exists":
type = WixRegistrySearchType.Exists;
break;
case "value":
type = WixRegistrySearchType.Value;
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName, result, "exists", "value"));
break;
}
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (!root.HasValue)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Root"));
}
if (null == key)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Key"));
}
if (expand == YesNoType.Yes)
{
if (type == WixRegistrySearchType.Exists)
{
this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "ExpandEnvironmentVariables", expand.ToString(), "Result", "exists"));
}
attributes |= WixRegistrySearchAttributes.ExpandEnvironmentVariables;
}
if (win64)
{
attributes |= WixRegistrySearchAttributes.Win64;
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("wrs", variable, condition, after, root.ToString(), key, value, attributes.ToString(), type.ToString());
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
this.ParseHelper.CreateWixSearchSymbol(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
section.AddSymbol(new WixRegistrySearchSymbol(sourceLineNumbers, id)
{
Root = root.Value,
Key = key,
Value = value,
Attributes = attributes,
Type = type,
});
}
}
///
/// Parses a RemoveFolderEx element.
///
/// Element to parse.
/// Identifier of parent component.
private void ParseRemoveFolderExElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
var mode = WixRemoveFolderExInstallMode.Uninstall;
string property = null;
string condition = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Condition":
condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "On":
var onValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
if (onValue.Length == 0)
{
}
else
{
switch (onValue)
{
case "install":
mode = WixRemoveFolderExInstallMode.Install;
break;
case "uninstall":
mode = WixRemoveFolderExInstallMode.Uninstall;
break;
case "both":
mode = WixRemoveFolderExInstallMode.Both;
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "On", onValue, "install", "uninstall", "both"));
break;
}
}
break;
case "Property":
property = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (String.IsNullOrEmpty(property))
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Property"));
}
if (id == null)
{
id = this.ParseHelper.CreateIdentifier("wrf", componentId, property, mode.ToString());
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4RemoveFoldersEx", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
section.AddSymbol(new WixRemoveFolderExSymbol(sourceLineNumbers, id)
{
ComponentRef = componentId,
Property = property,
InstallMode = mode,
Condition = condition
});
this.ParseHelper.EnsureTable(section, sourceLineNumbers, "RemoveFile");
}
}
///
/// Parses a RemoveRegistryKeyEx element.
///
/// Element to parse.
/// Identifier of parent component.
private void ParseRemoveRegistryKeyExElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
var mode = WixRemoveRegistryKeyExInstallMode.Uninstall;
string condition = null;
RegistryRootType? root = null;
string key = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Condition":
condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "On":
var actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
switch (actionValue)
{
case "":
break;
case "install":
mode = WixRemoveRegistryKeyExInstallMode.Install;
break;
case "uninstall":
mode = WixRemoveRegistryKeyExInstallMode.Uninstall;
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "On", actionValue, "install", "uninstall"));
break;
}
break;
case "Root":
root = this.ParseHelper.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, false);
break;
case "Key":
key = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (!root.HasValue)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Root"));
}
if (key == null)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Key"));
}
if (id == null)
{
id = this.ParseHelper.CreateIdentifier("rrx", componentId, condition, root.ToString(), key, mode.ToString());
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
this.ParseHelper.EnsureTable(section, sourceLineNumbers, "Registry");
this.ParseHelper.EnsureTable(section, sourceLineNumbers, "RemoveRegistry");
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4RemoveRegistryKeysEx", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
section.AddSymbol(new WixRemoveRegistryKeyExSymbol(sourceLineNumbers, id)
{
ComponentRef = componentId,
Root = root.Value,
Key = key,
InstallMode = mode,
Condition = condition
});
}
}
///
/// Parses a RestartResource element.
///
/// The element to parse.
/// The identity of the parent component.
private void ParseRestartResourceElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string resource = null;
WixRestartResourceAttributes? attributes = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Path":
resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
attributes = WixRestartResourceAttributes.Filename;
break;
case "ProcessName":
resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
attributes = WixRestartResourceAttributes.ProcessName;
break;
case "ServiceName":
resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
attributes = WixRestartResourceAttributes.ServiceName;
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
// Validate the attribute.
if (id == null)
{
id = this.ParseHelper.CreateIdentifier("wrr", componentId, resource, attributes.ToString());
}
if (!attributes.HasValue)
{
this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "Path", "ProcessName", "ServiceName"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4RegisterRestartResources", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
section.AddSymbol(new WixRestartResourceSymbol(sourceLineNumbers, id)
{
ComponentRef = componentId,
Resource = resource,
Attributes = attributes,
});
}
}
///
/// Parses a service configuration element.
///
/// Element to parse.
/// Identifier of parent component.
/// Name of parent element.
/// Optional name of service
private void ParseServiceConfigElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string parentTableName, string parentTableServiceName)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
string firstFailureActionType = null;
var newService = false;
string programCommandLine = null;
string rebootMessage = null;
int? resetPeriod = null;
int? restartServiceDelay = null;
string secondFailureActionType = null;
string serviceName = null;
string thirdFailureActionType = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "FirstFailureActionType":
firstFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "ProgramCommandLine":
programCommandLine = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "RebootMessage":
rebootMessage = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "ResetPeriodInDays":
resetPeriod = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
break;
case "RestartServiceDelayInSeconds":
restartServiceDelay = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue);
break;
case "SecondFailureActionType":
secondFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "ServiceName":
serviceName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "ThirdFailureActionType":
thirdFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
// if this element is a child of ServiceInstall then ignore the service name provided.
if ("ServiceInstall" == parentTableName)
{
if (null == serviceName || parentTableServiceName == serviceName)
{
serviceName = parentTableServiceName;
}
else
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, "ServiceName", parentTableName));
}
newService = true;
}
else
{
// not a child of ServiceInstall, so ServiceName must have been provided
if (null == serviceName)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ServiceName"));
}
}
var context = new Dictionary() { { "ServiceConfigComponentId", componentId }, { "ServiceConfigServiceName", serviceName } };
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element, context);
if (!this.Messaging.EncounteredError)
{
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedServiceConfig", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
section.AddSymbol(new ServiceConfigSymbol(sourceLineNumbers)
{
ServiceName = serviceName,
ComponentRef = componentId,
NewService = newService ? 1 : 0,
FirstFailureActionType = firstFailureActionType,
SecondFailureActionType = secondFailureActionType,
ThirdFailureActionType = thirdFailureActionType,
ResetPeriodInDays = resetPeriod,
RestartServiceDelayInSeconds = restartServiceDelay,
ProgramCommandLine = programCommandLine,
RebootMessage = rebootMessage,
});
}
}
///
/// Parses a touch file element.
///
/// Element to parse.
/// Identifier of parent component.
/// Indicates whether the path is a 64-bit path.
private void ParseTouchFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, bool win64)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string path = null;
var onInstall = YesNoType.NotSet;
var onReinstall = YesNoType.NotSet;
var onUninstall = YesNoType.NotSet;
var nonvital = YesNoType.NotSet;
int attributes = 0;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Path":
path = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "OnInstall":
onInstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "OnReinstall":
onReinstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "OnUninstall":
onUninstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "Nonvital":
nonvital = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == path)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path"));
}
// If none of the scheduling actions are set, default to touching on install and reinstall.
if (YesNoType.NotSet == onInstall && YesNoType.NotSet == onReinstall && YesNoType.NotSet == onUninstall)
{
onInstall = YesNoType.Yes;
onReinstall = YesNoType.Yes;
}
attributes |= YesNoType.Yes == onInstall ? 0x1 : 0;
attributes |= YesNoType.Yes == onReinstall ? 0x2 : 0;
attributes |= YesNoType.Yes == onUninstall ? 0x4 : 0;
attributes |= win64 ? 0x10 : 0;
attributes |= YesNoType.Yes == nonvital ? 0 : 0x20;
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("tf", path, attributes.ToString());
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new WixTouchFileSymbol(sourceLineNumbers, id)
{
ComponentRef = componentId,
Path = path,
Attributes = attributes,
});
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4TouchFileDuringInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
}
}
///
/// Parses an user element.
///
/// Element to parse.
/// Optional identifier of parent component.
private void ParseUserElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
int attributes = 0;
string domain = null;
string name = null;
string comment = null;
string password = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "CanNotChangePassword":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= UserPasswdCantChange;
}
break;
case "Comment":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
comment = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "CreateUser":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= UserDontCreateUser;
}
break;
case "Disabled":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= UserDisableAccount;
}
break;
case "Domain":
domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "FailIfExists":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= UserFailIfExists;
}
break;
case "LogonAsService":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= UserLogonAsService;
}
break;
case "LogonAsBatchJob":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= UserLogonAsBatchJob;
}
break;
case "Name":
name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Password":
password = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "PasswordExpired":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= UserPasswdChangeReqdOnLogin;
}
break;
case "PasswordNeverExpires":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= UserDontExpirePasswrd;
}
break;
case "RemoveComment":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= UserRemoveComment;
}
break;
case "RemoveOnUninstall":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= UserDontRemoveOnUninstall;
}
break;
case "UpdateIfExists":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= UserUpdateIfExists;
}
break;
case "Vital":
if (null == componentId)
{
this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= UserNonVital;
}
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("usr", componentId, name);
}
if (null == name)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
}
if (null != comment && (UserRemoveComment & attributes) != 0)
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Comment", "RemoveComment"));
}
foreach (var child in element.Elements())
{
if (this.Namespace == child.Name.Namespace)
{
switch (child.Name.LocalName)
{
case "GroupRef":
if (null == componentId)
{
var childSourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(child);
this.Messaging.Write(UtilErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
}
this.ParseGroupRefElement(intermediate, section, child, id.Id, groupType: false);
break;
default:
this.ParseHelper.UnexpectedElement(element, child);
break;
}
}
else
{
this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
}
}
if (null != componentId)
{
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureUsers", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
}
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new UserSymbol(sourceLineNumbers, id)
{
ComponentRef = componentId,
Name = name,
Domain = domain,
Password = password,
Comment = comment,
Attributes = attributes,
});
}
}
///
/// Parses a XmlFile element.
///
/// Element to parse.
/// Identifier of parent component.
private void ParseXmlFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string file = null;
string elementPath = null;
string name = null;
string value = null;
int sequence = -1;
int flags = 0;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Action":
var actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
switch (actionValue)
{
case "createElement":
flags |= 0x00000001; // XMLFILE_CREATE_ELEMENT
break;
case "deleteValue":
flags |= 0x00000002; // XMLFILE_DELETE_VALUE
break;
case "bulkSetValue":
flags |= 0x00000004; // XMLFILE_BULKWRITE_VALUE
break;
case "setValue":
// no flag for set value since it's the default
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Action", actionValue, "createElement", "deleteValue", "setValue", "bulkSetValue"));
break;
}
break;
case "SelectionLanguage":
var selectionLanguage = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
switch (selectionLanguage)
{
case "XPath":
flags |= 0x00000100; // XMLFILE_USE_XPATH
break;
case "XSLPattern":
// no flag for since it's the default
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "SelectionLanguage", selectionLanguage, "XPath", "XSLPattern"));
break;
}
break;
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "File":
file = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "ElementPath":
elementPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Name":
name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Permanent":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
flags |= 0x00010000; // XMLFILE_DONT_UNINSTALL
}
break;
case "Sequence":
sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue);
break;
case "Value":
value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "PreserveModifiedDate":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
flags |= 0x00001000; // XMLFILE_PRESERVE_MODIFIED
}
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("uxf", componentId, file, elementPath, name);
}
if (null == file)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "File"));
}
if (null == elementPath)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ElementPath"));
}
if ((0x00000001 /*XMLFILE_CREATE_ELEMENT*/ & flags) != 0 && null == name)
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "Action", "Name"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
var symbol = section.AddSymbol(new XmlFileSymbol(sourceLineNumbers, id)
{
File = file,
ElementPath = elementPath,
Name = name,
Value = value,
Flags = flags,
ComponentRef = componentId,
});
if (-1 != sequence)
{
symbol.Sequence = sequence;
}
}
this.AddReferenceToSchedXmlFile(sourceLineNumbers, section);
}
///
/// Parses a XmlConfig element.
///
/// Element to parse.
/// Identifier of parent component.
/// Whether or not the element is nested.
private void ParseXmlConfigElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, bool nested)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string elementId = null;
string elementPath = null;
int flags = 0;
string file = null;
string name = null;
var sequence = CompilerConstants.IntegerNotSet;
string value = null;
string verifyPath = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Action":
if (nested)
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
}
else
{
var actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
switch (actionValue)
{
case "create":
flags |= 0x10; // XMLCONFIG_CREATE
break;
case "delete":
flags |= 0x20; // XMLCONFIG_DELETE
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, actionValue, "create", "delete"));
break;
}
}
break;
case "ElementId":
elementId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "ElementPath":
elementPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "File":
file = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Name":
name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Node":
if (nested)
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
}
else
{
var nodeValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
switch (nodeValue)
{
case "element":
flags |= 0x1; // XMLCONFIG_ELEMENT
break;
case "value":
flags |= 0x2; // XMLCONFIG_VALUE
break;
case "document":
flags |= 0x4; // XMLCONFIG_DOCUMENT
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, nodeValue, "element", "value", "document"));
break;
}
}
break;
case "On":
if (nested)
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
}
else
{
var onValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
switch (onValue)
{
case "install":
flags |= 0x100; // XMLCONFIG_INSTALL
break;
case "uninstall":
flags |= 0x200; // XMLCONFIG_UNINSTALL
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, onValue, "install", "uninstall"));
break;
}
}
break;
case "PreserveModifiedDate":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
flags |= 0x00001000; // XMLCONFIG_PRESERVE_MODIFIED
}
break;
case "Sequence":
sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue);
break;
case "Value":
value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "VerifyPath":
verifyPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("uxc", componentId, file, elementId, elementPath);
}
if (null == file)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "File"));
}
if (null == elementId && null == elementPath)
{
this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "ElementId", "ElementPath"));
}
else if (null != elementId)
{
if (null != elementPath)
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "ElementId", "ElementPath"));
}
if (0 != flags)
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, "ElementId", "Action", "Node", "On"));
}
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, UtilSymbolDefinitions.XmlConfig, elementId);
}
// find unexpected child elements
foreach (var child in element.Elements())
{
if (this.Namespace == child.Name.Namespace)
{
switch (child.Name.LocalName)
{
case "XmlConfig":
if (nested)
{
this.Messaging.Write(ErrorMessages.UnexpectedElement(sourceLineNumbers, element.Name.LocalName, child.Name.LocalName));
}
else
{
this.ParseXmlConfigElement(intermediate, section, child, componentId, true);
}
break;
default:
this.ParseHelper.UnexpectedElement(element, child);
break;
}
}
else
{
this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
}
}
if (!this.Messaging.EncounteredError)
{
var symbol = section.AddSymbol(new XmlConfigSymbol(sourceLineNumbers, id)
{
File = file,
ElementId = elementId,
ElementPath = elementPath,
VerifyPath = verifyPath,
Name = name,
Value = value,
Flags = flags,
ComponentRef = componentId,
});
if (CompilerConstants.IntegerNotSet != sequence)
{
symbol.Sequence = sequence;
}
}
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedXmlConfig", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
}
///
/// Match evaluator to escape properties in a string.
///
private string EscapeProperties(Match match)
{
string escape = null;
switch (match.Value)
{
case "[":
escape = @"[\[]";
break;
case "]":
escape = @"[\]]";
break;
}
return escape;
}
private int CreateIntegerFromBitArray(BitArray bits)
{
if (32 != bits.Length)
{
throw new ArgumentException(String.Format("Can only convert a bit array with 32-bits to integer. Actual number of bits in array: {0}", bits.Length), "bits");
}
var intArray = new int[1];
bits.CopyTo(intArray, 0);
return intArray[0];
}
private bool TrySetBitFromName(string[] attributeNames, string attributeName, YesNoType attributeValue, BitArray bits, int offset)
{
for (var i = 0; i < attributeNames.Length; i++)
{
if (attributeName.Equals(attributeNames[i], StringComparison.Ordinal))
{
bits.Set(i + offset, YesNoType.Yes == attributeValue);
return true;
}
}
return false;
}
private void AddReferenceToSchedXmlFile(SourceLineNumber sourceLineNumbers, IntermediateSection section)
{
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedXmlFile", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
}
///
/// Private class that stores the data from a parsed PerformanceCounter element.
///
private class ParsedPerformanceCounter
{
internal ParsedPerformanceCounter(string name, string help, System.Diagnostics.PerformanceCounterType type, int language)
{
this.Name = name;
this.Help = help;
this.Type = (int)type;
this.Language = language.ToString("D3", CultureInfo.InvariantCulture);
}
internal string Name { get; }
internal string Help { get; }
internal int Type { get; }
internal string Language { get; }
}
}
}