/****************************************************************************  
 | 
**  
 | 
** Copyright (C) 2016 The Qt Company Ltd.  
 | 
** Contact: https://www.qt.io/licensing/  
 | 
**  
 | 
** This file is part of the Qt VS Tools.  
 | 
**  
 | 
** $QT_BEGIN_LICENSE:GPL-EXCEPT$  
 | 
** Commercial License Usage  
 | 
** Licensees holding valid commercial Qt licenses may use this file in  
 | 
** accordance with the commercial license agreement provided with the  
 | 
** Software or, alternatively, in accordance with the terms contained in  
 | 
** a written agreement between you and The Qt Company. For licensing terms  
 | 
** and conditions see https://www.qt.io/terms-conditions. For further  
 | 
** information use the contact form at https://www.qt.io/contact-us.  
 | 
**  
 | 
** GNU General Public License Usage  
 | 
** Alternatively, this file may be used under the terms of the GNU  
 | 
** General Public License version 3 as published by the Free Software  
 | 
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT  
 | 
** included in the packaging of this file. Please review the following  
 | 
** information to ensure the GNU General Public License requirements will  
 | 
** be met: https://www.gnu.org/licenses/gpl-3.0.html.  
 | 
**  
 | 
** $QT_END_LICENSE$  
 | 
**  
 | 
****************************************************************************/  
 | 
  
 | 
using EnvDTE;  
 | 
using Microsoft.VisualStudio.VCProjectEngine;  
 | 
using Microsoft.Win32;  
 | 
using QtVsTools.Core.QtMsBuild;  
 | 
using System;  
 | 
using System.Collections.Generic;  
 | 
using System.Diagnostics;  
 | 
using System.Drawing;  
 | 
using System.IO;  
 | 
using System.Linq;  
 | 
using System.Reflection;  
 | 
using System.Text;  
 | 
using System.Text.RegularExpressions;  
 | 
using System.Windows.Forms;  
 | 
  
 | 
using Process = System.Diagnostics.Process;  
 | 
  
 | 
