| | |
| | | /****************************************************************************
|
| | | **
|
| | | ** Copyright (C) 2016 The Qt Company Ltd.
|
| | | ** Copyright (C) 2022 The Qt Company Ltd.
|
| | | ** Contact: https://www.qt.io/licensing/
|
| | | **
|
| | | ** This file is part of the Qt VS Tools.
|
| | |
| | | **
|
| | | ****************************************************************************/
|
| | |
|
| | | using EnvDTE;
|
| | | using Microsoft.VisualStudio.VCProjectEngine;
|
| | | using Microsoft.Win32;
|
| | | using QtVsTools.Core.QtMsBuild;
|
| | | using System;
|
| | | using System.Collections.Generic;
|
| | | using System.Diagnostics;
|
| | |
| | | using System.Text;
|
| | | using System.Text.RegularExpressions;
|
| | | using System.Windows.Forms;
|
| | | using Microsoft.VisualStudio.Shell;
|
| | | using Microsoft.VisualStudio.VCProjectEngine;
|
| | | #if VS2017
|
| | | using Microsoft.Win32;
|
| | | #endif
|
| | | using EnvDTE;
|
| | |
|
| | | using Process = System.Diagnostics.Process;
|
| | |
|
| | | namespace QtVsTools.Core
|
| | | {
|
| | | using QtMsBuild;
|
| | |
|
| | | 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)
|
| | | public static 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)
|
| | | public static bool IsHeaderFile(string fileName)
|
| | | {
|
| | | return _headers.Contains(Path.GetExtension(fileName));
|
| | | }
|
| | |
| | | return ".qml".Equals(Path.GetExtension(fileName), StringComparison.OrdinalIgnoreCase);
|
| | | }
|
| | |
|
| | | static public void SetDebuggingEnvironment(Project prj)
|
| | | public static void SetDebuggingEnvironment(Project prj)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | | SetDebuggingEnvironment(prj, string.Empty);
|
| | | }
|
| | |
|
| | | static public void SetDebuggingEnvironment(Project prj, string solutionConfig)
|
| | | public static void SetDebuggingEnvironment(Project prj, string solutionConfig)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | | SetDebuggingEnvironment(prj, "PATH=$(QTDIR)\\bin;$(PATH)", false, solutionConfig);
|
| | | }
|
| | |
|
| | | static public void SetDebuggingEnvironment(Project prj, string envpath, bool overwrite)
|
| | | public static void SetDebuggingEnvironment(Project prj, string envpath, bool overwrite)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | | SetDebuggingEnvironment(prj, envpath, overwrite, string.Empty);
|
| | | }
|
| | |
|
| | | static public void SetDebuggingEnvironment(Project prj, string envpath, bool overwrite, string solutionConfig)
|
| | | public static void SetDebuggingEnvironment(Project prj, string envpath, bool overwrite, string solutionConfig)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | if (QtProject.GetFormatVersion(prj) >= Resources.qtMinFormatVersion_Settings)
|
| | | return;
|
| | |
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | public static bool IsProjectInSolution(DTE dteObject, string fullName)
|
| | | public static Project ProjectFromSolution(DTE dteObject, string fullName)
|
| | | {
|
| | | var fi = new FileInfo(fullName);
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | fullName = new FileInfo(fullName).FullName;
|
| | | foreach (var p in ProjectsInSolution(dteObject)) {
|
| | | if (p.FullName.ToLower() == fi.FullName.ToLower())
|
| | | return true;
|
| | | if (p.FullName.Equals(fullName, StringComparison.OrdinalIgnoreCase))
|
| | | return p;
|
| | | }
|
| | | return false;
|
| | | return null;
|
| | | }
|
| | |
|
| | | /// <summary>
|
| | | /// Returns the normalized file path of a given file.
|
| | | /// </summary>
|
| | | /// <param name="name">file name</param>
|
| | | static public string NormalizeFilePath(string name)
|
| | | public static string NormalizeFilePath(string name)
|
| | | {
|
| | | var fi = new FileInfo(name);
|
| | | return fi.FullName;
|
| | | }
|
| | |
|
| | | static public string NormalizeRelativeFilePath(string path)
|
| | | public static string NormalizeRelativeFilePath(string path)
|
| | | {
|
| | | if (path == null)
|
| | | return ".\\";
|
| | |
| | | return path;
|
| | | }
|
| | |
|
| | | static public bool IsAbsoluteFilePath(string path)
|
| | | public static bool IsAbsoluteFilePath(string path)
|
| | | {
|
| | | path = path.Trim();
|
| | | if (path.Length >= 2 && path[1] == ':')
|
| | |
| | | /// </summary>
|
| | | /// <param name="streamReader"></param>
|
| | | /// <returns>the composite string</returns>
|
| | | static private string ReadProFileLine(StreamReader streamReader)
|
| | | private static string ReadProFileLine(StreamReader streamReader)
|
| | | {
|
| | | var line = streamReader.ReadLine();
|
| | | if (line == null)
|
| | |
| | | /// </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)
|
| | | public static bool IsSubDirsFile(string profile)
|
| | | {
|
| | | StreamReader sr = null;
|
| | | try {
|
| | |
| | | }
|
| | |
|
| | | /// <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.
|
| | |
| | | /// </summary>
|
| | | /// <param name="config">File configuration</param>
|
| | | /// <returns></returns>
|
| | | static public VCCustomBuildTool GetCustomBuildTool(VCFileConfiguration config)
|
| | | public static 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;
|
| | | if (config.File is VCFile file
|
| | | && file.ItemType == "CustomBuild"
|
| | | && config.Tool is VCCustomBuildTool tool) {
|
| | | try {
|
| | | _ = tool.CommandLine;
|
| | | } catch {
|
| | | return null;
|
| | | }
|
| | | return tool;
|
| | | }
|
| | | return tool;
|
| | | return null;
|
| | | }
|
| | |
|
| | | /// <summary>
|
| | |
| | | /// has to be "CustomBuild"
|
| | | /// </summary>
|
| | | /// <param name="projectItem">Project Item which needs to have custom build tool</param>
|
| | | static public void EnsureCustomBuildToolAvailable(ProjectItem projectItem)
|
| | | public static void EnsureCustomBuildToolAvailable(ProjectItem projectItem)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | foreach (Property prop in projectItem.Properties) {
|
| | | if (prop.Name == "ItemType") {
|
| | | if ((string)prop.Value != "CustomBuild")
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | /// <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)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | var vcProject = project.Object as VCProject;
|
| | | if (vcProject == null)
|
| | | return null;
|
| | |
| | | }
|
| | |
|
| | | /// <summary>
|
| | | /// Return true if the project is a Qt project, otherwise false.
|
| | | /// Return true if the project is a VS tools project; false otherwise.
|
| | | /// </summary>
|
| | | /// <param name="proj">project</param>
|
| | | /// <returns></returns>
|
| | | public static bool IsQtProject(VCProject proj)
|
| | | public static bool IsVsToolsProject(Project proj)
|
| | | {
|
| | | if (!IsQMakeProject(proj))
|
| | | ThreadHelper.ThrowIfNotOnUIThread(); // C++ Project Type GUID
|
| | | if (proj == null || proj.Kind != "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}")
|
| | | return false;
|
| | | return IsVsToolsProject(proj.Object as VCProject);
|
| | | }
|
| | |
|
| | | /// <summary>
|
| | | /// Return true if the project is a VS tools project; false otherwise.
|
| | | /// </summary>
|
| | | /// <param name="proj">project</param>
|
| | | public static bool IsVsToolsProject(VCProject proj)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | | if (!IsQtProject(proj))
|
| | | return false;
|
| | |
|
| | | if (QtProject.GetFormatVersion(proj) >= Resources.qtMinFormatVersion_Settings)
|
| | |
| | | return false;
|
| | |
|
| | | foreach (var global in envPro.Globals.VariableNames as string[]) {
|
| | | if (global.StartsWith("Qt5Version", StringComparison.Ordinal) && envPro.Globals.get_VariablePersists(global))
|
| | | 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.
|
| | | /// Return true if the project is a Qt project; false otherwise.
|
| | | /// </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;
|
| | | ThreadHelper.ThrowIfNotOnUIThread(); //C++ Project Type GUID
|
| | | if (proj == null || proj.Kind != "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}")
|
| | | return false;
|
| | | return IsQtProject(proj.Object as VCProject);
|
| | | }
|
| | |
|
| | | /// <summary>
|
| | | /// Return true if the project is a QMake -tp vc project, otherwise false.
|
| | | /// Return true if the project is a Qt project; false otherwise.
|
| | | /// </summary>
|
| | | /// <param name="proj">project</param>
|
| | | /// <returns></returns>
|
| | | public static bool IsQMakeProject(VCProject proj)
|
| | | public static bool IsQtProject(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))) {
|
| | | if (string.IsNullOrEmpty(keyword))
|
| | | 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;
|
| | | }
|
| | | return keyword.StartsWith(Resources.qtProjectKeyword, StringComparison.Ordinal)
|
| | | || keyword.StartsWith(Resources.qtProjectV2Keyword, StringComparison.Ordinal);
|
| | | }
|
| | |
|
| | | /// <summary>
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | /// <summary>
|
| | | /// Converts all directory separators of the path to the alternate character
|
| | | /// directory separator. For instance, FromNativeSeparators("c:\\winnt\\system32")
|
| | | /// returns "c:/winnt/system32".
|
| | | /// </summary>
|
| | | /// <param name="path">The path to convert.</param>
|
| | | /// <returns>Returns path using '/' as file separator.</returns>
|
| | | public static string FromNativeSeparators(string path)
|
| | | {
|
| | | return path.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
| | | }
|
| | |
|
| | | /// <summary>
|
| | | /// Converts all alternate directory separators characters of the path to the native
|
| | | /// directory separator. For instance, ToNativeSeparators("c:/winnt/system32")
|
| | | /// returns "c:\\winnt\\system32".
|
| | | /// </summary>
|
| | | /// <param name="path">The path to convert.</param>
|
| | | /// <returns>Returns path using '\' as file separator.</returns>
|
| | | public static string ToNativeSeparator(string path)
|
| | | {
|
| | | return path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
| | | }
|
| | |
|
| | | public static string ChangePathFormat(string path)
|
| | | {
|
| | | return path.Replace('\\', '/');
|
| | |
| | |
|
| | | public static void CollapseFilter(UIHierarchyItem item, UIHierarchy hierarchy, string nodeToCollapseFilter)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | if (string.IsNullOrEmpty(nodeToCollapseFilter))
|
| | | return;
|
| | |
|
| | |
| | |
|
| | | public static void CollapseFilter(UIHierarchyItem item, UIHierarchy hierarchy)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | var subItems = item.UIHierarchyItems;
|
| | | if (subItems != null) {
|
| | | foreach (UIHierarchyItem innerItem in subItems) {
|
| | |
| | |
|
| | | public static List<string> GetProjectFiles(Project pro, FilesToList filter)
|
| | | {
|
| | | var fileList = new List<string>();
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | VCProject vcpro;
|
| | | try {
|
| | |
| | | return null;
|
| | | }
|
| | |
|
| | | var fileList = new List<string>();
|
| | | var configurationName = pro.ConfigurationManager.ActiveConfiguration.ConfigurationName;
|
| | |
|
| | | foreach (VCFile vcfile in (IVCCollection)vcpro.Files) {
|
| | |
| | | /// <param name="fileName"></param>
|
| | | public static void RemoveFileInProject(VCProject vcpro, string fileName)
|
| | | {
|
| | | var qtProj = QtProject.Create(vcpro);
|
| | | var fi = new FileInfo(fileName);
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | fileName = new FileInfo(fileName).FullName;
|
| | | foreach (VCFile vcfile in (IVCCollection)vcpro.Files) {
|
| | | if (vcfile.FullPath.ToLower() == fi.FullName.ToLower()) {
|
| | | if (vcfile.FullPath.Equals(fileName, StringComparison.OrdinalIgnoreCase)) {
|
| | | vcpro.RemoveFile(vcfile);
|
| | | qtProj.MoveFileToDeletedFolder(vcfile);
|
| | | QtProject.Create(vcpro)?.MoveFileToDeletedFolder(vcfile);
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | public static Project GetSelectedProject(DTE dteObject)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | if (dteObject == null)
|
| | | return null;
|
| | |
|
| | | Array prjs = null;
|
| | | try {
|
| | | prjs = (Array)dteObject.ActiveSolutionProjects;
|
| | |
| | | return null;
|
| | |
|
| | | // don't handle multiple selection... use the first one
|
| | | if (prjs.GetValue(0) is Project)
|
| | | return (Project)prjs.GetValue(0);
|
| | | if (prjs.GetValue(0) is Project project)
|
| | | return project;
|
| | | 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;
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | | return dteObject?.ActiveDocument?.ProjectItem?.ContainingProject;
|
| | | }
|
| | |
|
| | | public static Project GetSingleProjectInSolution(DTE dteObject)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | var projectList = ProjectsInSolution(dteObject);
|
| | | if (dteObject == null || dteObject.Solution == null ||
|
| | | projectList.Count != 1)
|
| | | if (projectList.Count != 1)
|
| | | return null; // no way to know which one to select
|
| | |
|
| | | return projectList[0];
|
| | |
| | | /// </summary>
|
| | | public static Project GetSelectedQtProject(DTE dteObject)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | // can happen sometimes shortly after starting VS
|
| | | if (dteObject == null || dteObject.Solution == null
|
| | | || ProjectsInSolution(dteObject).Count == 0)
|
| | | if (ProjectsInSolution(dteObject).Count == 0)
|
| | | return null;
|
| | |
|
| | | Project pro;
|
| | |
|
| | | if ((pro = GetSelectedProject(dteObject)) == null) {
|
| | | var pro = GetSelectedProject(dteObject);
|
| | | if (pro == null) {
|
| | | if ((pro = GetSingleProjectInSolution(dteObject)) == null)
|
| | | pro = GetActiveDocumentProject(dteObject);
|
| | | }
|
| | | return IsQtProject(pro) ? pro : null;
|
| | | return IsVsToolsProject(pro) ? pro : null;
|
| | | }
|
| | |
|
| | | public static VCFile[] GetSelectedFiles(DTE dteObject)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | if (GetSelectedQtProject(dteObject) == null)
|
| | | return null;
|
| | |
|
| | |
| | |
|
| | | public static RccOptions ParseRccOptions(string cmdLine, VCFile qrcFile)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | var pro = VCProjectToProject((VCProject)qrcFile.project);
|
| | |
|
| | | var rccOpts = new RccOptions(pro, qrcFile);
|
| | |
| | |
|
| | | public static Project VCProjectToProject(VCProject vcproj)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | | return (Project)vcproj.Object;
|
| | | }
|
| | |
|
| | | public static List<Project> ProjectsInSolution(DTE dteObject)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | if (dteObject == null)
|
| | | return new List<Project>();
|
| | |
|
| | | var projects = new List<Project>();
|
| | | var solution = dteObject.Solution;
|
| | | if (solution != null) {
|
| | |
| | |
|
| | | private static void addSubProjects(Project prj, ref List<Project> projects)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | // If the actual object of the project is null then the project was probably unloaded.
|
| | | if (prj.Object == null)
|
| | | return;
|
| | |
| | |
|
| | | private static void addSubProjects(ProjectItems subItems, ref List<Project> projects)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | if (subItems == null)
|
| | | return;
|
| | |
|
| | |
| | | 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.
|
| | |
| | | string platformName,
|
| | | string filePath = null)
|
| | | {
|
| | | ThreadHelper.ThrowIfNotOnUIThread();
|
| | |
|
| | | 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
|
| | |
| | | VCProject vcProj = null;
|
| | | VCFile vcFile = null;
|
| | | string configName = "", platformName = "";
|
| | | var vcConfig = config as VCConfiguration;
|
| | | if (vcConfig != null) {
|
| | | if (config is VCConfiguration vcConfig) {
|
| | | vcProj = vcConfig.project as VCProject;
|
| | | configName = vcConfig.ConfigurationName;
|
| | | var vcPlatform = vcConfig.Platform as VCPlatform;
|
| | | if (vcPlatform != null)
|
| | | if (vcConfig.Platform is VCPlatform vcPlatform)
|
| | | platformName = vcPlatform.Name;
|
| | | try {
|
| | | expanded = vcConfig.Evaluate(expanded);
|
| | |
| | | vcFile = vcFileConfig.File as VCFile;
|
| | | if (vcFile != null)
|
| | | vcProj = vcFile.project as VCProject;
|
| | | var vcProjConfig = vcFileConfig.ProjectConfiguration as VCConfiguration;
|
| | | if (vcProjConfig != null) {
|
| | | if (vcFileConfig.ProjectConfiguration is VCConfiguration vcProjConfig) {
|
| | | configName = vcProjConfig.ConfigurationName;
|
| | | var vcPlatform = vcProjConfig.Platform as VCPlatform;
|
| | | if (vcPlatform != null)
|
| | | if (vcProjConfig.Platform is VCPlatform vcPlatform)
|
| | | platformName = vcPlatform.Name;
|
| | | }
|
| | | try {
|
| | |
| | | return true;
|
| | | }
|
| | |
|
| | | #if VS2017
|
| | | private static string GetRegistrySoftwareString(string subKeyName, string valueName)
|
| | | {
|
| | | var keyName = new StringBuilder();
|
| | |
| | | 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 "";
|
| | | }
|
| | | }
|
| | | #endif
|
| | |
|
| | | public static string GetWindows10SDKVersion()
|
| | | {
|
| | |
| | | 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)
|
| | |
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | // Get PATH
|
| | | string envPath = startInfo.EnvironmentVariables["PATH"];
|
| | | string clPath = envPath.Split(';')
|
| | |
|
| | | // Remove invalid chars
|
| | | envPath = string.Join("", envPath.Split(Path.GetInvalidPathChars()));
|
| | |
|
| | | // Split into list of paths
|
| | | var paths = envPath
|
| | | .Split(';')
|
| | | .Where(x => !string.IsNullOrEmpty(x))
|
| | | .Select(x => x.Trim());
|
| | |
|
| | | // Check if cl.exe is in PATH
|
| | | string clPath = paths
|
| | | .Select(path => Path.Combine(path, "cl.exe"))
|
| | | .Where(pathToCl => File.Exists(pathToCl))
|
| | | .FirstOrDefault();
|
| | |
| | | } 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)
|