| Index: obsolete/Microsoft.VisualStudio.Project/ProjectNode.cs
|
| diff --git a/obsolete/Microsoft.VisualStudio.Project/ProjectNode.cs b/obsolete/Microsoft.VisualStudio.Project/ProjectNode.cs
|
| deleted file mode 100644
|
| index 9815a2614eca2e29e8ebe1bade6637865a18c7b7..0000000000000000000000000000000000000000
|
| --- a/obsolete/Microsoft.VisualStudio.Project/ProjectNode.cs
|
| +++ /dev/null
|
| @@ -1,5935 +0,0 @@
|
| -/// Copyright (c) Microsoft Corporation. All rights reserved.
|
| -
|
| -using System;
|
| -using System.CodeDom.Compiler;
|
| -using System.Collections.Generic;
|
| -using System.Collections.Specialized;
|
| -using System.Diagnostics;
|
| -using System.Diagnostics.CodeAnalysis;
|
| -using System.Globalization;
|
| -using System.IO;
|
| -using System.Runtime.InteropServices;
|
| -using System.Windows.Forms;
|
| -using System.Xml;
|
| -using EnvDTE;
|
| -using Microsoft.VisualStudio.OLE.Interop;
|
| -using Microsoft.VisualStudio.Shell;
|
| -using Microsoft.VisualStudio.Shell.Interop;
|
| -using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
|
| -using IServiceProvider = System.IServiceProvider;
|
| -using MSBuild = Microsoft.Build.BuildEngine;
|
| -using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants;
|
| -using VsCommands = Microsoft.VisualStudio.VSConstants.VSStd97CmdID;
|
| -using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID;
|
| -
|
| -namespace Microsoft.VisualStudio.Project
|
| -{
|
| - /// <summary>
|
| - /// Manages the persistent state of the project (References, options, files, etc.) and deals with user interaction via a GUI in the form a hierarchy.
|
| - /// </summary>
|
| - [CLSCompliant(false)]
|
| - [ComVisible(true)]
|
| - public abstract partial class ProjectNode : HierarchyNode,
|
| - IVsGetCfgProvider,
|
| - IVsProject3,
|
| - IVsAggregatableProject,
|
| - IVsProjectFlavorCfgProvider,
|
| - IPersistFileFormat,
|
| - IVsProjectBuildSystem,
|
| - IVsBuildPropertyStorage,
|
| - IVsComponentUser,
|
| - IVsDependencyProvider,
|
| - IVsSccProject2,
|
| - IBuildDependencyUpdate,
|
| - IProjectEventsListener,
|
| - IProjectEventsProvider,
|
| - IReferenceContainerProvider,
|
| - IVsProjectSpecialFiles
|
| - {
|
| - #region nested types
|
| -
|
| - public enum ImageName
|
| - {
|
| - OfflineWebApp = 0,
|
| - WebReferencesFolder = 1,
|
| - OpenReferenceFolder = 2,
|
| - ReferenceFolder = 3,
|
| - Reference = 4,
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "SDL")]
|
| - SDLWebReference = 5,
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "DISCO")]
|
| - DISCOWebReference = 6,
|
| - Folder = 7,
|
| - OpenFolder = 8,
|
| - ExcludedFolder = 9,
|
| - OpenExcludedFolder = 10,
|
| - ExcludedFile = 11,
|
| - DependentFile = 12,
|
| - MissingFile = 13,
|
| - WindowsForm = 14,
|
| - WindowsUserControl = 15,
|
| - WindowsComponent = 16,
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "XML")]
|
| - XMLSchema = 17,
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "XML")]
|
| - XMLFile = 18,
|
| - WebForm = 19,
|
| - WebService = 20,
|
| - WebUserControl = 21,
|
| - WebCustomUserControl = 22,
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "ASP")]
|
| - ASPPage = 23,
|
| - GlobalApplicationClass = 24,
|
| - WebConfig = 25,
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "HTML")]
|
| - HTMLPage = 26,
|
| - StyleSheet = 27,
|
| - ScriptFile = 28,
|
| - TextFile = 29,
|
| - SettingsFile = 30,
|
| - Resources = 31,
|
| - Bitmap = 32,
|
| - Icon = 33,
|
| - Image = 34,
|
| - ImageMap = 35,
|
| - XWorld = 36,
|
| - Audio = 37,
|
| - Video = 38,
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "CAB")]
|
| - CAB = 39,
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "JAR")]
|
| - JAR = 40,
|
| - DataEnvironment = 41,
|
| - PreviewFile = 42,
|
| - DanglingReference = 43,
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "XSLT")]
|
| - XSLTFile = 44,
|
| - Cursor = 45,
|
| - AppDesignerFolder = 46,
|
| - Data = 47,
|
| - Application = 48,
|
| - DataSet = 49,
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "PFX")]
|
| - PFX = 50,
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "SNK")]
|
| - SNK = 51,
|
| -
|
| - ImageLast = 51
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Flags for specifying which events to stop triggering.
|
| - /// </summary>
|
| - [Flags]
|
| - internal enum EventTriggering
|
| - {
|
| - TriggerAll = 0,
|
| - DoNotTriggerHierarchyEvents = 1,
|
| - DoNotTriggerTrackerEvents = 2
|
| - }
|
| -
|
| - #endregion
|
| -
|
| - #region constants
|
| - /// <summary>
|
| - /// The user file extension.
|
| - /// </summary>
|
| - internal const string PerUserFileExtension = ".user";
|
| - #endregion
|
| -
|
| - #region fields
|
| - /// <summary>
|
| - /// List of output groups names and their associated target
|
| - /// </summary>
|
| - private static KeyValuePair<string, string>[] outputGroupNames =
|
| - { // Name Target (MSBuild)
|
| - new KeyValuePair<string, string>("Built", "BuiltProjectOutputGroup"),
|
| - new KeyValuePair<string, string>("ContentFiles", "ContentFilesProjectOutputGroup"),
|
| - new KeyValuePair<string, string>("LocalizedResourceDlls", "SatelliteDllsProjectOutputGroup"),
|
| - new KeyValuePair<string, string>("Documentation", "DocumentationProjectOutputGroup"),
|
| - new KeyValuePair<string, string>("Symbols", "DebugSymbolsProjectOutputGroup"),
|
| - new KeyValuePair<string, string>("SourceFiles", "SourceFilesProjectOutputGroup"),
|
| - new KeyValuePair<string, string>("XmlSerializer", "SGenFilesOutputGroup"),
|
| - };
|
| -
|
| - /// <summary>A project will only try to build if it can obtain a lock on this object</summary>
|
| - private volatile static object BuildLock = new object();
|
| -
|
| - /// <summary>Maps integer ids to project item instances</summary>
|
| - private EventSinkCollection itemIdMap = new EventSinkCollection();
|
| -
|
| - /// <summary>A service provider call back object provided by the IDE hosting the project manager</summary>
|
| - private IServiceProvider site;
|
| -
|
| - private TrackDocumentsHelper tracker;
|
| -
|
| - /// <summary>
|
| - /// This property returns the time of the last change made to this project.
|
| - /// It is not the time of the last change on the project file, but actually of
|
| - /// the in memory project settings. In other words, it is the last time that
|
| - /// SetProjectDirty was called.
|
| - /// </summary>
|
| - private DateTime lastModifiedTime;
|
| -
|
| - /// <summary>
|
| - /// MSBuild engine we are going to use
|
| - /// </summary>
|
| - private MSBuild.Engine buildEngine;
|
| -
|
| - private Microsoft.Build.Utilities.Logger buildLogger;
|
| -
|
| - private bool useProvidedLogger;
|
| -
|
| - private MSBuild.Project buildProject;
|
| -
|
| - private MSBuild.BuildPropertyGroup currentConfig;
|
| -
|
| - private ConfigProvider configProvider;
|
| -
|
| - private TaskProvider taskProvider;
|
| -
|
| - private string filename;
|
| -
|
| - private Microsoft.VisualStudio.Shell.Url baseUri;
|
| -
|
| - private bool isDirty;
|
| -
|
| - private bool isNewProject;
|
| -
|
| - private bool projectOpened;
|
| -
|
| - private bool buildIsPrepared;
|
| -
|
| - private ImageHandler imageHandler;
|
| -
|
| - private string errorString;
|
| -
|
| - private string warningString;
|
| -
|
| - private Guid projectIdGuid;
|
| -
|
| - private ProjectOptions options;
|
| -
|
| -
|
| - private bool isClosed;
|
| -
|
| - private EventTriggering eventTriggeringFlag = EventTriggering.TriggerAll;
|
| -
|
| - private bool invokeMSBuildWhenResumed;
|
| -
|
| - private uint suspendMSBuildCounter;
|
| -
|
| - private bool canFileNodesHaveChilds;
|
| -
|
| - private bool isProjectEventsListener = true;
|
| -
|
| - /// <summary>
|
| - /// The build dependency list passed to IVsDependencyProvider::EnumDependencies
|
| - /// </summary>
|
| - private List<IVsBuildDependency> buildDependencyList = new List<IVsBuildDependency>();
|
| -
|
| - /// <summary>
|
| - /// Defines if Project System supports Project Designer
|
| - /// </summary>
|
| - private bool supportsProjectDesigner;
|
| -
|
| - private bool showProjectInSolutionPage = true;
|
| -
|
| - private bool buildInProcess;
|
| -
|
| - /// <summary>
|
| - /// Field for determining whether sourcecontrol should be disabled.
|
| - /// </summary>
|
| - private bool disableScc;
|
| -
|
| - private string sccProjectName;
|
| -
|
| - private string sccLocalPath;
|
| -
|
| - private string sccAuxPath;
|
| -
|
| - private string sccProvider;
|
| -
|
| - /// <summary>
|
| - /// Flag for controling how many times we register with the Scc manager.
|
| - /// </summary>
|
| - private bool isRegisteredWithScc;
|
| -
|
| - /// <summary>
|
| - /// Flag for controling query edit should communicate with the scc manager.
|
| - /// </summary>
|
| - private bool disableQueryEdit;
|
| -
|
| - /// <summary>
|
| - /// Control if command with potential destructive behavior such as delete should
|
| - /// be enabled for nodes of this project.
|
| - /// </summary>
|
| - private bool canProjectDeleteItems;
|
| -
|
| - /// <summary>
|
| - /// Token processor used by the project sample.
|
| - /// </summary>
|
| - private TokenProcessor tokenProcessor;
|
| -
|
| - /// <summary>
|
| - /// Member to store output base relative path. Used by OutputBaseRelativePath property
|
| - /// </summary>
|
| - private string outputBaseRelativePath = "bin";
|
| -
|
| - private IProjectEvents projectEventsProvider;
|
| -
|
| - /// <summary>
|
| - /// Used for flavoring to hold the XML fragments
|
| - /// </summary>
|
| - private XmlDocument xmlFragments;
|
| -
|
| - /// <summary>
|
| - /// Used to map types to CATID. This provide a generic way for us to do this
|
| - /// and make it simpler for a project to provide it's CATIDs for the different type of objects
|
| - /// for which it wants to support extensibility. This also enables us to have multiple
|
| - /// type mapping to the same CATID if we choose to.
|
| - /// </summary>
|
| - private Dictionary<Type, Guid> catidMapping = new Dictionary<Type, Guid>();
|
| -
|
| - /// <summary>
|
| - /// The globalProperty handler object in charge of maintaining global properties for this project.
|
| - /// </summary>
|
| - private GlobalPropertyHandler globalPropertyHandler;
|
| -
|
| - /// <summary>
|
| - /// Flag for specifying that the project has passed security checks.
|
| - /// </summary>
|
| - private bool hasPassedSecurityChecks;
|
| -
|
| - /// <summary>
|
| - /// The internal package implementation.
|
| - /// </summary>
|
| - private ProjectPackage package;
|
| -
|
| - // Has the object been disposed.
|
| - private bool isDisposed;
|
| - #endregion
|
| -
|
| - #region abstract properties
|
| - /// <summary>
|
| - /// This Guid must match the Guid you registered under
|
| - /// HKLM\Software\Microsoft\VisualStudio\%version%\Projects.
|
| - /// Among other things, the Project framework uses this
|
| - /// guid to find your project and item templates.
|
| - /// </summary>
|
| - public abstract Guid ProjectGuid
|
| - {
|
| - get;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Returns a caption for VSHPROPID_TypeName.
|
| - /// </summary>
|
| - /// <returns></returns>
|
| - public abstract string ProjectType
|
| - {
|
| - get;
|
| - }
|
| - #endregion
|
| -
|
| - #region virtual properties
|
| - /// <summary>
|
| - /// This is the project instance guid that is peristed in the project file
|
| - /// </summary>
|
| - [System.ComponentModel.BrowsableAttribute(false)]
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "ID")]
|
| - public virtual Guid ProjectIDGuid
|
| - {
|
| - get
|
| - {
|
| - return this.projectIdGuid;
|
| - }
|
| - set
|
| - {
|
| - if(this.projectIdGuid != value)
|
| - {
|
| - this.projectIdGuid = value;
|
| - if(this.buildProject != null)
|
| - {
|
| - this.SetProjectProperty("ProjectGuid", this.projectIdGuid.ToString("B"));
|
| - }
|
| - }
|
| - }
|
| - }
|
| - #endregion
|
| -
|
| - #region properties
|
| -
|
| -
|
| - #region overridden properties
|
| - public override int MenuCommandId
|
| - {
|
| - get
|
| - {
|
| - return VsMenus.IDM_VS_CTXT_PROJNODE;
|
| - }
|
| - }
|
| -
|
| - public override string Url
|
| - {
|
| - get
|
| - {
|
| - return this.GetMkDocument();
|
| - }
|
| - }
|
| -
|
| - public override string Caption
|
| - {
|
| - get
|
| - {
|
| - // Default to file name
|
| - string caption = this.buildProject.FullFileName;
|
| - if(String.IsNullOrEmpty(caption))
|
| - {
|
| - if(this.buildProject.EvaluatedProperties[ProjectFileConstants.Name] != null)
|
| - {
|
| - caption = this.buildProject.EvaluatedProperties[ProjectFileConstants.Name].Value;
|
| - if(caption == null || caption.Length == 0)
|
| - {
|
| - caption = this.ItemNode.GetMetadata(ProjectFileConstants.Include);
|
| - }
|
| - }
|
| - }
|
| - else
|
| - {
|
| - caption = Path.GetFileNameWithoutExtension(caption);
|
| - }
|
| -
|
| - return caption;
|
| - }
|
| - }
|
| -
|
| - public override Guid ItemTypeGuid
|
| - {
|
| - get
|
| - {
|
| - return this.ProjectGuid;
|
| - }
|
| - }
|
| -
|
| - public override int ImageIndex
|
| - {
|
| - get
|
| - {
|
| - return (int)ProjectNode.ImageName.Application;
|
| - }
|
| - }
|
| -
|
| -
|
| - #endregion
|
| -
|
| - #region virtual properties
|
| -
|
| - public virtual string ErrorString
|
| - {
|
| - get
|
| - {
|
| - if(this.errorString == null)
|
| - {
|
| - this.errorString = SR.GetString(SR.Error, CultureInfo.CurrentUICulture);
|
| - }
|
| -
|
| - return this.errorString;
|
| - }
|
| - }
|
| -
|
| - public virtual string WarningString
|
| - {
|
| - get
|
| - {
|
| - if(this.warningString == null)
|
| - {
|
| - this.warningString = SR.GetString(SR.Warning, CultureInfo.CurrentUICulture);
|
| - }
|
| -
|
| - return this.warningString;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// The target name that will be used for evaluating the project file (i.e., pseudo-builds).
|
| - /// This target is used to trigger a build with when the project system changes.
|
| - /// Example: The language projrcts are triggering a build with the Compile target whenever
|
| - /// the project system changes.
|
| - /// </summary>
|
| - [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "ReEvaluate")]
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Re")]
|
| - protected internal virtual string ReEvaluateProjectFileTargetName
|
| - {
|
| - get
|
| - {
|
| - return null;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// This is the object that will be returned by EnvDTE.Project.Object for this project
|
| - /// </summary>
|
| - protected internal virtual object ProjectObject
|
| - {
|
| - get
|
| - {
|
| - return null;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Override this property to specify when the project file is dirty.
|
| - /// </summary>
|
| - protected virtual bool IsProjectFileDirty
|
| - {
|
| - get
|
| - {
|
| - string document = this.GetMkDocument();
|
| -
|
| - if(String.IsNullOrEmpty(document))
|
| - {
|
| - return this.isDirty;
|
| - }
|
| -
|
| - return (this.isDirty || !File.Exists(document));
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// True if the project uses the Project Designer Editor instead of the property page frame to edit project properties.
|
| - /// </summary>
|
| - protected virtual bool SupportsProjectDesigner
|
| - {
|
| - get
|
| - {
|
| - return this.supportsProjectDesigner;
|
| - }
|
| - set
|
| - {
|
| - this.supportsProjectDesigner = value;
|
| - }
|
| -
|
| - }
|
| -
|
| - protected virtual Guid ProjectDesignerEditor
|
| - {
|
| - get
|
| - {
|
| - return VSConstants.GUID_ProjectDesignerEditor;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Defines the flag that supports the VSHPROPID.ShowProjInSolutionPage
|
| - /// </summary>
|
| - protected virtual bool ShowProjectInSolutionPage
|
| - {
|
| - get
|
| - {
|
| - return this.showProjectInSolutionPage;
|
| - }
|
| - set
|
| - {
|
| - this.showProjectInSolutionPage = value;
|
| - }
|
| - }
|
| -
|
| - #endregion
|
| -
|
| - /// <summary>
|
| - /// Gets or sets the ability of a project filenode to have child nodes (sub items).
|
| - /// Example would be C#/VB forms having resx and designer files.
|
| - /// </summary>
|
| - protected internal bool CanFileNodesHaveChilds
|
| - {
|
| - get
|
| - {
|
| - return canFileNodesHaveChilds;
|
| - }
|
| - set
|
| - {
|
| - canFileNodesHaveChilds = value;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Get and set the Token processor.
|
| - /// </summary>
|
| - public TokenProcessor FileTemplateProcessor
|
| - {
|
| - get
|
| - {
|
| - if(tokenProcessor == null)
|
| - tokenProcessor = new TokenProcessor();
|
| - return tokenProcessor;
|
| - }
|
| - set
|
| - {
|
| - tokenProcessor = value;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets a service provider object provided by the IDE hosting the project
|
| - /// </summary>
|
| - [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")]
|
| - public IServiceProvider Site
|
| - {
|
| - get
|
| - {
|
| - return this.site;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets an ImageHandler for the project node.
|
| - /// </summary>
|
| - public ImageHandler ImageHandler
|
| - {
|
| - get
|
| - {
|
| - if(null == imageHandler)
|
| - {
|
| - imageHandler = new ImageHandler(Resources.imagelis);
|
| - }
|
| - return imageHandler;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// This property returns the time of the last change made to this project.
|
| - /// It is not the time of the last change on the project file, but actually of
|
| - /// the in memory project settings. In other words, it is the last time that
|
| - /// SetProjectDirty was called.
|
| - /// </summary>
|
| - public DateTime LastModifiedTime
|
| - {
|
| - get
|
| - {
|
| - return this.lastModifiedTime;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Determines whether this project is a new project.
|
| - /// </summary>
|
| - public bool IsNewProject
|
| - {
|
| - get
|
| - {
|
| - return this.isNewProject;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets the path to the folder containing the project.
|
| - /// </summary>
|
| - public string ProjectFolder
|
| - {
|
| - get
|
| - {
|
| - return Path.GetDirectoryName(this.filename);
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets or sets the project filename.
|
| - /// </summary>
|
| - public string ProjectFile
|
| - {
|
| - get
|
| - {
|
| - return Path.GetFileName(this.filename);
|
| - }
|
| - set
|
| - {
|
| - this.SetEditLabel(value);
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets the Base Uniform Resource Identifier (URI).
|
| - /// </summary>
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "URI")]
|
| - public Microsoft.VisualStudio.Shell.Url BaseURI
|
| - {
|
| - get
|
| - {
|
| - if(baseUri == null && this.buildProject != null)
|
| - {
|
| - string path = System.IO.Path.GetDirectoryName(this.buildProject.FullFileName);
|
| - // Uri/Url behave differently when you have trailing slash and when you dont
|
| - if(!path.EndsWith("\\", StringComparison.Ordinal) && !path.EndsWith("/", StringComparison.Ordinal))
|
| - path += "\\";
|
| - baseUri = new Url(path);
|
| - }
|
| -
|
| - Debug.Assert(baseUri != null, "Base URL should not be null. Did you call BaseURI before loading the project?");
|
| - return baseUri;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets whether or not the project is closed.
|
| - /// </summary>
|
| - public bool IsClosed
|
| - {
|
| - get
|
| - {
|
| - return this.isClosed;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets whether or not the project is being built.
|
| - /// </summary>
|
| - public bool BuildInProgress
|
| - {
|
| - get
|
| - {
|
| - return buildInProcess;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets or set the relative path to the folder containing the project ouput.
|
| - /// </summary>
|
| - public virtual string OutputBaseRelativePath
|
| - {
|
| - get
|
| - {
|
| - return this.outputBaseRelativePath;
|
| - }
|
| - set
|
| - {
|
| - if(Path.IsPathRooted(value))
|
| - {
|
| - throw new ArgumentException("Path must not be rooted.");
|
| - }
|
| -
|
| - this.outputBaseRelativePath = value;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets or sets the flag whether query edit should communicate with the scc manager.
|
| - /// </summary>
|
| - protected bool DisableQueryEdit
|
| - {
|
| - get
|
| - {
|
| - return this.disableQueryEdit;
|
| - }
|
| - set
|
| - {
|
| - this.disableQueryEdit = value;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets a collection of integer ids that maps to project item instances
|
| - /// </summary>
|
| - internal EventSinkCollection ItemIdMap
|
| - {
|
| - get
|
| - {
|
| - return this.itemIdMap;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Get the helper object that track document changes.
|
| - /// </summary>
|
| - internal TrackDocumentsHelper Tracker
|
| - {
|
| - get
|
| - {
|
| - return this.tracker;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets or sets the build logger.
|
| - /// </summary>
|
| - protected Microsoft.Build.Utilities.Logger BuildLogger
|
| - {
|
| - get
|
| - {
|
| - return this.buildLogger;
|
| - }
|
| - set
|
| - {
|
| - this.buildLogger = value;
|
| - this.useProvidedLogger = true;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets the taskprovider.
|
| - /// </summary>
|
| - protected TaskProvider TaskProvider
|
| - {
|
| - get
|
| - {
|
| - return this.taskProvider;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets the project file name.
|
| - /// </summary>
|
| - protected string FileName
|
| - {
|
| - get
|
| - {
|
| - return this.filename;
|
| - }
|
| - }
|
| -
|
| -
|
| - /// <summary>
|
| - /// Gets the configuration provider.
|
| - /// </summary>
|
| - protected ConfigProvider ConfigProvider
|
| - {
|
| - get
|
| - {
|
| - if(this.configProvider == null)
|
| - {
|
| - this.configProvider = CreateConfigProvider();
|
| - }
|
| -
|
| - return this.configProvider;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets or sets whether or not source code control is disabled for this project.
|
| - /// </summary>
|
| - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Scc")]
|
| - protected bool IsSccDisabled
|
| - {
|
| - get
|
| - {
|
| - return this.disableScc;
|
| - }
|
| - set
|
| - {
|
| - this.disableScc = value;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets or set whether items can be deleted for this project.
|
| - /// Enabling this feature can have the potential destructive behavior such as deleting files from disk.
|
| - /// </summary>
|
| - protected internal bool CanProjectDeleteItems
|
| - {
|
| - get
|
| - {
|
| - return canProjectDeleteItems;
|
| - }
|
| - set
|
| - {
|
| - canProjectDeleteItems = value;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Determines whether the project was fully opened. This is set when the OnAfterOpenProject has triggered.
|
| - /// </summary>
|
| - protected internal bool HasProjectOpened
|
| - {
|
| - get
|
| - {
|
| - return this.projectOpened;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets or sets event triggering flags.
|
| - /// </summary>
|
| - internal EventTriggering EventTriggeringFlag
|
| - {
|
| - get
|
| - {
|
| - return this.eventTriggeringFlag;
|
| - }
|
| - set
|
| - {
|
| - this.eventTriggeringFlag = value;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Defines the build project that has loaded the project file.
|
| - /// </summary>
|
| - protected internal Microsoft.Build.BuildEngine.Project BuildProject
|
| - {
|
| - get
|
| - {
|
| - return this.buildProject;
|
| - }
|
| - set
|
| - {
|
| - this.buildProject = value;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Defines the build engine that is used to build the project file.
|
| - /// </summary>
|
| - internal Microsoft.Build.BuildEngine.Engine BuildEngine
|
| - {
|
| - get
|
| - {
|
| - return this.buildEngine;
|
| - }
|
| - set
|
| - {
|
| - this.buildEngine = value;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// The object in charge of maintaining global properties for this project.
|
| - /// </summary>
|
| - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
| - internal GlobalPropertyHandler GlobalPropetyHandler
|
| - {
|
| - get
|
| - {
|
| - return this.globalPropertyHandler;
|
| - }
|
| -
|
| - set
|
| - {
|
| - this.globalPropertyHandler = value;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Has the project passed security checks?
|
| - /// </summary>
|
| - internal bool HasPassedSecurityChecks
|
| - {
|
| - get
|
| - {
|
| - return this.hasPassedSecurityChecks;
|
| - }
|
| - set
|
| - {
|
| - this.hasPassedSecurityChecks = value;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// The internal package implementation.
|
| - /// </summary>
|
| - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
| - internal ProjectPackage Package
|
| - {
|
| - get
|
| - {
|
| - return this.package;
|
| - }
|
| - set
|
| - {
|
| - this.package = value;
|
| - }
|
| - }
|
| - #endregion
|
| -
|
| - #region ctor
|
| -
|
| - protected ProjectNode()
|
| - {
|
| - this.Initialize();
|
| - }
|
| - #endregion
|
| -
|
| - #region overridden methods
|
| - protected override NodeProperties CreatePropertiesObject()
|
| - {
|
| - return new ProjectNodeProperties(this);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Sets the properties for the project node.
|
| - /// </summary>
|
| - /// <param name="propid">Identifier of the hierarchy property. For a list of propid values, <see cref="__VSHPROPID"/> </param>
|
| - /// <param name="value">The value to set. </param>
|
| - /// <returns>A success or failure value.</returns>
|
| - public override int SetProperty(int propid, object value)
|
| - {
|
| - __VSHPROPID id = (__VSHPROPID)propid;
|
| -
|
| - switch(id)
|
| - {
|
| - case __VSHPROPID.VSHPROPID_ShowProjInSolutionPage:
|
| - this.ShowProjectInSolutionPage = (bool)value;
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - return base.SetProperty(propid, value);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Renames the project node.
|
| - /// </summary>
|
| - /// <param name="label">The new name</param>
|
| - /// <returns>A success or failure value.</returns>
|
| - public override int SetEditLabel(string label)
|
| - {
|
| - // Validate the filename.
|
| - if(String.IsNullOrEmpty(label))
|
| - {
|
| - throw new InvalidOperationException(SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture));
|
| - }
|
| - else if(this.ProjectFolder.Length + label.Length + 1 > NativeMethods.MAX_PATH)
|
| - {
|
| - throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.PathTooLong, CultureInfo.CurrentUICulture), label));
|
| - }
|
| - else if(Utilities.IsFileNameInvalid(label))
|
| - {
|
| - throw new InvalidOperationException(SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture));
|
| - }
|
| -
|
| - string fileName = Path.GetFileNameWithoutExtension(label);
|
| -
|
| - // if there is no filename or it starts with a leading dot issue an error message and quit.
|
| - if(String.IsNullOrEmpty(fileName) || fileName[0] == '.')
|
| - {
|
| - throw new InvalidOperationException(SR.GetString(SR.FileNameCannotContainALeadingPeriod, CultureInfo.CurrentUICulture));
|
| - }
|
| -
|
| - // Nothing to do if the name is the same
|
| - string oldFileName = Path.GetFileNameWithoutExtension(this.Url);
|
| - if(String.Compare(oldFileName, label, StringComparison.Ordinal) == 0)
|
| - {
|
| - return VSConstants.S_FALSE;
|
| - }
|
| -
|
| - // Now check whether the original file is still there. It could have been renamed.
|
| - if(!File.Exists(this.Url))
|
| - {
|
| - throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.FileOrFolderCannotBeFound, CultureInfo.CurrentUICulture), this.ProjectFile));
|
| - }
|
| -
|
| - // Get the full file name and then rename the project file.
|
| - string newFile = Path.Combine(this.ProjectFolder, label);
|
| - string extension = Path.GetExtension(this.Url);
|
| -
|
| - // Make sure it has the correct extension
|
| - if(String.Compare(Path.GetExtension(newFile), extension, StringComparison.OrdinalIgnoreCase) != 0)
|
| - {
|
| - newFile += extension;
|
| - }
|
| -
|
| - this.RenameProjectFile(newFile);
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets the automation object for the project node.
|
| - /// </summary>
|
| - /// <returns>An instance of an EnvDTE.Project implementation object representing the automation object for the project.</returns>
|
| - public override object GetAutomationObject()
|
| - {
|
| - return new Automation.OAProject(this);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Closes the project node.
|
| - /// </summary>
|
| - /// <returns>A success or failure value.</returns>
|
| - public override int Close()
|
| - {
|
| - int hr = VSConstants.S_OK;
|
| - try
|
| - {
|
| - // Walk the tree and close all nodes.
|
| - // This has to be done before the project closes, since we want still state available for the ProjectMgr on the nodes
|
| - // when nodes are closing.
|
| - try
|
| - {
|
| - CloseAllNodes(this);
|
| - }
|
| - finally
|
| - {
|
| - this.Dispose(true);
|
| - }
|
| - }
|
| - catch(COMException e)
|
| - {
|
| - hr = e.ErrorCode;
|
| - }
|
| - finally
|
| - {
|
| - ErrorHandler.ThrowOnFailure(base.Close());
|
| - }
|
| -
|
| - this.isClosed = true;
|
| -
|
| - return hr;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Sets the service provider from which to access the services.
|
| - /// </summary>
|
| - /// <param name="site">An instance to an Microsoft.VisualStudio.OLE.Interop object</param>
|
| - /// <returns>A success or failure value.</returns>
|
| - public override int SetSite(Microsoft.VisualStudio.OLE.Interop.IServiceProvider site)
|
| - {
|
| - CCITracing.TraceCall();
|
| - this.site = new ServiceProvider(site);
|
| -
|
| - if(taskProvider != null)
|
| - {
|
| - taskProvider.Dispose();
|
| - }
|
| - taskProvider = new TaskProvider(this.site);
|
| -
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets the properties of the project node.
|
| - /// </summary>
|
| - /// <param name="propId">The __VSHPROPID of the property.</param>
|
| - /// <returns>A property dependent value. See: <see cref="__VSHPROPID"/> for details.</returns>
|
| - public override object GetProperty(int propId)
|
| - {
|
| - switch((__VSHPROPID)propId)
|
| - {
|
| - case __VSHPROPID.VSHPROPID_ConfigurationProvider:
|
| - return this.ConfigProvider;
|
| -
|
| - case __VSHPROPID.VSHPROPID_ProjectName:
|
| - return this.Caption;
|
| -
|
| - case __VSHPROPID.VSHPROPID_ProjectDir:
|
| - return this.ProjectFolder;
|
| -
|
| - case __VSHPROPID.VSHPROPID_TypeName:
|
| - return this.ProjectType;
|
| -
|
| - case __VSHPROPID.VSHPROPID_ShowProjInSolutionPage:
|
| - return this.ShowProjectInSolutionPage;
|
| -
|
| - case __VSHPROPID.VSHPROPID_ExpandByDefault:
|
| - return true;
|
| -
|
| - // Use the same icon as if the folder was closed
|
| - case __VSHPROPID.VSHPROPID_OpenFolderIconIndex:
|
| - return GetProperty((int)__VSHPROPID.VSHPROPID_IconIndex);
|
| - }
|
| -
|
| - switch((__VSHPROPID2)propId)
|
| - {
|
| - case __VSHPROPID2.VSHPROPID_SupportsProjectDesigner:
|
| - return this.SupportsProjectDesigner;
|
| -
|
| - case __VSHPROPID2.VSHPROPID_PropertyPagesCLSIDList:
|
| - return Utilities.CreateSemicolonDelimitedListOfStringFromGuids(this.GetConfigurationIndependentPropertyPages());
|
| -
|
| - case __VSHPROPID2.VSHPROPID_CfgPropertyPagesCLSIDList:
|
| - return Utilities.CreateSemicolonDelimitedListOfStringFromGuids(this.GetConfigurationDependentPropertyPages());
|
| -
|
| - case __VSHPROPID2.VSHPROPID_PriorityPropertyPagesCLSIDList:
|
| - return Utilities.CreateSemicolonDelimitedListOfStringFromGuids(this.GetPriorityProjectDesignerPages());
|
| -
|
| - case __VSHPROPID2.VSHPROPID_Container:
|
| - return true;
|
| - default:
|
| - break;
|
| - }
|
| -
|
| - return base.GetProperty(propId);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets the GUID value of the node.
|
| - /// </summary>
|
| - /// <param name="propid">A __VSHPROPID or __VSHPROPID2 value of the guid property</param>
|
| - /// <param name="guid">The guid to return for the property.</param>
|
| - /// <returns>A success or failure value.</returns>
|
| - public override int GetGuidProperty(int propid, out Guid guid)
|
| - {
|
| - guid = Guid.Empty;
|
| - if((__VSHPROPID)propid == __VSHPROPID.VSHPROPID_ProjectIDGuid)
|
| - {
|
| - guid = this.ProjectIDGuid;
|
| - }
|
| - else if(propid == (int)__VSHPROPID.VSHPROPID_CmdUIGuid)
|
| - {
|
| - guid = this.ProjectGuid;
|
| - }
|
| - else if((__VSHPROPID2)propid == __VSHPROPID2.VSHPROPID_ProjectDesignerEditor && this.SupportsProjectDesigner)
|
| - {
|
| - guid = this.ProjectDesignerEditor;
|
| - }
|
| - else
|
| - {
|
| - base.GetGuidProperty(propid, out guid);
|
| - }
|
| -
|
| - if(guid.CompareTo(Guid.Empty) == 0)
|
| - {
|
| - return VSConstants.DISP_E_MEMBERNOTFOUND;
|
| - }
|
| -
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Sets Guid properties for the project node.
|
| - /// </summary>
|
| - /// <param name="propid">A __VSHPROPID or __VSHPROPID2 value of the guid property</param>
|
| - /// <param name="guid">The guid value to set.</param>
|
| - /// <returns>A success or failure value.</returns>
|
| - public override int SetGuidProperty(int propid, ref Guid guid)
|
| - {
|
| - switch((__VSHPROPID)propid)
|
| - {
|
| - case __VSHPROPID.VSHPROPID_ProjectIDGuid:
|
| - this.ProjectIDGuid = guid;
|
| - return VSConstants.S_OK;
|
| - }
|
| - CCITracing.TraceCall(String.Format(CultureInfo.CurrentCulture, "Property {0} not found", propid));
|
| - return VSConstants.DISP_E_MEMBERNOTFOUND;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Removes items from the hierarchy.
|
| - /// </summary>
|
| - /// <devdoc>Project overwrites this.</devdoc>
|
| - public override void Remove(bool removeFromStorage)
|
| - {
|
| - // the project will not be deleted from disk, just removed
|
| - if(removeFromStorage)
|
| - {
|
| - return;
|
| - }
|
| -
|
| - // Remove the entire project from the solution
|
| - IVsSolution solution = this.Site.GetService(typeof(SVsSolution)) as IVsSolution;
|
| - uint iOption = 1; // SLNSAVEOPT_PromptSave
|
| - ErrorHandler.ThrowOnFailure(solution.CloseSolutionElement(iOption, this, 0));
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets the moniker for the project node. That is the full path of the project file.
|
| - /// </summary>
|
| - /// <returns>The moniker for the project file.</returns>
|
| - public override string GetMkDocument()
|
| - {
|
| - Debug.Assert(!String.IsNullOrEmpty(this.filename));
|
| - Debug.Assert(this.BaseURI != null && !String.IsNullOrEmpty(this.BaseURI.AbsoluteUrl));
|
| - return Path.Combine(this.BaseURI.AbsoluteUrl, this.filename);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Disposes the project node object.
|
| - /// </summary>
|
| - /// <param name="disposing">Flag determining ehether it was deterministic or non deterministic clean up.</param>
|
| - protected override void Dispose(bool disposing)
|
| - {
|
| - if(this.isDisposed)
|
| - {
|
| - return;
|
| - }
|
| -
|
| - try
|
| - {
|
| - try
|
| - {
|
| - this.UnRegisterProject();
|
| - }
|
| - finally
|
| - {
|
| - try
|
| - {
|
| - this.RegisterClipboardNotifications(false);
|
| - }
|
| - finally
|
| - {
|
| - try
|
| - {
|
| - if(this.globalPropertyHandler != null)
|
| - {
|
| - this.globalPropertyHandler.ActiveConfigurationChanged -= new EventHandler<ActiveConfigurationChangedEventArgs>(this.OnHandleConfigurationRelatedGlobalProperties);
|
| -
|
| - this.globalPropertyHandler.Dispose();
|
| - }
|
| -
|
| - if(this.projectEventsProvider != null)
|
| - {
|
| - this.projectEventsProvider.AfterProjectFileOpened -= this.OnAfterProjectOpen;
|
| - }
|
| - if(this.taskProvider != null)
|
| - {
|
| - taskProvider.Tasks.Clear();
|
| - this.taskProvider.Dispose();
|
| - this.taskProvider = null;
|
| - }
|
| - if(buildLogger != null)
|
| - {
|
| - buildLogger = null;
|
| - }
|
| - this.site = null;
|
| - }
|
| - finally
|
| - {
|
| - if(this.buildEngine != null)
|
| - {
|
| - this.buildEngine.UnregisterAllLoggers();
|
| - this.buildEngine = null;
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - if(this.buildProject != null)
|
| - {
|
| - this.buildProject.ParentEngine.UnloadProject(this.buildProject);
|
| - this.buildProject = null;
|
| - }
|
| -
|
| - if(null != imageHandler)
|
| - {
|
| - imageHandler.Close();
|
| - imageHandler = null;
|
| - }
|
| - }
|
| - finally
|
| - {
|
| - base.Dispose(disposing);
|
| - this.isDisposed = true;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Handles command status on the project node. If a command cannot be handled then the base should be called.
|
| - /// </summary>
|
| - /// <param name="cmdGroup">A unique identifier of the command group. The pguidCmdGroup parameter can be NULL to specify the standard group.</param>
|
| - /// <param name="cmd">The command to query status for.</param>
|
| - /// <param name="pCmdText">Pointer to an OLECMDTEXT structure in which to return the name and/or status information of a single command. Can be NULL to indicate that the caller does not require this information.</param>
|
| - /// <param name="result">An out parameter specifying the QueryStatusResult of the command.</param>
|
| - /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns>
|
| - protected override int QueryStatusOnNode(Guid cmdGroup, uint cmd, IntPtr pCmdText, ref QueryStatusResult result)
|
| - {
|
| - if(cmdGroup == VsMenus.guidStandardCommandSet97)
|
| - {
|
| - switch((VsCommands)cmd)
|
| - {
|
| - case VsCommands.Copy:
|
| - case VsCommands.Paste:
|
| - case VsCommands.Cut:
|
| - case VsCommands.Rename:
|
| - case VsCommands.Exit:
|
| - case VsCommands.ProjectSettings:
|
| - case VsCommands.BuildSln:
|
| - case VsCommands.UnloadProject:
|
| - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED;
|
| - return VSConstants.S_OK;
|
| -
|
| - case VsCommands.ViewForm:
|
| - if(this.HasDesigner)
|
| - {
|
| - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED;
|
| - return VSConstants.S_OK;
|
| - }
|
| - break;
|
| -
|
| - case VsCommands.CancelBuild:
|
| - result |= QueryStatusResult.SUPPORTED;
|
| - if(this.buildInProcess)
|
| - result |= QueryStatusResult.ENABLED;
|
| - else
|
| - result |= QueryStatusResult.INVISIBLE;
|
| - return VSConstants.S_OK;
|
| -
|
| - case VsCommands.NewFolder:
|
| - case VsCommands.AddNewItem:
|
| - case VsCommands.AddExistingItem:
|
| - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED;
|
| - return VSConstants.S_OK;
|
| -
|
| - case VsCommands.SetStartupProject:
|
| - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED;
|
| - return VSConstants.S_OK;
|
| - }
|
| - }
|
| - else if(cmdGroup == VsMenus.guidStandardCommandSet2K)
|
| - {
|
| -
|
| - switch((VsCommands2K)cmd)
|
| - {
|
| - case VsCommands2K.ADDREFERENCE:
|
| - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED;
|
| - return VSConstants.S_OK;
|
| -
|
| - case VsCommands2K.EXCLUDEFROMPROJECT:
|
| - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.INVISIBLE;
|
| - return VSConstants.S_OK;
|
| - }
|
| - }
|
| - else
|
| - {
|
| - return (int)OleConstants.OLECMDERR_E_UNKNOWNGROUP;
|
| - }
|
| -
|
| - return base.QueryStatusOnNode(cmdGroup, cmd, pCmdText, ref result);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Handles command execution.
|
| - /// </summary>
|
| - /// <param name="cmdGroup">Unique identifier of the command group</param>
|
| - /// <param name="cmd">The command to be executed.</param>
|
| - /// <param name="nCmdexecopt">Values describe how the object should execute the command.</param>
|
| - /// <param name="pvaIn">Pointer to a VARIANTARG structure containing input arguments. Can be NULL</param>
|
| - /// <param name="pvaOut">VARIANTARG structure to receive command output. Can be NULL.</param>
|
| - /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns>
|
| - protected override int ExecCommandOnNode(Guid cmdGroup, uint cmd, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
|
| - {
|
| - if(cmdGroup == VsMenus.guidStandardCommandSet97)
|
| - {
|
| - switch((VsCommands)cmd)
|
| - {
|
| -
|
| - case VsCommands.UnloadProject:
|
| - return this.UnloadProject();
|
| - case VsCommands.CleanSel:
|
| - case VsCommands.CleanCtx:
|
| - return this.CleanProject();
|
| - }
|
| - }
|
| - else if(cmdGroup == VsMenus.guidStandardCommandSet2K)
|
| - {
|
| - switch((VsCommands2K)cmd)
|
| - {
|
| - case VsCommands2K.ADDREFERENCE:
|
| - return this.AddProjectReference();
|
| -
|
| - case VsCommands2K.ADDWEBREFERENCE:
|
| - case VsCommands2K.ADDWEBREFERENCECTX:
|
| - return this.AddWebReference();
|
| - }
|
| - }
|
| -
|
| - return base.ExecCommandOnNode(cmdGroup, cmd, nCmdexecopt, pvaIn, pvaOut);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Get the boolean value for the deletion of a project item
|
| - /// </summary>
|
| - /// <param name="deleteOperation">A flag that specifies the type of delete operation (delete from storage or remove from project)</param>
|
| - /// <returns>true if item can be deleted from project</returns>
|
| - protected override bool CanDeleteItem(__VSDELETEITEMOPERATION deleteOperation)
|
| - {
|
| - if(deleteOperation == __VSDELETEITEMOPERATION.DELITEMOP_RemoveFromProject)
|
| - {
|
| - return true;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Returns a specific Document manager to handle opening and closing of the Project(Application) Designer if projectdesigner is supported.
|
| - /// </summary>
|
| - /// <returns>Document manager object</returns>
|
| - protected internal override DocumentManager GetDocumentManager()
|
| - {
|
| - if(this.SupportsProjectDesigner)
|
| - {
|
| - return new ProjectDesignerDocumentManager(this);
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - #endregion
|
| -
|
| - #region virtual methods
|
| -
|
| - /// <summary>
|
| - /// Executes a wizard.
|
| - /// </summary>
|
| - /// <param name="parentNode">The node to which the wizard should add item(s).</param>
|
| - /// <param name="itemName">The name of the file that the user typed in.</param>
|
| - /// <param name="wizardToRun">The name of the wizard to run.</param>
|
| - /// <param name="dlgOwner">The owner of the dialog box.</param>
|
| - /// <returns>A VSADDRESULT enum value describing success or failure.</returns>
|
| - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily"), SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dlg")]
|
| - public virtual VSADDRESULT RunWizard(HierarchyNode parentNode, string itemName, string wizardToRun, IntPtr dlgOwner)
|
| - {
|
| - Debug.Assert(!String.IsNullOrEmpty(itemName), "The Add item dialog was passing in a null or empty item to be added to the hierrachy.");
|
| - Debug.Assert(!String.IsNullOrEmpty(this.ProjectFolder), "The Project Folder is not specified for this project.");
|
| -
|
| - // We just validate for length, since we assume other validation has been performed by the dlgOwner.
|
| - if(this.ProjectFolder.Length + itemName.Length + 1 > NativeMethods.MAX_PATH)
|
| - {
|
| - string errorMessage = String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.PathTooLong, CultureInfo.CurrentUICulture), itemName);
|
| - if(!Utilities.IsInAutomationFunction(this.Site))
|
| - {
|
| - string title = null;
|
| - OLEMSGICON icon = OLEMSGICON.OLEMSGICON_CRITICAL;
|
| - OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK;
|
| - OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST;
|
| - VsShellUtilities.ShowMessageBox(this.Site, title, errorMessage, icon, buttons, defaultButton);
|
| - return VSADDRESULT.ADDRESULT_Failure;
|
| - }
|
| - else
|
| - {
|
| - throw new InvalidOperationException(errorMessage);
|
| - }
|
| - }
|
| -
|
| -
|
| - // Build up the ContextParams safearray
|
| - // [0] = Wizard type guid (bstr)
|
| - // [1] = Project name (bstr)
|
| - // [2] = ProjectItems collection (bstr)
|
| - // [3] = Local Directory (bstr)
|
| - // [4] = Filename the user typed (bstr)
|
| - // [5] = Product install Directory (bstr)
|
| - // [6] = Run silent (bool)
|
| -
|
| - object[] contextParams = new object[7];
|
| - contextParams[0] = EnvDTE.Constants.vsWizardAddItem;
|
| - contextParams[1] = this.Caption;
|
| - object automationObject = parentNode.GetAutomationObject();
|
| - if(automationObject is EnvDTE.Project)
|
| - {
|
| - EnvDTE.Project project = (EnvDTE.Project)automationObject;
|
| - contextParams[2] = project.ProjectItems;
|
| - }
|
| - else
|
| - {
|
| - // This would normally be a folder unless it is an item with subitems
|
| - ProjectItem item = (ProjectItem)automationObject;
|
| - contextParams[2] = item.ProjectItems;
|
| - }
|
| -
|
| - contextParams[3] = this.ProjectFolder;
|
| -
|
| - contextParams[4] = itemName;
|
| -
|
| - object objInstallationDir = null;
|
| - IVsShell shell = (IVsShell)this.GetService(typeof(IVsShell));
|
| - ErrorHandler.ThrowOnFailure(shell.GetProperty((int)__VSSPROPID.VSSPROPID_InstallDirectory, out objInstallationDir));
|
| - string installDir = (string)objInstallationDir;
|
| -
|
| - // append a '\' to the install dir to mimic what the shell does (though it doesn't add one to destination dir)
|
| - if(!installDir.EndsWith("\\", StringComparison.Ordinal))
|
| - {
|
| - installDir += "\\";
|
| - }
|
| -
|
| - contextParams[5] = installDir;
|
| -
|
| - contextParams[6] = true;
|
| -
|
| - IVsExtensibility3 ivsExtensibility = this.GetService(typeof(IVsExtensibility)) as IVsExtensibility3;
|
| - Debug.Assert(ivsExtensibility != null, "Failed to get IVsExtensibility3 service");
|
| - if(ivsExtensibility == null)
|
| - {
|
| - return VSADDRESULT.ADDRESULT_Failure;
|
| - }
|
| -
|
| - // Determine if we have the trust to run this wizard.
|
| - IVsDetermineWizardTrust wizardTrust = this.GetService(typeof(SVsDetermineWizardTrust)) as IVsDetermineWizardTrust;
|
| - if(wizardTrust != null)
|
| - {
|
| - Guid guidProjectAdding = Guid.Empty;
|
| - ErrorHandler.ThrowOnFailure(wizardTrust.OnWizardInitiated(wizardToRun, ref guidProjectAdding));
|
| - }
|
| -
|
| - int wizResultAsInt;
|
| - try
|
| - {
|
| - Array contextParamsAsArray = contextParams;
|
| -
|
| - int result = ivsExtensibility.RunWizardFile(wizardToRun, (int)dlgOwner, ref contextParamsAsArray, out wizResultAsInt);
|
| -
|
| - if(!ErrorHandler.Succeeded(result) && result != VSConstants.OLE_E_PROMPTSAVECANCELLED)
|
| - {
|
| - ErrorHandler.ThrowOnFailure(result);
|
| - }
|
| - }
|
| - finally
|
| - {
|
| - if(wizardTrust != null)
|
| - {
|
| - ErrorHandler.ThrowOnFailure(wizardTrust.OnWizardCompleted());
|
| - }
|
| - }
|
| -
|
| - EnvDTE.wizardResult wizardResult = (EnvDTE.wizardResult)wizResultAsInt;
|
| -
|
| - switch(wizardResult)
|
| - {
|
| - default:
|
| - return VSADDRESULT.ADDRESULT_Cancel;
|
| - case wizardResult.wizardResultSuccess:
|
| - return VSADDRESULT.ADDRESULT_Success;
|
| - case wizardResult.wizardResultFailure:
|
| - return VSADDRESULT.ADDRESULT_Failure;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Override this method if you want to modify the behavior of the Add Reference dialog
|
| - /// By example you could change which pages are visible and which is visible by default.
|
| - /// </summary>
|
| - /// <returns></returns>
|
| - public virtual int AddProjectReference()
|
| - {
|
| - CCITracing.TraceCall();
|
| -
|
| - IVsComponentSelectorDlg componentDialog;
|
| - Guid guidEmpty = Guid.Empty;
|
| - VSCOMPONENTSELECTORTABINIT[] tabInit = new VSCOMPONENTSELECTORTABINIT[2];
|
| - string strBrowseLocations = Path.GetDirectoryName(this.BaseURI.Uri.LocalPath);
|
| -
|
| - tabInit[0].dwSize = (uint)Marshal.SizeOf(typeof(VSCOMPONENTSELECTORTABINIT));
|
| - // Tell the Add Reference dialog to call hierarchies GetProperty with the following
|
| - // propID to enablefiltering out ourself from the Project to Project reference
|
| - tabInit[0].varTabInitInfo = (int)__VSHPROPID.VSHPROPID_ShowProjInSolutionPage;
|
| - tabInit[0].guidTab = VSConstants.GUID_SolutionPage;
|
| -
|
| - // Add the Browse for file page
|
| - tabInit[1].dwSize = (uint)Marshal.SizeOf(typeof(VSCOMPONENTSELECTORTABINIT));
|
| - tabInit[1].guidTab = VSConstants.GUID_BrowseFilePage;
|
| - tabInit[1].varTabInitInfo = 0;
|
| -
|
| -
|
| - componentDialog = this.GetService(typeof(IVsComponentSelectorDlg)) as IVsComponentSelectorDlg;
|
| - try
|
| - {
|
| - // call the container to open the add reference dialog.
|
| - if(componentDialog != null)
|
| - {
|
| - // Let the project know not to show itself in the Add Project Reference Dialog page
|
| - this.ShowProjectInSolutionPage = false;
|
| -
|
| - // call the container to open the add reference dialog.
|
| - string browseFilters = "Component files (*.dll)" + "\0*.dll\0";
|
| - ErrorHandler.ThrowOnFailure(componentDialog.ComponentSelectorDlg(
|
| - (System.UInt32)(__VSCOMPSELFLAGS.VSCOMSEL_MultiSelectMode | __VSCOMPSELFLAGS.VSCOMSEL_IgnoreMachineName),
|
| - (IVsComponentUser)this,
|
| - SR.GetString(SR.AddReferenceDialogTitle, CultureInfo.CurrentUICulture), // Title
|
| - "VS.AddReference", // Help topic
|
| - ref guidEmpty,
|
| - ref guidEmpty,
|
| - String.Empty, // Machine Name
|
| - (uint)tabInit.Length,
|
| - tabInit,
|
| - browseFilters,
|
| - ref strBrowseLocations));
|
| - }
|
| - }
|
| - catch(COMException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - return e.ErrorCode;
|
| - }
|
| - finally
|
| - {
|
| - // Let the project know it can show itself in the Add Project Reference Dialog page
|
| - this.ShowProjectInSolutionPage = true;
|
| - }
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Returns the Compiler associated to the project
|
| - /// </summary>
|
| - /// <returns>Null</returns>
|
| - public virtual ICodeCompiler GetCompiler()
|
| - {
|
| -
|
| - return null;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Override this method if you have your own project specific
|
| - /// subclass of ProjectOptions
|
| - /// </summary>
|
| - /// <returns>This method returns a new instance of the ProjectOptions base class.</returns>
|
| - public virtual ProjectOptions CreateProjectOptions()
|
| - {
|
| - return new ProjectOptions();
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Loads a project file. Called from the factory CreateProject to load the project.
|
| - /// </summary>
|
| - /// <param name="fileName">File name of the project that will be created. </param>
|
| - /// <param name="location">Location where the project will be created.</param>
|
| - /// <param name="name">If applicable, the name of the template to use when cloning a new project.</param>
|
| - /// <param name="flags">Set of flag values taken from the VSCREATEPROJFLAGS enumeration.</param>
|
| - /// <param name="iidProject">Identifier of the interface that the caller wants returned. </param>
|
| - /// <param name="canceled">An out parameter specifying if the project creation was canceled</param>
|
| - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "iid")]
|
| - public virtual void Load(string fileName, string location, string name, uint flags, ref Guid iidProject, out int canceled)
|
| - {
|
| - try
|
| - {
|
| - this.disableQueryEdit = true;
|
| -
|
| - // set up internal members and icons
|
| - canceled = 0;
|
| -
|
| - this.ProjectMgr = this;
|
| - this.isNewProject = false;
|
| -
|
| - // We need to set the project guid before we check the project for security.
|
| - if((flags & (uint)__VSCREATEPROJFLAGS.CPF_CLONEFILE) == (uint)__VSCREATEPROJFLAGS.CPF_CLONEFILE)
|
| - {
|
| - // we need to generate a new guid for the project
|
| - this.projectIdGuid = Guid.NewGuid();
|
| - }
|
| - else
|
| - {
|
| - this.SetProjectGuidFromProjectFile();
|
| - }
|
| -
|
| - ProjectLoadOption loadOption = this.IsProjectSecure();
|
| - if(loadOption == ProjectLoadOption.DonNotLoad)
|
| - {
|
| - canceled = 1;
|
| - return;
|
| - }
|
| - else if(loadOption == ProjectLoadOption.LoadNormally)
|
| - {
|
| - this.hasPassedSecurityChecks = true;
|
| - }
|
| -
|
| - // This is almost a No op if the engine has already been instantiated in the factory.
|
| - this.buildEngine = Utilities.InitializeMsBuildEngine(this.buildEngine, this.Site);
|
| -
|
| - Debug.Assert(this.globalPropertyHandler != null, "The global property handler should have been initialized at this point");
|
| -
|
| - // Now register with the configuration change event.
|
| - this.globalPropertyHandler.ActiveConfigurationChanged += new EventHandler<ActiveConfigurationChangedEventArgs>(this.OnHandleConfigurationRelatedGlobalProperties);
|
| -
|
| - // based on the passed in flags, this either reloads/loads a project, or tries to create a new one
|
| - // now we create a new project... we do that by loading the template and then saving under a new name
|
| - // we also need to copy all the associated files with it.
|
| - if((flags & (uint)__VSCREATEPROJFLAGS.CPF_CLONEFILE) == (uint)__VSCREATEPROJFLAGS.CPF_CLONEFILE)
|
| - {
|
| - Debug.Assert(!String.IsNullOrEmpty(fileName) && File.Exists(fileName), "Invalid filename passed to load the project. A valid filename is expected");
|
| -
|
| - this.isNewProject = true;
|
| -
|
| - // This should be a very fast operation if the build project is already initialized by the Factory.
|
| - this.buildProject = Utilities.ReinitializeMsBuildProject(this.buildEngine, fileName, this.buildProject);
|
| -
|
| -
|
| - // Compute the file name
|
| - // We try to solve two problems here. When input comes from a wizzard in case of zipped based projects
|
| - // the parameters are different.
|
| - // In that case the filename has the new filename in a temporay path.
|
| -
|
| - // First get the extension from the template.
|
| - // Then get the filename from the name.
|
| - // Then create the new full path of the project.
|
| - string extension = Path.GetExtension(fileName);
|
| -
|
| - string tempName = String.Empty;
|
| -
|
| - // We have to be sure that we are not going to loose data here. If the project name is a.b.c then for a project that was based on a zipped template(the wizzard calls us) GetFileNameWithoutExtension will suppress "c".
|
| - // We are going to check if the parameter "name" is extension based and the extension is the same as the one from the "filename" parameter.
|
| - string tempExtension = Path.GetExtension(name);
|
| - if(!String.IsNullOrEmpty(tempExtension))
|
| - {
|
| - bool isSameExtension = (String.Compare(tempExtension, extension, StringComparison.OrdinalIgnoreCase) == 0);
|
| -
|
| - if(isSameExtension)
|
| - {
|
| - tempName = Path.GetFileNameWithoutExtension(name);
|
| - }
|
| - // If the tempExtension is not the same as the extension that the project name comes from then assume that the project name is a dotted name.
|
| - else
|
| - {
|
| - tempName = Path.GetFileName(name);
|
| - }
|
| - }
|
| - else
|
| - {
|
| - tempName = Path.GetFileName(name);
|
| - }
|
| -
|
| - Debug.Assert(!String.IsNullOrEmpty(tempName), "Could not compute project name");
|
| - string tempProjectFileName = tempName + extension;
|
| - this.filename = Path.Combine(location, tempProjectFileName);
|
| -
|
| - // Initialize the common project properties.
|
| - this.InitializeProjectProperties();
|
| -
|
| - ErrorHandler.ThrowOnFailure(this.Save(this.filename, 1, 0));
|
| -
|
| - // now we do have the project file saved. we need to create embedded files.
|
| - MSBuild.BuildItemGroup projectFiles = this.buildProject.EvaluatedItems;
|
| - foreach(MSBuild.BuildItem item in projectFiles)
|
| - {
|
| - // Ignore the item if it is a reference or folder
|
| - if(this.FilterItemTypeToBeAddedToHierarchy(item.Name))
|
| - {
|
| - continue;
|
| - }
|
| -
|
| - // MSBuilds tasks/targets can create items (such as object files),
|
| - // such items are not part of the project per say, and should not be displayed.
|
| - // so ignore those items.
|
| - if(!this.IsItemTypeFileType(item.Name))
|
| - {
|
| - continue;
|
| - }
|
| -
|
| - string strRelFilePath = item.FinalItemSpec;
|
| - string basePath = Path.GetDirectoryName(fileName);
|
| - string strPathToFile;
|
| - string newFileName;
|
| - // taking the base name from the project template + the relative pathname,
|
| - // and you get the filename
|
| - strPathToFile = Path.Combine(basePath, strRelFilePath);
|
| - // the new path should be the base dir of the new project (location) + the rel path of the file
|
| - newFileName = Path.Combine(location, strRelFilePath);
|
| - // now the copy file
|
| - AddFileFromTemplate(strPathToFile, newFileName);
|
| - }
|
| - }
|
| - else
|
| - {
|
| - this.filename = fileName;
|
| - }
|
| -
|
| - // now reload to fix up references
|
| - this.Reload();
|
| - }
|
| - finally
|
| - {
|
| - this.disableQueryEdit = false;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Called to add a file to the project from a template.
|
| - /// Override to do it yourself if you want to customize the file
|
| - /// </summary>
|
| - /// <param name="source">Full path of template file</param>
|
| - /// <param name="target">Full path of file once added to the project</param>
|
| - public virtual void AddFileFromTemplate(string source, string target)
|
| - {
|
| - if(String.IsNullOrEmpty(source))
|
| - {
|
| - throw new ArgumentNullException("source");
|
| - }
|
| - if(String.IsNullOrEmpty(target))
|
| - {
|
| - throw new ArgumentNullException("target");
|
| - }
|
| -
|
| - try
|
| - {
|
| - string directory = Path.GetDirectoryName(target);
|
| - if(!String.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
| - {
|
| - Directory.CreateDirectory(directory);
|
| - }
|
| -
|
| - FileInfo fiOrg = new FileInfo(source);
|
| - FileInfo fiNew = fiOrg.CopyTo(target, true);
|
| -
|
| - fiNew.Attributes = FileAttributes.Normal; // remove any read only attributes.
|
| - }
|
| - catch(IOException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - catch(UnauthorizedAccessException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - catch(ArgumentException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - catch(NotSupportedException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Called when the project opens an editor window for the given file
|
| - /// </summary>
|
| - public virtual void OnOpenItem(string fullPathToSourceFile)
|
| - {
|
| - }
|
| -
|
| - /// <summary>
|
| - /// This add methos adds the "key" item to the hierarchy, potentially adding other subitems in the process
|
| - /// This method may recurse if the parent is an other subitem
|
| - ///
|
| - /// </summary>
|
| - /// <param name="subitems">List of subitems not yet added to the hierarchy</param>
|
| - /// <param name="key">Key to retrieve the target item from the subitems list</param>
|
| - /// <returns>Newly added node</returns>
|
| - /// <remarks>If the parent node was found we add the dependent item to it otherwise we add the item ignoring the "DependentUpon" metatdata</remarks>
|
| - protected virtual HierarchyNode AddDependentFileNode(IDictionary<String, MSBuild.BuildItem> subitems, string key)
|
| - {
|
| - MSBuild.BuildItem item = subitems[key];
|
| - subitems.Remove(key);
|
| -
|
| - HierarchyNode newNode;
|
| - HierarchyNode parent = null;
|
| -
|
| - string dependentOf = item.GetMetadata(ProjectFileConstants.DependentUpon);
|
| - Debug.Assert(String.Compare(dependentOf, key, StringComparison.OrdinalIgnoreCase) != 0, "File dependent upon itself is not valid. Ignoring the DependentUpon metadata");
|
| - if(subitems.ContainsKey(dependentOf))
|
| - {
|
| - // The parent item is an other subitem, so recurse into this method to add the parent first
|
| - parent = AddDependentFileNode(subitems, dependentOf);
|
| - }
|
| - else
|
| - {
|
| - // See if the parent node already exist in the hierarchy
|
| - uint parentItemID;
|
| - string path = Path.Combine(this.ProjectFolder, dependentOf);
|
| - ErrorHandler.ThrowOnFailure(this.ParseCanonicalName(path, out parentItemID));
|
| - if(parentItemID != 0)
|
| - parent = this.NodeFromItemId(parentItemID);
|
| - Debug.Assert(parent != null, "File dependent upon a non existing item or circular dependency. Ignoring the DependentUpon metadata");
|
| - }
|
| -
|
| - // If the parent node was found we add the dependent item to it otherwise we add the item ignoring the "DependentUpon" metatdata
|
| - if(parent != null)
|
| - newNode = this.AddDependentFileNodeToNode(item, parent);
|
| - else
|
| - newNode = this.AddIndependentFileNode(item);
|
| -
|
| - return newNode;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// This is called from the main thread before the background build starts.
|
| - /// cleanBuild is not part of the vsopts, but passed down as the callpath is differently
|
| - /// PrepareBuild mainly creates directories and cleans house if cleanBuild is true
|
| - /// </summary>
|
| - /// <param name="config"></param>
|
| - /// <param name="cleanBuild"></param>
|
| - public virtual void PrepareBuild(string config, bool cleanBuild)
|
| - {
|
| - if(this.buildIsPrepared && !cleanBuild) return;
|
| -
|
| - ProjectOptions options = this.GetProjectOptions(config);
|
| - string outputPath = Path.GetDirectoryName(options.OutputAssembly);
|
| -
|
| - if(cleanBuild && this.buildProject.Targets.Exists(MsBuildTarget.Clean))
|
| - {
|
| - this.InvokeMsBuild(MsBuildTarget.Clean);
|
| - }
|
| -
|
| - PackageUtilities.EnsureOutputPath(outputPath);
|
| - if(!String.IsNullOrEmpty(options.XmlDocFileName))
|
| - {
|
| - PackageUtilities.EnsureOutputPath(Path.GetDirectoryName(options.XmlDocFileName));
|
| - }
|
| -
|
| - this.buildIsPrepared = true;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Do the build by invoking msbuild
|
| - /// </summary>
|
| - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "vsopts")]
|
| - public virtual MSBuildResult Build(uint vsopts, string config, IVsOutputWindowPane output, string target)
|
| - {
|
| - lock(ProjectNode.BuildLock)
|
| - {
|
| - bool engineLogOnlyCritical = false;
|
| - // If there is some output, then we can ask the build engine to log more than
|
| - // just the critical events.
|
| - if(null != output)
|
| - {
|
| - engineLogOnlyCritical = BuildEngine.OnlyLogCriticalEvents;
|
| - BuildEngine.OnlyLogCriticalEvents = false;
|
| - }
|
| - this.SetOutputLogger(output);
|
| - MSBuildResult result = MSBuildResult.Failed;
|
| -
|
| - try
|
| - {
|
| - this.SetBuildConfigurationProperties(config);
|
| - result = this.InvokeMsBuild(target);
|
| - }
|
| - finally
|
| - {
|
| - // Unless someone specifically request to use an output window pane, we should not output to it
|
| - if(null != output)
|
| - {
|
| - this.SetOutputLogger(null);
|
| - BuildEngine.OnlyLogCriticalEvents = engineLogOnlyCritical;
|
| - }
|
| - }
|
| -
|
| - return result;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Return the value of a project property
|
| - /// </summary>
|
| - /// <param name="propertyName">Name of the property to get</param>
|
| - /// <param name="resetCache">True to avoid using the cache</param>
|
| - /// <returns>null if property does not exist, otherwise value of the property</returns>
|
| - public virtual string GetProjectProperty(string propertyName, bool resetCache)
|
| - {
|
| - MSBuild.BuildProperty property = GetMsBuildProperty(propertyName, resetCache);
|
| - if(property == null)
|
| - return null;
|
| -
|
| - return property.FinalValue;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Set value of project property
|
| - /// </summary>
|
| - /// <param name="propertyName">Name of property</param>
|
| - /// <param name="propertyValue">Value of property</param>
|
| - public virtual void SetProjectProperty(string propertyName, string propertyValue)
|
| - {
|
| - if(propertyName == null)
|
| - throw new ArgumentNullException("propertyName", "Cannot set a null project property");
|
| -
|
| - string oldValue = (string)GetMsBuildProperty(propertyName, true);
|
| - if(propertyValue == null)
|
| - {
|
| - // if property already null, do nothing
|
| - if(oldValue == null)
|
| - return;
|
| - // otherwise, set it to empty
|
| - propertyValue = String.Empty;
|
| - }
|
| -
|
| - // Only do the work if this is different to what we had before
|
| - if(String.Compare(oldValue, propertyValue, StringComparison.Ordinal) != 0)
|
| - {
|
| - // Check out the project file.
|
| - if(!this.ProjectMgr.QueryEditProjectFile(false))
|
| - {
|
| - throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED);
|
| - }
|
| -
|
| - this.buildProject.SetProperty(propertyName, propertyValue, null);
|
| - RaiseProjectPropertyChanged(propertyName, oldValue, propertyValue);
|
| -
|
| - // property cache will need to be updated
|
| - this.currentConfig = null;
|
| - this.SetProjectFileDirty(true);
|
| - }
|
| - return;
|
| - }
|
| -
|
| - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")]
|
| - public virtual ProjectOptions GetProjectOptions(string config)
|
| - {
|
| - bool configNotChanged = String.Compare(
|
| - currentConfig[ProjectFileConstants.Configuration].Value,
|
| - config, StringComparison.OrdinalIgnoreCase) == 0;
|
| -
|
| - if (this.options != null && configNotChanged)
|
| - return this.options;
|
| -
|
| - ProjectOptions options = this.options = CreateProjectOptions();
|
| -
|
| - if(config == null)
|
| - return options;
|
| -
|
| - options.GenerateExecutable = true;
|
| -
|
| - this.SetConfiguration(config);
|
| -
|
| - string outputPath = this.GetOutputPath(this.currentConfig);
|
| - if(!String.IsNullOrEmpty(outputPath))
|
| - {
|
| - // absolutize relative to project folder location
|
| - outputPath = Path.Combine(this.ProjectFolder, outputPath);
|
| - }
|
| -
|
| - // Set some default values
|
| - options.OutputAssembly = outputPath + this.Caption + ".exe";
|
| - options.ModuleKind = ModuleKindFlags.ConsoleApplication;
|
| -
|
| - options.RootNamespace = GetProjectProperty(ProjectFileConstants.RootNamespace, false);
|
| - options.OutputAssembly = outputPath + this.GetAssemblyName(config);
|
| -
|
| - string outputtype = GetProjectProperty(ProjectFileConstants.OutputType, false);
|
| - if(!string.IsNullOrEmpty(outputtype))
|
| - {
|
| - outputtype = outputtype.ToLower(CultureInfo.InvariantCulture);
|
| - }
|
| -
|
| - if(outputtype == "library")
|
| - {
|
| - options.ModuleKind = ModuleKindFlags.DynamicallyLinkedLibrary;
|
| - options.GenerateExecutable = false; // DLL's have no entry point.
|
| - }
|
| - else if(outputtype == "winexe")
|
| - options.ModuleKind = ModuleKindFlags.WindowsApplication;
|
| - else
|
| - options.ModuleKind = ModuleKindFlags.ConsoleApplication;
|
| -
|
| - options.Win32Icon = GetProjectProperty("ApplicationIcon", false);
|
| - options.MainClass = GetProjectProperty("StartupObject", false);
|
| -
|
| - string targetPlatform = GetProjectProperty("TargetPlatform", false);
|
| -
|
| - if(targetPlatform != null && targetPlatform.Length > 0)
|
| - {
|
| - try
|
| - {
|
| - options.TargetPlatform = (PlatformType)Enum.Parse(typeof(PlatformType), targetPlatform);
|
| - }
|
| - catch(ArgumentException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - options.TargetPlatformLocation = GetProjectProperty("TargetPlatformLocation", false);
|
| - this.SetTargetPlatform(options);
|
| - }
|
| -
|
| - // other settings from CSharp we may want to adopt at some point...
|
| - // AssemblyKeyContainerName = "" //This is the key file used to sign the interop assembly generated when importing a com object via add reference
|
| - // AssemblyOriginatorKeyFile = ""
|
| - // DelaySign = "false"
|
| - // DefaultClientScript = "JScript"
|
| - // DefaultHTMLPageLayout = "Grid"
|
| - // DefaultTargetSchema = "IE50"
|
| - // PreBuildEvent = ""
|
| - // PostBuildEvent = ""
|
| - // RunPostBuildEvent = "OnBuildSuccess"
|
| -
|
| - // transfer all config build options...
|
| - if(GetBoolAttr(this.currentConfig, "AllowUnsafeBlocks"))
|
| - {
|
| - options.AllowUnsafeCode = true;
|
| - }
|
| -
|
| - if(GetProjectProperty("BaseAddress", false) != null)
|
| - {
|
| - try
|
| - {
|
| - options.BaseAddress = Int64.Parse(GetProjectProperty("BaseAddress", false), CultureInfo.InvariantCulture);
|
| - }
|
| - catch(ArgumentNullException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - catch(ArgumentException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - catch(FormatException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - catch(OverflowException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - }
|
| -
|
| - if(GetBoolAttr(this.currentConfig, "CheckForOverflowUnderflow"))
|
| - {
|
| - options.CheckedArithmetic = true;
|
| - }
|
| -
|
| - if(GetProjectProperty("DefineConstants", false) != null)
|
| - {
|
| - options.DefinedPreprocessorSymbols = new StringCollection();
|
| - foreach(string s in GetProjectProperty("DefineConstants", false).Replace(" \t\r\n", "").Split(';'))
|
| - {
|
| - options.DefinedPreprocessorSymbols.Add(s);
|
| - }
|
| - }
|
| -
|
| - string docFile = GetProjectProperty("DocumentationFile", false);
|
| - if(!String.IsNullOrEmpty(docFile))
|
| - {
|
| - options.XmlDocFileName = Path.Combine(this.ProjectFolder, docFile);
|
| - }
|
| -
|
| - if(GetBoolAttr(this.currentConfig, "DebugSymbols"))
|
| - {
|
| - options.IncludeDebugInformation = true;
|
| - }
|
| -
|
| - if(GetProjectProperty("FileAlignment", false) != null)
|
| - {
|
| - try
|
| - {
|
| - options.FileAlignment = Int32.Parse(GetProjectProperty("FileAlignment", false), CultureInfo.InvariantCulture);
|
| - }
|
| - catch(ArgumentNullException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - catch(ArgumentException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - catch(FormatException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - catch(OverflowException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - }
|
| -
|
| - if(GetBoolAttr(this.currentConfig, "IncrementalBuild"))
|
| - {
|
| - options.IncrementalCompile = true;
|
| - }
|
| -
|
| - if(GetBoolAttr(this.currentConfig, "Optimize"))
|
| - {
|
| - options.Optimize = true;
|
| - }
|
| -
|
| - if(GetBoolAttr(this.currentConfig, "RegisterForComInterop"))
|
| - {
|
| - }
|
| -
|
| - if(GetBoolAttr(this.currentConfig, "RemoveIntegerChecks"))
|
| - {
|
| - }
|
| -
|
| - if(GetBoolAttr(this.currentConfig, "TreatWarningsAsErrors"))
|
| - {
|
| - options.TreatWarningsAsErrors = true;
|
| - }
|
| -
|
| - if(GetProjectProperty("WarningLevel", false) != null)
|
| - {
|
| - try
|
| - {
|
| - options.WarningLevel = Int32.Parse(GetProjectProperty("WarningLevel", false), CultureInfo.InvariantCulture);
|
| - }
|
| - catch(ArgumentNullException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - catch(ArgumentException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - catch(FormatException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - catch(OverflowException e)
|
| - {
|
| - Trace.WriteLine("Exception : " + e.Message);
|
| - }
|
| - }
|
| -
|
| - return options;
|
| - }
|
| -
|
| - public virtual void SetTargetPlatform(ProjectOptions options)
|
| - {
|
| - }
|
| -
|
| - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Attr")]
|
| - [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "bool")]
|
| - public virtual bool GetBoolAttr(string config, string name)
|
| - {
|
| - this.SetConfiguration(config);
|
| - MSBuild.BuildPropertyGroup properties = this.buildProject.EvaluatedProperties;
|
| -
|
| - return this.GetBoolAttr(properties, name);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Get the assembly name for a give configuration
|
| - /// </summary>
|
| - /// <param name="config">the matching configuration in the msbuild file</param>
|
| - /// <returns>assembly name</returns>
|
| - public virtual string GetAssemblyName(string config)
|
| - {
|
| - this.SetConfiguration(config);
|
| - MSBuild.BuildPropertyGroup properties = this.buildProject.EvaluatedProperties;
|
| -
|
| - return GetAssemblyName(properties);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Determines whether a file is a code file.
|
| - /// </summary>
|
| - /// <param name="fileName">Name of the file to be evaluated</param>
|
| - /// <returns>false by default for any fileName</returns>
|
| - public virtual bool IsCodeFile(string fileName)
|
| - {
|
| - return false;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Determines whether the given file is a resource file (resx file).
|
| - /// </summary>
|
| - /// <param name="fileName">Name of the file to be evaluated.</param>
|
| - /// <returns>true if the file is a resx file, otherwise false.</returns>
|
| - public virtual bool IsEmbeddedResource(string fileName)
|
| - {
|
| - if(String.Compare(Path.GetExtension(fileName), ".ResX", StringComparison.OrdinalIgnoreCase) == 0)
|
| - return true;
|
| - return false;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Create a file node based on an msbuild item.
|
| - /// </summary>
|
| - /// <param name="item">msbuild item</param>
|
| - /// <returns>FileNode added</returns>
|
| - public virtual FileNode CreateFileNode(ProjectElement item)
|
| - {
|
| - return new FileNode(this, item);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Create a file node based on a string.
|
| - /// </summary>
|
| - /// <param name="file">filename of the new filenode</param>
|
| - /// <returns>File node added</returns>
|
| - public virtual FileNode CreateFileNode(string file)
|
| - {
|
| - ProjectElement item = this.AddFileToMsBuild(file);
|
| - return this.CreateFileNode(item);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Create dependent file node based on an msbuild item
|
| - /// </summary>
|
| - /// <param name="item">msbuild item</param>
|
| - /// <returns>dependent file node</returns>
|
| - public virtual DependentFileNode CreateDependentFileNode(ProjectElement item)
|
| - {
|
| - return new DependentFileNode(this, item);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Create a dependent file node based on a string.
|
| - /// </summary>
|
| - /// <param name="file">filename of the new dependent file node</param>
|
| - /// <returns>Dependent node added</returns>
|
| - public virtual DependentFileNode CreateDependentFileNode(string file)
|
| - {
|
| - ProjectElement item = this.AddFileToMsBuild(file);
|
| - return this.CreateDependentFileNode(item);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Walks the subpaths of a project relative path and checks if the folder nodes hierarchy is already there, if not creates it.
|
| - /// </summary>
|
| - /// <param name="strPath">Path of the folder, can be relative to project or absolute</param>
|
| - public virtual HierarchyNode CreateFolderNodes(string path)
|
| - {
|
| - if(String.IsNullOrEmpty(path))
|
| - {
|
| - throw new ArgumentNullException("path");
|
| - }
|
| -
|
| - if(Path.IsPathRooted(path))
|
| - {
|
| - // Ensure we are using a relative path
|
| - if(String.Compare(this.ProjectFolder, 0, path, 0, this.ProjectFolder.Length, StringComparison.OrdinalIgnoreCase) != 0)
|
| - throw new ArgumentException("The path is not relative", "path");
|
| -
|
| - path = path.Substring(this.ProjectFolder.Length);
|
| - }
|
| -
|
| - string[] parts;
|
| - HierarchyNode curParent;
|
| -
|
| - parts = path.Split(Path.DirectorySeparatorChar);
|
| - path = String.Empty;
|
| - curParent = this;
|
| -
|
| - // now we have an array of subparts....
|
| - for(int i = 0; i < parts.Length; i++)
|
| - {
|
| - if(parts[i].Length > 0)
|
| - {
|
| - path += parts[i] + "\\";
|
| - curParent = VerifySubFolderExists(path, curParent);
|
| - }
|
| - }
|
| - return curParent;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Defines if Node has Designer. By default we do not support designers for nodes
|
| - /// </summary>
|
| - /// <param name="itemPath">Path to item to query for designer support</param>
|
| - /// <returns>true if node has designer</returns>
|
| - public virtual bool NodeHasDesigner(string itemPath)
|
| - {
|
| - return false;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Checks if project is save to load
|
| - /// </summary>
|
| - /// <returns></returns>
|
| - protected virtual ProjectLoadOption IsProjectSecure()
|
| - {
|
| - // If we are in command line mode then we do no security checks and assume it is trusted.
|
| - if(Utilities.IsShellInCommandLineMode(this.Site))
|
| - {
|
| - return ProjectLoadOption.LoadNormally;
|
| - }
|
| -
|
| - // Make sure we've first read the project trust information out of the .SUO, if we haven't already.
|
| - this.package.ReadProjectTrustInformation();
|
| -
|
| - // If the project is trusted because it has been checked previously and marked as such in
|
| - // the .SUO file, then no need to go through all this.
|
| - ProjectTrustLevel projectTrustLevel = this.package.GetProjectTrustLevel(this.projectIdGuid);
|
| - if(projectTrustLevel == ProjectTrustLevel.Trusted)
|
| - {
|
| - return ProjectLoadOption.LoadNormally;
|
| - }
|
| -
|
| - // Instantiate the project security checker and do the security checking
|
| - ProjectSecurityChecker securityChecker = this.CreateProjectSecurityChecker(this.buildProject.FullFileName);
|
| - ProjectSecurityChecker userProjecSecurityChecker = null;
|
| - string perUserFile = this.buildProject.FullFileName + ProjectNode.PerUserFileExtension;
|
| -
|
| - if(File.Exists(perUserFile))
|
| - {
|
| - userProjecSecurityChecker = this.CreateUserProjectSecurityChecker(perUserFile);
|
| - ((UserProjectSecurityChecker)userProjecSecurityChecker).MainProjectShim = securityChecker.ProjectShim;
|
| - }
|
| -
|
| - return this.CheckProjectForSecurity(securityChecker, userProjecSecurityChecker);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Creates an instance of a ProjectSecurityChecker object that is in charge of checking the project fier for security defects.
|
| - /// </summary>
|
| - /// <returns>An instance of a ProjectSecurityChecker</returns>
|
| - protected virtual ProjectSecurityChecker CreateProjectSecurityChecker(string projectFileName)
|
| - {
|
| - return new ProjectSecurityChecker(this.Site, projectFileName);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Creates an instance of a ProjectSecurityChecker object that is in charge of checking the user project file for security defects.
|
| - /// </summary>
|
| - /// <returns>An instance of a ProjectSecurityChecker</returns>
|
| - protected virtual ProjectSecurityChecker CreateUserProjectSecurityChecker(string projectFileName)
|
| - {
|
| - return new UserProjectSecurityChecker(this.Site, projectFileName);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Checks the project for security. If there is a security violation a dialog box will be popped asking the user for
|
| - /// either open the project for browsing, or open it normally, or cancel project loading.
|
| - /// </summary>
|
| - /// <param name="projectSecurityChecker">An instance of the project security object.</param>
|
| - /// <param name="userProjectSecurityChecker">An instance of the user project security object.</param>
|
| - /// <returns>Either a flag specifying to load the project normally, or not to load the project</returns>
|
| - protected virtual ProjectLoadOption CheckProjectForSecurity(ProjectSecurityChecker projectSecurityChecker, ProjectSecurityChecker userProjectSecurityChecker)
|
| - {
|
| - // We will first test on the project file and then if that is not loaded for browsing we are going to test on the user file.
|
| - ProjectLoadOption projectLoadOption = ProjectLoadOption.DonNotLoad;
|
| - string securityMessage = String.Empty;
|
| - bool isProjectSafe = projectSecurityChecker.IsProjectSafeAtLoadTime(out securityMessage);
|
| - if(!isProjectSafe)
|
| - {
|
| - projectLoadOption = this.ShowSecurityDialogBox(securityMessage);
|
| -
|
| - if(projectLoadOption == ProjectLoadOption.LoadNormally)
|
| - {
|
| - if(userProjectSecurityChecker == null)
|
| - {
|
| - // The project was unsafe, and the user has opted to treat it as safe.
|
| - // Mark the project as "Trusted" in the .SUO file, so we never have to
|
| - // go through all this again.
|
| - this.package.SetProjectTrustLevel(this.projectIdGuid, ProjectTrustLevel.Trusted);
|
| - }
|
| - else
|
| - {
|
| - // If we have a user project we will have to redo all this, since that Load Normally was meant only for the project file.
|
| - projectLoadOption = this.CheckProjectForSecurity(userProjectSecurityChecker, null);
|
| -
|
| - if(projectLoadOption == ProjectLoadOption.LoadNormally)
|
| - {
|
| - this.package.SetProjectTrustLevel(this.projectIdGuid, ProjectTrustLevel.Trusted);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - else
|
| - {
|
| - // If we have a user file do teh check there too.
|
| - if(userProjectSecurityChecker != null)
|
| - {
|
| - projectLoadOption = this.CheckProjectForSecurity(userProjectSecurityChecker, null);
|
| - }
|
| - else
|
| - {
|
| - projectLoadOption = ProjectLoadOption.LoadNormally;
|
| - }
|
| - }
|
| -
|
| - return projectLoadOption;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Informs the user of the security situation, and gives an opportunity to treat the project
|
| - /// as trusted (safe) despite the risk.
|
| - /// This method is called during project load time, thus no state is yet available on the project.
|
| - /// </summary>
|
| - /// <param name="messageBox">The messageBox string to be shown to the user.</param>
|
| - /// <returns>A ProjectLoadOption</returns>
|
| - protected virtual ProjectLoadOption ShowSecurityDialogBox(string messageBox)
|
| - {
|
| - // If we're under automation right now, don't pop up a dialog... just assume the
|
| - // more secure option which is to load the project for Browsing.
|
| - if(Utilities.IsInAutomationFunction(this.Site))
|
| - {
|
| - return ProjectLoadOption.LoadOnlyForBrowsing;
|
| - }
|
| -
|
| - IVsSolution solution = this.Site.GetService(typeof(SVsSolution)) as IVsSolution;
|
| -
|
| - if(solution == null)
|
| - {
|
| - throw new InvalidOperationException();
|
| - }
|
| -
|
| - ProjectLoadOption projectLoadOption = ProjectLoadOption.DonNotLoad;
|
| -
|
| - object dialogStateAsObject;
|
| - ErrorHandler.ThrowOnFailure(solution.GetProperty((int)__VSPROPID2.VSPROPID_ProjectLoadSecurityDialogState, out dialogStateAsObject));
|
| -
|
| - _ProjectLoadSecurityDialogState dialogState = (_ProjectLoadSecurityDialogState)dialogStateAsObject;
|
| -
|
| - // If the user had the "Ask me always" box checked ...
|
| - if(dialogState != _ProjectLoadSecurityDialogState.PLSDS_DontShowAgainBrowse &&
|
| - dialogState != _ProjectLoadSecurityDialogState.PLSDS_DontShowAgainUnload &&
|
| - dialogState != _ProjectLoadSecurityDialogState.PLSDS_DontShowAgainFullLoad)
|
| - {
|
| - // ... then we need to actually show the dialog and get a response from the user.
|
| - SecurityWarningDialog dialog = new SecurityWarningDialog(this.Site, messageBox, this.buildProject.FullFileName);
|
| -
|
| - DialogResult result = dialog.ShowDialog();
|
| - if(result != DialogResult.Cancel)
|
| - {
|
| - projectLoadOption = dialog.ProjectLoadOption;
|
| -
|
| - if(!dialog.AskAgainCheckBoxValue)
|
| - {
|
| - // The user unchecked the "Ask me always" checkbox. So save his response in the
|
| - // solution (not the solution file) so that we can re-use the same response later.
|
| - switch(projectLoadOption)
|
| - {
|
| - case ProjectLoadOption.LoadNormally:
|
| - Utilities.SaveDialogStateInSolution(this.Site, _ProjectLoadSecurityDialogState.PLSDS_DontShowAgainFullLoad);
|
| - break;
|
| -
|
| - case ProjectLoadOption.DonNotLoad:
|
| - Utilities.SaveDialogStateInSolution(this.Site, _ProjectLoadSecurityDialogState.PLSDS_DontShowAgainUnload);
|
| - break;
|
| -
|
| - case ProjectLoadOption.LoadOnlyForBrowsing:
|
| - Utilities.SaveDialogStateInSolution(this.Site, _ProjectLoadSecurityDialogState.PLSDS_DontShowAgainBrowse);
|
| - break;
|
| -
|
| - default:
|
| - throw new InvalidOperationException();
|
| - }
|
| - }
|
| - }
|
| - }
|
| - else
|
| - {
|
| - switch(dialogState)
|
| - {
|
| - case _ProjectLoadSecurityDialogState.PLSDS_DontShowAgainBrowse:
|
| - projectLoadOption = ProjectLoadOption.LoadOnlyForBrowsing;
|
| - break;
|
| -
|
| - case _ProjectLoadSecurityDialogState.PLSDS_DontShowAgainFullLoad:
|
| - projectLoadOption = ProjectLoadOption.LoadNormally;
|
| - break;
|
| -
|
| - case _ProjectLoadSecurityDialogState.PLSDS_DontShowAgainUnload:
|
| - projectLoadOption = ProjectLoadOption.DonNotLoad;
|
| - break;
|
| -
|
| - default:
|
| - throw new InvalidOperationException();
|
| - }
|
| - }
|
| -
|
| - return projectLoadOption;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// List of Guids of the config independent property pages. It is called by the GetProperty for VSHPROPID_PropertyPagesCLSIDList property.
|
| - /// </summary>
|
| - /// <returns></returns>
|
| - protected virtual Guid[] GetConfigurationIndependentPropertyPages()
|
| - {
|
| - return new Guid[] { Guid.Empty };
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Returns a list of Guids of the configuration dependent property pages. It is called by the GetProperty for VSHPROPID_CfgPropertyPagesCLSIDList property.
|
| - /// </summary>
|
| - /// <returns></returns>
|
| - protected virtual Guid[] GetConfigurationDependentPropertyPages()
|
| - {
|
| - return new Guid[0];
|
| - }
|
| -
|
| - /// <summary>
|
| - /// An ordered list of guids of the prefered property pages. See <see cref="__VSHPROPID.VSHPROPID_PriorityPropertyPagesCLSIDList"/>
|
| - /// </summary>
|
| - /// <returns>An array of guids.</returns>
|
| - protected virtual Guid[] GetPriorityProjectDesignerPages()
|
| - {
|
| - return new Guid[] { Guid.Empty };
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Takes a path and verifies that we have a node with that name.
|
| - /// It is meant to be a helper method for CreateFolderNodes().
|
| - /// For some scenario it may be useful to override.
|
| - /// </summary>
|
| - /// <param name="path">full path to the subfolder we want to verify.</param>
|
| - /// <param name="parent">the parent node where to add the subfolder if it does not exist.</param>
|
| - /// <returns>the foldernode correcsponding to the path.</returns>
|
| - [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "SubFolder")]
|
| - protected virtual FolderNode VerifySubFolderExists(string path, HierarchyNode parent)
|
| - {
|
| - FolderNode folderNode = null;
|
| - uint uiItemId;
|
| - Url url = new Url(this.BaseURI, path);
|
| - string strFullPath = url.AbsoluteUrl;
|
| - // Folders end in our storage with a backslash, so add one...
|
| - ErrorHandler.ThrowOnFailure(this.ParseCanonicalName(strFullPath, out uiItemId));
|
| - if(uiItemId != 0)
|
| - {
|
| - Debug.Assert(this.NodeFromItemId(uiItemId) is FolderNode, "Not a FolderNode");
|
| - folderNode = (FolderNode)this.NodeFromItemId(uiItemId);
|
| - }
|
| -
|
| - if(folderNode == null)
|
| - {
|
| - // folder does not exist yet...
|
| - // We could be in the process of loading so see if msbuild knows about it
|
| - MSBuild.BuildItemGroup folders = buildProject.GetEvaluatedItemsByName(ProjectFileConstants.Folder);
|
| - ProjectElement item = null;
|
| - foreach(MSBuild.BuildItem folder in folders)
|
| - {
|
| - if(String.Compare(folder.FinalItemSpec.TrimEnd('\\'), path.TrimEnd('\\'), StringComparison.OrdinalIgnoreCase) == 0)
|
| - {
|
| - item = new ProjectElement(this, folder, false);
|
| - break;
|
| - }
|
| - }
|
| - // If MSBuild did not know about it, create a new one
|
| - if(item == null)
|
| - item = this.AddFolderToMsBuild(path);
|
| - folderNode = this.CreateFolderNode(path, item);
|
| - parent.AddChild(folderNode);
|
| - }
|
| -
|
| - return folderNode;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// To support virtual folders, override this method to return your own folder nodes
|
| - /// </summary>
|
| - /// <param name="path">Path to store for this folder</param>
|
| - /// <param name="element">Element corresponding to the folder</param>
|
| - /// <returns>A FolderNode that can then be added to the hierarchy</returns>
|
| - protected internal virtual FolderNode CreateFolderNode(string path, ProjectElement element)
|
| - {
|
| - FolderNode folderNode = new FolderNode(this, path, element);
|
| - return folderNode;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Gets the list of selected HierarchyNode objects
|
| - /// </summary>
|
| - /// <returns>A list of HierarchyNode objects</returns>
|
| - protected internal virtual IList<HierarchyNode> GetSelectedNodes()
|
| - {
|
| - // Retrieve shell interface in order to get current selection
|
| - IVsMonitorSelection monitorSelection = this.GetService(typeof(IVsMonitorSelection)) as IVsMonitorSelection;
|
| -
|
| - if(monitorSelection == null)
|
| - {
|
| - throw new InvalidOperationException();
|
| - }
|
| -
|
| - List<HierarchyNode> selectedNodes = new List<HierarchyNode>();
|
| - IntPtr hierarchyPtr = IntPtr.Zero;
|
| - IntPtr selectionContainer = IntPtr.Zero;
|
| - try
|
| - {
|
| - // Get the current project hierarchy, project item, and selection container for the current selection
|
| - // If the selection spans multiple hierachies, hierarchyPtr is Zero
|
| - uint itemid;
|
| - IVsMultiItemSelect multiItemSelect = null;
|
| - ErrorHandler.ThrowOnFailure(monitorSelection.GetCurrentSelection(out hierarchyPtr, out itemid, out multiItemSelect, out selectionContainer));
|
| -
|
| - // We only care if there are one ore more nodes selected in the tree
|
| - if(itemid != VSConstants.VSITEMID_NIL && hierarchyPtr != IntPtr.Zero)
|
| - {
|
| - IVsHierarchy hierarchy = Marshal.GetObjectForIUnknown(hierarchyPtr) as IVsHierarchy;
|
| -
|
| - if(itemid != VSConstants.VSITEMID_SELECTION)
|
| - {
|
| - // This is a single selection. Compare hirarchy with our hierarchy and get node from itemid
|
| - if(Utilities.IsSameComObject(this, hierarchy))
|
| - {
|
| - HierarchyNode node = this.NodeFromItemId(itemid);
|
| - if(node != null)
|
| - {
|
| - selectedNodes.Add(node);
|
| - }
|
| - }
|
| - else
|
| - {
|
| - NestedProjectNode node = this.GetNestedProjectForHierarchy(hierarchy);
|
| - if(node != null)
|
| - {
|
| - selectedNodes.Add(node);
|
| - }
|
| - }
|
| - }
|
| - else if(multiItemSelect != null)
|
| - {
|
| - // This is a multiple item selection.
|
| -
|
| - //Get number of items selected and also determine if the items are located in more than one hierarchy
|
| - uint numberOfSelectedItems;
|
| - int isSingleHierarchyInt;
|
| - ErrorHandler.ThrowOnFailure(multiItemSelect.GetSelectionInfo(out numberOfSelectedItems, out isSingleHierarchyInt));
|
| - bool isSingleHierarchy = (isSingleHierarchyInt != 0);
|
| -
|
| - // Now loop all selected items and add to the list only those that are selected within this hierarchy
|
| - if(!isSingleHierarchy || (isSingleHierarchy && Utilities.IsSameComObject(this, hierarchy)))
|
| - {
|
| - Debug.Assert(numberOfSelectedItems > 0, "Bad number of selected itemd");
|
| - VSITEMSELECTION[] vsItemSelections = new VSITEMSELECTION[numberOfSelectedItems];
|
| - uint flags = (isSingleHierarchy) ? (uint)__VSGSIFLAGS.GSI_fOmitHierPtrs : 0;
|
| - ErrorHandler.ThrowOnFailure(multiItemSelect.GetSelectedItems(flags, numberOfSelectedItems, vsItemSelections));
|
| - foreach(VSITEMSELECTION vsItemSelection in vsItemSelections)
|
| - {
|
| - if(isSingleHierarchy || Utilities.IsSameComObject(this, vsItemSelection.pHier))
|
| - {
|
| - HierarchyNode node = this.NodeFromItemId(vsItemSelection.itemid);
|
| - if(node != null)
|
| - {
|
| - selectedNodes.Add(node);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| - finally
|
| - {
|
| - if(hierarchyPtr != IntPtr.Zero)
|
| - {
|
| - Marshal.Release(hierarchyPtr);
|
| - }
|
| - if(selectionContainer != IntPtr.Zero)
|
| - {
|
| - Marshal.Release(selectionContainer);
|
| - }
|
| - }
|
| -
|
| - return selectedNodes;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Recursevily walks the hierarchy nodes and redraws the state icons
|
| - /// </summary>
|
| - protected internal override void UpdateSccStateIcons()
|
| - {
|
| - if(this.FirstChild == null)
|
| - {
|
| - return;
|
| - }
|
| -
|
| - for(HierarchyNode n = this.FirstChild; n != null; n = n.NextSibling)
|
| - {
|
| - n.UpdateSccStateIcons();
|
| - }
|
| - }
|
| -
|
| -
|
| - /// <summary>
|
| - /// Handles the shows all objects command.
|
| - /// </summary>
|
| - /// <returns></returns>
|
| - protected internal virtual int ShowAllFiles()
|
| - {
|
| - return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Handles the Add web reference command.
|
| - /// </summary>
|
| - /// <returns></returns>
|
| - protected internal virtual int AddWebReference()
|
| - {
|
| - return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Unloads the project.
|
| - /// </summary>
|
| - /// <returns></returns>
|
| - protected internal virtual int UnloadProject()
|
| - {
|
| - return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Handles the clean project command.
|
| - /// </summary>
|
| - /// <returns></returns>
|
| - protected virtual int CleanProject()
|
| - {
|
| - return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Reload project from project file
|
| - /// </summary>
|
| - protected virtual void Reload()
|
| - {
|
| - Debug.Assert(this.buildEngine != null, "There is no build engine defined for this project");
|
| -
|
| - try
|
| - {
|
| - this.disableQueryEdit = true;
|
| -
|
| - this.isClosed = false;
|
| - this.eventTriggeringFlag = ProjectNode.EventTriggering.DoNotTriggerHierarchyEvents | ProjectNode.EventTriggering.DoNotTriggerTrackerEvents;
|
| -
|
| - this.buildProject = Utilities.ReinitializeMsBuildProject(this.buildEngine, this.filename, this.buildProject);
|
| - MSBuild.BuildPropertyGroup projectProperties = buildProject.EvaluatedProperties;
|
| -
|
| - // Load the guid
|
| - if(projectProperties != null)
|
| - {
|
| - this.SetProjectGuidFromProjectFile();
|
| - }
|
| -
|
| - this.ProcessReferences();
|
| -
|
| - this.ProcessFiles();
|
| -
|
| - this.ProcessFolders();
|
| -
|
| - this.LoadNonBuildInformation();
|
| -
|
| - this.InitSccInfo();
|
| -
|
| - this.RegisterSccProject();
|
| - }
|
| - finally
|
| - {
|
| - this.SetProjectFileDirty(false);
|
| - this.eventTriggeringFlag = ProjectNode.EventTriggering.TriggerAll;
|
| - this.disableQueryEdit = false;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Renames the project file
|
| - /// </summary>
|
| - /// <param name="newFile">The full path of the new project file.</param>
|
| - protected virtual void RenameProjectFile(string newFile)
|
| - {
|
| - IVsUIShell shell = this.Site.GetService(typeof(SVsUIShell)) as IVsUIShell;
|
| - Debug.Assert(shell != null, "Could not get the ui shell from the project");
|
| - if(shell == null)
|
| - {
|
| - throw new InvalidOperationException();
|
| - }
|
| -
|
| - // Do some name validation
|
| - if(Microsoft.VisualStudio.Project.Utilities.ContainsInvalidFileNameChars(newFile))
|
| - {
|
| - throw new InvalidOperationException(SR.GetString(SR.ErrorInvalidProjectName, CultureInfo.CurrentUICulture));
|
| - }
|
| -
|
| - // Figure out what the new full name is
|
| - string oldFile = this.Url;
|
| -
|
| - int canContinue = 0;
|
| - IVsSolution vsSolution = (IVsSolution)this.GetService(typeof(SVsSolution));
|
| - if(ErrorHandler.Succeeded(vsSolution.QueryRenameProject(this, oldFile, newFile, 0, out canContinue))
|
| - && canContinue != 0)
|
| - {
|
| - bool isFileSame = NativeMethods.IsSamePath(oldFile, newFile);
|
| -
|
| - // If file already exist and is not the same file with different casing
|
| - if(!isFileSame && File.Exists(newFile))
|
| - {
|
| - // Prompt the user for replace
|
| - string message = SR.GetString(SR.FileAlreadyExists, newFile);
|
| -
|
| - if(!Utilities.IsInAutomationFunction(this.Site))
|
| - {
|
| - if(!VsShellUtilities.PromptYesNo(message, null, OLEMSGICON.OLEMSGICON_WARNING, shell))
|
| - {
|
| - throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED);
|
| - }
|
| - }
|
| - else
|
| - {
|
| - throw new InvalidOperationException(message);
|
| - }
|
| -
|
| - // Delete the destination file after making sure it is not read only
|
| - File.SetAttributes(newFile, FileAttributes.Normal);
|
| - File.Delete(newFile);
|
| - }
|
| -
|
| - SuspendFileChanges fileChanges = new SuspendFileChanges(this.Site, this.filename);
|
| - fileChanges.Suspend();
|
| - try
|
| - {
|
| - // Actual file rename
|
| - this.SaveMSBuildProjectFileAs(newFile);
|
| -
|
| - this.SetProjectFileDirty(false);
|
| -
|
| - if(!isFileSame)
|
| - {
|
| - // Now that the new file name has been created delete the old one.
|
| - // TODO: Handle source control issues.
|
| - File.SetAttributes(oldFile, FileAttributes.Normal);
|
| - File.Delete(oldFile);
|
| - }
|
| -
|
| - this.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_Caption, 0);
|
| -
|
| - // Update solution
|
| - ErrorHandler.ThrowOnFailure(vsSolution.OnAfterRenameProject((IVsProject)this, oldFile, newFile, 0));
|
| -
|
| - ErrorHandler.ThrowOnFailure(shell.RefreshPropertyBrowser(0));
|
| - }
|
| - finally
|
| - {
|
| - fileChanges.Resume();
|
| - }
|
| - }
|
| - else
|
| - {
|
| - throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED);
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Called by the project to know if the item is a file (that is part of the project)
|
| - /// or an intermediate file used by the MSBuild tasks/targets
|
| - /// Override this method if your project has more types or different ones
|
| - /// </summary>
|
| - /// <param name="type">Type name</param>
|
| - /// <returns>True = items of this type should be included in the project</returns>
|
| - protected virtual bool IsItemTypeFileType(string type)
|
| - {
|
| - if(String.Compare(type, BuildAction.Compile.ToString(), StringComparison.OrdinalIgnoreCase) == 0
|
| - || String.Compare(type, BuildAction.Content.ToString(), StringComparison.OrdinalIgnoreCase) == 0
|
| - || String.Compare(type, BuildAction.EmbeddedResource.ToString(), StringComparison.OrdinalIgnoreCase) == 0
|
| - || String.Compare(type, BuildAction.None.ToString(), StringComparison.OrdinalIgnoreCase) == 0)
|
| - return true;
|
| -
|
| - // we don't know about this type, so ignore it.
|
| - return false;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Filter items that should not be processed as file items. Example: Folders and References.
|
| - /// </summary>
|
| - protected virtual bool FilterItemTypeToBeAddedToHierarchy(string itemType)
|
| - {
|
| - return (String.Compare(itemType, ProjectFileConstants.Reference, StringComparison.OrdinalIgnoreCase) == 0
|
| - || String.Compare(itemType, ProjectFileConstants.ProjectReference, StringComparison.OrdinalIgnoreCase) == 0
|
| - || String.Compare(itemType, ProjectFileConstants.COMReference, StringComparison.OrdinalIgnoreCase) == 0
|
| - || String.Compare(itemType, ProjectFileConstants.Folder, StringComparison.OrdinalIgnoreCase) == 0
|
| - || String.Compare(itemType, ProjectFileConstants.WebReference, StringComparison.OrdinalIgnoreCase) == 0
|
| - || String.Compare(itemType, ProjectFileConstants.WebReferenceFolder, StringComparison.OrdinalIgnoreCase) == 0);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Associate window output pane to the build logger
|
| - /// </summary>
|
| - /// <param name="output"></param>
|
| - protected virtual void SetOutputLogger(IVsOutputWindowPane output)
|
| - {
|
| - // Create our logger, if it was not specified
|
| - if(!this.useProvidedLogger || this.buildLogger == null)
|
| - {
|
| - // Because we may be aggregated, we need to make sure to get the outer IVsHierarchy
|
| - IntPtr unknown = IntPtr.Zero;
|
| - IVsHierarchy hierarchy = null;
|
| - try
|
| - {
|
| - unknown = Marshal.GetIUnknownForObject(this);
|
| - hierarchy = Marshal.GetTypedObjectForIUnknown(unknown, typeof(IVsHierarchy)) as IVsHierarchy;
|
| - }
|
| - finally
|
| - {
|
| - if(unknown != IntPtr.Zero)
|
| - Marshal.Release(unknown);
|
| - }
|
| - // Create the logger
|
| - this.buildLogger = new IDEBuildLogger(output, this.TaskProvider, hierarchy);
|
| -
|
| - // To retrive the verbosity level, the build logger depends on the registry root
|
| - // (otherwise it will used an hardcoded default)
|
| - ILocalRegistry2 registry = this.GetService(typeof(SLocalRegistry)) as ILocalRegistry2;
|
| - if(null != registry)
|
| - {
|
| - string registryRoot;
|
| - ErrorHandler.ThrowOnFailure(registry.GetLocalRegistryRoot(out registryRoot));
|
| - IDEBuildLogger logger = this.BuildLogger as IDEBuildLogger;
|
| - if(!String.IsNullOrEmpty(registryRoot) && (null != logger))
|
| - {
|
| - logger.BuildVerbosityRegistryRoot = registryRoot;
|
| - logger.ErrorString = this.ErrorString;
|
| - logger.WarningString = this.WarningString;
|
| - }
|
| - }
|
| - }
|
| - else
|
| - {
|
| - ((IDEBuildLogger)this.BuildLogger).OutputWindowPane = output;
|
| - }
|
| -
|
| - if(this.buildEngine != null)
|
| - {
|
| - this.buildEngine.UnregisterAllLoggers();
|
| - this.buildEngine.RegisterLogger(this.buildLogger);
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Set configuration properties for a specific configuration
|
| - /// </summary>
|
| - /// <param name="config">configuration name</param>
|
| - protected virtual void SetBuildConfigurationProperties(string config)
|
| - {
|
| - ProjectOptions options = null;
|
| -
|
| - if(!String.IsNullOrEmpty(config))
|
| - {
|
| - options = this.GetProjectOptions(config);
|
| - }
|
| -
|
| - if(options != null && this.buildProject != null)
|
| - {
|
| - // Make sure the project configuration is set properly
|
| - this.SetConfiguration(config);
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// This execute an MSBuild target.
|
| - /// If you depend on the items/properties generated by the target
|
| - /// you should be aware that any call to BuildTarget on any project
|
| - /// will reset the list of generated items/properties
|
| - /// </summary>
|
| - /// <param name="target">Name of the MSBuild target to execute</param>
|
| - /// <returns>Result from executing the target (success/failure)</returns>
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Ms")]
|
| - protected virtual MSBuildResult InvokeMsBuild(string target)
|
| - {
|
| - MSBuildResult result = MSBuildResult.Failed;
|
| -
|
| - if(!this.hasPassedSecurityChecks)
|
| - {
|
| - return result;
|
| - }
|
| -
|
| - try
|
| - {
|
| - this.buildInProcess = true;
|
| -
|
| - // Enable build if all security checks have been passed.
|
| - this.buildEngine.BuildEnabled = true;
|
| - // Do the actual Build
|
| - if(this.buildProject != null)
|
| - {
|
| - result = this.buildProject.Build(target) ? MSBuildResult.Successful : MSBuildResult.Failed;
|
| - }
|
| - }
|
| - finally
|
| - {
|
| - // Comment from VSCore. We might be in the same scenario:
|
| - // For security purposes, restore the engine back to the original state where
|
| - // build is not enabled except for projects explicitly marked as safe by the
|
| - // project system. This is so that in case the user now does an Add Existing
|
| - // Project of a project that seems safe to us but contains a P2P reference to
|
| - // a random unsafe project on disk, the user is still protected from the potential
|
| - // harm of resolving that P2P reference (thereby running targets in the malicious
|
| - // project).
|
| - this.buildEngine.BuildEnabled = false;
|
| - this.buildInProcess = false;
|
| - this.buildEngine.UnregisterAllLoggers();
|
| - }
|
| -
|
| - return result;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Initialize common project properties with default value if they are empty
|
| - /// </summary>
|
| - /// <remarks>The following common project properties are defaulted to projectName (if empty):
|
| - /// AssemblyName, Name and RootNamespace.
|
| - /// If the project filename is not set then no properties are set</remarks>
|
| - protected virtual void InitializeProjectProperties()
|
| - {
|
| - // Get projectName from project filename. Return if not set
|
| - string projectName = Path.GetFileNameWithoutExtension(this.filename);
|
| - if(String.IsNullOrEmpty(projectName))
|
| - {
|
| - return;
|
| - }
|
| -
|
| - if(String.IsNullOrEmpty(GetProjectProperty(ProjectFileConstants.AssemblyName)))
|
| - {
|
| - SetProjectProperty(ProjectFileConstants.AssemblyName, projectName);
|
| - }
|
| - if(String.IsNullOrEmpty(GetProjectProperty(ProjectFileConstants.Name)))
|
| - {
|
| - SetProjectProperty(ProjectFileConstants.Name, projectName);
|
| - }
|
| - if(String.IsNullOrEmpty(GetProjectProperty(ProjectFileConstants.RootNamespace)))
|
| - {
|
| - SetProjectProperty(ProjectFileConstants.RootNamespace, projectName);
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Factory method for configuration provider
|
| - /// </summary>
|
| - /// <returns>Configuration provider created</returns>
|
| - protected virtual ConfigProvider CreateConfigProvider()
|
| - {
|
| - return new ConfigProvider(this);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Factory method for reference container node
|
| - /// </summary>
|
| - /// <returns>ReferenceContainerNode created</returns>
|
| - protected virtual ReferenceContainerNode CreateReferenceContainerNode()
|
| - {
|
| - return new ReferenceContainerNode(this);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Saves the project file on a new name.
|
| - /// </summary>
|
| - /// <param name="newFileName">The new name of the project file.</param>
|
| - /// <returns>Success value or an error code.</returns>
|
| - protected virtual int SaveAs(string newFileName)
|
| - {
|
| - Debug.Assert(!String.IsNullOrEmpty(newFileName), "Cannot save project file for an empty or null file name");
|
| -
|
| - newFileName = newFileName.Trim();
|
| -
|
| - string errorMessage = String.Empty;
|
| -
|
| - if(newFileName.Length > NativeMethods.MAX_PATH)
|
| - {
|
| - errorMessage = String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.PathTooLong, CultureInfo.CurrentUICulture), newFileName);
|
| - }
|
| - else
|
| - {
|
| - string fileName = String.Empty;
|
| -
|
| - try
|
| - {
|
| - fileName = Path.GetFileNameWithoutExtension(newFileName);
|
| - }
|
| - // We want to be consistent in the error message and exception we throw. fileName could be for example #¤&%"¤&"% and that would trigger an ArgumentException on Path.IsRooted.
|
| - catch(ArgumentException)
|
| - {
|
| - errorMessage = SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture);
|
| - }
|
| -
|
| - if(errorMessage.Length == 0)
|
| - {
|
| - // If there is no filename or it starts with a leading dot issue an error message and quit.
|
| - // For some reason the save as dialog box allows to save files like "......ext"
|
| - if(String.IsNullOrEmpty(fileName) || fileName[0] == '.')
|
| - {
|
| - errorMessage = SR.GetString(SR.FileNameCannotContainALeadingPeriod, CultureInfo.CurrentUICulture);
|
| - }
|
| - else if(Utilities.ContainsInvalidFileNameChars(newFileName))
|
| - {
|
| - errorMessage = SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture);
|
| - }
|
| - else
|
| - {
|
| - string url = Path.GetDirectoryName(newFileName);
|
| - string oldUrl = Path.GetDirectoryName(this.Url);
|
| -
|
| - if(!NativeMethods.IsSamePath(oldUrl, url))
|
| - {
|
| - errorMessage = String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.SaveOfProjectFileOutsideCurrentDirectory, CultureInfo.CurrentUICulture), this.ProjectFolder);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - if(errorMessage.Length > 0)
|
| - {
|
| - // If it is not called from an automation method show a dialog box.
|
| - if(!Utilities.IsInAutomationFunction(this.Site))
|
| - {
|
| - string title = null;
|
| - OLEMSGICON icon = OLEMSGICON.OLEMSGICON_CRITICAL;
|
| - OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK;
|
| - OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST;
|
| - VsShellUtilities.ShowMessageBox(this.Site, title, errorMessage, icon, buttons, defaultButton);
|
| - return VSConstants.OLE_E_PROMPTSAVECANCELLED;
|
| - }
|
| -
|
| - throw new InvalidOperationException(errorMessage);
|
| - }
|
| -
|
| - string oldName = this.filename;
|
| -
|
| - IVsSolution solution = this.Site.GetService(typeof(IVsSolution)) as IVsSolution;
|
| - Debug.Assert(solution != null, "Could not retrieve the solution form the service provider");
|
| - if(solution == null)
|
| - {
|
| - throw new InvalidOperationException();
|
| - }
|
| -
|
| - int canRenameContinue = 0;
|
| - ErrorHandler.ThrowOnFailure(solution.QueryRenameProject(this, this.filename, newFileName, 0, out canRenameContinue));
|
| -
|
| - if(canRenameContinue == 0)
|
| - {
|
| - return VSConstants.OLE_E_PROMPTSAVECANCELLED;
|
| - }
|
| -
|
| - SuspendFileChanges fileChanges = new SuspendFileChanges(this.Site, oldName);
|
| - fileChanges.Suspend();
|
| - try
|
| - {
|
| - // Save the project file and project file related properties.
|
| - this.SaveMSBuildProjectFileAs(newFileName);
|
| -
|
| - this.SetProjectFileDirty(false);
|
| -
|
| -
|
| - // TODO: If source control is enabled check out the project file.
|
| -
|
| - //Redraw.
|
| - this.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_Caption, 0);
|
| -
|
| - ErrorHandler.ThrowOnFailure(solution.OnAfterRenameProject(this, oldName, this.filename, 0));
|
| -
|
| - IVsUIShell shell = this.Site.GetService(typeof(SVsUIShell)) as IVsUIShell;
|
| - Debug.Assert(shell != null, "Could not get the ui shell from the project");
|
| - if(shell == null)
|
| - {
|
| - throw new InvalidOperationException();
|
| - }
|
| - ErrorHandler.ThrowOnFailure(shell.RefreshPropertyBrowser(0));
|
| - }
|
| - finally
|
| - {
|
| - fileChanges.Resume();
|
| - }
|
| -
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Saves project file related information to the new file name. It also calls msbuild API to save the project file.
|
| - /// It is called by the SaveAs method and the SetEditLabel before the project file rename related events are triggered.
|
| - /// An implementer can override this method to provide specialized semantics on how the project file is renamed in the msbuild file.
|
| - /// </summary>
|
| - /// <param name="newFileName">The new full path of the project file</param>
|
| - protected virtual void SaveMSBuildProjectFileAs(string newFileName)
|
| - {
|
| - Debug.Assert(!String.IsNullOrEmpty(newFileName), "Cannot save project file for an empty or null file name");
|
| -
|
| - this.buildProject.FullFileName = newFileName;
|
| -
|
| - this.filename = newFileName;
|
| -
|
| - string newFileNameWithoutExtension = Path.GetFileNameWithoutExtension(newFileName);
|
| -
|
| - // Refresh solution explorer
|
| - this.SetProjectProperty(ProjectFileConstants.Name, newFileNameWithoutExtension);
|
| -
|
| - // Saves the project file on disk.
|
| - this.buildProject.Save(newFileName);
|
| -
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Adds a file to the msbuild project.
|
| - /// </summary>
|
| - /// <param name="file">The file to be added.</param>
|
| - /// <returns>A Projectelement describing the newly added file.</returns>
|
| - [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "ToMs")]
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Ms")]
|
| - protected virtual ProjectElement AddFileToMsBuild(string file)
|
| - {
|
| - ProjectElement newItem;
|
| -
|
| - string itemPath = PackageUtilities.MakeRelativeIfRooted(file, this.BaseURI);
|
| - Debug.Assert(!Path.IsPathRooted(itemPath), "Cannot add item with full path.");
|
| -
|
| - if(this.IsCodeFile(itemPath))
|
| - {
|
| - newItem = this.CreateMsBuildFileItem(itemPath, ProjectFileConstants.Compile);
|
| - newItem.SetMetadata(ProjectFileConstants.SubType, ProjectFileAttributeValue.Code);
|
| - }
|
| - else if(this.IsEmbeddedResource(itemPath))
|
| - {
|
| - newItem = this.CreateMsBuildFileItem(itemPath, ProjectFileConstants.EmbeddedResource);
|
| - }
|
| - else
|
| - {
|
| - newItem = this.CreateMsBuildFileItem(itemPath, ProjectFileConstants.Content);
|
| - newItem.SetMetadata(ProjectFileConstants.SubType, ProjectFileConstants.Content);
|
| - }
|
| -
|
| - return newItem;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Adds a folder to the msbuild project.
|
| - /// </summary>
|
| - /// <param name="folder">The folder to be added.</param>
|
| - /// <returns>A Projectelement describing the newly added folder.</returns>
|
| - [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "ToMs")]
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Ms")]
|
| - protected virtual ProjectElement AddFolderToMsBuild(string folder)
|
| - {
|
| - ProjectElement newItem;
|
| -
|
| - string itemPath = PackageUtilities.MakeRelativeIfRooted(folder, this.BaseURI);
|
| - Debug.Assert(!Path.IsPathRooted(itemPath), "Cannot add item with full path.");
|
| -
|
| - newItem = this.CreateMsBuildFileItem(itemPath, ProjectFileConstants.Folder);
|
| -
|
| - return newItem;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Determines whether an item can be owerwritten in the hierarchy.
|
| - /// </summary>
|
| - /// <param name="originalFileName">The orginal filname.</param>
|
| - /// <param name="computedNewFileName">The computed new file name, that will be copied to the project directory or into the folder .</param>
|
| - /// <returns>S_OK for success, or an error message</returns>
|
| - protected virtual int CanOverwriteExistingItem(string originalFileName, string computedNewFileName)
|
| - {
|
| - if(String.IsNullOrEmpty(originalFileName) || String.IsNullOrEmpty(computedNewFileName))
|
| - {
|
| - return VSConstants.E_INVALIDARG;
|
| - }
|
| -
|
| - string message = String.Empty;
|
| - string title = String.Empty;
|
| - OLEMSGICON icon = OLEMSGICON.OLEMSGICON_CRITICAL;
|
| - OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK;
|
| - OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST;
|
| -
|
| - // If the document is open then return error message.
|
| - IVsUIHierarchy hier;
|
| - IVsWindowFrame windowFrame;
|
| - uint itemid = VSConstants.VSITEMID_NIL;
|
| -
|
| - bool isOpen = VsShellUtilities.IsDocumentOpen(this.Site, computedNewFileName, Guid.Empty, out hier, out itemid, out windowFrame);
|
| -
|
| - if(isOpen)
|
| - {
|
| - message = String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.CannotAddFileThatIsOpenInEditor, CultureInfo.CurrentUICulture), Path.GetFileName(computedNewFileName));
|
| - VsShellUtilities.ShowMessageBox(this.Site, title, message, icon, buttons, defaultButton);
|
| - return VSConstants.E_ABORT;
|
| - }
|
| -
|
| -
|
| - // File already exists in project... message box
|
| - message = SR.GetString(SR.FileAlreadyInProject, CultureInfo.CurrentUICulture);
|
| - icon = OLEMSGICON.OLEMSGICON_QUERY;
|
| - buttons = OLEMSGBUTTON.OLEMSGBUTTON_YESNO;
|
| - int msgboxResult = VsShellUtilities.ShowMessageBox(this.Site, title, message, icon, buttons, defaultButton);
|
| - if(msgboxResult != NativeMethods.IDYES)
|
| - {
|
| - return (int)OleConstants.OLECMDERR_E_CANCELED;
|
| - }
|
| -
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Handle owerwriting of an existing item in the hierarchy.
|
| - /// </summary>
|
| - /// <param name="existingNode">The node that exists.</param>
|
| - protected virtual void OverwriteExistingItem(HierarchyNode existingNode)
|
| - {
|
| -
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Adds a new file node to the hierarchy.
|
| - /// </summary>
|
| - /// <param name="parentNode">The parent of the new fileNode</param>
|
| - /// <param name="fileName">The file name</param>
|
| - protected virtual void AddNewFileNodeToHierarchy(HierarchyNode parentNode, string fileName)
|
| - {
|
| - HierarchyNode child;
|
| -
|
| - // In the case of subitem, we want to create dependent file node
|
| - // and set the DependentUpon property
|
| - if(this.canFileNodesHaveChilds && (parentNode is FileNode || parentNode is DependentFileNode))
|
| - {
|
| - child = this.CreateDependentFileNode(fileName);
|
| - child.ItemNode.SetMetadata(ProjectFileConstants.DependentUpon, parentNode.ItemNode.GetMetadata(ProjectFileConstants.Include));
|
| -
|
| - // Make sure to set the HasNameRelation flag on the dependent node if it is related to the parent by name
|
| - if(!child.HasParentNodeNameRelation && string.Compare(child.GetRelationalName(), parentNode.GetRelationalName(), StringComparison.OrdinalIgnoreCase) == 0)
|
| - {
|
| - child.HasParentNodeNameRelation = true;
|
| - }
|
| - }
|
| - else
|
| - {
|
| - //Create and add new filenode to the project
|
| - child = this.CreateFileNode(fileName);
|
| - }
|
| -
|
| - parentNode.AddChild(child);
|
| -
|
| - // TODO : Revisit the VSADDFILEFLAGS here. Can it be a nested project?
|
| - this.tracker.OnItemAdded(fileName, VSADDFILEFLAGS.VSADDFILEFLAGS_NoFlags);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Defines whther the current mode of the project is in a supress command mode.
|
| - /// </summary>
|
| - /// <returns></returns>
|
| - protected internal virtual bool IsCurrentStateASuppressCommandsMode()
|
| - {
|
| - if(VsShellUtilities.IsSolutionBuilding(this.Site))
|
| - {
|
| - return true;
|
| - }
|
| -
|
| - DBGMODE dbgMode = VsShellUtilities.GetDebugMode(this.Site) & ~DBGMODE.DBGMODE_EncMask;
|
| - if(dbgMode == DBGMODE.DBGMODE_Run || dbgMode == DBGMODE.DBGMODE_Break)
|
| - {
|
| - return true;
|
| - }
|
| -
|
| - return false;
|
| -
|
| - }
|
| -
|
| -
|
| - /// <summary>
|
| - /// This is the list of output groups that the configuration object should
|
| - /// provide.
|
| - /// The first string is the name of the group.
|
| - /// The second string is the target name (MSBuild) for that group.
|
| - ///
|
| - /// To add/remove OutputGroups, simply override this method and edit the list.
|
| - ///
|
| - /// To get nice display names and description for your groups, override:
|
| - /// - GetOutputGroupDisplayName
|
| - /// - GetOutputGroupDescription
|
| - /// </summary>
|
| - /// <returns>List of output group name and corresponding MSBuild target</returns>
|
| - protected internal virtual IList<KeyValuePair<string, string>> GetOutputGroupNames()
|
| - {
|
| - return new List<KeyValuePair<string, string>>(outputGroupNames);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Get the display name of the given output group.
|
| - /// </summary>
|
| - /// <param name="canonicalName">Canonical name of the output group</param>
|
| - /// <returns>Display name</returns>
|
| - protected internal virtual string GetOutputGroupDisplayName(string canonicalName)
|
| - {
|
| - string result = SR.GetString(String.Format(CultureInfo.InvariantCulture, "Output{0}", canonicalName), CultureInfo.CurrentUICulture);
|
| - if(String.IsNullOrEmpty(result))
|
| - result = canonicalName;
|
| - return result;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Get the description of the given output group.
|
| - /// </summary>
|
| - /// <param name="canonicalName">Canonical name of the output group</param>
|
| - /// <returns>Description</returns>
|
| - protected internal virtual string GetOutputGroupDescription(string canonicalName)
|
| - {
|
| - string result = SR.GetString(String.Format(CultureInfo.InvariantCulture, "Output{0}Description", canonicalName), CultureInfo.CurrentUICulture);
|
| - if(String.IsNullOrEmpty(result))
|
| - result = canonicalName;
|
| - return result;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Set the configuration in MSBuild.
|
| - /// This does not get persisted and is used to evaluate msbuild conditions
|
| - /// which are based on the $(Configuration) property.
|
| - /// </summary>
|
| - protected internal virtual void SetCurrentConfiguration()
|
| - {
|
| - if(this.BuildInProgress)
|
| - {
|
| - // we are building so this should already be the current configuration
|
| - return;
|
| - }
|
| -
|
| - // Can't ask for the active config until the project is opened, so do nothing in that scenario
|
| - if(!this.projectOpened)
|
| - return;
|
| -
|
| - EnvDTE.Project automationObject = this.GetAutomationObject() as EnvDTE.Project;
|
| -
|
| - this.SetConfiguration(Utilities.GetActiveConfigurationName(automationObject));
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Set the configuration property in MSBuild.
|
| - /// This does not get persisted and is used to evaluate msbuild conditions
|
| - /// which are based on the $(Configuration) property.
|
| - /// </summary>
|
| - /// <param name="config">Configuration name</param>
|
| - protected internal virtual void SetConfiguration(string config)
|
| - {
|
| - if(config == null)
|
| - {
|
| - throw new ArgumentNullException("config");
|
| - }
|
| -
|
| - // Can't ask for the active config until the project is opened, so do nothing in that scenario
|
| - if(!projectOpened)
|
| - return;
|
| -
|
| - // We cannot change properties during the build so if the config
|
| - // we want to se is the current, we do nothing otherwise we fail.
|
| - if(this.BuildInProgress)
|
| - {
|
| - EnvDTE.Project automationObject = this.GetAutomationObject() as EnvDTE.Project;
|
| - string currentConfigName = Utilities.GetActiveConfigurationName(automationObject);
|
| - bool configsAreEqual = String.Compare(currentConfigName, config, StringComparison.OrdinalIgnoreCase) == 0;
|
| -
|
| - if(configsAreEqual)
|
| - {
|
| - return;
|
| - }
|
| - throw new InvalidOperationException(); ;
|
| - }
|
| -
|
| - this.buildProject.GlobalProperties.SetProperty(ProjectFileConstants.Configuration, config);
|
| - this.currentConfig = this.buildProject.EvaluatedProperties;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Loads reference items from the project file into the hierarchy.
|
| - /// </summary>
|
| - protected internal virtual void ProcessReferences()
|
| - {
|
| - IReferenceContainer container = GetReferenceContainer();
|
| - if(null == container)
|
| - {
|
| - // Process References
|
| - ReferenceContainerNode referencesFolder = CreateReferenceContainerNode();
|
| - if(null == referencesFolder)
|
| - {
|
| - // This project type does not support references or there is a problem
|
| - // creating the reference container node.
|
| - // In both cases there is no point to try to process references, so exit.
|
| - return;
|
| - }
|
| - this.AddChild(referencesFolder);
|
| - container = referencesFolder;
|
| - }
|
| -
|
| - // Load the referernces.
|
| - container.LoadReferencesFromBuildProject(buildProject);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Loads folders from the project file into the hierarchy.
|
| - /// </summary>
|
| - protected internal virtual void ProcessFolders()
|
| - {
|
| - // Process Folders (useful to persist empty folder)
|
| - MSBuild.BuildItemGroup folders = this.buildProject.GetEvaluatedItemsByName(ProjectFileConstants.Folder);
|
| - foreach(MSBuild.BuildItem folder in folders)
|
| - {
|
| - string strPath = folder.FinalItemSpec;
|
| -
|
| - // We do not need any special logic for assuring that a folder is only added once to the ui hierarchy.
|
| - // The below method will only add once the folder to the ui hierarchy
|
| - this.CreateFolderNodes(strPath);
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Loads file items from the project file into the hierarchy.
|
| - /// </summary>
|
| - protected internal virtual void ProcessFiles()
|
| - {
|
| - List<String> subitemsKeys = new List<String>();
|
| - Dictionary<String, MSBuild.BuildItem> subitems = new Dictionary<String, MSBuild.BuildItem>();
|
| -
|
| - // Define a set for our build items. The value does not really matter here.
|
| - Dictionary<String, MSBuild.BuildItem> items = new Dictionary<String, MSBuild.BuildItem>();
|
| -
|
| - // Process Files
|
| - MSBuild.BuildItemGroup projectFiles = this.buildProject.EvaluatedItems;
|
| - foreach(MSBuild.BuildItem item in projectFiles)
|
| - {
|
| - // Ignore the item if it is a reference or folder
|
| - if(this.FilterItemTypeToBeAddedToHierarchy(item.Name))
|
| - continue;
|
| -
|
| - // MSBuilds tasks/targets can create items (such as object files),
|
| - // such items are not part of the project per say, and should not be displayed.
|
| - // so ignore those items.
|
| - if(!this.IsItemTypeFileType(item.Name))
|
| - continue;
|
| -
|
| - // If the item is already contained do nothing.
|
| - // TODO: possibly report in the error list that the the item is already contained in the project file similar to Language projects.
|
| - if(items.ContainsKey(item.FinalItemSpec.ToUpperInvariant()))
|
| - continue;
|
| -
|
| - // Make sure that we do not want to add the item, dependent, or independent twice to the ui hierarchy
|
| - items.Add(item.FinalItemSpec.ToUpperInvariant(), item);
|
| -
|
| - string dependentOf = item.GetMetadata(ProjectFileConstants.DependentUpon);
|
| -
|
| - if(!this.CanFileNodesHaveChilds || String.IsNullOrEmpty(dependentOf))
|
| - {
|
| - AddIndependentFileNode(item);
|
| - }
|
| - else
|
| - {
|
| - // We will process dependent items later.
|
| - // Note that we use 2 lists as we want to remove elements from
|
| - // the collection as we loop through it
|
| - subitemsKeys.Add(item.FinalItemSpec);
|
| - subitems.Add(item.FinalItemSpec, item);
|
| - }
|
| - }
|
| -
|
| - // Now process the dependent items.
|
| - if(this.CanFileNodesHaveChilds)
|
| - {
|
| - ProcessDependentFileNodes(subitemsKeys, subitems);
|
| - }
|
| -
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Processes dependent filenodes from list of subitems. Multi level supported, but not circular dependencies.
|
| - /// </summary>
|
| - /// <param name="subitemsKeys">List of sub item keys </param>
|
| - /// <param name="subitems"></param>
|
| - protected internal virtual void ProcessDependentFileNodes(IList<String> subitemsKeys, Dictionary<String, MSBuild.BuildItem> subitems)
|
| - {
|
| - foreach(string key in subitemsKeys)
|
| - {
|
| - // A previous pass could have removed the key so make sure it still needs to be added
|
| - if(!subitems.ContainsKey(key))
|
| - continue;
|
| -
|
| - AddDependentFileNode(subitems, key);
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// For flavored projects which implement IPersistXMLFragment, load the information now
|
| - /// </summary>
|
| - protected internal virtual void LoadNonBuildInformation()
|
| - {
|
| - IPersistXMLFragment outerHierarchy = HierarchyNode.GetOuterHierarchy(this) as IPersistXMLFragment;
|
| - if(outerHierarchy != null)
|
| - {
|
| - this.LoadXmlFragment(outerHierarchy, null);
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Used to sort nodes in the hierarchy.
|
| - /// </summary>
|
| - protected internal virtual int CompareNodes(HierarchyNode node1, HierarchyNode node2)
|
| - {
|
| - Debug.Assert(node1 != null && node2 != null);
|
| -
|
| - if(node1.SortPriority == node2.SortPriority)
|
| - {
|
| - return String.Compare(node2.Caption, node1.Caption, true, CultureInfo.CurrentCulture);
|
| - }
|
| - else
|
| - {
|
| - return node2.SortPriority - node1.SortPriority;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Handles global properties related to configuration and platform changes invoked by a change in the active configuration.
|
| - /// </summary>
|
| - /// <param name="sender">The sender of the event.</param>
|
| - /// <param name="eventArgs">The event args</param>
|
| - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers",
|
| - Justification = "This method will give the opportunity to update global properties based on active configuration change. " +
|
| - "There is no security threat that could otherwise not be reached by listening to configuration chnage events.")]
|
| - protected virtual void OnHandleConfigurationRelatedGlobalProperties(object sender, ActiveConfigurationChangedEventArgs eventArgs)
|
| - {
|
| - Debug.Assert(eventArgs != null, "Wrong hierarchy passed as event arg for the configuration change listener.");
|
| -
|
| - // If (eventArgs.Hierarchy == NULL) then we received this event because the solution configuration
|
| - // was changed.
|
| - // If it is not null we got the event because a project in teh configuration manager has changed its active configuration.
|
| - // We care only about our project in the default implementation.
|
| - if(eventArgs.Hierarchy == null || !Utilities.IsSameComObject(eventArgs.Hierarchy, this))
|
| - {
|
| - return;
|
| - }
|
| -
|
| - string name, platform;
|
| - if(!Utilities.TryGetActiveConfigurationAndPlatform(this.Site, this, out name, out platform))
|
| - {
|
| - throw new InvalidOperationException();
|
| - }
|
| -
|
| - this.buildProject.GlobalProperties.SetProperty(GlobalProperty.Configuration.ToString(), name);
|
| -
|
| - // If the platform is "Any CPU" then it should be set to AnyCPU, since that is the property value in MsBuild terms.
|
| - if(String.Compare(platform, ConfigProvider.AnyCPUPlatform, StringComparison.Ordinal) == 0)
|
| - {
|
| - platform = ProjectFileValues.AnyCPU;
|
| - }
|
| -
|
| - this.buildProject.GlobalProperties.SetProperty(GlobalProperty.Platform.ToString(), platform);
|
| - }
|
| -
|
| - #endregion
|
| -
|
| - #region non-virtual methods
|
| -
|
| - /// <summary>
|
| - /// Suspends MSBuild
|
| - /// </summary>
|
| - public void SuspendMSBuild()
|
| - {
|
| - this.suspendMSBuildCounter++;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Resumes MSBuild.
|
| - /// </summary>
|
| - public void ResumeMSBuild(string config, IVsOutputWindowPane output, string target)
|
| - {
|
| - this.suspendMSBuildCounter--;
|
| -
|
| - if(this.suspendMSBuildCounter == 0 && this.invokeMSBuildWhenResumed)
|
| - {
|
| - try
|
| - {
|
| - this.Build(config, output, target);
|
| - }
|
| - finally
|
| - {
|
| - this.invokeMSBuildWhenResumed = false;
|
| - }
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Resumes MSBuild.
|
| - /// </summary>
|
| - public void ResumeMSBuild(string config, string target)
|
| - {
|
| - this.ResumeMSBuild(config, null, target);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Resumes MSBuild.
|
| - /// </summary>
|
| - public void ResumeMSBuild(string target)
|
| - {
|
| - this.ResumeMSBuild(String.Empty, null, target);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Calls MSBuild if it is not suspended. If it is suspended then it will remeber to call when msbuild is resumed.
|
| - /// </summary>
|
| - public MSBuildResult CallMSBuild(string config, IVsOutputWindowPane output, string target)
|
| - {
|
| - if(this.suspendMSBuildCounter > 0)
|
| - {
|
| - // remember to invoke MSBuild
|
| - this.invokeMSBuildWhenResumed = true;
|
| - return MSBuildResult.Suspended;
|
| - }
|
| - else
|
| - {
|
| - return this.Build(config, output, target);
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Overloaded method. Calls MSBuild if it is not suspended. Does not log on the outputwindow. If it is suspended then it will remeber to call when msbuild is resumed.
|
| - /// </summary>
|
| - public MSBuildResult CallMSBuild(string config, string target)
|
| - {
|
| - return this.CallMSBuild(config, null, target);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Calls MSBuild if it is not suspended. Does not log and uses current configuration. If it is suspended then it will remeber to call when msbuild is resumed.
|
| - /// </summary>
|
| - public MSBuildResult CallMSBuild(string target)
|
| - {
|
| - return this.CallMSBuild(String.Empty, null, target);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Calls MSBuild if it is not suspended. Uses current configuration. If it is suspended then it will remeber to call when msbuild is resumed.
|
| - /// </summary>
|
| - public MSBuildResult CallMSBuild(string target, IVsOutputWindowPane output)
|
| - {
|
| - return this.CallMSBuild(String.Empty, output, target);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Overloaded method to invoke MSBuild
|
| - /// </summary>
|
| - public MSBuildResult Build(string config, IVsOutputWindowPane output, string target)
|
| - {
|
| - return this.Build(0, config, output, target);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Overloaded method to invoke MSBuild. Does not log build results to the output window pane.
|
| - /// </summary>
|
| - public MSBuildResult Build(string config, string target)
|
| - {
|
| - return this.Build(0, config, null, target);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Overloaded method. Invokes MSBuild using the default configuration and does without logging on the output window pane.
|
| - /// </summary>
|
| - public MSBuildResult Build(string target)
|
| - {
|
| - return this.Build(0, String.Empty, null, target);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Overloaded method. Invokes MSBuild using the default configuration.
|
| - /// </summary>
|
| - public MSBuildResult Build(string target, IVsOutputWindowPane output)
|
| - {
|
| - return this.Build(0, String.Empty, output, target);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Get the output path for a specific configuration name
|
| - /// </summary>
|
| - /// <param name="config">name of configuration</param>
|
| - /// <returns>Output path</returns>
|
| - public string GetOutputPath(string config)
|
| - {
|
| - this.SetConfiguration(config);
|
| - MSBuild.BuildPropertyGroup properties = this.buildProject.EvaluatedProperties;
|
| -
|
| - return this.GetOutputPath(properties);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Get value of Project property
|
| - /// </summary>
|
| - /// <param name="propertyName">Name of Property to retrieve</param>
|
| - /// <returns>Value of property</returns>
|
| - public string GetProjectProperty(string propertyName)
|
| - {
|
| - return this.GetProjectProperty(propertyName, true);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Set dirty state of project
|
| - /// </summary>
|
| - /// <param name="value">boolean value indicating dirty state</param>
|
| - public void SetProjectFileDirty(bool value)
|
| - {
|
| - this.options = null;
|
| - this.isDirty = value;
|
| - if(this.isDirty)
|
| - {
|
| - this.lastModifiedTime = DateTime.Now;
|
| - this.buildIsPrepared = false;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Get output assembly for a specific configuration name
|
| - /// </summary>
|
| - /// <param name="config">Name of configuration</param>
|
| - /// <returns>Name of output assembly</returns>
|
| - public string GetOutputAssembly(string config)
|
| - {
|
| - ProjectOptions options = this.GetProjectOptions(config);
|
| -
|
| - return options.OutputAssembly;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Get Node from ItemID.
|
| - /// </summary>
|
| - /// <param name="itemId">ItemID for the requested node</param>
|
| - /// <returns>Node if found</returns>
|
| - public HierarchyNode NodeFromItemId(uint itemId)
|
| - {
|
| - if(VSConstants.VSITEMID_ROOT == itemId)
|
| - {
|
| - return this;
|
| - }
|
| - else if(VSConstants.VSITEMID_NIL == itemId)
|
| - {
|
| - return null;
|
| - }
|
| - else if(VSConstants.VSITEMID_SELECTION == itemId)
|
| - {
|
| - throw new NotImplementedException();
|
| - }
|
| -
|
| - return (HierarchyNode)this.ItemIdMap[itemId];
|
| - }
|
| -
|
| - /// <summary>
|
| - /// This method return new project element, and add new MSBuild item to the project/build hierarchy
|
| - /// </summary>
|
| - /// <param name="file">file name</param>
|
| - /// <param name="itemType">MSBuild item type</param>
|
| - /// <returns>new project element</returns>
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Ms")]
|
| - public ProjectElement CreateMsBuildFileItem(string file, string itemType)
|
| - {
|
| - return new ProjectElement(this, file, itemType);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// This method returns new project element based on existing MSBuild item. It does not modify/add project/build hierarchy at all.
|
| - /// </summary>
|
| - /// <param name="item">MSBuild item instance</param>
|
| - /// <returns>wrapping project element</returns>
|
| - public ProjectElement GetProjectElement(MSBuild.BuildItem item)
|
| - {
|
| - return new ProjectElement(this, item, false);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Create FolderNode from Path
|
| - /// </summary>
|
| - /// <param name="path">Path to folder</param>
|
| - /// <returns>FolderNode created that can be added to the hierarchy</returns>
|
| - protected internal FolderNode CreateFolderNode(string path)
|
| - {
|
| - ProjectElement item = this.AddFolderToMsBuild(path);
|
| - FolderNode folderNode = CreateFolderNode(path, item);
|
| - return folderNode;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Verify if the file can be written to.
|
| - /// Return false if the file is read only and/or not checked out
|
| - /// and the user did not give permission to change it.
|
| - /// Note that exact behavior can also be affected based on the SCC
|
| - /// settings under Tools->Options.
|
| - /// </summary>
|
| - internal bool QueryEditProjectFile(bool suppressUI)
|
| - {
|
| - bool result = true;
|
| - if(this.site == null)
|
| - {
|
| - // We're already zombied. Better return FALSE.
|
| - result = false;
|
| - }
|
| - else if(this.disableQueryEdit)
|
| - {
|
| - return true;
|
| - }
|
| - else
|
| - {
|
| - IVsQueryEditQuerySave2 queryEditQuerySave = this.GetService(typeof(SVsQueryEditQuerySave)) as IVsQueryEditQuerySave2;
|
| - if(queryEditQuerySave != null)
|
| - { // Project path dependends on server/client project
|
| - string path = this.filename;
|
| -
|
| - tagVSQueryEditFlags qef = tagVSQueryEditFlags.QEF_AllowInMemoryEdits;
|
| - if(suppressUI)
|
| - qef |= tagVSQueryEditFlags.QEF_SilentMode;
|
| -
|
| - // If we are debugging, we want to prevent our project from being reloaded. To
|
| - // do this, we pass the QEF_NoReload flag
|
| - if(!Utilities.IsVisualStudioInDesignMode(this.Site))
|
| - qef |= tagVSQueryEditFlags.QEF_NoReload;
|
| -
|
| - uint verdict;
|
| - uint moreInfo;
|
| - string[] files = new string[1];
|
| - files[0] = path;
|
| - uint[] flags = new uint[1];
|
| - VSQEQS_FILE_ATTRIBUTE_DATA[] attributes = new VSQEQS_FILE_ATTRIBUTE_DATA[1];
|
| - int hr = queryEditQuerySave.QueryEditFiles(
|
| - (uint)qef,
|
| - 1, // 1 file
|
| - files, // array of files
|
| - flags, // no per file flags
|
| - attributes, // no per file file attributes
|
| - out verdict,
|
| - out moreInfo /* ignore additional results */);
|
| -
|
| - tagVSQueryEditResult qer = (tagVSQueryEditResult)verdict;
|
| - if(ErrorHandler.Failed(hr) || (qer != tagVSQueryEditResult.QER_EditOK))
|
| - {
|
| - if(!suppressUI && !Utilities.IsInAutomationFunction(this.Site))
|
| - {
|
| - string message = SR.GetString(SR.CancelQueryEdit, path);
|
| - string title = string.Empty;
|
| - OLEMSGICON icon = OLEMSGICON.OLEMSGICON_CRITICAL;
|
| - OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK;
|
| - OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST;
|
| - VsShellUtilities.ShowMessageBox(this.Site, title, message, icon, buttons, defaultButton);
|
| - }
|
| - result = false;
|
| - }
|
| - }
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Checks whether a hierarchy is a nested project.
|
| - /// </summary>
|
| - /// <param name="hierarchy"></param>
|
| - /// <returns></returns>
|
| - internal NestedProjectNode GetNestedProjectForHierarchy(IVsHierarchy hierarchy)
|
| - {
|
| - IVsProject3 project = hierarchy as IVsProject3;
|
| -
|
| - if(project != null)
|
| - {
|
| - string mkDocument = String.Empty;
|
| - ErrorHandler.ThrowOnFailure(project.GetMkDocument(VSConstants.VSITEMID_ROOT, out mkDocument));
|
| -
|
| - if(!String.IsNullOrEmpty(mkDocument))
|
| - {
|
| - HierarchyNode node = this.FindChild(mkDocument);
|
| -
|
| - return node as NestedProjectNode;
|
| - }
|
| - }
|
| -
|
| - return null;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Given a node determines what is the directory that can accept files.
|
| - /// If the node is a FoldeNode than it is the Url of the Folder.
|
| - /// If the node is a ProjectNode it is the project folder.
|
| - /// Otherwise (such as FileNode subitem) it delegate the resolution to the parent node.
|
| - /// </summary>
|
| - internal string GetBaseDirectoryForAddingFiles(HierarchyNode nodeToAddFile)
|
| - {
|
| - string baseDir = String.Empty;
|
| -
|
| - if(nodeToAddFile is FolderNode)
|
| - {
|
| - baseDir = nodeToAddFile.Url;
|
| - }
|
| - else if(nodeToAddFile is ProjectNode)
|
| - {
|
| - baseDir = this.ProjectFolder;
|
| - }
|
| - else if(nodeToAddFile != null)
|
| - {
|
| - baseDir = GetBaseDirectoryForAddingFiles(nodeToAddFile.Parent);
|
| - }
|
| -
|
| - return baseDir;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// For internal use only.
|
| - /// This creates a copy of an existing configuration and add it to the project.
|
| - /// Caller should change the condition on the PropertyGroup.
|
| - /// If derived class want to accomplish this, they should call ConfigProvider.AddCfgsOfCfgName()
|
| - /// It is expected that in the future MSBuild will have support for this so we don't have to
|
| - /// do it manually.
|
| - /// </summary>
|
| - /// <param name="group">PropertyGroup to clone</param>
|
| - /// <returns></returns>
|
| - internal MSBuild.BuildPropertyGroup ClonePropertyGroup(MSBuild.BuildPropertyGroup group)
|
| - {
|
| - // Create a new (empty) PropertyGroup
|
| - MSBuild.BuildPropertyGroup newPropertyGroup = this.buildProject.AddNewPropertyGroup(false);
|
| -
|
| - // Now copy everything from the group we are trying to clone to the group we are creating
|
| - if(!String.IsNullOrEmpty(group.Condition))
|
| - newPropertyGroup.Condition = group.Condition;
|
| - foreach(MSBuild.BuildProperty prop in group)
|
| - {
|
| - MSBuild.BuildProperty newProperty = newPropertyGroup.AddNewProperty(prop.Name, prop.Value);
|
| - if(!String.IsNullOrEmpty(prop.Condition))
|
| - newProperty.Condition = prop.Condition;
|
| - }
|
| -
|
| - return newPropertyGroup;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Register the project with the Scc manager.
|
| - /// </summary>
|
| - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Scc")]
|
| - protected void RegisterSccProject()
|
| - {
|
| -
|
| - if(this.IsSccDisabled || this.isRegisteredWithScc || String.IsNullOrEmpty(this.sccProjectName))
|
| - {
|
| - return;
|
| - }
|
| -
|
| - IVsSccManager2 sccManager = this.Site.GetService(typeof(SVsSccManager)) as IVsSccManager2;
|
| -
|
| - if(sccManager != null)
|
| - {
|
| - ErrorHandler.ThrowOnFailure(sccManager.RegisterSccProject(this, this.sccProjectName, this.sccAuxPath, this.sccLocalPath, this.sccProvider));
|
| -
|
| - this.isRegisteredWithScc = true;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Unregisters us from the SCC manager
|
| - /// </summary>
|
| - [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "UnRegister")]
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Un")]
|
| - protected void UnRegisterProject()
|
| - {
|
| - if(this.IsSccDisabled || !this.isRegisteredWithScc)
|
| - {
|
| - return;
|
| - }
|
| -
|
| - IVsSccManager2 sccManager = this.Site.GetService(typeof(SVsSccManager)) as IVsSccManager2;
|
| -
|
| - if(sccManager != null)
|
| - {
|
| - ErrorHandler.ThrowOnFailure(sccManager.UnregisterSccProject(this));
|
| - this.isRegisteredWithScc = false;
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Get the CATID corresponding to the specified type.
|
| - /// </summary>
|
| - /// <param name="type">Type of the object for which you want the CATID</param>
|
| - /// <returns>CATID</returns>
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "CATID")]
|
| - protected internal Guid GetCATIDForType(Type type)
|
| - {
|
| - if(type == null)
|
| - throw new ArgumentNullException("type");
|
| -
|
| - if(catidMapping.ContainsKey(type))
|
| - return catidMapping[type];
|
| - // If you get here and you want your object to be extensible, then add a call to AddCATIDMapping() in your project constructor
|
| - return Guid.Empty;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// This is used to specify a CATID corresponding to a BrowseObject or an ExtObject.
|
| - /// The CATID can be any GUID you choose. For types which are your owns, you could use
|
| - /// their type GUID, while for other types (such as those provided in the MPF) you should
|
| - /// provide a different GUID.
|
| - /// </summary>
|
| - /// <param name="type">Type of the extensible object</param>
|
| - /// <param name="catid">GUID that extender can use to uniquely identify your object type</param>
|
| - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "catid")]
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "CATID")]
|
| - protected void AddCATIDMapping(Type type, Guid catid)
|
| - {
|
| - catidMapping.Add(type, catid);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Initialize an object with an XML fragment.
|
| - /// </summary>
|
| - /// <param name="iPersistXMLFragment">Object that support being initialized with an XML fragment</param>
|
| - /// <param name="configName">Name of the configuration being initialized, null if it is the project</param>
|
| - protected internal void LoadXmlFragment(IPersistXMLFragment persistXmlFragment, string configName)
|
| - {
|
| - if(xmlFragments == null)
|
| - {
|
| - // Retrieve the xml fragments from MSBuild
|
| - xmlFragments = new XmlDocument();
|
| - string fragments = this.BuildProject.GetProjectExtensions(ProjectFileConstants.VisualStudio);
|
| - fragments = String.Format(CultureInfo.InvariantCulture, "<root>{0}</root>", fragments);
|
| - xmlFragments.LoadXml(fragments);
|
| - }
|
| -
|
| - // We need to loop through all the flavors
|
| - string flavorsGuid;
|
| - ErrorHandler.ThrowOnFailure(((IVsAggregatableProject)this).GetAggregateProjectTypeGuids(out flavorsGuid));
|
| - foreach(Guid flavor in Utilities.GuidsArrayFromSemicolonDelimitedStringOfGuids(flavorsGuid))
|
| - {
|
| - // Look for a matching fragment
|
| - string flavorGuidString = flavor.ToString("B");
|
| - string fragment = null;
|
| - XmlNode node = null;
|
| - foreach(XmlNode child in xmlFragments.FirstChild.ChildNodes)
|
| - {
|
| - if(child.Attributes.Count > 0)
|
| - {
|
| - string guid = String.Empty;
|
| - string configuration = String.Empty;
|
| - if(child.Attributes[ProjectFileConstants.Guid] != null)
|
| - guid = child.Attributes[ProjectFileConstants.Guid].Value;
|
| - if(child.Attributes[ProjectFileConstants.Configuration] != null)
|
| - configuration = child.Attributes[ProjectFileConstants.Configuration].Value;
|
| -
|
| - if(String.Compare(child.Name, ProjectFileConstants.FlavorProperties, StringComparison.OrdinalIgnoreCase) == 0
|
| - && String.Compare(guid, flavorGuidString, StringComparison.OrdinalIgnoreCase) == 0
|
| - && ((String.IsNullOrEmpty(configName) && String.IsNullOrEmpty(configuration))
|
| - || (String.Compare(configuration, configName, StringComparison.OrdinalIgnoreCase) == 0)))
|
| - {
|
| - // we found the matching fragment
|
| - fragment = child.InnerXml;
|
| - node = child;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| -
|
| - Guid flavorGuid = flavor;
|
| - if(String.IsNullOrEmpty(fragment))
|
| - {
|
| - // the fragment was not found so init with default values
|
| - ErrorHandler.ThrowOnFailure(persistXmlFragment.InitNew(ref flavorGuid, (uint)_PersistStorageType.PST_PROJECT_FILE));
|
| - // While we don't yet support user files, our flavors might, so we will store that in the project file until then
|
| - // TODO: Refactor this code when we support user files
|
| - ErrorHandler.ThrowOnFailure(persistXmlFragment.InitNew(ref flavorGuid, (uint)_PersistStorageType.PST_USER_FILE));
|
| - }
|
| - else
|
| - {
|
| - ErrorHandler.ThrowOnFailure(persistXmlFragment.Load(ref flavorGuid, (uint)_PersistStorageType.PST_PROJECT_FILE, fragment));
|
| - // While we don't yet support user files, our flavors might, so we will store that in the project file until then
|
| - // TODO: Refactor this code when we support user files
|
| - if(node.NextSibling != null && node.NextSibling.Attributes[ProjectFileConstants.User] != null)
|
| - ErrorHandler.ThrowOnFailure(persistXmlFragment.Load(ref flavorGuid, (uint)_PersistStorageType.PST_USER_FILE, node.NextSibling.InnerXml));
|
| - }
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Retrieve all XML fragments that need to be saved from the flavors and store the information in msbuild.
|
| - /// </summary>
|
| - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "XML")]
|
| - protected void PersistXMLFragments()
|
| - {
|
| - if(this.IsFlavorDirty() != 0)
|
| - {
|
| - XmlDocument doc = new XmlDocument();
|
| - XmlElement root = doc.CreateElement("ROOT");
|
| -
|
| - // We will need the list of configuration inside the loop, so get it before entering the loop
|
| - uint[] count = new uint[1];
|
| - IVsCfg[] configs = null;
|
| - int hr = this.ConfigProvider.GetCfgs(0, null, count, null);
|
| - if(ErrorHandler.Succeeded(hr) && count[0] > 0)
|
| - {
|
| - configs = new IVsCfg[count[0]];
|
| - hr = this.ConfigProvider.GetCfgs((uint)configs.Length, configs, count, null);
|
| - if(ErrorHandler.Failed(hr))
|
| - count[0] = 0;
|
| - }
|
| - if(count[0] == 0)
|
| - configs = new IVsCfg[0];
|
| -
|
| - // We need to loop through all the flavors
|
| - string flavorsGuid;
|
| - ErrorHandler.ThrowOnFailure(((IVsAggregatableProject)this).GetAggregateProjectTypeGuids(out flavorsGuid));
|
| - foreach(Guid flavor in Utilities.GuidsArrayFromSemicolonDelimitedStringOfGuids(flavorsGuid))
|
| - {
|
| - IPersistXMLFragment outerHierarchy = HierarchyNode.GetOuterHierarchy(this) as IPersistXMLFragment;
|
| - // First check the project
|
| - if(outerHierarchy != null)
|
| - {
|
| - // Retrieve the XML fragment
|
| - string fragment = string.Empty;
|
| - Guid flavorGuid = flavor;
|
| - ErrorHandler.ThrowOnFailure((outerHierarchy).Save(ref flavorGuid, (uint)_PersistStorageType.PST_PROJECT_FILE, out fragment, 1));
|
| - if(!String.IsNullOrEmpty(fragment))
|
| - {
|
| - // Add the fragment to our XML
|
| - WrapXmlFragment(doc, root, flavor, null, fragment);
|
| - }
|
| - // While we don't yet support user files, our flavors might, so we will store that in the project file until then
|
| - // TODO: Refactor this code when we support user files
|
| - fragment = String.Empty;
|
| - ErrorHandler.ThrowOnFailure((outerHierarchy).Save(ref flavorGuid, (uint)_PersistStorageType.PST_USER_FILE, out fragment, 1));
|
| - if(!String.IsNullOrEmpty(fragment))
|
| - {
|
| - // Add the fragment to our XML
|
| - XmlElement node = WrapXmlFragment(doc, root, flavor, null, fragment);
|
| - node.Attributes.Append(doc.CreateAttribute(ProjectFileConstants.User));
|
| - }
|
| - }
|
| -
|
| - // Then look at the configurations
|
| - foreach(IVsCfg config in configs)
|
| - {
|
| - // Get the fragment for this flavor/config pair
|
| - string fragment;
|
| - ErrorHandler.ThrowOnFailure(((ProjectConfig)config).GetXmlFragment(flavor, _PersistStorageType.PST_PROJECT_FILE, out fragment));
|
| - if(!String.IsNullOrEmpty(fragment))
|
| - {
|
| - string configName;
|
| - ErrorHandler.ThrowOnFailure(config.get_DisplayName(out configName));
|
| - WrapXmlFragment(doc, root, flavor, configName, fragment);
|
| - }
|
| - }
|
| - }
|
| - if(root.ChildNodes != null && root.ChildNodes.Count > 0)
|
| - {
|
| - // Save our XML (this is only the non-build information for each flavor) in msbuild
|
| - this.BuildProject.SetProjectExtensions(ProjectFileConstants.VisualStudio, root.InnerXml.ToString());
|
| - }
|
| - }
|
| - }
|
| -
|
| - #endregion
|
| -
|
| - #region IVsGetCfgProvider Members
|
| - //=================================================================================
|
| -
|
| - public virtual int GetCfgProvider(out IVsCfgProvider p)
|
| - {
|
| - CCITracing.TraceCall();
|
| - // Be sure to call the property here since that is doing a polymorhic ProjectConfig creation.
|
| - p = this.ConfigProvider;
|
| - return (p == null ? VSConstants.E_NOTIMPL : VSConstants.S_OK);
|
| - }
|
| - #endregion
|
| -
|
| - #region IPersist Members
|
| -
|
| - public int GetClassID(out Guid clsid)
|
| - {
|
| - clsid = this.ProjectGuid;
|
| - return VSConstants.S_OK;
|
| - }
|
| - #endregion
|
| -
|
| - #region IPersistFileFormat Members
|
| -
|
| - int IPersistFileFormat.GetClassID(out Guid clsid)
|
| - {
|
| - clsid = this.ProjectGuid;
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - public virtual int GetCurFile(out string name, out uint formatIndex)
|
| - {
|
| - name = this.filename;
|
| - formatIndex = 0;
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - public virtual int GetFormatList(out string formatlist)
|
| - {
|
| - formatlist = String.Empty;
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - public virtual int InitNew(uint formatIndex)
|
| - {
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - public virtual int IsDirty(out int isDirty)
|
| - {
|
| - isDirty = 0;
|
| - if(this.buildProject.IsDirty || this.IsProjectFileDirty)
|
| - {
|
| - isDirty = 1;
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - isDirty = IsFlavorDirty();
|
| -
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - protected int IsFlavorDirty()
|
| - {
|
| - int isDirty = 0;
|
| - // See if one of our flavor consider us dirty
|
| - IPersistXMLFragment outerHierarchy = HierarchyNode.GetOuterHierarchy(this) as IPersistXMLFragment;
|
| - if(outerHierarchy != null)
|
| - {
|
| - // First check the project
|
| - ErrorHandler.ThrowOnFailure(outerHierarchy.IsFragmentDirty((uint)_PersistStorageType.PST_PROJECT_FILE, out isDirty));
|
| - // While we don't yet support user files, our flavors might, so we will store that in the project file until then
|
| - // TODO: Refactor this code when we support user files
|
| - if(isDirty == 0)
|
| - ErrorHandler.ThrowOnFailure(outerHierarchy.IsFragmentDirty((uint)_PersistStorageType.PST_USER_FILE, out isDirty));
|
| - }
|
| - if(isDirty == 0)
|
| - {
|
| - // Then look at the configurations
|
| - uint[] count = new uint[1];
|
| - int hr = this.ConfigProvider.GetCfgs(0, null, count, null);
|
| - if(ErrorHandler.Succeeded(hr) && count[0] > 0)
|
| - {
|
| - // We need to loop through the configurations
|
| - IVsCfg[] configs = new IVsCfg[count[0]];
|
| - hr = this.ConfigProvider.GetCfgs((uint)configs.Length, configs, count, null);
|
| - Debug.Assert(ErrorHandler.Succeeded(hr), "failed to retrieve configurations");
|
| - foreach(IVsCfg config in configs)
|
| - {
|
| - isDirty = ((ProjectConfig)config).IsFlavorDirty(_PersistStorageType.PST_PROJECT_FILE);
|
| - if(isDirty != 0)
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - return isDirty;
|
| - }
|
| -
|
| - public virtual int Load(string fileName, uint mode, int readOnly)
|
| - {
|
| - this.filename = fileName;
|
| - this.Reload();
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - public virtual int Save(string fileToBeSaved, int remember, uint formatIndex)
|
| - {
|
| -
|
| - // The file name can be null. Then try to use the Url.
|
| - string tempFileToBeSaved = fileToBeSaved;
|
| - if(String.IsNullOrEmpty(tempFileToBeSaved) && !String.IsNullOrEmpty(this.Url))
|
| - {
|
| - tempFileToBeSaved = this.Url;
|
| - }
|
| -
|
| - if(String.IsNullOrEmpty(tempFileToBeSaved))
|
| - {
|
| - throw new ArgumentException(SR.GetString(SR.InvalidParameter, CultureInfo.CurrentUICulture), "fileToBeSaved");
|
| - }
|
| -
|
| - bool setProjectFileDirtyAfterSave = false;
|
| - if(remember == 0)
|
| - {
|
| - setProjectFileDirtyAfterSave = this.IsProjectFileDirty;
|
| - }
|
| -
|
| - // Update the project with the latest flavor data (if needed)
|
| - PersistXMLFragments();
|
| -
|
| - int result = VSConstants.S_OK;
|
| - bool saveAs = true;
|
| - if(NativeMethods.IsSamePath(tempFileToBeSaved, this.filename))
|
| - {
|
| - saveAs = false;
|
| - }
|
| - if(!saveAs)
|
| - {
|
| - SuspendFileChanges fileChanges = new SuspendFileChanges(this.Site, this.filename);
|
| - fileChanges.Suspend();
|
| - try
|
| - {
|
| - this.buildProject.Save(tempFileToBeSaved);
|
| - this.SetProjectFileDirty(false);
|
| - }
|
| - finally
|
| - {
|
| - fileChanges.Resume();
|
| - }
|
| - }
|
| - else
|
| - {
|
| - result = this.SaveAs(tempFileToBeSaved);
|
| - if(result != VSConstants.OLE_E_PROMPTSAVECANCELLED)
|
| - {
|
| - ErrorHandler.ThrowOnFailure(result);
|
| - }
|
| -
|
| - }
|
| -
|
| - if(setProjectFileDirtyAfterSave)
|
| - {
|
| - this.SetProjectFileDirty(true);
|
| - }
|
| -
|
| - return result;
|
| - }
|
| -
|
| - public virtual int SaveCompleted(string filename)
|
| - {
|
| - // TODO: turn file watcher back on.
|
| - return VSConstants.S_OK;
|
| - }
|
| - #endregion
|
| -
|
| - #region IVsProject3 Members
|
| -
|
| - /// <summary>
|
| - /// Callback from the additem dialog. Deals with adding new and existing items
|
| - /// </summary>
|
| - public virtual int GetMkDocument(uint itemId, out string mkDoc)
|
| - {
|
| - mkDoc = null;
|
| - if(itemId == VSConstants.VSITEMID_SELECTION)
|
| - {
|
| - return VSConstants.E_UNEXPECTED;
|
| - }
|
| -
|
| - HierarchyNode n = this.NodeFromItemId(itemId);
|
| - if(n == null)
|
| - {
|
| - return VSConstants.E_INVALIDARG;
|
| - }
|
| -
|
| - mkDoc = n.GetMkDocument();
|
| -
|
| - if(String.IsNullOrEmpty(mkDoc))
|
| - {
|
| - return VSConstants.E_FAIL;
|
| - }
|
| -
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| -
|
| - public virtual int AddItem(uint itemIdLoc, VSADDITEMOPERATION op, string itemName, uint filesToOpen, string[] files, IntPtr dlgOwner, VSADDRESULT[] result)
|
| - {
|
| - Guid empty = Guid.Empty;
|
| -
|
| - return AddItemWithSpecific(itemIdLoc, op, itemName, filesToOpen, files, dlgOwner, 0, ref empty, null, ref empty, result);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Creates new items in a project, adds existing files to a project, or causes Add Item wizards to be run
|
| - /// </summary>
|
| - /// <param name="itemIdLoc"></param>
|
| - /// <param name="op"></param>
|
| - /// <param name="itemName"></param>
|
| - /// <param name="filesToOpen"></param>
|
| - /// <param name="files">Array of file names.
|
| - /// If dwAddItemOperation is VSADDITEMOP_CLONEFILE the first item in the array is the name of the file to clone.
|
| - /// If dwAddItemOperation is VSADDITEMOP_OPENDIRECTORY, the first item in the array is the directory to open.
|
| - /// If dwAddItemOperation is VSADDITEMOP_RUNWIZARD, the first item is the name of the wizard to run,
|
| - /// and the second item is the file name the user supplied (same as itemName).</param>
|
| - /// <param name="dlgOwner"></param>
|
| - /// <param name="editorFlags"></param>
|
| - /// <param name="editorType"></param>
|
| - /// <param name="physicalView"></param>
|
| - /// <param name="logicalView"></param>
|
| - /// <param name="result"></param>
|
| - /// <returns>S_OK if it succeeds </returns>
|
| - /// <remarks>The result array is initalized to failure.</remarks>
|
| - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
|
| - public virtual int AddItemWithSpecific(uint itemIdLoc, VSADDITEMOPERATION op, string itemName, uint filesToOpen, string[] files, IntPtr dlgOwner, uint editorFlags, ref Guid editorType, string physicalView, ref Guid logicalView, VSADDRESULT[] result)
|
| - {
|
| - if(files == null || result == null || files.Length == 0 || result.Length == 0)
|
| - {
|
| - return VSConstants.E_INVALIDARG;
|
| - }
|
| -
|
| - // Locate the node to be the container node for the file(s) being added
|
| - // only projectnode or foldernode and file nodes are valid container nodes
|
| - // We need to locate the parent since the item wizard expects the parent to be passed.
|
| - HierarchyNode n = this.NodeFromItemId(itemIdLoc);
|
| - if(n == null)
|
| - {
|
| - return VSConstants.E_INVALIDARG;
|
| - }
|
| -
|
| - while((!(n is ProjectNode)) && (!(n is FolderNode)) && (!this.CanFileNodesHaveChilds || !(n is FileNode)))
|
| - {
|
| - n = n.Parent;
|
| - }
|
| - Debug.Assert(n != null, "We should at this point have either a ProjectNode or FolderNode or a FileNode as a container for the new filenodes");
|
| -
|
| - // handle link and runwizard operations at this point
|
| - switch(op)
|
| - {
|
| - case VSADDITEMOPERATION.VSADDITEMOP_LINKTOFILE:
|
| - // we do not support this right now
|
| - throw new NotImplementedException("VSADDITEMOP_LINKTOFILE");
|
| -
|
| - case VSADDITEMOPERATION.VSADDITEMOP_RUNWIZARD:
|
| - result[0] = this.RunWizard(n, itemName, files[0], dlgOwner);
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - string[] actualFiles = new string[files.Length];
|
| -
|
| -
|
| - VSQUERYADDFILEFLAGS[] flags = this.GetQueryAddFileFlags(files);
|
| -
|
| - string baseDir = this.GetBaseDirectoryForAddingFiles(n);
|
| - // If we did not get a directory for node that is the parent of the item then fail.
|
| - if(String.IsNullOrEmpty(baseDir))
|
| - {
|
| - return VSConstants.E_FAIL;
|
| - }
|
| -
|
| - // Pre-calculates some paths that we can use when calling CanAddItems
|
| - List<string> filesToAdd = new List<string>();
|
| - for(int index = 0; index < files.Length; index++)
|
| - {
|
| - string newFileName = String.Empty;
|
| -
|
| - string file = files[index];
|
| -
|
| - switch(op)
|
| - {
|
| - case VSADDITEMOPERATION.VSADDITEMOP_CLONEFILE:
|
| - // New item added. Need to copy template to new location and then add new location
|
| - newFileName = Path.Combine(baseDir, itemName);
|
| - break;
|
| -
|
| - case VSADDITEMOPERATION.VSADDITEMOP_OPENFILE:
|
| - {
|
| - string fileName = Path.GetFileName(file);
|
| - newFileName = Path.Combine(baseDir, fileName);
|
| - }
|
| - break;
|
| - }
|
| - filesToAdd.Add(newFileName);
|
| - }
|
| -
|
| - // Ask tracker objects if we can add files
|
| - if(!this.tracker.CanAddItems(filesToAdd.ToArray(), flags))
|
| - {
|
| - // We were not allowed to add the files
|
| - return VSConstants.E_FAIL;
|
| - }
|
| -
|
| - if(!this.ProjectMgr.QueryEditProjectFile(false))
|
| - {
|
| - throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED);
|
| - }
|
| -
|
| - // Add the files to the hierarchy
|
| - int actualFilesAddedIndex = 0;
|
| - for(int index = 0; index < filesToAdd.Count; index++)
|
| - {
|
| - HierarchyNode child;
|
| - bool overwrite = false;
|
| - string newFileName = filesToAdd[index];
|
| -
|
| - string file = files[index];
|
| - result[0] = VSADDRESULT.ADDRESULT_Failure;
|
| -
|
| - child = this.FindChild(newFileName);
|
| - if(child != null)
|
| - {
|
| - // If the file to be added is an existing file part of the hierarchy then continue.
|
| - if(NativeMethods.IsSamePath(file, newFileName))
|
| - {
|
| - result[0] = VSADDRESULT.ADDRESULT_Cancel;
|
| - continue;
|
| - }
|
| -
|
| - int canOverWriteExistingItem = this.CanOverwriteExistingItem(file, newFileName);
|
| -
|
| - if(canOverWriteExistingItem == (int)OleConstants.OLECMDERR_E_CANCELED)
|
| - {
|
| - result[0] = VSADDRESULT.ADDRESULT_Cancel;
|
| - return canOverWriteExistingItem;
|
| - }
|
| - else if(canOverWriteExistingItem == VSConstants.S_OK)
|
| - {
|
| - overwrite = true;
|
| - }
|
| - else
|
| - {
|
| - return canOverWriteExistingItem;
|
| - }
|
| - }
|
| -
|
| - // If the file to be added is not in the same path copy it.
|
| - if(NativeMethods.IsSamePath(file, newFileName) == false)
|
| - {
|
| - if(!overwrite && File.Exists(newFileName))
|
| - {
|
| - string message = String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.FileAlreadyExists, CultureInfo.CurrentUICulture), newFileName);
|
| - string title = string.Empty;
|
| - OLEMSGICON icon = OLEMSGICON.OLEMSGICON_QUERY;
|
| - OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_YESNO;
|
| - OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST;
|
| - int messageboxResult = VsShellUtilities.ShowMessageBox(this.Site, title, message, icon, buttons, defaultButton);
|
| - if(messageboxResult == NativeMethods.IDNO)
|
| - {
|
| - result[0] = VSADDRESULT.ADDRESULT_Cancel;
|
| - return (int)OleConstants.OLECMDERR_E_CANCELED;
|
| - }
|
| - }
|
| -
|
| - // Copy the file to the correct location.
|
| - // We will suppress the file change events to be triggered to this item, since we are going to copy over the existing file and thus we will trigger a file change event.
|
| - // We do not want the filechange event to ocur in this case, similar that we do not want a file change event to occur when saving a file.
|
| - IVsFileChangeEx fileChange = this.site.GetService(typeof(SVsFileChangeEx)) as IVsFileChangeEx;
|
| - if(fileChange == null)
|
| - {
|
| - throw new InvalidOperationException();
|
| - }
|
| -
|
| - try
|
| - {
|
| - ErrorHandler.ThrowOnFailure(fileChange.IgnoreFile(VSConstants.VSCOOKIE_NIL, newFileName, 1));
|
| - if(op == VSADDITEMOPERATION.VSADDITEMOP_CLONEFILE)
|
| - {
|
| - this.AddFileFromTemplate(file, newFileName);
|
| - }
|
| - else
|
| - {
|
| - PackageUtilities.CopyUrlToLocal(new Uri(file), newFileName);
|
| - }
|
| - }
|
| - finally
|
| - {
|
| - ErrorHandler.ThrowOnFailure(fileChange.IgnoreFile(VSConstants.VSCOOKIE_NIL, newFileName, 0));
|
| - }
|
| - }
|
| -
|
| - if(overwrite)
|
| - {
|
| - this.OverwriteExistingItem(child);
|
| - }
|
| - else
|
| - {
|
| - //Add new filenode/dependentfilenode
|
| - this.AddNewFileNodeToHierarchy(n, newFileName);
|
| - }
|
| -
|
| - result[0] = VSADDRESULT.ADDRESULT_Success;
|
| - actualFiles[actualFilesAddedIndex++] = newFileName;
|
| - }
|
| -
|
| - // Notify listeners that items were appended.
|
| - if(actualFilesAddedIndex > 0)
|
| - n.OnItemsAppended(n);
|
| -
|
| - //Open files if this was requested through the editorFlags
|
| - bool openFiles = (editorFlags & (uint)__VSSPECIFICEDITORFLAGS.VSSPECIFICEDITOR_DoOpen) != 0;
|
| - if(openFiles && actualFiles.Length <= filesToOpen)
|
| - {
|
| - for(int i = 0; i < filesToOpen; i++)
|
| - {
|
| - if(!String.IsNullOrEmpty(actualFiles[i]))
|
| - {
|
| - string name = actualFiles[i];
|
| - HierarchyNode child = this.FindChild(name);
|
| - Debug.Assert(child != null, "We should have been able to find the new element in the hierarchy");
|
| - if(child != null)
|
| - {
|
| - IVsWindowFrame frame;
|
| - if(editorType == Guid.Empty)
|
| - {
|
| - Guid view = Guid.Empty;
|
| - ErrorHandler.ThrowOnFailure(this.OpenItem(child.ID, ref view, IntPtr.Zero, out frame));
|
| - }
|
| - else
|
| - {
|
| - ErrorHandler.ThrowOnFailure(this.OpenItemWithSpecific(child.ID, editorFlags, ref editorType, physicalView, ref logicalView, IntPtr.Zero, out frame));
|
| - }
|
| -
|
| - // Show the window frame in the UI and make it the active window
|
| - if(frame != null)
|
| - {
|
| - ErrorHandler.ThrowOnFailure(frame.Show());
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// for now used by add folder. Called on the ROOT, as only the project should need
|
| - /// to implement this.
|
| - /// for folders, called with parent folder, blank extension and blank suggested root
|
| - /// </summary>
|
| - public virtual int GenerateUniqueItemName(uint itemIdLoc, string ext, string suggestedRoot, out string itemName)
|
| - {
|
| - string rootName = "";
|
| - string extToUse;
|
| - int cb = 1;//force new items to have a number
|
| - bool found = false;
|
| - bool fFolderCase = false;
|
| - HierarchyNode parent = this.NodeFromItemId(itemIdLoc);
|
| -
|
| - extToUse = ext.Trim();
|
| - suggestedRoot = suggestedRoot.Trim();
|
| - if(suggestedRoot.Length == 0)
|
| - {
|
| - // foldercase, we assume...
|
| - suggestedRoot = "NewFolder";
|
| - fFolderCase = true;
|
| - }
|
| -
|
| - while(!found)
|
| - {
|
| - rootName = suggestedRoot;
|
| - if(cb > 0)
|
| - rootName += cb.ToString(CultureInfo.CurrentCulture);
|
| -
|
| - if(extToUse.Length > 0)
|
| - {
|
| - rootName += extToUse;
|
| - }
|
| -
|
| - cb++;
|
| - found = true;
|
| - for(HierarchyNode n = parent.FirstChild; n != null; n = n.NextSibling)
|
| - {
|
| - if(rootName == n.GetEditLabel())
|
| - {
|
| - found = false;
|
| - break;
|
| - }
|
| -
|
| - //if parent is a folder, we need the whole url
|
| - string parentFolder = parent.Url;
|
| - if(parent is ProjectNode)
|
| - parentFolder = Path.GetDirectoryName(parent.Url);
|
| -
|
| - string checkFile = Path.Combine(parentFolder, rootName);
|
| -
|
| - if(fFolderCase)
|
| - {
|
| - if(Directory.Exists(checkFile))
|
| - {
|
| - found = false;
|
| - break;
|
| - }
|
| - }
|
| - else
|
| - {
|
| - if(File.Exists(checkFile))
|
| - {
|
| - found = false;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - itemName = rootName;
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| -
|
| - public virtual int GetItemContext(uint itemId, out Microsoft.VisualStudio.OLE.Interop.IServiceProvider psp)
|
| - {
|
| - CCITracing.TraceCall();
|
| - psp = null;
|
| - HierarchyNode child = this.NodeFromItemId(itemId);
|
| - if(child != null)
|
| - {
|
| - psp = child.OleServiceProvider as IOleServiceProvider;
|
| - }
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| -
|
| - public virtual int IsDocumentInProject(string mkDoc, out int found, VSDOCUMENTPRIORITY[] pri, out uint itemId)
|
| - {
|
| - CCITracing.TraceCall();
|
| - if(pri != null && pri.Length >= 1)
|
| - {
|
| - pri[0] = VSDOCUMENTPRIORITY.DP_Unsupported;
|
| - }
|
| - found = 0;
|
| - itemId = 0;
|
| -
|
| - // If it is the project file just return.
|
| - if(NativeMethods.IsSamePath(mkDoc, this.GetMkDocument()))
|
| - {
|
| - found = 1;
|
| - itemId = VSConstants.VSITEMID_ROOT;
|
| - }
|
| - else
|
| - {
|
| - HierarchyNode child = this.FindChild(mkDoc);
|
| - if(child != null)
|
| - {
|
| - found = 1;
|
| - itemId = child.ID;
|
| - }
|
| - }
|
| -
|
| - if(found == 1)
|
| - {
|
| - if(pri != null && pri.Length >= 1)
|
| - {
|
| - pri[0] = VSDOCUMENTPRIORITY.DP_Standard;
|
| - }
|
| - }
|
| -
|
| - return VSConstants.S_OK;
|
| -
|
| - }
|
| -
|
| -
|
| - public virtual int OpenItem(uint itemId, ref Guid logicalView, IntPtr punkDocDataExisting, out IVsWindowFrame frame)
|
| - {
|
| - // Init output params
|
| - frame = null;
|
| -
|
| - HierarchyNode n = this.NodeFromItemId(itemId);
|
| - if(n == null)
|
| - {
|
| - throw new ArgumentException(SR.GetString(SR.ParameterMustBeAValidItemId, CultureInfo.CurrentUICulture), "itemId");
|
| - }
|
| -
|
| - // Delegate to the document manager object that knows how to open the item
|
| - DocumentManager documentManager = n.GetDocumentManager();
|
| - if(documentManager != null)
|
| - {
|
| - return documentManager.Open(ref logicalView, punkDocDataExisting, out frame, WindowFrameShowAction.DoNotShow);
|
| - }
|
| -
|
| - // This node does not have an associated document manager and we must fail
|
| - return VSConstants.E_FAIL;
|
| - }
|
| -
|
| -
|
| - public virtual int OpenItemWithSpecific(uint itemId, uint editorFlags, ref Guid editorType, string physicalView, ref Guid logicalView, IntPtr docDataExisting, out IVsWindowFrame frame)
|
| - {
|
| - // Init output params
|
| - frame = null;
|
| -
|
| - HierarchyNode n = this.NodeFromItemId(itemId);
|
| - if(n == null)
|
| - {
|
| - throw new ArgumentException(SR.GetString(SR.ParameterMustBeAValidItemId, CultureInfo.CurrentUICulture), "itemId");
|
| - }
|
| -
|
| - // Delegate to the document manager object that knows how to open the item
|
| - DocumentManager documentManager = n.GetDocumentManager();
|
| - if(documentManager != null)
|
| - {
|
| - return documentManager.OpenWithSpecific(editorFlags, ref editorType, physicalView, ref logicalView, docDataExisting, out frame, WindowFrameShowAction.DoNotShow);
|
| - }
|
| -
|
| - // This node does not have an associated document manager and we must fail
|
| - return VSConstants.E_FAIL;
|
| - }
|
| -
|
| -
|
| - public virtual int RemoveItem(uint reserved, uint itemId, out int result)
|
| - {
|
| - HierarchyNode n = this.NodeFromItemId(itemId);
|
| - if(n == null)
|
| - {
|
| - throw new ArgumentException(SR.GetString(SR.ParameterMustBeAValidItemId, CultureInfo.CurrentUICulture), "itemId");
|
| - }
|
| - n.Remove(true);
|
| - result = 1;
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| -
|
| - public virtual int ReopenItem(uint itemId, ref Guid editorType, string physicalView, ref Guid logicalView, IntPtr docDataExisting, out IVsWindowFrame frame)
|
| - {
|
| - // Init output params
|
| - frame = null;
|
| -
|
| - HierarchyNode n = this.NodeFromItemId(itemId);
|
| - if(n == null)
|
| - {
|
| - throw new ArgumentException(SR.GetString(SR.ParameterMustBeAValidItemId, CultureInfo.CurrentUICulture), "itemId");
|
| - }
|
| -
|
| - // Delegate to the document manager object that knows how to open the item
|
| - DocumentManager documentManager = n.GetDocumentManager();
|
| - if(documentManager != null)
|
| - {
|
| - return documentManager.OpenWithSpecific(0, ref editorType, physicalView, ref logicalView, docDataExisting, out frame, WindowFrameShowAction.DoNotShow);
|
| - }
|
| -
|
| - // This node does not have an associated document manager and we must fail
|
| - return VSConstants.E_FAIL;
|
| - }
|
| -
|
| -
|
| - /// <summary>
|
| - /// Implements IVsProject3::TransferItem
|
| - /// This function is called when an open miscellaneous file is being transferred
|
| - /// to our project. The sequence is for the shell to call AddItemWithSpecific and
|
| - /// then use TransferItem to transfer the open document to our project.
|
| - /// </summary>
|
| - /// <param name="oldMkDoc">Old document name</param>
|
| - /// <param name="newMkDoc">New document name</param>
|
| - /// <param name="frame">Optional frame if the document is open</param>
|
| - /// <returns></returns>
|
| - public virtual int TransferItem(string oldMkDoc, string newMkDoc, IVsWindowFrame frame)
|
| - {
|
| - // Fail if hierarchy already closed
|
| - if(this.ProjectMgr == null || this.ProjectMgr.IsClosed)
|
| - {
|
| - return VSConstants.E_FAIL;
|
| - }
|
| - //Fail if the document names passed are null.
|
| - if(oldMkDoc == null || newMkDoc == null)
|
| - return VSConstants.E_INVALIDARG;
|
| -
|
| - int hr = VSConstants.S_OK;
|
| - VSDOCUMENTPRIORITY[] priority = new VSDOCUMENTPRIORITY[1];
|
| - uint itemid = VSConstants.VSITEMID_NIL;
|
| - uint cookie = 0;
|
| - uint grfFlags = 0;
|
| -
|
| - IVsRunningDocumentTable pRdt = GetService(typeof(IVsRunningDocumentTable)) as IVsRunningDocumentTable;
|
| - if(pRdt == null)
|
| - return VSConstants.E_ABORT;
|
| -
|
| - string doc;
|
| - int found;
|
| - IVsHierarchy pHier;
|
| - uint id, readLocks, editLocks;
|
| - IntPtr docdataForCookiePtr = IntPtr.Zero;
|
| - IntPtr docDataPtr = IntPtr.Zero;
|
| - IntPtr hierPtr = IntPtr.Zero;
|
| -
|
| - // We get the document from the running doc table so that we can see if it is transient
|
| - try
|
| - {
|
| - ErrorHandler.ThrowOnFailure(pRdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, oldMkDoc, out pHier, out id, out docdataForCookiePtr, out cookie));
|
| - }
|
| - finally
|
| - {
|
| - if(docdataForCookiePtr != IntPtr.Zero)
|
| - Marshal.Release(docdataForCookiePtr);
|
| - }
|
| -
|
| - //Get the document info
|
| - try
|
| - {
|
| - ErrorHandler.ThrowOnFailure(pRdt.GetDocumentInfo(cookie, out grfFlags, out readLocks, out editLocks, out doc, out pHier, out id, out docDataPtr));
|
| - }
|
| - finally
|
| - {
|
| - if(docDataPtr != IntPtr.Zero)
|
| - Marshal.Release(docDataPtr);
|
| - }
|
| -
|
| - // Now see if the document is in the project. If not, we fail
|
| - try
|
| - {
|
| - ErrorHandler.ThrowOnFailure(IsDocumentInProject(newMkDoc, out found, priority, out itemid));
|
| - Debug.Assert(itemid != VSConstants.VSITEMID_NIL && itemid != VSConstants.VSITEMID_ROOT);
|
| - hierPtr = Marshal.GetComInterfaceForObject(this, typeof(IVsUIHierarchy));
|
| - // Now rename the document
|
| - ErrorHandler.ThrowOnFailure(pRdt.RenameDocument(oldMkDoc, newMkDoc, hierPtr, itemid));
|
| - }
|
| - finally
|
| - {
|
| - if(hierPtr != IntPtr.Zero)
|
| - Marshal.Release(hierPtr);
|
| - }
|
| -
|
| - //Change the caption if we are passed a window frame
|
| - if(frame != null)
|
| - {
|
| - string caption = "%2";
|
| - hr = frame.SetProperty((int)(__VSFPROPID.VSFPROPID_OwnerCaption), caption);
|
| - }
|
| - return hr;
|
| - }
|
| -
|
| - #endregion
|
| -
|
| - #region IVsProjectBuidSystem Members
|
| - public virtual int SetHostObject(string targetName, string taskName, object hostObject)
|
| - {
|
| - Debug.Assert(targetName != null && taskName != null && this.buildProject != null && this.buildProject.Targets != null);
|
| -
|
| - if(targetName == null || taskName == null || this.buildProject == null || this.buildProject.Targets == null)
|
| - {
|
| - return VSConstants.E_INVALIDARG;
|
| - }
|
| -
|
| -
|
| - foreach(MSBuild.Target target in this.buildProject.Targets)
|
| - {
|
| - if(String.Compare(target.Name, targetName, StringComparison.OrdinalIgnoreCase) == 0)
|
| - {
|
| - System.Collections.IEnumerator enumerator = target.GetEnumerator();
|
| - Debug.Assert(enumerator != null);
|
| -
|
| - if(enumerator == null)
|
| - {
|
| - return VSConstants.E_FAIL;
|
| - }
|
| -
|
| - while(enumerator.MoveNext())
|
| - {
|
| - MSBuild.BuildTask buildTask = (MSBuild.BuildTask)enumerator.Current;
|
| - if(String.Compare(buildTask.Name, taskName, true, CultureInfo.CurrentCulture) == 0)
|
| - {
|
| - buildTask.HostObject = (Microsoft.Build.Framework.ITaskHost)hostObject;
|
| - return VSConstants.S_OK;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - return VSConstants.E_FAIL;
|
| - }
|
| -
|
| - public int BuildTarget(string targetName, out bool success)
|
| - {
|
| - success = false;
|
| -
|
| - MSBuildResult result = this.Build(targetName);
|
| -
|
| - if(result == MSBuildResult.Successful)
|
| - {
|
| - success = true;
|
| - }
|
| -
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - public virtual int CancelBatchEdit()
|
| - {
|
| - return VSConstants.E_NOTIMPL;
|
| - }
|
| -
|
| - public virtual int EndBatchEdit()
|
| - {
|
| - return VSConstants.E_NOTIMPL;
|
| - }
|
| -
|
| - public virtual int StartBatchEdit()
|
| - {
|
| - return VSConstants.E_NOTIMPL;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Used to determine the kind of build system, in VS 2005 there's only one defined kind: MSBuild
|
| - /// </summary>
|
| - /// <param name="kind"></param>
|
| - /// <returns></returns>
|
| - public virtual int GetBuildSystemKind(out uint kind)
|
| - {
|
| - kind = (uint)_BuildSystemKindFlags.BSK_MSBUILD;
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - #endregion
|
| -
|
| - #region IVsComponentUser methods
|
| -
|
| - /// <summary>
|
| - /// Add Components to the Project.
|
| - /// Used by the environment to add components specified by the user in the Component Selector dialog
|
| - /// to the specified project
|
| - /// </summary>
|
| - /// <param name="dwAddCompOperation">The component operation to be performed.</param>
|
| - /// <param name="cComponents">Number of components to be added</param>
|
| - /// <param name="rgpcsdComponents">array of component selector data</param>
|
| - /// <param name="hwndDialog">Handle to the component picker dialog</param>
|
| - /// <param name="pResult">Result to be returned to the caller</param>
|
| - public virtual int AddComponent(VSADDCOMPOPERATION dwAddCompOperation, uint cComponents, System.IntPtr[] rgpcsdComponents, System.IntPtr hwndDialog, VSADDCOMPRESULT[] pResult)
|
| - {
|
| - //initalize the out parameter
|
| - pResult[0] = VSADDCOMPRESULT.ADDCOMPRESULT_Success;
|
| -
|
| - IReferenceContainer references = GetReferenceContainer();
|
| - if(null == references)
|
| - {
|
| - // This project does not support references or the reference container was not created.
|
| - // In both cases this operation is not supported.
|
| - return VSConstants.E_NOTIMPL;
|
| - }
|
| - for(int cCount = 0; cCount < cComponents; cCount++)
|
| - {
|
| - VSCOMPONENTSELECTORDATA selectorData = new VSCOMPONENTSELECTORDATA();
|
| - IntPtr ptr = rgpcsdComponents[cCount];
|
| - selectorData = (VSCOMPONENTSELECTORDATA)Marshal.PtrToStructure(ptr, typeof(VSCOMPONENTSELECTORDATA));
|
| - if(null == references.AddReferenceFromSelectorData(selectorData))
|
| - {
|
| - //Skip further proccessing since a reference has to be added
|
| - pResult[0] = VSADDCOMPRESULT.ADDCOMPRESULT_Failure;
|
| - return VSConstants.S_OK;
|
| - }
|
| - }
|
| - return VSConstants.S_OK;
|
| - }
|
| - #endregion
|
| -
|
| - #region IVsDependencyProvider Members
|
| - public int EnumDependencies(out IVsEnumDependencies enumDependencies)
|
| - {
|
| - enumDependencies = new EnumDependencies(this.buildDependencyList);
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - public int OpenDependency(string szDependencyCanonicalName, out IVsDependency dependency)
|
| - {
|
| - dependency = null;
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - #endregion
|
| -
|
| - #region IVsSccProject2 Members
|
| - /// <summary>
|
| - /// This method is called to determine which files should be placed under source control for a given VSITEMID within this hierarchy.
|
| - /// </summary>
|
| - /// <param name="itemid">Identifier for the VSITEMID being queried.</param>
|
| - /// <param name="stringsOut">Pointer to an array of CALPOLESTR strings containing the file names for this item.</param>
|
| - /// <param name="flagsOut">Pointer to a CADWORD array of flags stored in DWORDs indicating that some of the files have special behaviors.</param>
|
| - /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code. </returns>
|
| - public virtual int GetSccFiles(uint itemid, CALPOLESTR[] stringsOut, CADWORD[] flagsOut)
|
| - {
|
| - if(itemid == VSConstants.VSITEMID_SELECTION)
|
| - {
|
| - throw new ArgumentException(SR.GetString(SR.InvalidParameter, CultureInfo.CurrentUICulture), "itemid");
|
| - }
|
| -
|
| - HierarchyNode n = this.NodeFromItemId(itemid);
|
| - if(n == null)
|
| - {
|
| - throw new ArgumentException(SR.GetString(SR.InvalidParameter, CultureInfo.CurrentUICulture), "itemid");
|
| - }
|
| -
|
| - List<string> files = new List<string>();
|
| - List<tagVsSccFilesFlags> flags = new List<tagVsSccFilesFlags>();
|
| -
|
| - n.GetSccFiles(files, flags);
|
| -
|
| - if(stringsOut != null && stringsOut.Length > 0)
|
| - {
|
| - stringsOut[0] = Utilities.CreateCALPOLESTR(files);
|
| - }
|
| -
|
| - if(flagsOut != null && flagsOut.Length > 0)
|
| - {
|
| - flagsOut[0] = Utilities.CreateCADWORD(flags);
|
| - }
|
| -
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// This method is called to discover special (hidden files) associated with a given VSITEMID within this hierarchy.
|
| - /// </summary>
|
| - /// <param name="itemid">Identifier for the VSITEMID being queried.</param>
|
| - /// <param name="sccFile">One of the files associated with the node</param>
|
| - /// <param name="stringsOut">Pointer to an array of CALPOLESTR strings containing the file names for this item.</param>
|
| - /// <param name="flagsOut">Pointer to a CADWORD array of flags stored in DWORDs indicating that some of the files have special behaviors.</param>
|
| - /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code. </returns>
|
| - /// <remarks>This method is called to discover any special or hidden files associated with an item in the project hierarchy. It is called when GetSccFiles returns with the SFF_HasSpecialFiles flag set for any of the files associated with the node.</remarks>
|
| - public virtual int GetSccSpecialFiles(uint itemid, string sccFile, CALPOLESTR[] stringsOut, CADWORD[] flagsOut)
|
| - {
|
| - if(itemid == VSConstants.VSITEMID_SELECTION)
|
| - {
|
| - throw new ArgumentException(SR.GetString(SR.InvalidParameter, CultureInfo.CurrentUICulture), "itemid");
|
| - }
|
| -
|
| - HierarchyNode n = this.NodeFromItemId(itemid);
|
| - if(n == null)
|
| - {
|
| - throw new ArgumentException(SR.GetString(SR.InvalidParameter, CultureInfo.CurrentUICulture), "itemid");
|
| - }
|
| -
|
| - List<string> files = new List<string>();
|
| -
|
| - List<tagVsSccFilesFlags> flags = new List<tagVsSccFilesFlags>();
|
| -
|
| - n.GetSccSpecialFiles(sccFile, files, flags);
|
| -
|
| - if(stringsOut != null && stringsOut.Length > 0)
|
| - {
|
| - stringsOut[0] = Utilities.CreateCALPOLESTR(files);
|
| - }
|
| -
|
| - if(flagsOut != null && flagsOut.Length > 0)
|
| - {
|
| - flagsOut[0] = Utilities.CreateCADWORD(flags);
|
| - }
|
| -
|
| - return VSConstants.S_OK;
|
| -
|
| - }
|
| -
|
| - /// <summary>
|
| - /// This method is called by the source control portion of the environment to inform the project of changes to the source control glyph on various nodes.
|
| - /// </summary>
|
| - /// <param name="affectedNodes">Count of changed nodes.</param>
|
| - /// <param name="itemidAffectedNodes">An array of VSITEMID identifiers of the changed nodes.</param>
|
| - /// <param name="newGlyphs">An array of VsStateIcon glyphs representing the new state of the corresponding item in rgitemidAffectedNodes.</param>
|
| - /// <param name="newSccStatus">An array of status flags from SccStatus corresponding to rgitemidAffectedNodes. </param>
|
| - /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code. </returns>
|
| - public virtual int SccGlyphChanged(int affectedNodes, uint[] itemidAffectedNodes, VsStateIcon[] newGlyphs, uint[] newSccStatus)
|
| - {
|
| - // if all the paramaters are null adn the count is 0, it means scc wants us to updated everything
|
| - if(affectedNodes == 0 && itemidAffectedNodes == null && newGlyphs == null && newSccStatus == null)
|
| - {
|
| - this.ReDraw(UIHierarchyElement.SccState);
|
| - this.UpdateSccStateIcons();
|
| - }
|
| - else if(affectedNodes > 0 && itemidAffectedNodes != null && newGlyphs != null && newSccStatus != null)
|
| - {
|
| - for(int i = 0; i < affectedNodes; i++)
|
| - {
|
| - HierarchyNode n = this.NodeFromItemId(itemidAffectedNodes[i]);
|
| - if(n == null)
|
| - {
|
| - throw new ArgumentException(SR.GetString(SR.InvalidParameter, CultureInfo.CurrentUICulture), "itemidAffectedNodes");
|
| - }
|
| -
|
| - n.ReDraw(UIHierarchyElement.SccState);
|
| - }
|
| - }
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// This method is called by the source control portion of the environment when a project is initially added to source control, or to change some of the project's settings.
|
| - /// </summary>
|
| - /// <param name="sccProjectName">String, opaque to the project, that identifies the project location on the server. Persist this string in the project file. </param>
|
| - /// <param name="sccLocalPath">String, opaque to the project, that identifies the path to the server. Persist this string in the project file.</param>
|
| - /// <param name="sccAuxPath">String, opaque to the project, that identifies the local path to the project. Persist this string in the project file.</param>
|
| - /// <param name="sccProvider">String, opaque to the project, that identifies the source control package. Persist this string in the project file.</param>
|
| - /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns>
|
| - public virtual int SetSccLocation(string sccProjectName, string sccAuxPath, string sccLocalPath, string sccProvider)
|
| - {
|
| - if(this.IsSccDisabled)
|
| - {
|
| - throw new NotImplementedException();
|
| - }
|
| -
|
| - if(sccProjectName == null)
|
| - {
|
| - throw new ArgumentNullException("sccProjectName");
|
| - }
|
| -
|
| - if(sccAuxPath == null)
|
| - {
|
| - throw new ArgumentNullException("sccAuxPath");
|
| - }
|
| -
|
| - if(sccLocalPath == null)
|
| - {
|
| - throw new ArgumentNullException("sccLocalPath");
|
| - }
|
| -
|
| - if(sccProvider == null)
|
| - {
|
| - throw new ArgumentNullException("sccProvider");
|
| - }
|
| -
|
| - // Save our settings (returns true if something changed)
|
| - if(!this.SetSccSettings(sccProjectName, sccLocalPath, sccAuxPath, sccProvider))
|
| - {
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - bool unbinding = (sccProjectName.Length == 0 && sccProvider.Length == 0);
|
| -
|
| - if(unbinding || this.QueryEditProjectFile(false))
|
| - {
|
| - this.buildProject.SetProperty(ProjectFileConstants.SccProjectName, sccProjectName);
|
| - this.buildProject.SetProperty(ProjectFileConstants.SccProvider, sccProvider);
|
| - this.buildProject.SetProperty(ProjectFileConstants.SccAuxPath, sccAuxPath);
|
| - this.buildProject.SetProperty(ProjectFileConstants.SccLocalPath, sccLocalPath);
|
| - }
|
| -
|
| - this.isRegisteredWithScc = true;
|
| -
|
| - return VSConstants.S_OK;
|
| - }
|
| - #endregion
|
| -
|
| - #region IVsProjectSpecialFiles Members
|
| - /// <summary>
|
| - /// Allows you to query the project for special files and optionally create them.
|
| - /// </summary>
|
| - /// <param name="fileId">__PSFFILEID of the file</param>
|
| - /// <param name="flags">__PSFFLAGS flags for the file</param>
|
| - /// <param name="itemid">The itemid of the node in the hierarchy</param>
|
| - /// <param name="fileName">The file name of the special file.</param>
|
| - /// <returns></returns>
|
| - public virtual int GetFile(int fileId, uint flags, out uint itemid, out string fileName)
|
| - {
|
| - itemid = VSConstants.VSITEMID_NIL;
|
| - fileName = String.Empty;
|
| -
|
| - // We need to return S_OK, otherwise the property page tabs will not be shown.
|
| - return VSConstants.E_NOTIMPL;
|
| - }
|
| - #endregion
|
| -
|
| - #region IAggregatedHierarchy Members
|
| -
|
| - /// <summary>
|
| - /// Get the inner object of an aggregated hierarchy
|
| - /// </summary>
|
| - /// <returns>A HierarchyNode</returns>
|
| - public virtual HierarchyNode GetInner()
|
| - {
|
| - return this;
|
| - }
|
| -
|
| - #endregion
|
| -
|
| - #region IBuildDependencyUpdate Members
|
| -
|
| - public virtual IVsBuildDependency[] BuildDependencies
|
| - {
|
| - get
|
| - {
|
| - return this.buildDependencyList.ToArray();
|
| - }
|
| - }
|
| -
|
| - public virtual void AddBuildDependency(IVsBuildDependency dependency)
|
| - {
|
| - if(this.isClosed || dependency == null)
|
| - {
|
| - return;
|
| - }
|
| -
|
| - if(!this.buildDependencyList.Contains(dependency))
|
| - {
|
| - this.buildDependencyList.Add(dependency);
|
| - }
|
| - }
|
| -
|
| - public virtual void RemoveBuildDependency(IVsBuildDependency dependency)
|
| - {
|
| - if(this.isClosed || dependency == null)
|
| - {
|
| - return;
|
| - }
|
| -
|
| - if(this.buildDependencyList.Contains(dependency))
|
| - {
|
| - this.buildDependencyList.Remove(dependency);
|
| - }
|
| - }
|
| -
|
| - #endregion
|
| -
|
| - #region IReferenceDataProvider Members
|
| - /// <summary>
|
| - /// Returns the reference container node.
|
| - /// </summary>
|
| - /// <returns></returns>
|
| - public IReferenceContainer GetReferenceContainer()
|
| - {
|
| - return this.FindChild(ReferenceContainerNode.ReferencesNodeVirtualName) as IReferenceContainer;
|
| - }
|
| -
|
| - #endregion
|
| -
|
| - #region IProjectEventsListener Members
|
| - public bool IsProjectEventsListener
|
| - {
|
| - get { return this.isProjectEventsListener; }
|
| - set { this.isProjectEventsListener = value; }
|
| - }
|
| - #endregion
|
| -
|
| - #region IProjectEventsProvider Members
|
| -
|
| - /// <summary>
|
| - /// Defines the provider for the project events
|
| - /// </summary>
|
| - IProjectEvents IProjectEventsProvider.ProjectEventsProvider
|
| - {
|
| - get
|
| - {
|
| - return this.projectEventsProvider;
|
| - }
|
| - set
|
| - {
|
| - if(null != this.projectEventsProvider)
|
| - {
|
| - this.projectEventsProvider.AfterProjectFileOpened -= this.OnAfterProjectOpen;
|
| - }
|
| - this.projectEventsProvider = value;
|
| - if(null != this.projectEventsProvider)
|
| - {
|
| - this.projectEventsProvider.AfterProjectFileOpened += this.OnAfterProjectOpen;
|
| - }
|
| - }
|
| - }
|
| -
|
| - #endregion
|
| -
|
| - #region IVsAggregatableProject Members
|
| -
|
| - /// <summary>
|
| - /// Retrieve the list of project GUIDs that are aggregated together to make this project.
|
| - /// </summary>
|
| - /// <param name="projectTypeGuids">Semi colon separated list of Guids. Typically, the last GUID would be the GUID of the base project factory</param>
|
| - /// <returns>HResult</returns>
|
| - public int GetAggregateProjectTypeGuids(out string projectTypeGuids)
|
| - {
|
| - projectTypeGuids = this.GetProjectProperty(ProjectFileConstants.ProjectTypeGuids);
|
| - // In case someone manually removed this from our project file, default to our project without flavors
|
| - if(String.IsNullOrEmpty(projectTypeGuids))
|
| - projectTypeGuids = this.ProjectGuid.ToString("B");
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// This is where the initialization occurs.
|
| - /// </summary>
|
| - public virtual int InitializeForOuter(string filename, string location, string name, uint flags, ref Guid iid, out IntPtr projectPointer, out int canceled)
|
| - {
|
| - canceled = 0;
|
| - projectPointer = IntPtr.Zero;
|
| -
|
| - // Initialize the project
|
| - this.Load(filename, location, name, flags, ref iid, out canceled);
|
| -
|
| - if(canceled != 1)
|
| - {
|
| - // Set ourself as the project
|
| - return Marshal.QueryInterface(Marshal.GetIUnknownForObject(this), ref iid, out projectPointer);
|
| - }
|
| -
|
| - return VSConstants.OLE_E_PROMPTSAVECANCELLED;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// This is called after the project is done initializing the different layer of the aggregations
|
| - /// </summary>
|
| - /// <returns>HResult</returns>
|
| - public virtual int OnAggregationComplete()
|
| - {
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Set the list of GUIDs that are aggregated together to create this project.
|
| - /// </summary>
|
| - /// <param name="projectTypeGuids">Semi-colon separated list of GUIDs, the last one is usually the project factory of the base project factory</param>
|
| - /// <returns>HResult</returns>
|
| - public int SetAggregateProjectTypeGuids(string projectTypeGuids)
|
| - {
|
| - this.SetProjectProperty(ProjectFileConstants.ProjectTypeGuids, projectTypeGuids);
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// We are always the inner most part of the aggregation
|
| - /// and as such we don't support setting an inner project
|
| - /// </summary>
|
| - public int SetInnerProject(object innerProject)
|
| - {
|
| - return VSConstants.E_NOTIMPL;
|
| - }
|
| -
|
| - #endregion
|
| -
|
| - #region IVsProjectFlavorCfgProvider Members
|
| -
|
| - int IVsProjectFlavorCfgProvider.CreateProjectFlavorCfg(IVsCfg pBaseProjectCfg, out IVsProjectFlavorCfg ppFlavorCfg)
|
| - {
|
| - // Our config object is also our IVsProjectFlavorCfg object
|
| - ppFlavorCfg = pBaseProjectCfg as IVsProjectFlavorCfg;
|
| -
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - #endregion
|
| -
|
| - #region IVsBuildPropertyStorage Members
|
| -
|
| - /// <summary>
|
| - /// Get the property of an item
|
| - /// </summary>
|
| - /// <param name="item">ItemID</param>
|
| - /// <param name="attributeName">Name of the property</param>
|
| - /// <param name="attributeValue">Value of the property (out parameter)</param>
|
| - /// <returns>HRESULT</returns>
|
| - int IVsBuildPropertyStorage.GetItemAttribute(uint item, string attributeName, out string attributeValue)
|
| - {
|
| - attributeValue = null;
|
| -
|
| - HierarchyNode node = NodeFromItemId(item);
|
| - if(node == null)
|
| - throw new ArgumentException("Invalid item id", "item");
|
| -
|
| - attributeValue = node.ItemNode.GetMetadata(attributeName);
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Get the value of the property in the project file
|
| - /// </summary>
|
| - /// <param name="propertyName">Name of the property to remove</param>
|
| - /// <param name="configName">Configuration for which to remove the property</param>
|
| - /// <param name="storage">Project or user file (_PersistStorageType)</param>
|
| - /// <param name="propertyValue">Value of the property (out parameter)</param>
|
| - /// <returns>HRESULT</returns>
|
| - int IVsBuildPropertyStorage.GetPropertyValue(string propertyName, string configName, uint storage, out string propertyValue)
|
| - {
|
| - // TODO: when adding support for User files, we need to update this method
|
| - propertyValue = null;
|
| - if(string.IsNullOrEmpty(configName))
|
| - {
|
| - propertyValue = this.GetProjectProperty(propertyName);
|
| - }
|
| - else
|
| - {
|
| - IVsCfg configurationInterface;
|
| - ErrorHandler.ThrowOnFailure(this.ConfigProvider.GetCfgOfName(configName, string.Empty, out configurationInterface));
|
| - ProjectConfig config = (ProjectConfig)configurationInterface;
|
| - propertyValue = config.GetConfigurationProperty(propertyName, true);
|
| - }
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Delete a property
|
| - /// In our case this simply mean defining it as null
|
| - /// </summary>
|
| - /// <param name="propertyName">Name of the property to remove</param>
|
| - /// <param name="configName">Configuration for which to remove the property</param>
|
| - /// <param name="storage">Project or user file (_PersistStorageType)</param>
|
| - /// <returns>HRESULT</returns>
|
| - int IVsBuildPropertyStorage.RemoveProperty(string propertyName, string configName, uint storage)
|
| - {
|
| - return ((IVsBuildPropertyStorage)this).SetPropertyValue(propertyName, configName, storage, null);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Set a property on an item
|
| - /// </summary>
|
| - /// <param name="item">ItemID</param>
|
| - /// <param name="attributeName">Name of the property</param>
|
| - /// <param name="attributeValue">New value for the property</param>
|
| - /// <returns>HRESULT</returns>
|
| - int IVsBuildPropertyStorage.SetItemAttribute(uint item, string attributeName, string attributeValue)
|
| - {
|
| - HierarchyNode node = NodeFromItemId(item);
|
| -
|
| - if(node == null)
|
| - throw new ArgumentException("Invalid item id", "item");
|
| -
|
| - node.ItemNode.SetMetadata(attributeName, attributeValue);
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Set a project property
|
| - /// </summary>
|
| - /// <param name="propertyName">Name of the property to set</param>
|
| - /// <param name="configName">Configuration for which to set the property</param>
|
| - /// <param name="storage">Project file or user file (_PersistStorageType)</param>
|
| - /// <param name="propertyValue">New value for that property</param>
|
| - /// <returns>HRESULT</returns>
|
| - int IVsBuildPropertyStorage.SetPropertyValue(string propertyName, string configName, uint storage, string propertyValue)
|
| - {
|
| - // TODO: when adding support for User files, we need to update this method
|
| - if(string.IsNullOrEmpty(configName))
|
| - {
|
| - this.SetProjectProperty(propertyName, propertyValue);
|
| - }
|
| - else
|
| - {
|
| - IVsCfg configurationInterface;
|
| - ErrorHandler.ThrowOnFailure(this.ConfigProvider.GetCfgOfName(configName, string.Empty, out configurationInterface));
|
| - ProjectConfig config = (ProjectConfig)configurationInterface;
|
| - config.SetConfigurationProperty(propertyName, propertyValue);
|
| - }
|
| - return VSConstants.S_OK;
|
| - }
|
| -
|
| - #endregion
|
| -
|
| - #region private helper methods
|
| -
|
| - /// <summary>
|
| - /// Initialize projectNode
|
| - /// </summary>
|
| - private void Initialize()
|
| - {
|
| - this.ID = VSConstants.VSITEMID_ROOT;
|
| - this.tracker = new TrackDocumentsHelper(this);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Add an item to the hierarchy based on the item path
|
| - /// </summary>
|
| - /// <param name="item">Item to add</param>
|
| - /// <returns>Added node</returns>
|
| - private HierarchyNode AddIndependentFileNode(MSBuild.BuildItem item)
|
| - {
|
| - HierarchyNode currentParent = GetItemParentNode(item);
|
| - return AddFileNodeToNode(item, currentParent);
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Add a dependent file node to the hierarchy
|
| - /// </summary>
|
| - /// <param name="item">msbuild item to add</param>
|
| - /// <param name="parentNode">Parent Node</param>
|
| - /// <returns>Added node</returns>
|
| - private HierarchyNode AddDependentFileNodeToNode(MSBuild.BuildItem item, HierarchyNode parentNode)
|
| - {
|
| - FileNode node = this.CreateDependentFileNode(new ProjectElement(this, item, false));
|
| - parentNode.AddChild(node);
|
| -
|
| - // Make sure to set the HasNameRelation flag on the dependent node if it is related to the parent by name
|
| - if(!node.HasParentNodeNameRelation && string.Compare(node.GetRelationalName(), parentNode.GetRelationalName(), StringComparison.OrdinalIgnoreCase) == 0)
|
| - {
|
| - node.HasParentNodeNameRelation = true;
|
| - }
|
| -
|
| - return node;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Add a file node to the hierarchy
|
| - /// </summary>
|
| - /// <param name="item">msbuild item to add</param>
|
| - /// <param name="parentNode">Parent Node</param>
|
| - /// <returns>Added node</returns>
|
| - private HierarchyNode AddFileNodeToNode(MSBuild.BuildItem item, HierarchyNode parentNode)
|
| - {
|
| - FileNode node = this.CreateFileNode(new ProjectElement(this, item, false));
|
| - parentNode.AddChild(node);
|
| - return node;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Get the parent node of an msbuild item
|
| - /// </summary>
|
| - /// <param name="item">msbuild item</param>
|
| - /// <returns>parent node</returns>
|
| - private HierarchyNode GetItemParentNode(MSBuild.BuildItem item)
|
| - {
|
| - HierarchyNode currentParent = this;
|
| - string strPath = item.FinalItemSpec;
|
| -
|
| - strPath = Path.GetDirectoryName(strPath);
|
| - if(strPath.Length > 0)
|
| - {
|
| - // Use the relative to verify the folders...
|
| - currentParent = this.CreateFolderNodes(strPath);
|
| - }
|
| - return currentParent;
|
| - }
|
| -
|
| - private MSBuild.BuildProperty GetMsBuildProperty(string propertyName, bool resetCache)
|
| - {
|
| - if(resetCache || this.currentConfig == null)
|
| - {
|
| - // Get properties from project file and cache it
|
| - this.SetCurrentConfiguration();
|
| - this.currentConfig = this.buildProject.EvaluatedProperties;
|
| - }
|
| -
|
| - if(this.currentConfig == null)
|
| - throw new Exception(String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.FailedToRetrieveProperties, CultureInfo.CurrentUICulture), propertyName));
|
| -
|
| - // return property asked for
|
| - return this.currentConfig[propertyName];
|
| - }
|
| -
|
| - private string GetOutputPath(MSBuild.BuildPropertyGroup properties)
|
| - {
|
| - this.currentConfig = properties;
|
| - string outputPath = GetProjectProperty("OutputPath");
|
| -
|
| - if(!String.IsNullOrEmpty(outputPath))
|
| - {
|
| - outputPath = outputPath.Replace('/', Path.DirectorySeparatorChar);
|
| - if(outputPath[outputPath.Length - 1] != Path.DirectorySeparatorChar)
|
| - outputPath += Path.DirectorySeparatorChar;
|
| - }
|
| -
|
| - return outputPath;
|
| - }
|
| -
|
| - private bool GetBoolAttr(MSBuild.BuildPropertyGroup properties, string name)
|
| - {
|
| - this.currentConfig = properties;
|
| - string s = GetProjectProperty(name);
|
| -
|
| - return (s != null && s.ToUpperInvariant().Trim() == "TRUE");
|
| - }
|
| -
|
| - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")]
|
| - private string GetAssemblyName(MSBuild.BuildPropertyGroup properties)
|
| - {
|
| - this.currentConfig = properties;
|
| - string name = null;
|
| -
|
| - name = GetProjectProperty(ProjectFileConstants.AssemblyName);
|
| - if(name == null)
|
| - name = this.Caption;
|
| -
|
| - string outputtype = GetProjectProperty(ProjectFileConstants.OutputType, false);
|
| -
|
| - if(outputtype == "library")
|
| - {
|
| - outputtype = outputtype.ToLowerInvariant();
|
| - name += ".dll";
|
| - }
|
| - else
|
| - {
|
| - name += ".exe";
|
| - }
|
| -
|
| - return name;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Updates our scc project settings.
|
| - /// </summary>
|
| - /// <param name="sccProjectName">String, opaque to the project, that identifies the project location on the server. Persist this string in the project file. </param>
|
| - /// <param name="sccLocalPath">String, opaque to the project, that identifies the path to the server. Persist this string in the project file.</param>
|
| - /// <param name="sccAuxPath">String, opaque to the project, that identifies the local path to the project. Persist this string in the project file.</param>
|
| - /// <param name="sccProvider">String, opaque to the project, that identifies the source control package. Persist this string in the project file.</param>
|
| - /// <returns>Returns true if something changed.</returns>
|
| - private bool SetSccSettings(string sccProjectName, string sccLocalPath, string sccAuxPath, string sccProvider)
|
| - {
|
| - bool changed = false;
|
| - Debug.Assert(sccProjectName != null && sccLocalPath != null && sccAuxPath != null && sccProvider != null);
|
| - if(String.Compare(sccProjectName, this.sccProjectName, StringComparison.OrdinalIgnoreCase) != 0 ||
|
| - String.Compare(sccLocalPath, this.sccLocalPath, StringComparison.OrdinalIgnoreCase) != 0 ||
|
| - String.Compare(sccAuxPath, this.sccAuxPath, StringComparison.OrdinalIgnoreCase) != 0 ||
|
| - String.Compare(sccProvider, this.sccProvider, StringComparison.OrdinalIgnoreCase) != 0)
|
| - {
|
| - changed = true;
|
| - this.sccProjectName = sccProjectName;
|
| - this.sccLocalPath = sccLocalPath;
|
| - this.sccAuxPath = sccAuxPath;
|
| - this.sccProvider = sccProvider;
|
| - }
|
| -
|
| -
|
| - return changed;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Sets the scc info from the project file.
|
| - /// </summary>
|
| - private void InitSccInfo()
|
| - {
|
| - this.sccProjectName = this.GetProjectProperty(ProjectFileConstants.SccProjectName);
|
| - this.sccLocalPath = this.GetProjectProperty(ProjectFileConstants.SccLocalPath);
|
| - this.sccProvider = this.GetProjectProperty(ProjectFileConstants.SccProvider);
|
| - this.sccAuxPath = this.GetProjectProperty(ProjectFileConstants.SccAuxPath);
|
| - }
|
| -
|
| - private void OnAfterProjectOpen(object sender, AfterProjectFileOpenedEventArgs e)
|
| - {
|
| - this.projectOpened = true;
|
| - }
|
| -
|
| - private static XmlElement WrapXmlFragment(XmlDocument document, XmlElement root, Guid flavor, string configuration, string fragment)
|
| - {
|
| - XmlElement node = document.CreateElement(ProjectFileConstants.FlavorProperties);
|
| - XmlAttribute attribute = document.CreateAttribute(ProjectFileConstants.Guid);
|
| - attribute.Value = flavor.ToString("B");
|
| - node.Attributes.Append(attribute);
|
| - if(!String.IsNullOrEmpty(configuration))
|
| - {
|
| - attribute = document.CreateAttribute(ProjectFileConstants.Configuration);
|
| - attribute.Value = configuration;
|
| - node.Attributes.Append(attribute);
|
| - }
|
| - node.InnerXml = fragment;
|
| - root.AppendChild(node);
|
| - return node;
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Sets the project guid from the project file. If no guid is found a new one is created and assigne for the instance project guid.
|
| - /// </summary>
|
| - private void SetProjectGuidFromProjectFile()
|
| - {
|
| - string projectGuid = this.GetProjectProperty(ProjectFileConstants.ProjectGuid);
|
| - if(String.IsNullOrEmpty(projectGuid))
|
| - {
|
| - this.projectIdGuid = Guid.NewGuid();
|
| - }
|
| - else
|
| - {
|
| - Guid guid = new Guid(projectGuid);
|
| - if(guid != this.projectIdGuid)
|
| - {
|
| - this.projectIdGuid = guid;
|
| - }
|
| - }
|
| - }
|
| -
|
| - /// <summary>
|
| - /// Recusively parses the tree and closes all nodes.
|
| - /// </summary>
|
| - /// <param name="node">The subtree to close.</param>
|
| - private static void CloseAllNodes(HierarchyNode node)
|
| - {
|
| - for(HierarchyNode n = node.FirstChild; n != null; n = n.NextSibling)
|
| - {
|
| - if(n.FirstChild != null)
|
| - {
|
| - CloseAllNodes(n);
|
| - }
|
| -
|
| - n.Close();
|
| - }
|
| - }
|
| - #endregion
|
| - }
|
| -}
|
|
|