namespace QtVsTools.Core  
 | 
{  
 | 
    public static class HelperFunctions  
 | 
    {  
 | 
        public static string FindQtDirWithTools(Project project)  
 | 
        {  
 | 
            var versionManager = QtVersionManager.The();  
 | 
            string projectQtVersion = null;  
 | 
            if (IsQtProject(project))  
 | 
                projectQtVersion = versionManager.GetProjectQtVersion(project);  
 | 
            return FindQtDirWithTools(projectQtVersion);  
 | 
        }  
 | 
  
 | 
        public static string FindQtDirWithTools(string projectQtVersion)  
 | 
        {  
 | 
            string tool = null;  
 | 
            return FindQtDirWithTools(tool, projectQtVersion);  
 | 
        }  
 | 
  
 | 
        public static string FindQtDirWithTools(string tool, string projectQtVersion)  
 | 
        {  
 | 
            if (!string.IsNullOrEmpty(tool)) {  
 | 
                if (!tool.StartsWith("\\bin\\", StringComparison.OrdinalIgnoreCase))  
 | 
                    tool = "\\bin\\" + tool;  
 | 
                if (!tool.EndsWith(".exe", StringComparison.OrdinalIgnoreCase))  
 | 
                    tool += ".exe";  
 | 
            }  
 | 
  
 | 
            var versionManager = QtVersionManager.The();  
 | 
            string qtDir = null;  
 | 
            if (projectQtVersion != null)  
 | 
                qtDir = versionManager.GetInstallPath(projectQtVersion);  
 | 
  
 | 
            if (qtDir == null)  
 | 
                qtDir = Environment.GetEnvironmentVariable("QTDIR");  
 | 
  
 | 
            var found = false;  
 | 
            if (tool == null) {  
 | 
                found = File.Exists(qtDir + "\\bin\\designer.exe")  
 | 
                    && File.Exists(qtDir + "\\bin\\linguist.exe");  
 | 
            } else {  
 | 
                found = File.Exists(qtDir + tool);  
 | 
            }  
 | 
            if (!found) {  
 | 
                VersionInformation exactlyMatchingVersion = null;  
 | 
                VersionInformation matchingVersion = null;  
 | 
                VersionInformation somehowMatchingVersion = null;  
 | 
                var viProjectQtVersion = versionManager.GetVersionInfo(projectQtVersion);  
 | 
                foreach (var qtVersion in versionManager.GetVersions()) {  
 | 
                    var vi = versionManager.GetVersionInfo(qtVersion);  
 | 
                    if (tool == null) {  
 | 
                        found = File.Exists(vi.qtDir + "\\bin\\designer.exe")  
 | 
                            && File.Exists(vi.qtDir + "\\bin\\linguist.exe");  
 | 
                    } else {  
 | 
                        found = File.Exists(vi.qtDir + tool);  
 | 
                    }  
 | 
                    if (!found)  
 | 
                        continue;  
 | 
  
 | 
                    if (viProjectQtVersion != null  
 | 
                        && vi.qtMajor == viProjectQtVersion.qtMajor  
 | 
                        && vi.qtMinor == viProjectQtVersion.qtMinor) {  
 | 
                        exactlyMatchingVersion = vi;  
 | 
                        break;  
 | 
                    }  
 | 
                    if (matchingVersion == null  
 | 
                        && viProjectQtVersion != null  
 | 
                        && vi.qtMajor == viProjectQtVersion.qtMajor) {  
 | 
                        matchingVersion = vi;  
 | 
                    }  
 | 
                    if (somehowMatchingVersion == null)  
 | 
                        somehowMatchingVersion = vi;  
 | 
                }  
 | 
  
 | 
                if (exactlyMatchingVersion != null)  
 | 
                    qtDir = exactlyMatchingVersion.qtDir;  
 | 
                else if (matchingVersion != null)  
 | 
                    qtDir = matchingVersion.qtDir;  
 | 
                else if (somehowMatchingVersion != null)  
 | 
                    qtDir = somehowMatchingVersion.qtDir;  
 | 
                else  
 | 
                    qtDir = null;  
 | 
            }  
 | 
            return qtDir;  
 | 
        }  
 | 
  
 | 
        static readonly HashSet<string> _sources = new HashSet<string>(new[] { ".c", ".cpp", ".cxx" },  
 | 
            StringComparer.OrdinalIgnoreCase);  
 | 
        static public bool IsSourceFile(string fileName)  
 | 
        {  
 | 
            return _sources.Contains(Path.GetExtension(fileName));  
 | 
        }  
 | 
  
 | 
        static readonly HashSet<string> _headers = new HashSet<string>(new[] { ".h", ".hpp", ".hxx" },  
 | 
            StringComparer.OrdinalIgnoreCase);  
 | 
        static public bool IsHeaderFile(string fileName)  
 | 
        {  
 | 
            return _headers.Contains(Path.GetExtension(fileName));  
 | 
        }  
 | 
  
 | 
        public static bool IsUicFile(string fileName)  
 | 
        {  
 | 
            return ".ui".Equals(Path.GetExtension(fileName), StringComparison.OrdinalIgnoreCase);  
 | 
        }  
 | 
  
 | 
        public static bool IsMocFile(string fileName)  
 | 
        {  
 | 
            return ".moc".Equals(Path.GetExtension(fileName), StringComparison.OrdinalIgnoreCase);  
 | 
        }  
 | 
  
 | 
        public static bool IsQrcFile(string fileName)  
 | 
        {  
 | 
            return ".qrc".Equals(Path.GetExtension(fileName), StringComparison.OrdinalIgnoreCase);  
 | 
        }  
 | 
  
 | 
        public static bool IsWinRCFile(string fileName)  
 | 
        {  
 | 
            return ".rc".Equals(Path.GetExtension(fileName), StringComparison.OrdinalIgnoreCase);  
 | 
        }  
 | 
  
 | 
        public static bool IsTranslationFile(string fileName)  
 | 
        {  
 | 
            return ".ts".Equals(Path.GetExtension(fileName), StringComparison.OrdinalIgnoreCase);  
 | 
        }  
 | 
  
 | 
        public static bool IsQmlFile(string fileName)  
 | 
        {  
 | 
            return ".qml".Equals(Path.GetExtension(fileName), StringComparison.OrdinalIgnoreCase);  
 | 
        }  
 | 
  
 | 
        static public void SetDebuggingEnvironment(Project prj)  
 | 
        {  
 | 
            SetDebuggingEnvironment(prj, string.Empty);  
 | 
        }  
 | 
  
 | 
        static public void SetDebuggingEnvironment(Project prj, string solutionConfig)  
 | 
        {  
 | 
            SetDebuggingEnvironment(prj, "PATH=$(QTDIR)\\bin;$(PATH)", false, solutionConfig);  
 | 
        }  
 | 
  
 | 
        static public void SetDebuggingEnvironment(Project prj, string envpath, bool overwrite)  
 | 
        {  
 | 
            SetDebuggingEnvironment(prj, envpath, overwrite, string.Empty);  
 | 
        }  
 | 
  
 | 
        static public void SetDebuggingEnvironment(Project prj, string envpath, bool overwrite, string solutionConfig)  
 | 
        {  
 | 
            if (QtProject.GetFormatVersion(prj) >= Resources.qtMinFormatVersion_Settings)  
 | 
                return;  
 | 
  
 | 
            // Get platform name from given solution configuration  
 | 
            // or if not available take the active configuration  
 | 
            var activePlatformName = string.Empty;  
 | 
            if (string.IsNullOrEmpty(solutionConfig)) {  
 | 
                // First get active configuration cause not given as parameter  
 | 
                try {  
 | 
                    var activeConf = prj.ConfigurationManager.ActiveConfiguration;  
 | 
                    activePlatformName = activeConf.PlatformName;  
 | 
                } catch {  
 | 
                    Messages.Print("Could not get the active platform name.");  
 | 
                }  
 | 
            } else {  
 | 
                activePlatformName = solutionConfig.Split('|')[1];  
 | 
            }  
 | 
  
 | 
            var vcprj = prj.Object as VCProject;  
 | 
            foreach (VCConfiguration conf in vcprj.Configurations as IVCCollection) {  
 | 
                // Set environment only for active (or given) platform  
 | 
                var currentPlatform = conf.Platform as VCPlatform;  
 | 
                if (currentPlatform == null || currentPlatform.Name != activePlatformName)  
 | 
                    continue;  
 | 
  
 | 
                var de = conf.DebugSettings as VCDebugSettings;  
 | 
                if (de == null)  
 | 
                    continue;  
 | 
  
 | 
                // See: https://connect.microsoft.com/VisualStudio/feedback/details/619702  
 | 
                // Project | Properties | Configuration Properties | Debugging | Environment  
 | 
                //  
 | 
                // Issue: Substitution of ";" to "%3b"  
 | 
                // Answer: This behavior currently is by design as ';' is a special MSBuild  
 | 
                // character and needs to be escaped. In the Project Properties we show this  
 | 
                // escaped value, but it should be the original when we use it.  
 | 
                envpath = envpath.Replace("%3b", ";");  
 | 
                de.Environment = de.Environment.Replace("%3b", ";");  
 | 
  
 | 
                var index = envpath.LastIndexOf(";$(PATH)", StringComparison.Ordinal);  
 | 
                var withoutPath = (index >= 0 ? envpath.Remove(index) : envpath);  
 | 
  
 | 
                if (overwrite || string.IsNullOrEmpty(de.Environment))  
 | 
                    de.Environment = envpath;  
 | 
                else if (!de.Environment.Contains(envpath) && !de.Environment.Contains(withoutPath)) {  
 | 
                    var m = Regex.Match(de.Environment, "PATH\\s*=\\s*");  
 | 
                    if (m.Success) {  
 | 
                        de.Environment = Regex.Replace(de.Environment, "PATH\\s*=\\s*", withoutPath + ";");  
 | 
                        if (!de.Environment.Contains("$(PATH)") && !de.Environment.Contains("%PATH%")) {  
 | 
                            if (!de.Environment.EndsWith(";", StringComparison.Ordinal))  
 | 
                                de.Environment = de.Environment + ";";  
 | 
                            de.Environment += "$(PATH)";  
 | 
                        }  
 | 
                    } else {  
 | 
                        if (!string.IsNullOrEmpty(de.Environment))  
 | 
                            de.Environment += "\n";  
 | 
                        de.Environment += envpath;  
 | 
                    }  
 | 
                }  
 | 
            }  
 | 
        }  
 | 
  
 | 
        public static bool IsProjectInSolution(DTE dteObject, string fullName)  
 | 
        {  
 | 
            var fi = new FileInfo(fullName);  
 | 
  
 | 
            foreach (var p in ProjectsInSolution(dteObject)) {  
 | 
                if (p.FullName.ToLower() == fi.FullName.ToLower())  
 | 
                    return true;  
 | 
            }  
 | 
            return false;  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Returns the normalized file path of a given file.  
 | 
        /// </summary>  
 | 
        /// <param name="name">file name</param>  
 | 
        static public string NormalizeFilePath(string name)  
 | 
        {  
 | 
            var fi = new FileInfo(name);  
 | 
            return fi.FullName;  
 | 
        }  
 | 
  
 | 
        static public string NormalizeRelativeFilePath(string path)  
 | 
        {  
 | 
            if (path == null)  
 | 
                return ".\\";  
 | 
  
 | 
            path = path.Trim();  
 | 
            path = path.Replace("/", "\\");  
 | 
  
 | 
            var tmp = string.Empty;  
 | 
            while (tmp != path) {  
 | 
                tmp = path;  
 | 
                path = path.Replace("\\\\", "\\");  
 | 
            }  
 | 
  
 | 
            path = path.Replace("\"", "");  
 | 
  
 | 
            if (path != "." && !IsAbsoluteFilePath(path) && !path.StartsWith(".\\", StringComparison.Ordinal)  
 | 
                 && !path.StartsWith("$", StringComparison.Ordinal))  
 | 
                path = ".\\" + path;  
 | 
  
 | 
            if (path.EndsWith("\\", StringComparison.Ordinal))  
 | 
                path = path.Substring(0, path.Length - 1);  
 | 
  
 | 
            return path;  
 | 
        }  
 | 
  
 | 
        static public bool IsAbsoluteFilePath(string path)  
 | 
        {  
 | 
            path = path.Trim();  
 | 
            if (path.Length >= 2 && path[1] == ':')  
 | 
                return true;  
 | 
            if (path.StartsWith("\\", StringComparison.Ordinal) || path.StartsWith("/", StringComparison.Ordinal))  
 | 
                return true;  
 | 
  
 | 
            return false;  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Reads lines from a .pro file that is opened with a StreamReader  
 | 
        /// and concatenates strings that end with a backslash.  
 | 
        /// </summary>  
 | 
        /// <param name="streamReader"></param>  
 | 
        /// <returns>the composite string</returns>  
 | 
        static private string ReadProFileLine(StreamReader streamReader)  
 | 
        {  
 | 
            var line = streamReader.ReadLine();  
 | 
            if (line == null)  
 | 
                return null;  
 | 
  
 | 
            line = line.TrimEnd(' ', '\t');  
 | 
            while (line.EndsWith("\\", StringComparison.Ordinal)) {  
 | 
                line = line.Remove(line.Length - 1);  
 | 
                var appendix = streamReader.ReadLine();  
 | 
                if (appendix != null)  
 | 
                    line += appendix.TrimEnd(' ', '\t');  
 | 
            }  
 | 
            return line;  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Reads a .pro file and returns true if it is a subdirs template.  
 | 
        /// </summary>  
 | 
        /// <param name="profile">full name of .pro file to read</param>  
 | 
        /// <returns>true if this is a subdirs file</returns>  
 | 
        static public bool IsSubDirsFile(string profile)  
 | 
        {  
 | 
            StreamReader sr = null;  
 | 
            try {  
 | 
                sr = new StreamReader(profile);  
 | 
  
 | 
                var line = string.Empty;  
 | 
                while ((line = ReadProFileLine(sr)) != null) {  
 | 
                    line = line.Replace(" ", string.Empty).Replace("\t", string.Empty);  
 | 
                    if (line.StartsWith("TEMPLATE", StringComparison.Ordinal))  
 | 
                        return line.StartsWith("TEMPLATE=subdirs", StringComparison.Ordinal);  
 | 
                }  
 | 
            } catch (Exception e) {  
 | 
                Messages.DisplayErrorMessage(e);  
 | 
            } finally {  
 | 
                if (sr != null)  
 | 
                    sr.Dispose();  
 | 
            }  
 | 
            return false;  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Returns the relative path between a given file and a path.  
 | 
        /// </summary>  
 | 
        /// <param name="path">absolute path</param>  
 | 
        /// <param name="file">absolute file name</param>  
 | 
        public static string GetRelativePath(string path, string file)  
 | 
        {  
 | 
            if (file == null || path == null)  
 | 
                return "";  
 | 
            var fi = new FileInfo(file);  
 | 
            var di = new DirectoryInfo(path);  
 | 
  
 | 
            char[] separator = { '\\' };  
 | 
            var fiArray = fi.FullName.Split(separator);  
 | 
            var dir = di.FullName;  
 | 
            while (dir.EndsWith("\\", StringComparison.Ordinal))  
 | 
                dir = dir.Remove(dir.Length - 1, 1);  
 | 
            var diArray = dir.Split(separator);  
 | 
  
 | 
            var minLen = fiArray.Length < diArray.Length ? fiArray.Length : diArray.Length;  
 | 
            int i = 0, j = 0, commonParts = 0;  
 | 
  
 | 
            while (i < minLen && fiArray[i].ToLower() == diArray[i].ToLower()) {  
 | 
                commonParts++;  
 | 
                i++;  
 | 
            }  
 | 
  
 | 
            if (commonParts < 1)  
 | 
                return fi.FullName;  
 | 
  
 | 
            var result = string.Empty;  
 | 
  
 | 
            for (j = i; j < fiArray.Length; j++) {  
 | 
                if (j == i)  
 | 
                    result = fiArray[j];  
 | 
                else  
 | 
                    result += "\\" + fiArray[j];  
 | 
            }  
 | 
            while (i < diArray.Length) {  
 | 
                result = "..\\" + result;  
 | 
                i++;  
 | 
            }  
 | 
            //MessageBox.Show(path + "\n" + file + "\n" + result);  
 | 
            if (result.StartsWith("..\\", StringComparison.Ordinal))  
 | 
                return result;  
 | 
            return ".\\" + result;  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Replaces a string in the commandLine, description, outputs and additional dependencies  
 | 
        /// in all Custom build tools of the project  
 | 
        /// </summary>  
 | 
        /// <param name="project">Project</param>  
 | 
        /// <param name="oldString">String, which is going to be replaced</param>  
 | 
        /// <param name="oldString">String, which is going to replace the other one</param>  
 | 
        /// <returns></returns>  
 | 
        public static void ReplaceInCustomBuildTools(Project project, string oldString, string replaceString)  
 | 
        {  
 | 
            var vcPro = (VCProject)project.Object;  
 | 
            if (vcPro == null)  
 | 
                return;  
 | 
  
 | 
            var qtMsBuild = new QtMsBuildContainer(new VCPropertyStorageProvider());  
 | 
            qtMsBuild.BeginSetItemProperties();  
 | 
            foreach (VCFile vcfile in (IVCCollection)vcPro.Files) {  
 | 
                foreach (VCFileConfiguration config in (IVCCollection)vcfile.FileConfigurations) {  
 | 
                    try {  
 | 
                        if (vcfile.ItemType == "CustomBuild") {  
 | 
                            var tool = GetCustomBuildTool(config);  
 | 
                            if (tool == null)  
 | 
                                continue;  
 | 
  
 | 
                            tool.CommandLine = tool.CommandLine  
 | 
                                .Replace(oldString, replaceString,  
 | 
                                StringComparison.OrdinalIgnoreCase);  
 | 
                            tool.Description = tool.Description  
 | 
                                .Replace(oldString, replaceString,  
 | 
                                StringComparison.OrdinalIgnoreCase);  
 | 
                            tool.Outputs = tool.Outputs  
 | 
                                .Replace(oldString, replaceString,  
 | 
                                StringComparison.OrdinalIgnoreCase);  
 | 
                            tool.AdditionalDependencies = tool.AdditionalDependencies  
 | 
                                .Replace(oldString, replaceString,  
 | 
                                StringComparison.OrdinalIgnoreCase);  
 | 
                        } else {  
 | 
                            var tool = new QtCustomBuildTool(config, qtMsBuild);  
 | 
                            tool.CommandLine = tool.CommandLine  
 | 
                                .Replace(oldString, replaceString,  
 | 
                                StringComparison.OrdinalIgnoreCase);  
 | 
                        }  
 | 
                    } catch (Exception) {  
 | 
                    }  
 | 
                }  
 | 
            }  
 | 
            qtMsBuild.EndSetItemProperties();  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Since VS2010 it is possible to have VCCustomBuildTools without commandlines  
 | 
        /// for certain filetypes. We are not interested in them and thus try to read the  
 | 
        /// tool's commandline. If this causes an exception, we ignore it.  
 | 
        /// There does not seem to be another way for checking which kind of tool it is.  
 | 
        /// </summary>  
 | 
        /// <param name="config">File configuration</param>  
 | 
        /// <returns></returns>  
 | 
        static public VCCustomBuildTool GetCustomBuildTool(VCFileConfiguration config)  
 | 
        {  
 | 
            var file = config.File as VCFile;  
 | 
            if (file == null || file.ItemType != "CustomBuild")  
 | 
                return null;  
 | 
  
 | 
            var tool = config.Tool as VCCustomBuildTool;  
 | 
            if (tool == null)  
 | 
                return null;  
 | 
  
 | 
            try {  
 | 
                // TODO: The return value is not used at all?  
 | 
                var cmdLine = tool.CommandLine;  
 | 
            } catch {  
 | 
                return null;  
 | 
            }  
 | 
            return tool;  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Since VS2010 we have to ensure, that a custom build tool is present  
 | 
        /// if we want to use it. In order to do so, the ProjectItem's ItemType  
 | 
        /// has to be "CustomBuild"  
 | 
        /// </summary>  
 | 
        /// <param name="projectItem">Project Item which needs to have custom build tool</param>  
 | 
        static public void EnsureCustomBuildToolAvailable(ProjectItem projectItem)  
 | 
        {  
 | 
            foreach (Property prop in projectItem.Properties) {  
 | 
                if (prop.Name == "ItemType") {  
 | 
                    if ((string)prop.Value != "CustomBuild")  
 | 
                        prop.Value = "CustomBuild";  
 | 
                    break;  
 | 
                }  
 | 
            }  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// As Qmake -tp vc Adds the full path to the additional dependencies  
 | 
        /// we need to do the same when toggling project kind to qmake generated.  
 | 
        /// </summary>  
 | 
        /// <returns></returns>  
 | 
        private static string AddFullPathToAdditionalDependencies(string qtDir, string additionalDependencies)  
 | 
        {  
 | 
            var returnString = additionalDependencies;  
 | 
            returnString =  
 | 
                Regex.Replace(returnString, "Qt(\\S+5?)\\.lib", qtDir + "\\lib\\Qt${1}.lib");  
 | 
            returnString =  
 | 
                Regex.Replace(returnString, "(qtmaind?5?)\\.lib", qtDir + "\\lib\\${1}.lib");  
 | 
            returnString =  
 | 
                Regex.Replace(returnString, "(enginiod?5?)\\.lib", qtDir + "\\lib\\${1}.lib");  
 | 
            return returnString;  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Toggles the kind of a project. If the project is a QMake generated project (qmake -tp vc)  
 | 
        /// it is transformed to an Qt VS Tools project and vice versa.  
 | 
        /// </summary>  
 | 
        /// <param name="project">Project</param>  
 | 
        /// <returns></returns>  
 | 
        public static void ToggleProjectKind(Project project)  
 | 
        {  
 | 
            if (QtProject.GetFormatVersion(project) >= Resources.qtMinFormatVersion_Settings)  
 | 
                return;  
 | 
  
 | 
            string qtDir = null;  
 | 
            var vcPro = (VCProject)project.Object;  
 | 
            if (!IsQMakeProject(project))  
 | 
                return;  
 | 
            if (IsQtProject(project)) {  
 | 
                // TODO: qtPro is never used.  
 | 
                var qtPro = QtProject.Create(project);  
 | 
                var vm = QtVersionManager.The();  
 | 
                qtDir = vm.GetInstallPath(project);  
 | 
  
 | 
                foreach (var global in (string[])project.Globals.VariableNames) {  
 | 
                    if (global.StartsWith("Qt5Version", StringComparison.Ordinal))  
 | 
                        project.Globals.set_VariablePersists(global, false);  
 | 
                }  
 | 
  
 | 
                foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {  
 | 
                    var compiler = CompilerToolWrapper.Create(config);  
 | 
                    var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");  
 | 
                    var librarian = (VCLibrarianTool)((IVCCollection)config.Tools).Item("VCLibrarianTool");  
 | 
                    if (compiler != null) {  
 | 
                        var additionalIncludes = compiler.GetAdditionalIncludeDirectories();  
 | 
                        additionalIncludes = additionalIncludes.Replace("$(QTDIR)", qtDir,  
 | 
                            StringComparison.OrdinalIgnoreCase);  
 | 
                        compiler.SetAdditionalIncludeDirectories(additionalIncludes);  
 | 
                    }  
 | 
                    if (linker != null) {  
 | 
                        linker.AdditionalLibraryDirectories = linker.AdditionalLibraryDirectories.  
 | 
                            Replace("$(QTDIR)", qtDir, StringComparison.OrdinalIgnoreCase);  
 | 
                        linker.AdditionalDependencies = AddFullPathToAdditionalDependencies(qtDir, linker.AdditionalDependencies);  
 | 
                    } else {  
 | 
                        librarian.AdditionalLibraryDirectories = librarian.AdditionalLibraryDirectories  
 | 
                            .Replace("$(QTDIR)", qtDir, StringComparison.OrdinalIgnoreCase);  
 | 
                        librarian.AdditionalDependencies = AddFullPathToAdditionalDependencies(qtDir, librarian.AdditionalDependencies);  
 | 
                    }  
 | 
                }  
 | 
  
 | 
                ReplaceInCustomBuildTools(project, "$(QTDIR)", qtDir);  
 | 
            } else {  
 | 
                qtDir = GetQtDirFromQMakeProject(project);  
 | 
  
 | 
                var vm = QtVersionManager.The();  
 | 
                var qtVersion = vm.GetQtVersionFromInstallDir(qtDir);  
 | 
                if (qtVersion == null)  
 | 
                    qtVersion = vm.GetDefaultVersion();  
 | 
                if (qtDir == null)  
 | 
                    qtDir = vm.GetInstallPath(qtVersion);  
 | 
                var vi = vm.GetVersionInfo(qtVersion);  
 | 
                var platformName = vi.GetVSPlatformName();  
 | 
                vm.SaveProjectQtVersion(project, qtVersion, platformName);  
 | 
                var qtPro = QtProject.Create(project);  
 | 
                if (!qtPro.SelectSolutionPlatform(platformName) || !qtPro.HasPlatform(platformName)) {  
 | 
                    var newProject = false;  
 | 
                    qtPro.CreatePlatform("Win32", platformName, null, vi, ref newProject);  
 | 
                    if (!qtPro.SelectSolutionPlatform(platformName))  
 | 
                        Messages.Print("Can't select the platform " + platformName + ".");  
 | 
                }  
 | 
  
 | 
                var activeConfig = project.ConfigurationManager.ActiveConfiguration.ConfigurationName;  
 | 
                var activeVCConfig = (VCConfiguration)((IVCCollection)qtPro.VCProject.Configurations).Item(activeConfig);  
 | 
                if (activeVCConfig.ConfigurationType == ConfigurationTypes.typeDynamicLibrary) {  
 | 
                    var compiler = CompilerToolWrapper.Create(activeVCConfig);  
 | 
                    var linker = (VCLinkerTool)((IVCCollection)activeVCConfig.Tools).Item("VCLinkerTool");  
 | 
                    var ppdefs = compiler.GetPreprocessorDefinitions();  
 | 
                    if (ppdefs != null  
 | 
                        && ppdefs.IndexOf("QT_PLUGIN", StringComparison.Ordinal) > -1  
 | 
                        && ppdefs.IndexOf("QDESIGNER_EXPORT_WIDGETS", StringComparison.Ordinal) > -1  
 | 
                        && ppdefs.IndexOf("QtDesigner", StringComparison.Ordinal) > -1  
 | 
                        && linker.AdditionalDependencies != null  
 | 
                        && linker.AdditionalDependencies.IndexOf("QtDesigner", StringComparison.Ordinal) > -1) {  
 | 
                        qtPro.MarkAsDesignerPluginProject();  
 | 
                    }  
 | 
                }  
 | 
  
 | 
                CleanupQMakeDependencies(project);  
 | 
  
 | 
                foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {  
 | 
                    var compiler = CompilerToolWrapper.Create(config);  
 | 
                    var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");  
 | 
  
 | 
                    if (compiler != null) {  
 | 
                        var additionalIncludes = compiler.AdditionalIncludeDirectories;  
 | 
                        if (additionalIncludes != null) {  
 | 
                            ReplaceDirectory(ref additionalIncludes, qtDir, "$(QTDIR)", project);  
 | 
                            compiler.AdditionalIncludeDirectories = additionalIncludes;  
 | 
                        }  
 | 
                    }  
 | 
                    if (linker != null) {  
 | 
                        var linkerToolWrapper = new LinkerToolWrapper(linker);  
 | 
                        var paths = linkerToolWrapper.AdditionalLibraryDirectories;  
 | 
                        if (paths != null) {  
 | 
                            ReplaceDirectory(ref paths, qtDir, "$(QTDIR)", project);  
 | 
                            linkerToolWrapper.AdditionalLibraryDirectories = paths;  
 | 
                        }  
 | 
                    }  
 | 
                }  
 | 
  
 | 
                ReplaceInCustomBuildTools(project, qtDir, "$(QTDIR)");  
 | 
                qtPro.TranslateFilterNames();  
 | 
            }  
 | 
            project.Save(project.FullName);  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Replaces every occurrence of oldDirectory with replacement in the array of strings.  
 | 
        /// Parameter oldDirectory must be an absolute path.  
 | 
        /// This function converts relative directories to absolute paths internally  
 | 
        /// and replaces them, if necessary. If no replacement is done, the path isn't altered.  
 | 
        /// </summary>  
 | 
        /// <param name="project">The project is needed to convert relative paths to absolute paths.</param>  
 | 
        private static void ReplaceDirectory(ref List<string> paths, string oldDirectory, string replacement, Project project)  
 | 
        {  
 | 
            for (var i = 0; i < paths.Count; ++i) {  
 | 
                var dirName = paths[i];  
 | 
                if (dirName.StartsWith("\"", StringComparison.Ordinal) && dirName.EndsWith("\"", StringComparison.Ordinal)) {  
 | 
                    dirName = dirName.Substring(1, dirName.Length - 2);  
 | 
                }  
 | 
                if (!Path.IsPathRooted(dirName)) {  
 | 
                    // convert to absolute path  
 | 
                    dirName = Path.Combine(Path.GetDirectoryName(project.FullName), dirName);  
 | 
                    dirName = Path.GetFullPath(dirName);  
 | 
                    var alteredDirName = dirName.Replace(oldDirectory, replacement, StringComparison  
 | 
                        .OrdinalIgnoreCase);  
 | 
                    if (alteredDirName == dirName)  
 | 
                        continue;  
 | 
                    dirName = alteredDirName;  
 | 
                } else {  
 | 
                    dirName = dirName.Replace(oldDirectory, replacement, StringComparison  
 | 
                        .OrdinalIgnoreCase);  
 | 
                }  
 | 
                paths[i] = dirName;  
 | 
            }  
 | 
        }  
 | 
  
 | 
        public static string GetQtDirFromQMakeProject(Project project)  
 | 
        {  
 | 
            var vcProject = project.Object as VCProject;  
 | 
            if (vcProject == null)  
 | 
                return null;  
 | 
  
 | 
            try {  
 | 
                foreach (VCConfiguration projectConfig in vcProject.Configurations as IVCCollection) {  
 | 
                    var compiler = CompilerToolWrapper.Create(projectConfig);  
 | 
                    if (compiler != null) {  
 | 
                        var additionalIncludeDirectories = compiler.AdditionalIncludeDirectories;  
 | 
                        if (additionalIncludeDirectories != null) {  
 | 
                            foreach (var dir in additionalIncludeDirectories) {  
 | 
                                var subdir = Path.GetFileName(dir);  
 | 
                                if (subdir != "QtCore" && subdir != "QtGui")    // looking for Qt include directories  
 | 
                                    continue;  
 | 
                                var dirName = Path.GetDirectoryName(dir);    // cd ..  
 | 
                                dirName = Path.GetDirectoryName(dirName);       // cd ..  
 | 
                                if (!Path.IsPathRooted(dirName)) {  
 | 
                                    var projectDir = Path.GetDirectoryName(project.FullName);  
 | 
                                    dirName = Path.Combine(projectDir, dirName);  
 | 
                                    dirName = Path.GetFullPath(dirName);  
 | 
                                }  
 | 
                                return dirName;  
 | 
                            }  
 | 
                        }  
 | 
                    }  
 | 
  
 | 
                    var linker = (VCLinkerTool)((IVCCollection)projectConfig.Tools).Item("VCLinkerTool");  
 | 
                    if (linker != null) {  
 | 
                        var linkerWrapper = new LinkerToolWrapper(linker);  
 | 
                        var linkerPaths = linkerWrapper.AdditionalDependencies;  
 | 
                        if (linkerPaths != null) {  
 | 
                            foreach (var library in linkerPaths) {  
 | 
                                var idx = library.IndexOf("\\lib\\qtmain.lib", StringComparison.OrdinalIgnoreCase);  
 | 
                                if (idx == -1)  
 | 
                                    idx = library.IndexOf("\\lib\\qtmaind.lib", StringComparison.OrdinalIgnoreCase);  
 | 
                                if (idx == -1)  
 | 
                                    idx = library.IndexOf("\\lib\\qtcore5.lib", StringComparison.OrdinalIgnoreCase);  
 | 
                                if (idx == -1)  
 | 
                                    idx = library.IndexOf("\\lib\\qtcored5.lib", StringComparison.OrdinalIgnoreCase);  
 | 
                                if (idx == -1)  
 | 
                                    continue;  
 | 
  
 | 
                                var dirName = Path.GetDirectoryName(library);  
 | 
                                dirName = Path.GetDirectoryName(dirName);   // cd ..  
 | 
                                if (!Path.IsPathRooted(dirName)) {  
 | 
                                    var projectDir = Path.GetDirectoryName(project.FullName);  
 | 
                                    dirName = Path.Combine(projectDir, dirName);  
 | 
                                    dirName = Path.GetFullPath(dirName);  
 | 
                                }  
 | 
  
 | 
                                return dirName;  
 | 
                            }  
 | 
                        }  
 | 
  
 | 
                        linkerPaths = linkerWrapper.AdditionalLibraryDirectories;  
 | 
                        if (linkerPaths != null) {  
 | 
                            foreach (var libDir in linkerPaths) {  
 | 
                                var dirName = libDir;  
 | 
                                if (!Path.IsPathRooted(dirName)) {  
 | 
                                    var projectDir = Path.GetDirectoryName(project.FullName);  
 | 
                                    dirName = Path.Combine(projectDir, dirName);  
 | 
                                    dirName = Path.GetFullPath(dirName);  
 | 
                                }  
 | 
  
 | 
                                if (File.Exists(dirName + "\\qtmain.lib") ||  
 | 
                                    File.Exists(dirName + "\\qtmaind.lib") ||  
 | 
                                    File.Exists(dirName + "\\QtCore5.lib") ||  
 | 
                                    File.Exists(dirName + "\\QtCored5.lib")) {  
 | 
                                    return Path.GetDirectoryName(dirName);  
 | 
                                }  
 | 
                            }  
 | 
                        }  
 | 
                    }  
 | 
                }  
 | 
            } catch { }  
 | 
  
 | 
            return null;  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Return true if the project is a Qt project, otherwise false.  
 | 
        /// </summary>  
 | 
        /// <param name="proj">project</param>  
 | 
        /// <returns></returns>  
 | 
        public static bool IsQtProject(VCProject proj)  
 | 
        {  
 | 
            if (!IsQMakeProject(proj))  
 | 
                return false;  
 | 
  
 | 
            if (QtProject.GetFormatVersion(proj) >= Resources.qtMinFormatVersion_Settings)  
 | 
                return true;  
 | 
  
 | 
            var envPro = proj.Object as Project;  
 | 
            if (envPro.Globals == null || envPro.Globals.VariableNames == null)  
 | 
                return false;  
 | 
  
 | 
            foreach (var global in envPro.Globals.VariableNames as string[]) {  
 | 
                if (global.StartsWith("Qt5Version", StringComparison.Ordinal) && envPro.Globals.get_VariablePersists(global))  
 | 
                    return true;  
 | 
            }  
 | 
            return false;  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Returns true if the specified project is a Qt Project.  
 | 
        /// </summary>  
 | 
        /// <param name="proj">project</param>  
 | 
        public static bool IsQtProject(Project proj)  
 | 
        {  
 | 
            try {  
 | 
                if (proj != null && proj.Kind == "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}")  
 | 
                    return IsQtProject(proj.Object as VCProject);  
 | 
            } catch { }  
 | 
            return false;  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Return true if the project is a QMake -tp vc project, otherwise false.  
 | 
        /// </summary>  
 | 
        /// <param name="proj">project</param>  
 | 
        /// <returns></returns>  
 | 
        public static bool IsQMakeProject(VCProject proj)  
 | 
        {  
 | 
            if (proj == null)  
 | 
                return false;  
 | 
            var keyword = proj.keyword;  
 | 
            if (keyword == null ||  
 | 
                (!keyword.StartsWith(Resources.qtProjectV2Keyword, StringComparison.Ordinal)  
 | 
                && !keyword.StartsWith(Resources.qtProjectKeyword, StringComparison.Ordinal))) {  
 | 
                return false;  
 | 
            }  
 | 
  
 | 
            return true;  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Returns true if the specified project is a QMake -tp vc Project.  
 | 
        /// </summary>  
 | 
        /// <param name="proj">project</param>  
 | 
        public static bool IsQMakeProject(Project proj)  
 | 
        {  
 | 
            try {  
 | 
                if (proj != null && proj.Kind == "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}")  
 | 
                    return IsQMakeProject(proj.Object as VCProject);  
 | 
            } catch { }  
 | 
            return false;  
 | 
        }  
 | 
  
 | 
        public static void CleanupQMakeDependencies(Project project)  
 | 
        {  
 | 
            var vcPro = (VCProject)project.Object;  
 | 
            // clean up qmake mess  
 | 
            var rxp1 = new Regex("\\bQt\\w+d?5?\\.lib\\b");  
 | 
            var rxp2 = new Regex("\\bQAx\\w+\\.lib\\b");  
 | 
            var rxp3 = new Regex("\\bqtmaind?.lib\\b");  
 | 
            var rxp4 = new Regex("\\benginiod?.lib\\b");  
 | 
            foreach (VCConfiguration cfg in (IVCCollection)vcPro.Configurations) {  
 | 
                var linker = (VCLinkerTool)((IVCCollection)cfg.Tools).Item("VCLinkerTool");  
 | 
                if (linker == null || linker.AdditionalDependencies == null)  
 | 
                    continue;  
 | 
                var linkerWrapper = new LinkerToolWrapper(linker);  
 | 
                var deps = linkerWrapper.AdditionalDependencies;  
 | 
                var newDeps = new List<string>();  
 | 
                foreach (var lib in deps) {  
 | 
                    var m1 = rxp1.Match(lib);  
 | 
                    var m2 = rxp2.Match(lib);  
 | 
                    var m3 = rxp3.Match(lib);  
 | 
                    var m4 = rxp4.Match(lib);  
 | 
                    if (m1.Success)  
 | 
                        newDeps.Add(m1.ToString());  
 | 
                    else if (m2.Success)  
 | 
                        newDeps.Add(m2.ToString());  
 | 
                    else if (m3.Success)  
 | 
                        newDeps.Add(m3.ToString());  
 | 
                    else if (m4.Success)  
 | 
                        newDeps.Add(m4.ToString());  
 | 
                    else  
 | 
                        newDeps.Add(lib);  
 | 
                }  
 | 
                // Remove Duplicates  
 | 
                var uniques = new Dictionary<string, int>();  
 | 
                foreach (var dep in newDeps)  
 | 
                    uniques[dep] = 1;  
 | 
                var uniqueList = new List<string>(uniques.Keys);  
 | 
                linkerWrapper.AdditionalDependencies = uniqueList;  
 | 
            }  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Deletes the file's directory if it is empty (not deleting the file itself so it must  
 | 
        /// have been deleted before) and every empty parent directory until the first, non-empty  
 | 
        /// directory is found.  
 | 
        /// </summary>  
 | 
        /// <param term='file'>Start point of the deletion</param>  
 | 
        public static void DeleteEmptyParentDirs(VCFile file)  
 | 
        {  
 | 
            var dir = file.FullPath.Remove(file.FullPath.LastIndexOf(Path.DirectorySeparatorChar));  
 | 
            DeleteEmptyParentDirs(dir);  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Deletes the directory if it is empty and every empty parent directory until the first,  
 | 
        /// non-empty directory is found.  
 | 
        /// </summary>  
 | 
        /// <param term='file'>Start point of the deletion</param>  
 | 
        public static void DeleteEmptyParentDirs(string directory)  
 | 
        {  
 | 
            var dirInfo = new DirectoryInfo(directory);  
 | 
            while (dirInfo.Exists && dirInfo.GetFileSystemInfos().Length == 0) {  
 | 
                var tmp = dirInfo;  
 | 
                dirInfo = dirInfo.Parent;  
 | 
                tmp.Delete();  
 | 
            }  
 | 
        }  
 | 
  
 | 
        public static bool HasQObjectDeclaration(VCFile file)  
 | 
        {  
 | 
            return CxxFileContainsNotCommented(file,  
 | 
                new[]  
 | 
                {  
 | 
                    "Q_OBJECT",  
 | 
                    "Q_GADGET",  
 | 
                    "Q_NAMESPACE"  
 | 
                },  
 | 
                StringComparison.Ordinal, true);  
 | 
        }  
 | 
  
 | 
        public static bool CxxFileContainsNotCommented(VCFile file, string str,  
 | 
            StringComparison comparisonType, bool suppressStrings)  
 | 
        {  
 | 
            return CxxFileContainsNotCommented(file, new[] { str }, comparisonType, suppressStrings);  
 | 
        }  
 | 
  
 | 
        public static bool CxxFileContainsNotCommented(VCFile file, string[] searchStrings,  
 | 
            StringComparison comparisonType, bool suppressStrings)  
 | 
        {  
 | 
            // Small optimization, we first read the whole content as a string and look for the  
 | 
            // search strings. Once we found at least one, ...  
 | 
            bool found = false;  
 | 
            var content = string.Empty;  
 | 
            try {  
 | 
                using (StreamReader sr = new StreamReader(file.FullPath))  
 | 
                    content = sr.ReadToEnd();  
 | 
  
 | 
                foreach (var key in searchStrings) {  
 | 
                    if (content.IndexOf(key, comparisonType) >= 0) {  
 | 
                        found = true;  
 | 
                        break;  
 | 
                    }  
 | 
                }  
 | 
            } catch { }  
 | 
  
 | 
            if (!found)  
 | 
                return false;  
 | 
  
 | 
            // ... we will start parsing the file again to see if the actual string is commented  
 | 
            // or not. The combination of string.IndexOf(...) and string.Split(...) seems to be  
 | 
            // way faster then reading the file line by line.  
 | 
            found = false;  
 | 
            CxxStreamReader cxxSr = null;  
 | 
            try {  
 | 
                cxxSr = new CxxStreamReader(content.Split(new[] { "\n", "\r\n" },  
 | 
                    StringSplitOptions.RemoveEmptyEntries));  
 | 
                string strLine;  
 | 
                while (!found && (strLine = cxxSr.ReadLine(suppressStrings)) != null) {  
 | 
                    foreach (var str in searchStrings) {  
 | 
                        if (strLine.IndexOf(str, comparisonType) != -1) {  
 | 
                            found = true;  
 | 
                            break;  
 | 
                        }  
 | 
                    }  
 | 
                }  
 | 
                cxxSr.Close();  
 | 
            } catch (Exception) {  
 | 
                if (cxxSr != null)  
 | 
                    cxxSr.Close();  
 | 
            }  
 | 
            return found;  
 | 
        }  
 | 
  
 | 
        public static void SetEnvironmentVariableEx(string environmentVariable, string variableValue)  
 | 
        {  
 | 
            try {  
 | 
                Environment.SetEnvironmentVariable(environmentVariable, variableValue);  
 | 
            } catch {  
 | 
                throw new QtVSException(SR.GetString("HelperFunctions_CannotWriteEnvQTDIR"));  
 | 
            }  
 | 
        }  
 | 
  
 | 
        public static string ChangePathFormat(string path)  
 | 
        {  
 | 
            return path.Replace('\\', '/');  
 | 
        }  
 | 
  
 | 
        public static string RemoveFileNameExtension(FileInfo fi)  
 | 
        {  
 | 
            var lastIndex = fi.Name.LastIndexOf(fi.Extension, StringComparison.Ordinal);  
 | 
            return fi.Name.Remove(lastIndex, fi.Extension.Length);  
 | 
        }  
 | 
  
 | 
        public static bool IsInFilter(VCFile vcfile, FakeFilter filter)  
 | 
        {  
 | 
            var item = (VCProjectItem)vcfile;  
 | 
  
 | 
            while ((item.Parent != null) && (item.Kind != "VCProject")) {  
 | 
                item = (VCProjectItem)item.Parent;  
 | 
  
 | 
                if (item.Kind == "VCFilter") {  
 | 
                    var f = (VCFilter)item;  
 | 
                    if (f.UniqueIdentifier != null  
 | 
                        && f.UniqueIdentifier.ToLower() == filter.UniqueIdentifier.ToLower())  
 | 
                        return true;  
 | 
                }  
 | 
            }  
 | 
            return false;  
 | 
        }  
 | 
  
 | 
        public static void CollapseFilter(UIHierarchyItem item, UIHierarchy hierarchy, string nodeToCollapseFilter)  
 | 
        {  
 | 
            if (string.IsNullOrEmpty(nodeToCollapseFilter))  
 | 
                return;  
 | 
  
 | 
            foreach (UIHierarchyItem innerItem in item.UIHierarchyItems) {  
 | 
                if (innerItem.Name == nodeToCollapseFilter)  
 | 
                    CollapseFilter(innerItem, hierarchy);  
 | 
                else if (innerItem.UIHierarchyItems.Count > 0)  
 | 
                    CollapseFilter(innerItem, hierarchy, nodeToCollapseFilter);  
 | 
            }  
 | 
        }  
 | 
  
 | 
        public static void CollapseFilter(UIHierarchyItem item, UIHierarchy hierarchy)  
 | 
        {  
 | 
            var subItems = item.UIHierarchyItems;  
 | 
            if (subItems != null) {  
 | 
                foreach (UIHierarchyItem innerItem in subItems) {  
 | 
                    if (innerItem.UIHierarchyItems.Count > 0) {  
 | 
                        CollapseFilter(innerItem, hierarchy);  
 | 
  
 | 
                        if (innerItem.UIHierarchyItems.Expanded) {  
 | 
                            innerItem.UIHierarchyItems.Expanded = false;  
 | 
                            if (innerItem.UIHierarchyItems.Expanded) {  
 | 
                                innerItem.Select(vsUISelectionType.vsUISelectionTypeSelect);  
 | 
                                hierarchy.DoDefaultAction();  
 | 
                            }  
 | 
                        }  
 | 
                    }  
 | 
                }  
 | 
            }  
 | 
            if (item.UIHierarchyItems.Expanded) {  
 | 
                item.UIHierarchyItems.Expanded = false;  
 | 
                if (item.UIHierarchyItems.Expanded) {  
 | 
                    item.Select(vsUISelectionType.vsUISelectionTypeSelect);  
 | 
                    hierarchy.DoDefaultAction();  
 | 
                }  
 | 
            }  
 | 
        }  
 | 
  
 | 
        // returns true if some exception occurs  
 | 
        public static bool IsGenerated(VCFile vcfile)  
 | 
        {  
 | 
            try {  
 | 
                return IsInFilter(vcfile, Filters.GeneratedFiles());  
 | 
            } catch (Exception e) {  
 | 
                MessageBox.Show(e.ToString());  
 | 
                return true;  
 | 
            }  
 | 
        }  
 | 
  
 | 
        // returns false if some exception occurs  
 | 
        public static bool IsResource(VCFile vcfile)  
 | 
        {  
 | 
            try {  
 | 
                return IsInFilter(vcfile, Filters.ResourceFiles());  
 | 
            } catch (Exception) {  
 | 
                return false;  
 | 
            }  
 | 
        }  
 | 
  
 | 
        public static List<string> GetProjectFiles(Project pro, FilesToList filter)  
 | 
        {  
 | 
            var fileList = new List<string>();  
 | 
  
 | 
            VCProject vcpro;  
 | 
            try {  
 | 
                vcpro = (VCProject)pro.Object;  
 | 
            } catch (Exception e) {  
 | 
                Messages.DisplayErrorMessage(e);  
 | 
                return null;  
 | 
            }  
 | 
  
 | 
            var configurationName = pro.ConfigurationManager.ActiveConfiguration.ConfigurationName;  
 | 
  
 | 
            foreach (VCFile vcfile in (IVCCollection)vcpro.Files) {  
 | 
                // Why project files are also returned?  
 | 
                if (vcfile.ItemName.EndsWith(".vcxproj.filters", StringComparison.Ordinal))  
 | 
                    continue;  
 | 
                var excluded = false;  
 | 
                var fileConfigurations = (IVCCollection)vcfile.FileConfigurations;  
 | 
                foreach (VCFileConfiguration config in fileConfigurations) {  
 | 
                    if (config.ExcludedFromBuild && config.MatchName(configurationName, false)) {  
 | 
                        excluded = true;  
 | 
                        break;  
 | 
                    }  
 | 
                }  
 | 
  
 | 
                if (excluded)  
 | 
                    continue;  
 | 
  
 | 
                // can be in any filter  
 | 
                if (IsTranslationFile(vcfile.Name) && (filter == FilesToList.FL_Translation))  
 | 
                    fileList.Add(ChangePathFormat(vcfile.RelativePath));  
 | 
  
 | 
                // can also be in any filter  
 | 
                if (IsWinRCFile(vcfile.Name) && (filter == FilesToList.FL_WinResource))  
 | 
                    fileList.Add(ChangePathFormat(vcfile.RelativePath));  
 | 
  
 | 
                if (IsGenerated(vcfile)) {  
 | 
                    if (filter == FilesToList.FL_Generated)  
 | 
                        fileList.Add(ChangePathFormat(vcfile.RelativePath));  
 | 
                    continue;  
 | 
                }  
 | 
  
 | 
                if (IsResource(vcfile)) {  
 | 
                    if (filter == FilesToList.FL_Resources)  
 | 
                        fileList.Add(ChangePathFormat(vcfile.RelativePath));  
 | 
                    continue;  
 | 
                }  
 | 
  
 | 
                switch (filter) {  
 | 
                case FilesToList.FL_UiFiles: // form files  
 | 
                    if (IsUicFile(vcfile.Name))  
 | 
                        fileList.Add(ChangePathFormat(vcfile.RelativePath));  
 | 
                    break;  
 | 
                case FilesToList.FL_HFiles:  
 | 
                    if (IsHeaderFile(vcfile.Name))  
 | 
                        fileList.Add(ChangePathFormat(vcfile.RelativePath));  
 | 
                    break;  
 | 
                case FilesToList.FL_CppFiles:  
 | 
                    if (IsSourceFile(vcfile.Name))  
 | 
                        fileList.Add(ChangePathFormat(vcfile.RelativePath));  
 | 
                    break;  
 | 
                case FilesToList.FL_QmlFiles:  
 | 
                    if (IsQmlFile(vcfile.Name))  
 | 
                        fileList.Add(ChangePathFormat(vcfile.RelativePath));  
 | 
                    break;  
 | 
                }  
 | 
            }  
 | 
  
 | 
            return fileList;  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Removes a file reference from the project and moves the file to the "Deleted" folder.  
 | 
        /// </summary>  
 | 
        /// <param name="vcpro"></param>  
 | 
        /// <param name="fileName"></param>  
 | 
        public static void RemoveFileInProject(VCProject vcpro, string fileName)  
 | 
        {  
 | 
            var qtProj = QtProject.Create(vcpro);  
 | 
            var fi = new FileInfo(fileName);  
 | 
  
 | 
            foreach (VCFile vcfile in (IVCCollection)vcpro.Files) {  
 | 
                if (vcfile.FullPath.ToLower() == fi.FullName.ToLower()) {  
 | 
                    vcpro.RemoveFile(vcfile);  
 | 
                    qtProj.MoveFileToDeletedFolder(vcfile);  
 | 
                }  
 | 
            }  
 | 
        }  
 | 
  
 | 
        public static Project GetSelectedProject(DTE dteObject)  
 | 
        {  
 | 
            if (dteObject == null)  
 | 
                return null;  
 | 
            Array prjs = null;  
 | 
            try {  
 | 
                prjs = (Array)dteObject.ActiveSolutionProjects;  
 | 
            } catch {  
 | 
                // When VS2010 is started from the command line,  
 | 
                // we may catch a "Unspecified error" here.  
 | 
            }  
 | 
            if (prjs == null || prjs.Length < 1)  
 | 
                return null;  
 | 
  
 | 
            // don't handle multiple selection... use the first one  
 | 
            if (prjs.GetValue(0) is Project)  
 | 
                return (Project)prjs.GetValue(0);  
 | 
            return null;  
 | 
        }  
 | 
  
 | 
        public static Project GetActiveDocumentProject(DTE dteObject)  
 | 
        {  
 | 
            if (dteObject == null)  
 | 
                return null;  
 | 
            var doc = dteObject.ActiveDocument;  
 | 
            if (doc == null)  
 | 
                return null;  
 | 
  
 | 
            if (doc.ProjectItem == null)  
 | 
                return null;  
 | 
  
 | 
            return doc.ProjectItem.ContainingProject;  
 | 
        }  
 | 
  
 | 
        public static Project GetSingleProjectInSolution(DTE dteObject)  
 | 
        {  
 | 
            var projectList = ProjectsInSolution(dteObject);  
 | 
            if (dteObject == null || dteObject.Solution == null ||  
 | 
                    projectList.Count != 1)  
 | 
                return null; // no way to know which one to select  
 | 
  
 | 
            return projectList[0];  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Returns the the current selected Qt Project. If not project  
 | 
        /// is selected or if the selected project is not a Qt project  
 | 
        /// this function returns null.  
 | 
        /// </summary>  
 | 
        public static Project GetSelectedQtProject(DTE dteObject)  
 | 
        {  
 | 
            // can happen sometimes shortly after starting VS  
 | 
            if (dteObject == null || dteObject.Solution == null  
 | 
                || ProjectsInSolution(dteObject).Count == 0)  
 | 
                return null;  
 | 
  
 | 
            Project pro;  
 | 
  
 | 
            if ((pro = GetSelectedProject(dteObject)) == null) {  
 | 
                if ((pro = GetSingleProjectInSolution(dteObject)) == null)  
 | 
                    pro = GetActiveDocumentProject(dteObject);  
 | 
            }  
 | 
            return IsQtProject(pro) ? pro : null;  
 | 
        }  
 | 
  
 | 
        public static VCFile[] GetSelectedFiles(DTE dteObject)  
 | 
        {  
 | 
            if (GetSelectedQtProject(dteObject) == null)  
 | 
                return null;  
 | 
  
 | 
            if (dteObject.SelectedItems.Count <= 0)  
 | 
                return null;  
 | 
  
 | 
            var items = dteObject.SelectedItems;  
 | 
  
 | 
            var files = new VCFile[items.Count + 1];  
 | 
            for (var i = 1; i <= items.Count; ++i) {  
 | 
                var item = items.Item(i);  
 | 
                if (item.ProjectItem == null)  
 | 
                    continue;  
 | 
  
 | 
                VCProjectItem vcitem;  
 | 
                try {  
 | 
                    vcitem = (VCProjectItem)item.ProjectItem.Object;  
 | 
                } catch (Exception) {  
 | 
                    return null;  
 | 
                }  
 | 
  
 | 
                if (vcitem.Kind == "VCFile")  
 | 
                    files[i - 1] = (VCFile)vcitem;  
 | 
            }  
 | 
            files[items.Count] = null;  
 | 
            return files;  
 | 
        }  
 | 
  
 | 
        public static Image GetSharedImage(string name)  
 | 
        {  
 | 
            Image image = null;  
 | 
            var a = Assembly.GetExecutingAssembly();  
 | 
            using (var imgStream = a.GetManifestResourceStream(name)) {  
 | 
                if (imgStream != null)  
 | 
                    image = Image.FromStream(imgStream);  
 | 
            }  
 | 
            return image;  
 | 
        }  
 | 
  
 | 
        public static RccOptions ParseRccOptions(string cmdLine, VCFile qrcFile)  
 | 
        {  
 | 
            var pro = VCProjectToProject((VCProject)qrcFile.project);  
 | 
  
 | 
            var rccOpts = new RccOptions(pro, qrcFile);  
 | 
  
 | 
            if (cmdLine.Length > 0) {  
 | 
                var cmdSplit = cmdLine.Split(' ', '\t');  
 | 
                for (var i = 0; i < cmdSplit.Length; ++i) {  
 | 
                    var lowercmdSplit = cmdSplit[i].ToLower();  
 | 
                    if (lowercmdSplit.Equals("-threshold")) {  
 | 
                        rccOpts.CompressFiles = true;  
 | 
                        rccOpts.CompressThreshold = int.Parse(cmdSplit[i + 1]);  
 | 
                    } else if (lowercmdSplit.Equals("-compress")) {  
 | 
                        rccOpts.CompressFiles = true;  
 | 
                        rccOpts.CompressLevel = int.Parse(cmdSplit[i + 1]);  
 | 
                    }  
 | 
                }  
 | 
            }  
 | 
            return rccOpts;  
 | 
        }  
 | 
  
 | 
        public static Project VCProjectToProject(VCProject vcproj)  
 | 
        {  
 | 
            return (Project)vcproj.Object;  
 | 
        }  
 | 
  
 | 
        public static List<Project> ProjectsInSolution(DTE dteObject)  
 | 
        {  
 | 
            var projects = new List<Project>();  
 | 
            var solution = dteObject.Solution;  
 | 
            if (solution != null) {  
 | 
                var c = solution.Count;  
 | 
                for (var i = 1; i <= c; ++i) {  
 | 
                    try {  
 | 
                        var prj = solution.Projects.Item(i);  
 | 
                        if (prj == null)  
 | 
                            continue;  
 | 
                        addSubProjects(prj, ref projects);  
 | 
                    } catch {  
 | 
                        // Ignore this exception... maybe the next project is ok.  
 | 
                        // This happens for example for Intel VTune projects.  
 | 
                    }  
 | 
                }  
 | 
            }  
 | 
            return projects;  
 | 
        }  
 | 
  
 | 
        private static void addSubProjects(Project prj, ref List<Project> projects)  
 | 
        {  
 | 
            // If the actual object of the project is null then the project was probably unloaded.  
 | 
            if (prj.Object == null)  
 | 
                return;  
 | 
  
 | 
            if (prj.ConfigurationManager != null &&  
 | 
                // Is this a Visual C++ project?  
 | 
                prj.Kind == "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") {  
 | 
                projects.Add(prj);  
 | 
            } else {  
 | 
                // In this case, prj is a solution folder  
 | 
                addSubProjects(prj.ProjectItems, ref projects);  
 | 
            }  
 | 
        }  
 | 
  
 | 
        private static void addSubProjects(ProjectItems subItems, ref List<Project> projects)  
 | 
        {  
 | 
            if (subItems == null)  
 | 
                return;  
 | 
  
 | 
            foreach (ProjectItem item in subItems) {  
 | 
                Project subprj = null;  
 | 
                try {  
 | 
                    subprj = item.SubProject;  
 | 
                } catch {  
 | 
                    // The property "SubProject" might not be implemented.  
 | 
                    // This is the case for Intel Fortran projects. (QTBUG-11567)  
 | 
                }  
 | 
                if (subprj != null)  
 | 
                    addSubProjects(subprj, ref projects);  
 | 
            }  
 | 
        }  
 | 
  
 | 
        public static int GetMaximumCommandLineLength()  
 | 
        {  
 | 
            var epsilon = 10;       // just to be sure :)  
 | 
            var os = Environment.OSVersion;  
 | 
            if (os.Version.Major >= 6 ||  
 | 
                (os.Version.Major == 5 && os.Version.Minor >= 1))  
 | 
                return 8191 - epsilon;    // Windows XP and above  
 | 
            return 2047 - epsilon;  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Translates the machine type given as command line argument to the linker  
 | 
        /// to the internal enum type VCProjectEngine.machineTypeOption.  
 | 
        /// </summary>  
 | 
        public static machineTypeOption TranslateMachineType(string cmdLineMachine)  
 | 
        {  
 | 
            switch (cmdLineMachine.ToUpper()) {  
 | 
            case "AM33":  
 | 
                return machineTypeOption.machineAM33;  
 | 
            case "X64":  
 | 
                return machineTypeOption.machineAMD64;  
 | 
            case "ARM":  
 | 
                return machineTypeOption.machineARM;  
 | 
            case "EBC":  
 | 
                return machineTypeOption.machineEBC;  
 | 
            case "IA-64":  
 | 
                return machineTypeOption.machineIA64;  
 | 
            case "M32R":  
 | 
                return machineTypeOption.machineM32R;  
 | 
            case "MIPS":  
 | 
                return machineTypeOption.machineMIPS;  
 | 
            case "MIPS16":  
 | 
                return machineTypeOption.machineMIPS16;  
 | 
            case "MIPSFPU":  
 | 
                return machineTypeOption.machineMIPSFPU;  
 | 
            case "MIPSFPU16":  
 | 
                return machineTypeOption.machineMIPSFPU16;  
 | 
            case "MIPS41XX":  
 | 
                return machineTypeOption.machineMIPSR41XX;  
 | 
            case "SH3":  
 | 
                return machineTypeOption.machineSH3;  
 | 
            case "SH3DSP":  
 | 
                return machineTypeOption.machineSH3DSP;  
 | 
            case "SH4":  
 | 
                return machineTypeOption.machineSH4;  
 | 
            case "SH5":  
 | 
                return machineTypeOption.machineSH5;  
 | 
            case "THUMB":  
 | 
                return machineTypeOption.machineTHUMB;  
 | 
            case "X86":  
 | 
                return machineTypeOption.machineX86;  
 | 
            default:  
 | 
                return machineTypeOption.machineNotSet;  
 | 
            }  
 | 
        }  
 | 
  
 | 
        public static bool ArraysEqual(Array array1, Array array2)  
 | 
        {  
 | 
            if (array1 == array2)  
 | 
                return true;  
 | 
  
 | 
            if (array1 == null || array2 == null)  
 | 
                return false;  
 | 
  
 | 
            if (array1.Length != array2.Length)  
 | 
                return false;  
 | 
  
 | 
            for (var i = 0; i < array1.Length; i++) {  
 | 
                if (!Equals(array1.GetValue(i), array2.GetValue(i)))  
 | 
                    return false;  
 | 
            }  
 | 
            return true;  
 | 
        }  
 | 
  
 | 
        public static string FindFileInPATH(string fileName)  
 | 
        {  
 | 
            var envPATH = Environment.ExpandEnvironmentVariables("%PATH%");  
 | 
            var directories = envPATH.Split(';');  
 | 
            foreach (var directory in directories) {  
 | 
                var fullFilePath = directory;  
 | 
                if (!fullFilePath.EndsWith("\\", StringComparison.Ordinal))  
 | 
                    fullFilePath += '\\';  
 | 
                fullFilePath += fileName;  
 | 
                if (File.Exists(fullFilePath))  
 | 
                    return fullFilePath;  
 | 
            }  
 | 
            return null;  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// This method copies the specified directory and all its child directories and files to  
 | 
        /// the specified destination. The destination directory is created if it does not exist.  
 | 
        /// </summary>  
 | 
        public static void CopyDirectory(string directory, string targetPath)  
 | 
        {  
 | 
            var sourceDir = new DirectoryInfo(directory);  
 | 
            if (!sourceDir.Exists)  
 | 
                return;  
 | 
  
 | 
            try {  
 | 
                if (!Directory.Exists(targetPath))  
 | 
                    Directory.CreateDirectory(targetPath);  
 | 
  
 | 
                var files = sourceDir.GetFiles();  
 | 
                foreach (var file in files) {  
 | 
                    try {  
 | 
                        file.CopyTo(Path.Combine(targetPath, file.Name), true);  
 | 
                    } catch { }  
 | 
                }  
 | 
            } catch { }  
 | 
  
 | 
            var subDirs = sourceDir.GetDirectories();  
 | 
            foreach (var subDir in subDirs)  
 | 
                CopyDirectory(subDir.FullName, Path.Combine(targetPath, subDir.Name));  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Performs an in-place expansion of MS Build properties in the form $(PropertyName)  
 | 
        /// and project item metadata in the form %(MetadataName).<para/>  
 | 
        /// Returns: 'true' if expansion was successful, 'false' otherwise<para/>  
 | 
        /// <paramref name="stringToExpand"/>: The string containing properties and/or metadata to  
 | 
        /// expand. This string is passed by ref and expansion is performed in-place.<para/>  
 | 
        /// <paramref name="project"/>: Current project.<para/>  
 | 
        /// <paramref name="configName"/>: Name of selected configuration (e.g. "Debug").<para/>  
 | 
        /// <paramref name="platformName"/>: Name of selected platform (e.g. "x64").<para/>  
 | 
        /// <paramref name="filePath"/>(optional): Evaluation context.<para/>  
 | 
        /// </summary>  
 | 
        public static bool ExpandString(  
 | 
            ref string stringToExpand,  
 | 
            EnvDTE.Project project,  
 | 
            string configName,  
 | 
            string platformName,  
 | 
            string filePath = null)  
 | 
        {  
 | 
            if (project == null  
 | 
                || string.IsNullOrEmpty(configName)  
 | 
                || string.IsNullOrEmpty(platformName))  
 | 
                return false;  
 | 
  
 | 
            var vcProject = project.Object as VCProject;  
 | 
  
 | 
            if (filePath == null) {  
 | 
                var vcConfig = (from VCConfiguration _config  
 | 
                                in (IVCCollection)vcProject.Configurations  
 | 
                                where _config.Name == configName + "|" + platformName  
 | 
                                select _config).FirstOrDefault();  
 | 
                return ExpandString(ref stringToExpand, vcConfig);  
 | 
            } else {  
 | 
                var vcFile = (from VCFile _file in (IVCCollection)vcProject.Files  
 | 
                              where _file.FullPath == filePath  
 | 
                              select _file).FirstOrDefault();  
 | 
                if (vcFile == null)  
 | 
                    return false;  
 | 
  
 | 
                var vcFileConfig = (from VCFileConfiguration _config  
 | 
                                    in (IVCCollection)vcFile.FileConfigurations  
 | 
                                    where _config.Name == configName + "|" + platformName  
 | 
                                    select _config).FirstOrDefault();  
 | 
                return ExpandString(ref stringToExpand, vcFileConfig);  
 | 
            }  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Performs an in-place expansion of MS Build properties in the form $(PropertyName)  
 | 
        /// and project item metadata in the form %(MetadataName).<para/>  
 | 
        /// Returns: 'true' if expansion was successful, 'false' otherwise<para/>  
 | 
        /// <paramref name="stringToExpand"/>: The string containing properties and/or metadata to  
 | 
        /// expand. This string is passed by ref and expansion is performed in-place.<para/>  
 | 
        /// <paramref name="config"/>: Either a VCConfiguration or VCFileConfiguration object to  
 | 
        /// use as provider of property expansion (through Evaluate()). Cannot be null.<para/>  
 | 
        /// </summary>  
 | 
        public static bool ExpandString(  
 | 
            ref string stringToExpand,  
 | 
            object config)  
 | 
        {  
 | 
            if (config == null)  
 | 
                return false;  
 | 
  
 | 
            /* try property expansion through VCConfiguration.Evaluate()  
 | 
             * or VCFileConfiguration.Evaluate() */  
 | 
            string expanded = stringToExpand;  
 | 
            VCProject vcProj = null;  
 | 
            VCFile vcFile = null;  
 | 
            string configName = "", platformName = "";  
 | 
            var vcConfig = config as VCConfiguration;  
 | 
            if (vcConfig != null) {  
 | 
                vcProj = vcConfig.project as VCProject;  
 | 
                configName = vcConfig.ConfigurationName;  
 | 
                var vcPlatform = vcConfig.Platform as VCPlatform;  
 | 
                if (vcPlatform != null)  
 | 
                    platformName = vcPlatform.Name;  
 | 
                try {  
 | 
                    expanded = vcConfig.Evaluate(expanded);  
 | 
                } catch { }  
 | 
            } else {  
 | 
                var vcFileConfig = config as VCFileConfiguration;  
 | 
                if (vcFileConfig == null)  
 | 
                    return false;  
 | 
                vcFile = vcFileConfig.File as VCFile;  
 | 
                if (vcFile != null)  
 | 
                    vcProj = vcFile.project as VCProject;  
 | 
                var vcProjConfig = vcFileConfig.ProjectConfiguration as VCConfiguration;  
 | 
                if (vcProjConfig != null) {  
 | 
                    configName = vcProjConfig.ConfigurationName;  
 | 
                    var vcPlatform = vcProjConfig.Platform as VCPlatform;  
 | 
                    if (vcPlatform != null)  
 | 
                        platformName = vcPlatform.Name;  
 | 
                }  
 | 
                try {  
 | 
                    expanded = vcFileConfig.Evaluate(expanded);  
 | 
                } catch { }  
 | 
            }  
 | 
  
 | 
            /* fail-safe */  
 | 
            foreach (Match propNameMatch in Regex.Matches(expanded, @"\$\(([^\)]+)\)")) {  
 | 
                string propName = propNameMatch.Groups[1].Value;  
 | 
                string propValue = "";  
 | 
                switch (propName) {  
 | 
                case "Configuration":  
 | 
                case "ConfigurationName":  
 | 
                    if (string.IsNullOrEmpty(configName))  
 | 
                        return false;  
 | 
                    propValue = configName;  
 | 
                    break;  
 | 
                case "Platform":  
 | 
                case "PlatformName":  
 | 
                    if (string.IsNullOrEmpty(platformName))  
 | 
                        return false;  
 | 
                    propValue = platformName;  
 | 
                    break;  
 | 
                default:  
 | 
                    return false;  
 | 
                }  
 | 
                expanded = expanded.Replace(string.Format("$({0})", propName), propValue);  
 | 
            }  
 | 
  
 | 
            /* because item metadata is not expanded in Evaluate() */  
 | 
            foreach (Match metaNameMatch in Regex.Matches(expanded, @"\%\(([^\)]+)\)")) {  
 | 
                string metaName = metaNameMatch.Groups[1].Value;  
 | 
                string metaValue = "";  
 | 
                switch (metaName) {  
 | 
                case "FullPath":  
 | 
                    if (vcFile == null)  
 | 
                        return false;  
 | 
                    metaValue = vcFile.FullPath;  
 | 
                    break;  
 | 
                case "RootDir":  
 | 
                    if (vcFile == null)  
 | 
                        return false;  
 | 
                    metaValue = Path.GetPathRoot(vcFile.FullPath);  
 | 
                    break;  
 | 
                case "Filename":  
 | 
                    if (vcFile == null)  
 | 
                        return false;  
 | 
                    metaValue = Path.GetFileNameWithoutExtension(vcFile.FullPath);  
 | 
                    break;  
 | 
                case "Extension":  
 | 
                    if (vcFile == null)  
 | 
                        return false;  
 | 
                    metaValue = Path.GetExtension(vcFile.FullPath);  
 | 
                    break;  
 | 
                case "RelativeDir":  
 | 
                    if (vcProj == null || vcFile == null)  
 | 
                        return false;  
 | 
                    metaValue = Path.GetDirectoryName(GetRelativePath(  
 | 
                        Path.GetDirectoryName(vcProj.ProjectFile),  
 | 
                        vcFile.FullPath));  
 | 
                    if (!metaValue.EndsWith("\\"))  
 | 
                        metaValue += "\\";  
 | 
                    if (metaValue.StartsWith(".\\"))  
 | 
                        metaValue = metaValue.Substring(2);  
 | 
                    break;  
 | 
                case "Directory":  
 | 
                    if (vcFile == null)  
 | 
                        return false;  
 | 
                    metaValue = Path.GetDirectoryName(GetRelativePath(  
 | 
                        Path.GetPathRoot(vcFile.FullPath),  
 | 
                        vcFile.FullPath));  
 | 
                    if (!metaValue.EndsWith("\\"))  
 | 
                        metaValue += "\\";  
 | 
                    if (metaValue.StartsWith(".\\"))  
 | 
                        metaValue = metaValue.Substring(2);  
 | 
                    break;  
 | 
                case "Identity":  
 | 
                    if (vcProj == null || vcFile == null)  
 | 
                        return false;  
 | 
                    metaValue = GetRelativePath(  
 | 
                        Path.GetDirectoryName(vcProj.ProjectFile),  
 | 
                        vcFile.FullPath);  
 | 
                    if (metaValue.StartsWith(".\\"))  
 | 
                        metaValue = metaValue.Substring(2);  
 | 
                    break;  
 | 
                case "RecursiveDir":  
 | 
                case "ModifiedTime":  
 | 
                case "CreatedTime":  
 | 
                case "AccessedTime":  
 | 
                    return false;  
 | 
                default:  
 | 
                    var vcFileConfig = config as VCFileConfiguration;  
 | 
                    if (vcFileConfig == null)  
 | 
                        return false;  
 | 
                    var propStoreTool = vcFileConfig.Tool as IVCRulePropertyStorage;  
 | 
                    if (propStoreTool == null)  
 | 
                        return false;  
 | 
                    try {  
 | 
                        metaValue = propStoreTool.GetEvaluatedPropertyValue(metaName);  
 | 
                    } catch {  
 | 
                        return false;  
 | 
                    }  
 | 
                    break;  
 | 
                }  
 | 
                expanded = expanded.Replace(string.Format("%({0})", metaName), metaValue);  
 | 
            }  
 | 
  
 | 
            stringToExpand = expanded;  
 | 
            return true;  
 | 
        }  
 | 
  
 | 
        private static string GetRegistrySoftwareString(string subKeyName, string valueName)  
 | 
        {  
 | 
            var keyName = new StringBuilder();  
 | 
            keyName.Append(@"SOFTWARE\");  
 | 
            if (System.Environment.Is64BitOperatingSystem && IntPtr.Size == 4)  
 | 
                keyName.Append(@"WOW6432Node\");  
 | 
            keyName.Append(subKeyName);  
 | 
  
 | 
            try {  
 | 
                using (var key = Registry.LocalMachine.OpenSubKey(keyName.ToString(), false)) {  
 | 
                    if (key == null)  
 | 
                        return ""; //key not found  
 | 
  
 | 
                    RegistryValueKind valueKind = key.GetValueKind(valueName);  
 | 
                    if (valueKind != RegistryValueKind.String  
 | 
                        && valueKind != RegistryValueKind.ExpandString) {  
 | 
                        return ""; //wrong value kind  
 | 
                    }  
 | 
  
 | 
                    Object objValue = key.GetValue(valueName);  
 | 
                    if (objValue == null)  
 | 
                        return ""; //error getting value  
 | 
  
 | 
                    return objValue.ToString();  
 | 
                }  
 | 
            } catch {  
 | 
                return "";  
 | 
            }  
 | 
        }  
 | 
  
 | 
        public static string GetWindows10SDKVersion()  
 | 
        {  
 | 
#if VS2019 || VS2022  
 | 
            // In Visual Studio 2019: WindowsTargetPlatformVersion=10.0  
 | 
            // will be treated as "use latest installed Windows 10 SDK".  
 | 
            // https://developercommunity.visualstudio.com/comments/407752/view.html  
 | 
            return "10.0";  
 | 
#else  
 | 
            string versionWin10SDK = HelperFunctions.GetRegistrySoftwareString(  
 | 
                @"Microsoft\Microsoft SDKs\Windows\v10.0", "ProductVersion");  
 | 
            if (string.IsNullOrEmpty(versionWin10SDK))  
 | 
                return versionWin10SDK;  
 | 
            while (versionWin10SDK.Split(new char[] { '.' }).Length < 4)  
 | 
                versionWin10SDK = versionWin10SDK + ".0";  
 | 
            return versionWin10SDK;  
 | 
#endif  
 | 
        }  
 | 
  
 | 
        static string _VCPath;  
 | 
        public static string VCPath  
 | 
        {  
 | 
            set { _VCPath = value; }  
 | 
            get  
 | 
            {  
 | 
                if (!string.IsNullOrEmpty(_VCPath))  
 | 
                    return _VCPath;  
 | 
                else  
 | 
                    return GetVCPathFromRegistry();  
 | 
            }  
 | 
        }  
 | 
  
 | 
        private static string GetVCPathFromRegistry()  
 | 
        {  
 | 
#if VS2022  
 | 
            Debug.Assert(false, "VCPath for VS2022 is not available through the registry");  
 | 
            string vcPath = string.Empty;  
 | 
#elif VS2019  
 | 
            Debug.Assert(false, "VCPath for VS2019 is not available through the registry");  
 | 
            string vcPath = string.Empty;  
 | 
#elif VS2017  
 | 
            string vsPath = GetRegistrySoftwareString(@"Microsoft\VisualStudio\SxS\VS7", "15.0");  
 | 
            if (string.IsNullOrEmpty(vsPath))  
 | 
                return "";  
 | 
            string vcPath = Path.Combine(vsPath, "VC");  
 | 
#endif  
 | 
            return vcPath;  
 | 
        }  
 | 
  
 | 
        public static bool SetVCVars(ProcessStartInfo startInfo)  
 | 
        {  
 | 
            return SetVCVars(null, startInfo);  
 | 
        }  
 | 
  
 | 
        public static bool SetVCVars(VersionInformation VersionInfo, ProcessStartInfo startInfo)  
 | 
        {  
 | 
            if (VersionInfo == null) {  
 | 
                VersionInfo = QtVersionManager.The().GetVersionInfo(  
 | 
                    QtVersionManager.The().GetDefaultVersion());  
 | 
            }  
 | 
            bool isOS64Bit = System.Environment.Is64BitOperatingSystem;  
 | 
            bool isQt64Bit = VersionInfo.is64Bit();  
 | 
  
 | 
            string vcPath = VCPath;  
 | 
            if (vcPath == "")  
 | 
                return false;  
 | 
  
 | 
            string comspecPath = Environment.GetEnvironmentVariable("COMSPEC");  
 | 
            string vcVarsCmd = "";  
 | 
            string vcVarsArg = "";  
 | 
            if (isOS64Bit && isQt64Bit)  
 | 
                vcVarsCmd = Path.Combine(vcPath, @"Auxiliary\Build\vcvars64.bat");  
 | 
            else if (!isOS64Bit && !isQt64Bit)  
 | 
                vcVarsCmd = Path.Combine(vcPath, @"Auxiliary\Build\vcvars32.bat");  
 | 
            else if (isOS64Bit && !isQt64Bit)  
 | 
                vcVarsCmd = Path.Combine(vcPath, @"Auxiliary\Build\vcvarsamd64_x86.bat");  
 | 
            else if (!isOS64Bit && isQt64Bit)  
 | 
                vcVarsCmd = Path.Combine(vcPath, @"Auxiliary\Build\vcvarsx86_amd64.bat");  
 | 
  
 | 
            Messages.Print($"vcvars: {vcVarsCmd}");  
 | 
  
 | 
            const string markSTX = ":@:@:@";  
 | 
            const string markEOL = ":#:#:#";  
 | 
            string command =  
 | 
                string.Format("/c \"{0}\" {1} && echo {2} && set", vcVarsCmd, vcVarsArg, markSTX);  
 | 
            var vcVarsStartInfo = new ProcessStartInfo(comspecPath, command);  
 | 
            vcVarsStartInfo.CreateNoWindow = true;  
 | 
            vcVarsStartInfo.UseShellExecute = false;  
 | 
            vcVarsStartInfo.RedirectStandardError = true;  
 | 
            vcVarsStartInfo.RedirectStandardOutput = true;  
 | 
  
 | 
            var process = Process.Start(vcVarsStartInfo);  
 | 
            StringBuilder stdOut = new StringBuilder();  
 | 
  
 | 
            process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>  
 | 
                stdOut.AppendFormat("{0}\n{1}\n", e.Data, markEOL);  
 | 
            process.BeginOutputReadLine();  
 | 
  
 | 
            process.WaitForExit();  
 | 
            bool ok = (process.ExitCode == 0);  
 | 
            process.Close();  
 | 
            if (!ok)  
 | 
                return false;  
 | 
  
 | 
            SortedDictionary<string, List<string>> vcVars =  
 | 
                new SortedDictionary<string, List<string>>();  
 | 
            string[] split =  
 | 
                stdOut.ToString().Split(new string[] { "\n", "=", ";" }, StringSplitOptions.None);  
 | 
            int i = 0;  
 | 
            for (; i < split.Length && split[i].Trim() != markSTX; i++) {  
 | 
                //Skip to start of data  
 | 
            }  
 | 
            i++; //Advance to next item  
 | 
            for (; i < split.Length && split[i].Trim() != markEOL; i++) {  
 | 
                //Skip to end of line  
 | 
            }  
 | 
            i++; //Advance to next item  
 | 
            for (; i < split.Length; i++) {  
 | 
                //Process first item (variable name)  
 | 
                string key = split[i].ToUpper().Trim();  
 | 
                i++; //Advance to next item  
 | 
                List<string> vcVarValue = vcVars[key] = new List<string>();  
 | 
                for (; i < split.Length && split[i].Trim() != markEOL; i++) {  
 | 
                    //Process items up to end of line (variable value(s))  
 | 
                    vcVarValue.Add(split[i].Trim());  
 | 
                }  
 | 
            }  
 | 
  
 | 
            foreach (var vcVar in vcVars) {  
 | 
                if (vcVar.Value.Count == 1) {  
 | 
                    startInfo.EnvironmentVariables[vcVar.Key] = vcVar.Value[0];  
 | 
                } else {  
 | 
                    if (!startInfo.EnvironmentVariables.ContainsKey(vcVar.Key)) {  
 | 
                        foreach (var vcVarValue in vcVar.Value) {  
 | 
                            if (!string.IsNullOrWhiteSpace(vcVarValue)) {  
 | 
                                startInfo.EnvironmentVariables[vcVar.Key] += vcVarValue + ";";  
 | 
                            }  
 | 
                        }  
 | 
                    } else {  
 | 
                        string[] startInfoVariableValues = startInfo.EnvironmentVariables[vcVar.Key]  
 | 
                            .Split(new string[] { ";" }, StringSplitOptions.None);  
 | 
                        foreach (var vcVarValue in vcVar.Value) {  
 | 
                            if (!string.IsNullOrWhiteSpace(vcVarValue)  
 | 
                                && !startInfoVariableValues.Any(s => s.Trim().Equals(  
 | 
                                    vcVarValue,  
 | 
                                    StringComparison.OrdinalIgnoreCase))) {  
 | 
                                if (!startInfo.EnvironmentVariables[vcVar.Key].EndsWith(";"))  
 | 
                                    startInfo.EnvironmentVariables[vcVar.Key] += ";";  
 | 
                                startInfo.EnvironmentVariables[vcVar.Key] += vcVarValue + ";";  
 | 
                            }  
 | 
                        }  
 | 
                    }  
 | 
                }  
 | 
            }  
 | 
            string envPath = startInfo.EnvironmentVariables["PATH"];  
 | 
            string clPath = envPath.Split(';')  
 | 
                .Select(path => Path.Combine(path, "cl.exe"))  
 | 
                .Where(pathToCl => File.Exists(pathToCl))  
 | 
                .FirstOrDefault();  
 | 
            Messages.Print($"cl: {clPath ?? "NOT FOUND"}");  
 | 
  
 | 
            return true;  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// Rooted canonical path is the absolute path for the specified path string  
 | 
        /// (cf. Path.GetFullPath()) without a trailing path separator.  
 | 
        /// </summary>  
 | 
        static string RootedCanonicalPath(string path)  
 | 
        {  
 | 
            try {  
 | 
                return Path  
 | 
                .GetFullPath(path)  
 | 
                .TrimEnd(new char[] {  
 | 
                    Path.DirectorySeparatorChar,  
 | 
                    Path.AltDirectorySeparatorChar  
 | 
                });  
 | 
            } catch {  
 | 
                return "";  
 | 
            }  
 | 
        }  
 | 
  
 | 
        /// <summary>  
 | 
        /// If the given path is relative and a sub-path of the current directory, returns  
 | 
        /// a "relative canonical path", containing only the steps beyond the current directory.  
 | 
        /// Otherwise, returns the absolute ("rooted") canonical path.  
 | 
        /// </summary>  
 | 
        public static string CanonicalPath(string path)  
 | 
        {  
 | 
            string canonicalPath = RootedCanonicalPath(path);  
 | 
            if (!Path.IsPathRooted(path)) {  
 | 
                string currentCanonical = RootedCanonicalPath(".");  
 | 
                if (canonicalPath.StartsWith(currentCanonical,  
 | 
                    StringComparison.InvariantCultureIgnoreCase)) {  
 | 
                    return canonicalPath  
 | 
                    .Substring(currentCanonical.Length)  
 | 
                    .TrimStart(new char[] {  
 | 
                        Path.DirectorySeparatorChar,  
 | 
                        Path.AltDirectorySeparatorChar  
 | 
                    });  
 | 
                } else {  
 | 
                    return canonicalPath;  
 | 
                }  
 | 
            } else {  
 | 
                return canonicalPath;  
 | 
            }  
 | 
        }  
 | 
  
 | 
        public static bool PathEquals(string path1, string path2)  
 | 
        {  
 | 
            return (CanonicalPath(path1).Equals(CanonicalPath(path2),  
 | 
                StringComparison.InvariantCultureIgnoreCase));  
 | 
        }  
 | 
  
 | 
        public static bool PathIsRelativeTo(string path, string subPath)  
 | 
        {  
 | 
            return CanonicalPath(path).EndsWith(CanonicalPath(subPath),  
 | 
                StringComparison.InvariantCultureIgnoreCase);  
 | 
        }  
 | 
  
 | 
        public static string Unquote(string text)  
 | 
        {  
 | 
            text = text.Trim();  
 | 
            if (string.IsNullOrEmpty(text)  
 | 
                || text.Length < 3  
 | 
                || !text.StartsWith("\"")  
 | 
                || !text.EndsWith("\"")) {  
 | 
                return text;  
 | 
            }  
 | 
            return text.Substring(1, text.Length - 2);  
 | 
        }  
 | 
  
 | 
        public static string NewProjectGuid()  
 | 
        {  
 | 
            return string.Format("{{{0}}}", Guid.NewGuid().ToString().ToUpper());  
 | 
        }  
 | 
  
 | 
        public static string SafePath(string path)  
 | 
        {  
 | 
            if (string.IsNullOrEmpty(path))  
 | 
                return null;  
 | 
            path = path.Replace("\"", "");  
 | 
            if (!path.Contains(' '))  
 | 
                return path;  
 | 
            if (path.EndsWith("\\"))  
 | 
                path += "\\";  
 | 
            return string.Format("\"{0}\"", path);  
 | 
        }  
 | 
    }  
 | 
}  
 |