Наша сборка Qt VS Tools
giy
2022-09-02 ca47896204482bf4a6979e3838bf7f09f61cebeb
QtVsTools.Core/QtProject.cs
@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt VS Tools.
@@ -26,22 +26,22 @@
**
****************************************************************************/
using EnvDTE;
using Microsoft.VisualStudio.VCProjectEngine;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;
using QtVsTools.Core.QtMsBuild;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.VCProjectEngine;
using EnvDTE;
namespace QtVsTools.Core
{
    using QtMsBuild;
    /// <summary>
    /// QtProject holds the Qt specific properties for a Visual Studio project.
    /// There exists at most one QtProject per EnvDTE.Project.
@@ -54,13 +54,14 @@
        private VCProject vcPro;
        private MocCmdChecker mocCmdChecker;
        private Array lastConfigurationRowNames;
        private static Dictionary<Project, QtProject> instances = new Dictionary<Project, QtProject>();
        private QtMsBuildContainer qtMsBuild;
        private static readonly Dictionary<Project, QtProject> instances = new Dictionary<Project, QtProject>();
        private readonly QtMsBuildContainer qtMsBuild;
        public static QtVsTools.VisualStudio.IProjectTracker ProjectTracker { get; set; }
        public static QtProject Create(VCProject vcProject)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            return Create((Project)vcProject.Object);
        }
@@ -81,6 +82,8 @@
        private QtProject(Project project)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            if (project == null)
                throw new QtVSException(SR.GetString("QtProject_CannotConstructWithoutValidProject"));
            envPro = project;
@@ -105,35 +108,10 @@
                return string.Empty;
            try {
                return config.GetEvaluatedPropertyValue(itemType + "RuleName");
            } catch (Exception e) {
                System.Diagnostics.Debug.WriteLine(
                    e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
            } catch (Exception exception) {
                exception.Log();
                return string.Empty;
            }
        }
        public static string GetRuleName(VCProject project, string itemType)
        {
            if (project == null)
                return string.Empty;
            var configs = project.Configurations as IVCCollection;
            if (configs.Count == 0)
                return string.Empty;
            try {
                var firstConfig = configs.Item(1) as VCConfiguration;
                if (firstConfig == null)
                    return string.Empty;
                return GetRuleName(firstConfig, itemType);
            } catch (Exception e) {
                System.Diagnostics.Debug.WriteLine(
                    e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
                return string.Empty;
            }
        }
        public string GetRuleName(string itemType)
        {
            return GetRuleName(vcPro, itemType);
        }
        public static bool IsQtMsBuildEnabled(VCProject project)
@@ -157,6 +135,8 @@
        public static bool IsQtMsBuildEnabled(Project project)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            if (project == null)
                return false;
            return IsQtMsBuildEnabled(project.Object as VCProject);
@@ -165,6 +145,8 @@
        private bool? isQtMsBuildEnabled = null;
        public bool IsQtMsBuildEnabled()
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            if (!isQtMsBuildEnabled.HasValue) {
                if (vcPro != null)
                    isQtMsBuildEnabled = IsQtMsBuildEnabled(vcPro);
@@ -192,6 +174,8 @@
        {
            get
            {
                ThreadHelper.ThrowIfNotOnUIThread();
                var ret = false;
                if (lastConfigurationRowNames == null) {
                    lastConfigurationRowNames = envPro.ConfigurationManager.ConfigurationRowNames as Array;
@@ -213,6 +197,8 @@
        /// <param name="uiFile">name of the ui file</param>
        public string GetUiGeneratedFileName(string uiFile)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            var fi = new FileInfo(uiFile);
            var file = fi.Name;
            if (HelperFunctions.IsUicFile(file)) {
@@ -248,8 +234,11 @@
        /// replaced by the value of configName.
        /// <param name="file">full file name of either the header or the source file</param>
        /// <returns></returns>
        private string GetRelativeMocFilePath(string file, string configName, string platformName)
        private string GetRelativeMocFilePath(string file, string configName = null,
                                              string platformName = null)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            var fileName = GetMocFileName(file);
            if (fileName == null)
                return null;
@@ -260,65 +249,38 @@
            return mocDir;
        }
        /// <summary>
        /// Returns the file name of the generated moc file relative to the
        /// project directory.
        /// </summary>
        /// The returned file path may contain the macros $(ConfigurationName) and $(PlatformName).
        /// <param name="file">full file name of either the header or the source file</param>
        /// <returns></returns>
        private string GetRelativeMocFilePath(string file)
        {
            return GetRelativeMocFilePath(file, null, null);
        }
        /// <summary>
        /// Marks the specified project as a Qt project.
        /// </summary>
        public void MarkAsQtProject()
        {
            vcPro.keyword = string.Format("{0}_v{1}",
                Resources.qtProjectKeyword, Resources.qtProjectFormatVersion);
        }
        public static int GetFormatVersion(VCProject vcPro)
        {
            if (vcPro == null)
                return 0;
            if (vcPro.keyword.StartsWith(Resources.qtProjectKeyword,
                StringComparison.InvariantCultureIgnoreCase)) {
            if (vcPro.keyword.StartsWith(Resources.qtProjectKeyword, StringComparison.Ordinal))
                return Convert.ToInt32(vcPro.keyword.Substring(6));
            } else if (vcPro.keyword.StartsWith(Resources.qtProjectV2Keyword,
                StringComparison.InvariantCultureIgnoreCase)) {
            if (vcPro.keyword.StartsWith(Resources.qtProjectV2Keyword, StringComparison.Ordinal))
                return 200;
            } else {
                return 0;
            }
            return 0;
        }
        public static int GetFormatVersion(Project pro)
        {
            if (pro == null)
                return 0;
            return GetFormatVersion(pro.Object as VCProject);
            ThreadHelper.ThrowIfNotOnUIThread();
            return GetFormatVersion(pro?.Object as VCProject);
        }
        public int FormatVersion { get { return GetFormatVersion(Project); } }
        public string GetPropertyValue(string propName)
        public int FormatVersion
        {
            return GetPropertyValue(Project, propName);
        }
        public string GetPropertyValue(string configName, string platformName, string propName)
        {
            return GetPropertyValue(Project, configName, platformName, propName);
            get
            {
                ThreadHelper.ThrowIfNotOnUIThread();
                return GetFormatVersion(Project);
            }
        }
        public static string GetPropertyValue(
            EnvDTE.Project dteProject,
            string propName)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            var activeConfig = dteProject.ConfigurationManager?.ActiveConfiguration;
            if (activeConfig == null)
                return null;
@@ -331,6 +293,8 @@
            EnvDTE.Configuration dteConfig,
            string propName)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            if (dteProject == null || dteConfig == null)
                return null;
            return GetPropertyValue(
@@ -338,16 +302,6 @@
                dteConfig.ConfigurationName,
                dteConfig.PlatformName,
                propName);
        }
        public static string GetPropertyValue(
            EnvDTE.Project dteProject,
            string configName,
            string platformName,
            string propName)
        {
            return GetPropertyValue(
                dteProject.Object as VCProject, configName, platformName, propName);
        }
        public static string GetPropertyValue(
@@ -374,123 +328,10 @@
            return vcConfig.GetEvaluatedPropertyValue(propName);
        }
        public void AddDefine(string define, uint bldConf)
        {
            foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
                var compiler = CompilerToolWrapper.Create(config);
                if (((!IsDebugConfiguration(config)) && ((bldConf & BuildConfig.Release) != 0)) ||
                    ((IsDebugConfiguration(config)) && ((bldConf & BuildConfig.Debug) != 0))) {
                    compiler.AddPreprocessorDefinition(define);
                }
            }
        }
        public void AddModule(int id)
        {
            if (HasModule(id))
                return;
            var vm = QtVersionManager.The();
            var versionInfo = vm.GetVersionInfo(Project);
            if (versionInfo == null)
                versionInfo = vm.GetVersionInfo(vm.GetDefaultVersion());
            foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
                var info = QtModules.Instance.Module(id);
                if (FormatVersion >= Resources.qtMinFormatVersion_Settings) {
                    var config3 = config as VCConfiguration3;
                    if (config3 == null)
                        continue;
                    if (!string.IsNullOrEmpty(info.proVarQT)) {
                        var qtModulesValue = config.GetUnevaluatedPropertyValue("QtModules");
                        var qtModules = new HashSet<string>(
                            !string.IsNullOrEmpty(qtModulesValue)
                                ? qtModulesValue.Split(';')
                                : new string[] { });
                        qtModules.UnionWith(info.proVarQT.Split(' '));
                        config3.SetPropertyValue(Resources.projLabelQtSettings, true,
                            "QtModules", string.Join(";", qtModules));
                    }
                    // In V3 project format, compiler and linker options
                    // required by modules are set by Qt/MSBuild.
                    continue;
                }
                var compiler = CompilerToolWrapper.Create(config);
                var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
                if (compiler != null) {
                    foreach (var define in info.Defines)
                        compiler.AddPreprocessorDefinition(define);
                    var incPathList = info.GetIncludePath();
                    foreach (var incPath in incPathList)
                        compiler.AddAdditionalIncludeDirectories(incPath);
                }
                if (linker != null) {
                    var moduleLibs = info.GetLibs(IsDebugConfiguration(config), versionInfo);
                    var linkerWrapper = new LinkerToolWrapper(linker);
                    var additionalDeps = linkerWrapper.AdditionalDependencies;
                    var dependenciesChanged = false;
                    if (additionalDeps == null || additionalDeps.Count == 0) {
                        additionalDeps = moduleLibs;
                        dependenciesChanged = true;
                    } else {
                        foreach (var moduleLib in moduleLibs) {
                            if (!additionalDeps.Contains(moduleLib)) {
                                additionalDeps.Add(moduleLib);
                                dependenciesChanged = true;
                            }
                        }
                    }
                    if (dependenciesChanged)
                        linkerWrapper.AdditionalDependencies = additionalDeps;
                }
            }
        }
        public void RemoveModule(int id)
        {
            foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
                var compiler = CompilerToolWrapper.Create(config);
                var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
                var info = QtModules.Instance.Module(id);
                if (compiler != null) {
                    foreach (var define in info.Defines)
                        compiler.RemovePreprocessorDefinition(define);
                    var additionalIncludeDirs = compiler.AdditionalIncludeDirectories;
                    if (additionalIncludeDirs != null) {
                        var lst = new List<string>(additionalIncludeDirs);
                        foreach (var includePath in info.IncludePath) {
                            lst.Remove(includePath);
                            lst.Remove('\"' + includePath + '\"');
                        }
                        compiler.AdditionalIncludeDirectories = lst;
                    }
                }
                if (linker != null && linker.AdditionalDependencies != null) {
                    var linkerWrapper = new LinkerToolWrapper(linker);
                    var vm = QtVersionManager.The();
                    var versionInfo = vm.GetVersionInfo(Project);
                    if (versionInfo == null)
                        versionInfo = vm.GetVersionInfo(vm.GetDefaultVersion());
                    var moduleLibs = info.GetLibs(IsDebugConfiguration(config), versionInfo);
                    var additionalDependencies = linkerWrapper.AdditionalDependencies;
                    var dependenciesChanged = false;
                    foreach (var moduleLib in moduleLibs)
                        dependenciesChanged |= additionalDependencies.Remove(moduleLib);
                    if (dependenciesChanged)
                        linkerWrapper.AdditionalDependencies = additionalDependencies;
                }
            }
        }
        public void UpdateModules(VersionInformation oldVersion, VersionInformation newVersion)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
                var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
