/// <summary>
 /// Sets the given property in the given property group.
 /// </summary>
 private void SetProperty(ToolsetPropertyDefinition property, PropertyDictionary <ProjectPropertyInstance> propertyGroup, PropertyDictionary <ProjectPropertyInstance> globalProperties)
 {
     try
     {
         // Global properties cannot be overwritten
         if (globalProperties[property.Name] == null)
         {
             propertyGroup.Set(ProjectPropertyInstance.Create(property.Name, EscapingUtilities.UnescapeAll(property.Value), true /* may be reserved */, false /* not immutable */));
         }
     }
     catch (ArgumentException ex)
     {
         InvalidToolsetDefinitionException.Throw(ex, "InvalidPropertyNameInToolset", property.Name, property.Source.LocationString, ex.Message);
     }
 }
        /// <summary>
        /// Provides an enumerator over property definitions for a specified sub-toolset version
        /// under a specified toolset version.
        /// </summary>
        /// <param name="toolsVersion">The tools version.</param>
        /// <param name="subToolsetVersion">The sub-toolset version.</param>
        /// <returns>An enumeration of property definitions.</returns>
        protected override IEnumerable <ToolsetPropertyDefinition> GetSubToolsetPropertyDefinitions(string toolsVersion, string subToolsetVersion)
        {
            ErrorUtilities.VerifyThrowArgumentLength(subToolsetVersion, "subToolsetVersion");

            RegistryKeyWrapper toolsVersionWrapper = null;
            RegistryKeyWrapper subToolsetWrapper   = null;

            try
            {
                try
                {
                    toolsVersionWrapper = _msbuildRegistryWrapper.OpenSubKey("ToolsVersions\\" + toolsVersion);
                }
                catch (RegistryException ex)
                {
                    InvalidToolsetDefinitionException.Throw(ex, "RegistryReadError", ex.Source, ex.Message);
                }

                try
                {
                    subToolsetWrapper = toolsVersionWrapper.OpenSubKey(subToolsetVersion);
                }
                catch (RegistryException ex)
                {
                    InvalidToolsetDefinitionException.Throw(ex, "RegistryReadError", ex.Source, ex.Message);
                }

                foreach (string propertyName in subToolsetWrapper.GetValueNames())
                {
                    yield return(CreatePropertyFromRegistry(subToolsetWrapper, propertyName));
                }
            }
            finally
            {
                if (toolsVersionWrapper != null)
                {
                    toolsVersionWrapper.Dispose();
                }

                if (subToolsetWrapper != null)
                {
                    subToolsetWrapper.Dispose();
                }
            }
        }
        /// <summary>
        /// Provides an enumerator over property definitions for a specified tools version
        /// </summary>
        protected override IEnumerable <ToolsetPropertyDefinition> GetPropertyDefinitions(string toolsVersion)
        {
            ToolsetElement toolsetElement = ConfigurationSection.Toolsets.GetElement(toolsVersion);

            if (toolsetElement == null)
            {
                yield break;
            }

            foreach (ToolsetElement.PropertyElement propertyElement in toolsetElement.PropertyElements)
            {
                ElementLocation location = ElementLocation.Create(propertyElement.ElementInformation.Source, propertyElement.ElementInformation.LineNumber, 0);

                if (propertyElement.Name != null && propertyElement.Name.Length == 0)
                {
                    InvalidToolsetDefinitionException.Throw("InvalidToolsetValueInConfigFileValue", location.LocationString);
                }

                yield return(new ToolsetPropertyDefinition(propertyElement.Name, propertyElement.Value, location));
            }
        }
        /// <summary>
        /// Provides an enumerator over the set of sub-toolset names available to a particular
        /// toolsversion
        /// </summary>
        /// <param name="toolsVersion">The tools version.</param>
        /// <returns>An enumeration of the sub-toolsets that belong to that toolsversion.</returns>
        protected override IEnumerable <string> GetSubToolsetVersions(string toolsVersion)
        {
            RegistryKeyWrapper toolsVersionWrapper = null;

            try
            {
                try
                {
                    toolsVersionWrapper = _msbuildRegistryWrapper.OpenSubKey("ToolsVersions\\" + toolsVersion);
                }
                catch (RegistryException ex)
                {
                    InvalidToolsetDefinitionException.Throw(ex, "RegistryReadError", ex.Source, ex.Message);
                }

                return(toolsVersionWrapper.GetSubKeyNames());
            }
            finally
            {
                toolsVersionWrapper?.Dispose();
            }
        }
        /// <summary>
        /// Given a registry location containing a property name and value, create the ToolsetPropertyDefinition that maps to it
        /// </summary>
        /// <param name="toolsetWrapper">Wrapper for the key that we're getting values from</param>
        /// <param name="propertyName">The name of the property whose value we wish to generate a ToolsetPropertyDefinition for.</param>
        /// <returns>A ToolsetPropertyDefinition instance corresponding to the property name requested.</returns>
        private static ToolsetPropertyDefinition CreatePropertyFromRegistry(RegistryKeyWrapper toolsetWrapper, string propertyName)
        {
            string propertyValue = null;

            if (propertyName != null && propertyName.Length == 0)
            {
                InvalidToolsetDefinitionException.Throw("PropertyNameInRegistryHasZeroLength", toolsetWrapper.Name);
            }

            try
            {
                propertyValue = GetValue(toolsetWrapper, propertyName);
            }
            catch (RegistryException ex)
            {
                InvalidToolsetDefinitionException.Throw(ex, "RegistryReadError", ex.Source, ex.Message);
            }

            // For the purposes of error location, use the registry path instead of a file name
            IElementLocation location = new RegistryLocation(toolsetWrapper.Name + "@" + propertyName);

            return(new ToolsetPropertyDefinition(propertyName, propertyValue, location));
        }
        /// <summary>
        /// Reads the settings for a specified tools version
        /// </summary>
        private Toolset ReadToolset
        (
            ToolsetPropertyDefinition toolsVersion,
            PropertyDictionary <ProjectPropertyInstance> globalProperties,
            PropertyDictionary <ProjectPropertyInstance> initialProperties,
            bool accumulateProperties
        )
        {
            // Initial properties is the set of properties we're going to use to expand property expressions like $(foo)
            // in the values we read out of the registry or config file. We'll add to it as we pick up properties (including binpath)
            // from the registry or config file, so that properties there can be referenced in values below them.
            // After processing all the properties, we don't need initialProperties anymore.
            string toolsPath = null;
            string binPath   = null;
            PropertyDictionary <ProjectPropertyInstance> properties = new PropertyDictionary <ProjectPropertyInstance>();

            IEnumerable <ToolsetPropertyDefinition> rawProperties = GetPropertyDefinitions(toolsVersion.Name);

            Expander <ProjectPropertyInstance, ProjectItemInstance> expander = new Expander <ProjectPropertyInstance, ProjectItemInstance>(initialProperties, FileSystems.Default);

            foreach (ToolsetPropertyDefinition property in rawProperties)
            {
                EvaluateAndSetProperty(property, properties, globalProperties, initialProperties, accumulateProperties, ref toolsPath, ref binPath, ref expander);
            }

            Dictionary <string, SubToolset> subToolsets        = new Dictionary <string, SubToolset>(StringComparer.OrdinalIgnoreCase);
            IEnumerable <string>            subToolsetVersions = GetSubToolsetVersions(toolsVersion.Name);

            foreach (string subToolsetVersion in subToolsetVersions)
            {
                string subToolsetToolsPath = null;
                string subToolsetBinPath   = null;
                IEnumerable <ToolsetPropertyDefinition>      rawSubToolsetProperties = GetSubToolsetPropertyDefinitions(toolsVersion.Name, subToolsetVersion);
                PropertyDictionary <ProjectPropertyInstance> subToolsetProperties    = new PropertyDictionary <ProjectPropertyInstance>();

                // If we have a sub-toolset, any values defined here will override the toolset properties.
                foreach (ToolsetPropertyDefinition property in rawSubToolsetProperties)
                {
                    EvaluateAndSetProperty(property, subToolsetProperties, globalProperties, initialProperties, false /* do not ever accumulate sub-toolset properties */, ref subToolsetToolsPath, ref subToolsetBinPath, ref expander);
                }

                if (subToolsetToolsPath != null || subToolsetBinPath != null)
                {
                    InvalidToolsetDefinitionException.Throw("MSBuildToolsPathNotSupportedInSubToolsets", toolsVersion.Name, toolsVersion.Source.LocationString, subToolsetVersion);
                }

                subToolsets[subToolsetVersion] = new SubToolset(subToolsetVersion, subToolsetProperties);
            }

            // All tools versions must specify a value for MSBuildToolsPath (or MSBuildBinPath)
            if (String.IsNullOrEmpty(toolsPath) && String.IsNullOrEmpty(binPath))
            {
                return(null);
            }

            // If both MSBuildBinPath and MSBuildToolsPath are present, they must be the same
            if (toolsPath != null && binPath != null && !toolsPath.Equals(binPath, StringComparison.OrdinalIgnoreCase))
            {
                InvalidToolsetDefinitionException.Throw("ConflictingValuesOfMSBuildToolsPath", toolsVersion.Name, toolsVersion.Source.LocationString);
            }

            AppendStandardProperties(properties, globalProperties, toolsVersion.Name, null, toolsPath);
            Toolset toolset = null;

            try
            {
                var importSearchPathsTable = GetProjectImportSearchPathsTable(toolsVersion.Name, NativeMethodsShared.GetOSNameForExtensionsPath());
                toolset = new Toolset(toolsVersion.Name, toolsPath == null ? binPath : toolsPath, properties, _environmentProperties, globalProperties, subToolsets, MSBuildOverrideTasksPath, DefaultOverrideToolsVersion, importSearchPathsTable);
            }
            catch (ArgumentException e)
            {
                InvalidToolsetDefinitionException.Throw("ErrorCreatingToolset", toolsVersion.Name, e.Message);
            }

            return(toolset);
        }