@@ -500,7 +341,7 @@
                        var additionalDependencies = linkerWrapper.AdditionalDependencies;
                        var libsDesktop = new List<string>();
                        foreach (var module in QtModules.Instance.GetAvailableModules()) {
                        foreach (var module in QtModules.Instance.GetAvailableModules(newVersion.qtMajor)) {
                            if (HasModule(module.Id))
                                libsDesktop.AddRange(module.AdditionalLibraries);
                        }
@@ -538,133 +379,11 @@
            }
        }
        // TODO: remove once all callers are moved into Legacy namespace
        public bool HasModule(int id)
        {
            var foundInIncludes = false;
            var foundInLibs = false;
            var vm = QtVersionManager.The();
            var versionInfo = vm.GetVersionInfo(Project);
            if (versionInfo == null)
                versionInfo = vm.GetVersionInfo(vm.GetDefaultVersion());
            if (versionInfo == null)
                return false; // neither a default or project Qt version
            var info = QtModules.Instance.Module(id);
            if (info == null)
                return false;
            foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
                var compiler = CompilerToolWrapper.Create(config);
                var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
                if (compiler != null) {
                    if (compiler.GetAdditionalIncludeDirectories() == null)
                        continue;
                    var incPathList = info.GetIncludePath();
                    var includeDirs = compiler.GetAdditionalIncludeDirectoriesList();
                    foundInIncludes = (incPathList.Count > 0);
                    foreach (var incPath in incPathList) {
                        var fixedIncludeDir = FixFilePathForComparison(incPath);
                        if (!includeDirs.Any(dir =>
                            FixFilePathForComparison(dir) == fixedIncludeDir)) {
                            foundInIncludes = false;
                            break;
                        }
                    }
                }
                if (foundInIncludes)
                    break;
                List<string> libs = null;
                if (linker != null) {
                    var linkerWrapper = new LinkerToolWrapper(linker);
                    libs = linkerWrapper.AdditionalDependencies;
                }
                if (libs != null) {
                    var moduleLibs = info.GetLibs(IsDebugConfiguration(config), versionInfo);
                    foundInLibs = moduleLibs.All(moduleLib => libs.Contains(moduleLib));
                }
            }
            return foundInIncludes || foundInLibs;
        }
        public void WriteProjectBasicConfigurations(uint type, bool usePrecompiledHeader)
        {
            WriteProjectBasicConfigurations(type, usePrecompiledHeader, null);
        }
        public void WriteProjectBasicConfigurations(uint type, bool usePrecompiledHeader, VersionInformation vi)
        {
            var configType = ConfigurationTypes.typeApplication;
            var targetExtension = ".exe";
            string qtVersion = null;
            var vm = QtVersionManager.The();
            if (vi == null) {
                qtVersion = vm.GetDefaultVersion();
                vi = vm.GetVersionInfo(qtVersion);
            }
            switch (type & TemplateType.ProjectType) {
            case TemplateType.DynamicLibrary:
                configType = ConfigurationTypes.typeDynamicLibrary;
                targetExtension = ".dll";
                break;
            case TemplateType.StaticLibrary:
                configType = ConfigurationTypes.typeStaticLibrary;
                targetExtension = ".lib";
                break;
            }
            foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
                config.ConfigurationType = configType;
                var compiler = CompilerToolWrapper.Create(config);
                var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
                var librarian = (VCLibrarianTool)((IVCCollection)config.Tools).Item("VCLibrarianTool");
                if (linker != null) {
                    if ((type & TemplateType.ConsoleSystem) != 0)
                        linker.SubSystem = subSystemOption.subSystemConsole;
                    else
                        linker.SubSystem = subSystemOption.subSystemWindows;
                    linker.OutputFile = "$(OutDir)\\$(ProjectName)" + targetExtension;
                } else {
                    librarian.OutputFile = "$(OutDir)\\$(ProjectName)" + targetExtension;
                }
                if ((type & TemplateType.PluginProject) != 0)
                    compiler.AddPreprocessorDefinition("QT_PLUGIN");
                var isDebugConfiguration = false;
                if (config.Name.StartsWith("Release", StringComparison.Ordinal)) {
                    compiler.SetDebugInformationFormat(debugOption.debugDisabled);
                    compiler.RuntimeLibrary = runtimeLibraryOption.rtMultiThreadedDLL;
                } else if (config.Name.StartsWith("Debug", StringComparison.Ordinal)) {
                    isDebugConfiguration = true;
                    compiler.SetOptimization(optimizeOption.optimizeDisabled);
                    compiler.SetDebugInformationFormat(debugOption.debugEnabled);
                    compiler.RuntimeLibrary = runtimeLibraryOption.rtMultiThreadedDebugDLL;
                }
                compiler.SetTreatWChar_tAsBuiltInType(true);
                if (linker != null)
                    linker.GenerateDebugInformation = isDebugConfiguration;
                if (usePrecompiledHeader)
                    UsePrecompiledHeaders(config);
            }
            if ((type & TemplateType.PluginProject) != 0)
                MarkAsDesignerPluginProject();
        }
        public void MarkAsDesignerPluginProject()
        {
            Project.Globals["IsDesignerPlugin"] = true.ToString();
            if (!Project.Globals.get_VariablePersists("IsDesignerPlugin"))
                Project.Globals.set_VariablePersists("IsDesignerPlugin", true);
            ThreadHelper.ThrowIfNotOnUIThread();
            return Legacy.QtProject.HasModule(envPro, id);
        }
        public void AddUic4BuildStepMsBuild(
@@ -672,8 +391,7 @@
            string description,
            string outputFile)
        {
            var file = config.File as VCFile;
            if (file != null)
            if (config.File is VCFile file)
                file.ItemType = QtUic.ItemTypeName;
            qtMsBuild.SetItemProperty(config, QtUic.Property.ExecutionDescription, description);
            qtMsBuild.SetItemProperty(config, QtUic.Property.OutputFile, outputFile);
@@ -701,6 +419,8 @@
        /// <param name="file">file</param>
        public void AddUic4BuildStep(VCFile file)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            if (GetFormatVersion(vcPro) >= Resources.qtMinFormatVersion_Settings) {
                file.ItemType = QtUic.ItemTypeName;
                return;
@@ -736,7 +456,7 @@
                    }
                }
                if (toolSettings == CustomTool.CustomBuildStep && !uiFileExists)
                    AddFileInFilter(Filters.GeneratedFiles(), uiFile);
                    AddFileInFilter(Filters.GeneratedFiles(), uiFile, false);
            } catch {
                throw new QtVSException(SR.GetString("QtProject_CannotAddUicStep", file.FullPath));
            }
@@ -796,15 +516,15 @@
        public string GetDefines(VCFileConfiguration conf)
        {
            var defines = string.Empty;
            var propsFile = conf.Tool as IVCRulePropertyStorage;
            var projectConfig = conf.ProjectConfiguration as VCConfiguration;
            var propsProject = projectConfig.Rules.Item("CL") as IVCRulePropertyStorage;
            if (propsFile != null) {
            if (conf.Tool is IVCRulePropertyStorage propsFile) {
                try {
                    defines = propsFile.GetUnevaluatedPropertyValue("PreprocessorDefinitions");
                } catch { }
            }
            if (string.IsNullOrEmpty(defines) && propsProject != null) {
            var projectConfig = conf.ProjectConfiguration as VCConfiguration;
            if (string.IsNullOrEmpty(defines)
                && projectConfig?.Rules.Item("CL") is IVCRulePropertyStorage propsProject) {
                try {
                    defines = propsProject.GetUnevaluatedPropertyValue("PreprocessorDefinitions");
                } catch { }
@@ -846,12 +566,11 @@
            var projectConfig = conf.ProjectConfiguration as VCConfiguration;
            includeList.AddRange(GetIncludesFromCompilerTool(CompilerToolWrapper.Create(projectConfig)));
            var propertySheets = projectConfig.PropertySheets as IVCCollection;
            if (propertySheets != null) {
            if (projectConfig.PropertySheets is IVCCollection propertySheets) {
                foreach (VCPropertySheet sheet in propertySheets)
                    includeList.AddRange(GetIncludesFromPropertySheet(sheet));
            }
            var ompModified = new List<string>();
            string sDir = "$(SolutionDir)";
            foreach (string inc in includeList) {
@@ -884,8 +603,7 @@
        private List<string> GetIncludesFromPropertySheet(VCPropertySheet sheet)
        {
            var includeList = GetIncludesFromCompilerTool(CompilerToolWrapper.Create(sheet));
            var propertySheets = sheet.PropertySheets as IVCCollection;
            if (propertySheets != null) {
            if (sheet.PropertySheets is IVCCollection propertySheets) {
                foreach (VCPropertySheet subSheet in propertySheets)
                    includeList.AddRange(GetIncludesFromPropertySheet(subSheet));
            }
@@ -903,18 +621,10 @@
            return new List<string>();
        }
        private static bool IsDebugConfiguration(VCConfiguration conf)
        {
            var tool = CompilerToolWrapper.Create(conf);
            if (tool != null) {
                return tool.RuntimeLibrary == runtimeLibraryOption.rtMultiThreadedDebug
                    || tool.RuntimeLibrary == runtimeLibraryOption.rtMultiThreadedDebugDLL;
            }
            return false;
        }
        private string GetPCHMocOptions(VCFile file, CompilerToolWrapper compiler)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            // As .moc files are included, we should not add anything there
            if (!HelperFunctions.IsHeaderFile(file.Name))
                return string.Empty;
@@ -941,12 +651,13 @@
            VCFileConfiguration workFileConfig,
            VCFile mocFile)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            var hasDifferentMocFilePerConfig =
                QtVSIPSettings.HasDifferentMocFilePerConfig(envPro);
            var hasDifferentMocFilePerPlatform =
                QtVSIPSettings.HasDifferentMocFilePerPlatform(envPro);
            var workFile = workFileConfig.File as VCFile;
            var mocFileName = GetMocFileName(sourceFile.FullPath);
            var mocableIsCPP = HelperFunctions.IsMocFile(mocFileName);
            var vcConfig = workFileConfig.ProjectConfiguration as VCConfiguration;
@@ -1025,6 +736,8 @@
            string includes,
            string description)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            var workFile = workFileConfig.File as VCFile;
            var mocFileName = GetMocFileName(sourceFile.FullPath);
            var mocableIsCPP = HelperFunctions.IsMocFile(mocFileName);
@@ -1068,6 +781,7 @@
                + mocFileName + "))";
            var regExp = new Regex(pattern);
            var matchList = regExp.Matches(tool.Outputs.Replace(ProjectMacros.Name, baseFileName));
            if (matchList.Count > 0) {
                if (matchList[0].Length > 0)
                    outputMocFile = matchList[0].ToString();
@@ -1202,6 +916,8 @@
            string includes,
            string description)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            var baseFileName = sourceFile.Name.Remove(sourceFile.Name.LastIndexOf('.'));
            var outputMocFile = GetRelativeMocFilePath(sourceFile.FullPath);
            var outputMocPath = Path.GetDirectoryName(outputMocFile);
@@ -1233,7 +949,8 @@
            VCFileConfiguration workConfig,
            CustomTool toolSettings)
        {
            var workFile = workConfig.File as VCFile;
            ThreadHelper.ThrowIfNotOnUIThread();
            var mocFileName = GetMocFileName(sourceFile.FullPath);
            var mocableIsCPP = HelperFunctions.IsMocFile(mocFileName);
            var vcConfig = workConfig.ProjectConfiguration as VCConfiguration;
@@ -1316,6 +1033,8 @@
        /// <param name="file">file</param>
        public void AddMocStep(VCFile file)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            if (GetFormatVersion(vcPro) >= Resources.qtMinFormatVersion_Settings) {
                file.ItemType = QtMoc.ItemTypeName;
                if (HelperFunctions.IsSourceFile(file.FullPath)) {
@@ -1343,8 +1062,7 @@
                    File.WriteAllText(cbtFullPath, string.Format(
                        "This is a dummy file needed to create {0}", mocFileName));
                    file = AddFileInSubfilter(Filters.GeneratedFiles(), null, cbtFullPath, true);
                    var mocFileItem = file.Object as ProjectItem;
                    if (mocFileItem != null)
                    if (file.Object is ProjectItem mocFileItem)
                        HelperFunctions.EnsureCustomBuildToolAvailable(mocFileItem);
                }
@@ -1417,6 +1135,8 @@
        public bool HasMocStep(VCFile file, string mocOutDir = null)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            if (file.ItemType == QtMoc.ItemTypeName)
                return true;
@@ -1452,6 +1172,8 @@
        public void RefreshRccSteps()
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            Messages.Print("\r\n=== Update rcc steps ===");
            var files = GetResourceFiles();
@@ -1482,6 +1204,8 @@
        public void RefreshRccSteps(string oldRccDir)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            RefreshRccSteps();
            UpdateCompilerIncludePaths(oldRccDir, QtVSIPSettings.GetRccDirectory(envPro));
        }
@@ -1493,8 +1217,7 @@
            string nameOnly,
            string qrcCppFile)
        {
            var file = vfc.File as VCFile;
            if (file != null)
            if (vfc.File is VCFile file)
                file.ItemType = QtRcc.ItemTypeName;
            qtMsBuild.SetItemProperty(vfc,
                QtRcc.Property.ExecutionDescription, "Rcc'ing " + ProjectMacros.FileName + "...");
@@ -1509,16 +1232,15 @@
            string nameOnly,
            string qrcCppFile)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            var qrcFile = vfc.File as VCFile;
            var rccOptsCfg = rccOpts;
            var cmdLine = string.Empty;
            var cbt = HelperFunctions.GetCustomBuildTool(vfc);
            cbt.AdditionalDependencies = filesInQrcFile;
            cbt.Description = "Rcc'ing " + ProjectMacros.FileName + "...";
            cbt.Outputs = qrcCppFile.Replace(nameOnly, ProjectMacros.Name);
            cmdLine += "\"" + Resources.rcc4Command + "\""
@@ -1539,6 +1261,8 @@
        public void UpdateRccStep(VCFile qrcFile, RccOptions rccOpts)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            if (GetFormatVersion(vcPro) >= Resources.qtMinFormatVersion_Settings) {
                qrcFile.ItemType = QtRcc.ItemTypeName;
                return;
@@ -1548,8 +1272,6 @@
                IsQtMsBuildEnabled() ? CustomTool.MSBuildTarget : CustomTool.CustomBuildStep;
            var vcpro = (VCProject)qrcFile.project;
            var dteObject = ((Project)vcpro.Object).DTE;
            var qtPro = Create(vcpro);
            var parser = new QrcParser(qrcFile.FullPath);
            var filesInQrcFile = ProjectMacros.Path;
@@ -1606,7 +1328,7 @@
            }
        }
        static public void ExcludeFromAllBuilds(VCFile file)
        public static void ExcludeFromAllBuilds(VCFile file)
        {
            if (file == null)
                return;
@@ -1672,8 +1394,7 @@
        List<VCFile> GetCppMocFiles(VCFile cppFile)
        {
            List<VCFile> mocFiles = new List<VCFile>();
            var vcProj = cppFile.project as VCProject;
            if (vcProj != null) {
            if (cppFile.project is VCProject vcProj) {
                mocFiles.AddRange(from VCFile vcFile
                                  in (IVCCollection)vcProj.Files
                                  where vcFile.ItemType == "CustomBuild"
@@ -1697,27 +1418,29 @@
        bool HasCppMocFiles(VCFile cppFile)
        {
            if (!IsQtMsBuildEnabled()) {
            ThreadHelper.ThrowIfNotOnUIThread();
            if (!IsQtMsBuildEnabled())
                return File.Exists(Path.ChangeExtension(cppFile.FullPath, ".cbt"));
            } else {
                var vcProj = cppFile.project as VCProject;
                if (vcProj != null) {
                    foreach (VCFile vcFile in (IVCCollection)vcProj.Files) {
                        if (vcFile.ItemType == "CustomBuild") {
                            if (IsCppMocFileCustomBuild(vcProj, vcFile, cppFile))
                                return true;
                        } else if (vcFile.ItemType == QtMoc.ItemTypeName) {
                            if (IsCppMocFileQtMsBuild(vcProj, vcFile, cppFile))
                                return true;
                        }
            if (cppFile.project is VCProject vcProj) {
                foreach (VCFile vcFile in (IVCCollection)vcProj.Files) {
                    if (vcFile.ItemType == "CustomBuild") {
                        if (IsCppMocFileCustomBuild(vcProj, vcFile, cppFile))
                            return true;
                    } else if (vcFile.ItemType == QtMoc.ItemTypeName) {
                        if (IsCppMocFileQtMsBuild(vcProj, vcFile, cppFile))
                            return true;
                    }
                }
                return false;
            }
            return false;
        }
        public void RemoveMocStep(VCFile file)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            if (file.ItemType == QtMoc.ItemTypeName) {
                RemoveMocStepQtMsBuild(file);
            } else if (HelperFunctions.IsHeaderFile(file.Name)) {
@@ -1756,6 +1479,7 @@
        /// <param name="file">file</param>
        public void RemoveMocStepCustomBuild(VCFile file)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            try {
                if (!HasMocStep(file))
                    return;
@@ -1890,14 +1614,11 @@
        public VCFile GetFileFromProject(string fileName)
        {
            fileName = HelperFunctions.NormalizeRelativeFilePath(fileName);
            var nf = fileName;
            if (!HelperFunctions.IsAbsoluteFilePath(fileName))
                nf = HelperFunctions.NormalizeFilePath(vcPro.ProjectDirectory + "\\" + fileName);
            nf = nf.ToLower();
                fileName = HelperFunctions.NormalizeFilePath(vcPro.ProjectDirectory + "\\" + fileName);
            foreach (VCFile f in (IVCCollection)vcPro.Files) {
                if (f.FullPath.ToLower() == nf)
                if (f.FullPath.Equals(fileName, StringComparison.OrdinalIgnoreCase))
                    return f;
            }
            return null;
@@ -1913,7 +1634,7 @@
        {
            var fi = new FileInfo(HelperFunctions.NormalizeRelativeFilePath(fileName));
            foreach (VCFile f in (IVCCollection)vcPro.Files) {
                if (string.Equals(f.Name, fi.Name, StringComparison.OrdinalIgnoreCase))
                if (f.Name.Equals(fi.Name, StringComparison.OrdinalIgnoreCase))
                    yield return f;
            }
        }
@@ -1924,34 +1645,6 @@
            foreach (VCFilter subfilter in (IVCCollection)filter.Filters)
                tmpList.AddRange(GetAllFilesFromFilter(subfilter));
            return tmpList;
        }
        /// <summary>
        /// Adds a file to a filter. If the filter doesn't exist yet, it
        /// will be created. (Doesn't check for duplicates)
        /// </summary>
        /// <param name="filter">fake filter</param>
        /// <param name="fileName">relative file name</param>
        /// <returns>A VCFile object of the added file.</returns>
        public VCFile AddFileInFilter(FakeFilter filter, string fileName)
        {
            return AddFileInFilter(filter, fileName, false);
        }
        public void RemoveItem(ProjectItem item)
        {
            foreach (ProjectItem tmpFilter in Project.ProjectItems) {
                if (tmpFilter.Name == item.Name) {
                    tmpFilter.Remove();
                    return;
                }
                foreach (ProjectItem tmpItem in tmpFilter.ProjectItems) {
                    if (tmpItem.Name == item.Name) {
                        tmpItem.Remove();
                        return;
                    }
                }
            }
        }
        /// <summary>
@@ -1972,7 +1665,8 @@
            return AddFileInSubfilter(filter, subfilterName, fileName, false);
        }
        public VCFile AddFileInSubfilter(FakeFilter filter, string subfilterName, string fileName, bool checkForDuplicates)
        public VCFile AddFileInSubfilter(FakeFilter filter, string subfilterName, string fileName,
            bool checkForDuplicates)
        {
            try {
                var vfilt = FindFilterFromGuid(filter.UniqueIdentifier);
@@ -1981,7 +1675,7 @@
                        // check if user already created this filter... then add guid
                        vfilt = FindFilterFromName(filter.Name);
                        if (vfilt == null)
                            throw new QtVSException(SR.GetString("QtProject_CannotAddFilter", filter.Name));
                            throw new QtVSException($"Project cannot add filter {filter.Name}");
                    } else {
                        vfilt = (VCFilter)vcPro.AddFilter(filter.Name);
                    }
@@ -2014,14 +1708,7 @@
                    }
                    if (!subfilterFound) {
                        if (!vfilt.CanAddFilter(subfilterName))
                            throw new QtVSException(SR.GetString("QtProject_CannotAddFilter", filter.Name));
#if !(VS2017 || VS2019 || VS2022)
                        // TODO: Enable once the freeze gets fixed in VS.
                        vfilt = (VCFilter)vfilt.AddFilter(subfilterName);
                        vfilt.Filter = "cpp;moc";
                        vfilt.SourceControlFiles = false;
#endif
                            throw new QtVSException($"Project cannot add filter {filter.Name}");
                    }
                }
@@ -2034,10 +1721,13 @@
                if (vfilt.CanAddFile(fileName))
                    return (VCFile)(vfilt.AddFile(fileName));
                throw new QtVSException(SR.GetString("QtProject_CannotAddFile", fileName));
            } catch {
                throw new QtVSException(SR.GetString("QtProject_CannotAddFile", fileName));
                throw new QtVSException($"Cannot add file {fileName} to filter.");
            } catch (QtVSException) {
                throw;
            } catch (Exception e){
                throw new QtVSException($"Cannot add file {fileName} to filter.", e);
            }
        }
        /// <summary>
@@ -2165,94 +1855,38 @@
            }
        }
        public void AddDirectories()
        public static bool IsQtPlugin(Core.QtProject qtPro)
        {
            try {
                // resource directory
                var fi = new FileInfo(envPro.FullName);
                var dfi = new DirectoryInfo(fi.DirectoryName + "\\" + Resources.resourceDir);
                dfi.Create();
            } catch {
                throw new QtVSException(SR.GetString("QtProject_CannotCreateResourceDir"));
            }
            AddFilterToProject(Filters.ResourceFiles());
        }
            ThreadHelper.ThrowIfNotOnUIThread();
        public void Finish()
        {
            try {
                var solutionExplorer = dte.Windows.Item(Constants.vsWindowKindSolutionExplorer);
                if (solutionExplorer != null) {
                    var hierarchy = (UIHierarchy)solutionExplorer.Object;
                    var projects = hierarchy.UIHierarchyItems.Item(1).UIHierarchyItems;
            if (qtPro.FormatVersion < Resources.qtMinFormatVersion_Settings)
                return false;
                    foreach (UIHierarchyItem itm in projects) {
                        if (itm.Name == envPro.Name) {
                            foreach (UIHierarchyItem i in itm.UIHierarchyItems) {
                                if (i.Name == Filters.GeneratedFiles().Name)
                                    i.UIHierarchyItems.Expanded = false;
                            }
                            break;
                        }
                    }
                }
            } catch { }
            ProjectTracker?.AddProject(envPro);
        }
        public bool IsDesignerPluginProject()
        {
            var b = false;
            if (Project.Globals.get_VariablePersists("IsDesignerPlugin")) {
                var s = (string)Project.Globals["IsDesignerPlugin"];
                try {
                    b = bool.Parse(s);
                } catch { }
            }
            return b;
        }
        /// <summary>
        /// Adds a file to a specified filter in a project.
        /// </summary>
        /// <param name="destName">name of the file in the project (relative to the project directory)</param>
        /// <param name="filter">filter</param>
        /// <returns>VCFile</returns>
        public VCFile AddFileToProject(string destName, FakeFilter filter)
        {
            VCFile file = null;
            if (filter != null)
                file = AddFileInFilter(filter, destName);
            else
                file = (VCFile)vcPro.AddFile(destName);
            if (file == null)
                return null;
            if (HelperFunctions.IsHeaderFile(file.Name)) {
                foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
                    var compiler = CompilerToolWrapper.Create(config);
                    if (compiler == null)
                        continue;
                    var paths = compiler.GetAdditionalIncludeDirectoriesList();
                    var fi = new FileInfo(file.FullPath);
                    var relativePath = HelperFunctions.GetRelativePath(ProjectDir, fi.Directory.ToString());
                    var fixedRelativePath = FixFilePathForComparison(relativePath);
                    if (!paths.Any(p => FixFilePathForComparison(p) == fixedRelativePath))
                        compiler.AddAdditionalIncludeDirectories(relativePath);
            foreach (VCConfiguration config in qtPro.VCProject.Configurations as IVCCollection) {
                if ((config.Rules.Item("QtRule10_Settings") as IVCRulePropertyStorage)
                        .GetEvaluatedPropertyValue("QtPlugin") == "true") {
                    return true;
                }
            }
            return file;
            return false;
        }
        public static void MarkAsQtPlugin(Core.QtProject qtPro)
        {
            foreach (VCConfiguration config in qtPro.VCProject.Configurations as IVCCollection) {
                (config.Rules.Item("QtRule10_Settings") as IVCRulePropertyStorage)
                    .SetPropertyValue("QtPlugin", "true");
            }
        }
        /// <summary>
        /// adjusts the whitespaces, tabs in the given file according to VS settings
        /// </summary>
        /// <param name="file"></param>
        public void AdjustWhitespace(string file)
        public static void AdjustWhitespace(DTE dte, string file)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            if (!File.Exists(file))
                return;
@@ -2299,89 +1933,6 @@
            return whitespaces;
        }
        /// <summary>
        /// Copy a file to the projects folder. Does not add the file to the project.
        /// </summary>
        /// <param name="srcFile">full name of the file to add</param>
        /// <param name="destFolder">the name of the project folder</param>
        /// <param name="destName">name of the file in the project (relative to the project directory)</param>
        /// <returns>full name of the destination file</returns>
        public static string CopyFileToFolder(string srcFile, string destFolder, string destName)
        {
            var fullDestName = destFolder + "\\" + destName;
            var fi = new FileInfo(fullDestName);
            var replace = true;
            if (File.Exists(fullDestName)) {
                if (DialogResult.No == MessageBox.Show(SR.GetString("QtProject_FileExistsInProjectFolder", destName)
                    , SR.GetString("Resources_QtVsTools"), MessageBoxButtons.YesNo, MessageBoxIcon.Question)) {
                    replace = false;
                }
            }
            if (replace) {
                if (!fi.Directory.Exists)
                    fi.Directory.Create();
                File.Copy(srcFile, fullDestName, true);
                var attribs = File.GetAttributes(fullDestName);
                File.SetAttributes(fullDestName, attribs & (~FileAttributes.ReadOnly));
            }
            return fi.FullName;
        }
        public static void ReplaceTokenInFile(string file, string token, string replacement)
        {
            var text = string.Empty;
            try {
                var reader = new StreamReader(file);
                text = reader.ReadToEnd();
                reader.Close();
            } catch (Exception e) {
                Messages.DisplayErrorMessage(
                    SR.GetString("QtProject_CannotReplaceTokenRead", token, replacement, e.ToString()));
                return;
            }
            try {
                if (token.ToUpper() == "%PRE_DEF%" && !Char.IsLetter(replacement[0]))
                    replacement = "_" + replacement;
                text = text.Replace(token, replacement);
                var writer = new StreamWriter(file);
                writer.Write(text);
                writer.Close();
            } catch (Exception e) {
                Messages.DisplayErrorMessage(
                    SR.GetString("QtProject_CannotReplaceTokenWrite", token, replacement, e.ToString()));
            }
        }
        public void RepairGeneratedFilesStructure()
        {
            DeleteGeneratedFiles();
            var files = new ConcurrentBag<VCFile>();
            Task.WaitAll(
                Task.Run(() =>
                    Parallel.ForEach(((IVCCollection)vcPro.Files).Cast<VCFile>(), file =>
                    {
                        var name = file.Name;
                        if (!HelperFunctions.IsHeaderFile(name) && !HelperFunctions.IsSourceFile(name))
                            return;
                        if (HelperFunctions.HasQObjectDeclaration(file))
                            files.Add(file);
                    })
                )
            );
            qtMsBuild.BeginSetItemProperties();
            foreach (var file in files) {
                RemoveMocStep(file);
                AddMocStep(file);
            }
            qtMsBuild.EndSetItemProperties();
        }
        public void TranslateFilterNames()
        {
            var filters = vcPro.Filters as IVCCollection;
@@ -2402,37 +1953,10 @@
            }
        }
        public static string CreateQrcFile(string projectDir, string className, string destName)
        {
            var fullDestName = projectDir + "\\" + destName;
            if (!File.Exists(fullDestName)) {
                FileStream s = null;
                try {
                    s = File.Open(fullDestName, FileMode.CreateNew);
                    if (s.CanWrite) {
                        using (var sw = new StreamWriter(s)) {
                            s = null;
                            sw.WriteLine("<RCC>");
                            sw.WriteLine("    <qresource prefix=\"" + className + "\">");
                            sw.WriteLine("    </qresource>");
                            sw.WriteLine("</RCC>");
                        }
                    }
                } finally {
                    if (s != null)
                        s.Dispose();
                }
                var attribs = File.GetAttributes(fullDestName);
                File.SetAttributes(fullDestName, attribs & (~FileAttributes.ReadOnly));
            }
            var fi = new FileInfo(fullDestName);
            return fi.FullName;
        }
        public void AddActiveQtBuildStep(string version, string defFile = null)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            if (FormatVersion < Resources.qtMinFormatVersion_ClProperties)
                return;
@@ -2463,6 +1987,8 @@
        private void UpdateCompilerIncludePaths(string oldDir, string newDir)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            var fixedOldDir = FixFilePathForComparison(oldDir);
            var dirs = new[] {
                FixFilePathForComparison(QtVSIPSettings.GetUicDirectory(envPro)),
@@ -2516,6 +2042,8 @@
        public void UpdateUicSteps(string oldUicDir, bool update_inc_path)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            Messages.Print("\r\n=== Update uic steps ===");
            var vcFilter = FindFilterFromGuid(Filters.GeneratedFiles().UniqueIdentifier);
            if (vcFilter != null) {
@@ -2538,7 +2066,7 @@
            qtMsBuild.BeginSetItemProperties();
            foreach (var file in files) {
                if (HelperFunctions.IsUicFile(file.Name) && !IsUic3File(file)) {
                if (HelperFunctions.IsUicFile(file.Name)) {
                    AddUic4BuildStep(file);
                    Messages.Print("Update uic step for " + file.Name + ".");
                    ++updatedFiles;
@@ -2549,42 +2077,6 @@
                UpdateCompilerIncludePaths(oldUicDir, QtVSIPSettings.GetUicDirectory(envPro));
            Messages.Print("\r\n=== " + updatedFiles + " uic steps updated. ===\r\n");
        }
        private static bool IsUic3File(VCFile file)
        {
            foreach (VCFileConfiguration config in (IVCCollection)file.FileConfigurations) {
                var tool = HelperFunctions.GetCustomBuildTool(config);
                if (tool == null)
                    return false;
                if (tool.CommandLine.IndexOf("uic3.exe", StringComparison.OrdinalIgnoreCase) > -1)
                    return true;
            }
            return false;
        }
        public bool UsePrecompiledHeaders(VCConfiguration config)
        {
            var compiler = CompilerToolWrapper.Create(config);
            return UsePrecompiledHeaders(compiler);
        }
        private bool UsePrecompiledHeaders(CompilerToolWrapper compiler)
        {
            try {
                compiler.SetUsePrecompiledHeader(pchOption.pchUseUsingSpecific);
                var pcHeaderThrough = GetPrecompiledHeaderThrough();
                if (string.IsNullOrEmpty(pcHeaderThrough))
                    pcHeaderThrough = "stdafx.h";
                compiler.SetPrecompiledHeaderThrough(pcHeaderThrough);
                var pcHeaderFile = GetPrecompiledHeaderFile();
                if (string.IsNullOrEmpty(pcHeaderFile))
                    pcHeaderFile = ".\\$(ConfigurationName)/" + Project.Name + ".pch";
                compiler.SetPrecompiledHeaderFile(pcHeaderFile);
                return true;
            } catch {
                return false;
            }
        }
        public bool UsesPrecompiledHeaders()
@@ -2637,32 +2129,6 @@
            return null;
        }
        public string GetPrecompiledHeaderFile()
        {
            foreach (VCConfiguration config in vcPro.Configurations as IVCCollection) {
                var file = GetPrecompiledHeaderFile(config);
                if (!string.IsNullOrEmpty(file))
                    return file;
            }
            return null;
        }
        public static string GetPrecompiledHeaderFile(VCConfiguration config)
        {
            var compiler = CompilerToolWrapper.Create(config);
            return GetPrecompiledHeaderFile(compiler);
        }
        private static string GetPrecompiledHeaderFile(CompilerToolWrapper compiler)
        {
            try {
                var file = compiler.GetPrecompiledHeaderFile();
                if (!string.IsNullOrEmpty(file))
                    return file;
            } catch { }
            return null;
        }
        public static void SetPCHOption(VCFile vcFile, pchOption option)
        {
            foreach (VCFileConfiguration config in vcFile.FileConfigurations as IVCCollection) {
@@ -2692,6 +2158,8 @@
        /// <returns></returns>
        private VCFile GetGeneratedMocFile(string fileName, VCFileConfiguration fileConfig)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            if (QtVSIPSettings.HasDifferentMocFilePerConfig(envPro)
                || QtVSIPSettings.HasDifferentMocFilePerPlatform(envPro)) {
                var projectConfig = (VCConfiguration)fileConfig.ProjectConfiguration;
@@ -2763,6 +2231,8 @@
        public void RefreshMocSteps()
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            // Ignore when using shared compiler properties
            if (GetFormatVersion(vcPro) >= Resources.qtMinFormatVersion_ClProperties)
                return;
@@ -2790,6 +2260,7 @@
        public void RefreshMocStep(VCFile vcfile)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            RefreshMocStep(vcfile, true);
        }
@@ -2803,6 +2274,8 @@
        /// <param name="vcfile"></param>
        private void RefreshMocStep(VCFile vcfile, bool singleFile)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            var isHeaderFile = HelperFunctions.IsHeaderFile(vcfile.FullPath);
            if (!isHeaderFile && !HelperFunctions.IsSourceFile(vcfile.FullPath))
                return;
@@ -2942,6 +2415,8 @@
        public void OnExcludedFromBuildChanged(VCFile vcFile, VCFileConfiguration vcFileCfg)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            // Update the ExcludedFromBuild flags of the mocced file
            // according to the ExcludedFromBuild flag of the mocable source file.
            var moccedFileName = GetMocFileName(vcFile.Name);
@@ -3011,6 +2486,8 @@
        public void UpdateMocSteps(string oldMocDir)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            Messages.Print("\r\n=== Update moc steps ===");
            var orgFiles = new List<VCFile>();
            var abandonedMocFiles = new List<string>();
@@ -3053,8 +2530,8 @@
                try {
                    RemoveMocStep(file);
                    AddMocStep(file);
                } catch (QtVSException e) {
                    Messages.Print(e.Message);
                } catch (QtVSException exception) {
                    exception.Log();
                    continue;
                }
                Messages.Print("Moc step updated successfully for " + file.Name + ".");
@@ -3073,6 +2550,8 @@
        private void Clean()
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            var solutionConfigs = envPro.DTE.Solution.SolutionBuild.SolutionConfigurations;
            var backup = new List<KeyValuePair<SolutionContext, bool>>();
            foreach (SolutionConfiguration config in solutionConfigs) {
@@ -3125,47 +2604,6 @@
            }
        }
        public bool isWinRT()
        {
            try {
                var vcProject = Project.Object as VCProject;
                var vcConfigs = vcProject.Configurations as IVCCollection;
                var vcConfig = vcConfigs.Item(1) as VCConfiguration;
                var appType = vcConfig.GetEvaluatedPropertyValue("ApplicationType");
                if (appType == "Windows Store")
                    return true;
            } catch { }
            return false;
        }
        public bool PromptChangeQtVersion(string oldVersion, string newVersion)
        {
            var versionManager = QtVersionManager.The();
            var viOld = versionManager.GetVersionInfo(oldVersion);
            var viNew = versionManager.GetVersionInfo(newVersion);
            if (viOld == null || viNew == null)
                return true;
            var oldIsWinRt = viOld.isWinRT();
            var newIsWinRt = viNew.isWinRT();
            if (newIsWinRt == oldIsWinRt || newIsWinRt == isWinRT())
                return true;
            var promptCaption = string.Format("Change Qt Version ({0})", Project.Name);
            var promptText = string.Format(
                "Changing Qt version from {0} to {1}.\r\n" +
                "Project might not build. Are you sure?",
                newIsWinRt ? "Win32" : "WinRT",
                newIsWinRt ? "WinRT" : "Win32"
                );
            return (MessageBox.Show(
                promptText, promptCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Warning)
                == DialogResult.Yes);
        }
        /// <summary>
        /// Changes the Qt version of this project.
        /// </summary>
@@ -3175,6 +2613,8 @@
        /// <returns>true, if the operation performed successfully</returns>
        public bool ChangeQtVersion(string oldVersion, string newVersion, ref bool newProjectCreated)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            newProjectCreated = false;
            var versionManager = QtVersionManager.The();
            var viNew = versionManager.GetVersionInfo(newVersion);
@@ -3243,6 +2683,8 @@
        public bool SelectSolutionPlatform(string platformName)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            foreach (SolutionConfiguration solutionCfg in dte.Solution.SolutionBuild.SolutionConfigurations) {
                var contexts = solutionCfg.SolutionContexts;
                for (var i = 1; i <= contexts.Count; ++i) {
@@ -3268,6 +2710,8 @@
        public void CreatePlatform(string oldPlatform, string newPlatform,
                                   VersionInformation viOld, VersionInformation viNew, ref bool newProjectCreated)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            try {
                var cfgMgr = envPro.ConfigurationManager;
                cfgMgr.AddPlatform(newPlatform, oldPlatform, true);
@@ -3329,9 +2773,7 @@
            if (genVCFilter == null)
                return;
            var error = false;
            error = DeleteFilesFromFilter(genVCFilter);
            if (error)
            if (DeleteFilesFromFilter(genVCFilter))
                Messages.Print(SR.GetString("DeleteGeneratedFilesError"));
        }
@@ -3389,7 +2831,7 @@
                resFile.Remove();
        }
        static private void AddPlatformToVCProj(string projectFileName, string oldPlatformName, string newPlatformName)
        private static void AddPlatformToVCProj(string projectFileName, string oldPlatformName, string newPlatformName)
        {
            var tempFileName = Path.GetTempFileName();
            var fi = new FileInfo(projectFileName);
@@ -3404,7 +2846,7 @@
            fi.Delete();
        }
        static private void AddPlatformToVCProj(XmlDocument doc, string oldPlatformName, string newPlatformName)
        private static void AddPlatformToVCProj(XmlDocument doc, string oldPlatformName, string newPlatformName)
        {
            var vsProj = doc.DocumentElement.SelectSingleNode("/VisualStudioProject");
            var platforms = vsProj.SelectSingleNode("Platforms");
@@ -3438,7 +2880,7 @@
            }
        }
        static private void SetTargetMachine(VCLinkerTool linker, VersionInformation versionInfo)
        private static void SetTargetMachine(VCLinkerTool linker, VersionInformation versionInfo)
        {
            var qMakeLFlagsWindows = versionInfo.GetQMakeConfEntry("QMAKE_LFLAGS_WINDOWS");
            var rex = new Regex("/MACHINE:(\\S+)");
@@ -3476,6 +2918,8 @@
        public void CollapseFilter(string filterName)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            var solutionExplorer = (UIHierarchy)dte.Windows.Item(Constants.vsext_wk_SProjectWindow).Object;
            if (solutionExplorer.UIHierarchyItems.Count == 0)
                return;
@@ -3489,6 +2933,8 @@
        private UIHierarchyItem FindProjectHierarchyItem(UIHierarchy hierarchy)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            if (hierarchy.UIHierarchyItems.Count == 0)
                return null;
@@ -3504,6 +2950,8 @@
        private UIHierarchyItem FindProjectHierarchyItem(UIHierarchyItem root)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            UIHierarchyItem projectItem = null;
            try {
                if (root.Name == envPro.Name)
@@ -3524,6 +2972,7 @@
        /// </summary>
        public string GetQtVersion()
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            return QtVersionManager.The().GetProjectQtVersion(envPro);
        }
@@ -3532,6 +2981,7 @@
        /// </summary>
        public void SetQtEnvironment()
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            SetQtEnvironment(QtVersionManager.The().GetProjectQtVersion(envPro));
        }
@@ -3540,6 +2990,7 @@
        /// </summary>
        public void SetQtEnvironment(string qtVersion)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            SetQtEnvironment(qtVersion, string.Empty);
        }
@@ -3548,6 +2999,8 @@
        /// </summary>
        public void SetQtEnvironment(string qtVersion, string solutionConfig, bool build = false)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            if (string.IsNullOrEmpty(qtVersion))
                return;
@@ -3558,6 +3011,7 @@
            if (qtVersion != "$(QTDIR)")
                qtDir = QtVersionManager.The().GetInstallPath(qtVersion);
            HelperFunctions.SetEnvironmentVariableEx("QTDIR", qtDir);
            try {
                var propertyAccess = (IVCBuildPropertyStorage)vcPro;
                var vcprj = envPro.Object as VCProject;
@@ -3590,8 +3044,7 @@
                            debuggerEnv = propertyAccess.GetPropertyValue(
                                "LocalDebuggerEnvironment", cur_solution, "UserFile");
                            if (!string.IsNullOrEmpty(debuggerEnv)) {
                                var debugSettings = conf.DebugSettings as VCDebugSettings;
                                if (debugSettings != null) {
                                if (conf.DebugSettings is VCDebugSettings debugSettings) {
                                    //Get original value without expanded properties
                                    debuggerEnv = debugSettings.Environment;
                                }
@@ -3624,9 +3077,8 @@
                var projProps = vcProj as IVCBuildPropertyStorage;
                try {
                    return projProps.GetPropertyValue(pszPropName, Config.Name, "UserFile");
                } catch (Exception e) {
                    System.Diagnostics.Debug.WriteLine(
                        e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
                } catch (Exception exception) {
                    exception.Log();
                    return string.Empty;
                }
            }
@@ -3637,9 +3089,8 @@
                var projProps = vcProj as IVCBuildPropertyStorage;
                try {
                    projProps.SetPropertyValue(pszPropName, Config.Name, "UserFile", pszPropValue);
                } catch (Exception e) {
                    System.Diagnostics.Debug.WriteLine(
                        e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
                } catch (Exception exception) {
                    exception.Log();
                }
            }
@@ -3649,9 +3100,8 @@
                var projProps = vcProj as IVCBuildPropertyStorage;
                try {
                    projProps.RemoveProperty(pszPropName, Config.Name, "UserFile");
                } catch (Exception e) {
                    System.Diagnostics.Debug.WriteLine(
                        e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
                } catch (Exception exception) {
                    exception.Log();
                }
            }
        }
@@ -3970,10 +3420,10 @@
        {
            if (propertyStorage == null)
                return null;
            if (propertyStorage is VCFileConfiguration)
                return GetParentProject(propertyStorage as VCFileConfiguration);
            else if (propertyStorage is VCConfiguration)
                return GetParentProject(propertyStorage as VCConfiguration);
            if (propertyStorage is VCFileConfiguration configuration)
                return GetParentProject(configuration);
            else if (propertyStorage is VCConfiguration storage)
                return GetParentProject(storage);
            return null;
        }
@@ -4026,8 +3476,7 @@
    public class VCMacroExpander : IVSMacroExpander
    {
        object config;
        readonly object config;
        public VCMacroExpander(object config)
        {
            this.config = config;
@@ -4042,14 +3491,15 @@
    public class QtCustomBuildTool
    {
        QtMsBuildContainer qtMsBuild;
        VCFileConfiguration vcConfig;
        VCFile vcFile;
        VCCustomBuildTool tool;
        VCMacroExpander macros;
        readonly QtMsBuildContainer qtMsBuild;
        readonly VCFileConfiguration vcConfig;
        readonly VCFile vcFile;
        readonly VCCustomBuildTool tool;
        readonly VCMacroExpander macros;
        enum FileItemType { Other = 0, CustomBuild, QtMoc, QtRcc, QtRepc, QtUic };
        FileItemType itemType = FileItemType.Other;
        readonly FileItemType itemType = FileItemType.Other;
        public QtCustomBuildTool(VCFileConfiguration vcConfig, QtMsBuildContainer container = null)
        {
            if (container != null)