PageRenderTime 66ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/DevTools/MPF/ProjectNode.cs

https://bitbucket.org/greenboxdevelopment/greenbox3d
C# | 6613 lines | 5798 code | 317 blank | 498 comment | 222 complexity | 59e07259d68891bbfa288652f7048cf8 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. // ProjectNode.cs
  2. //
  3. // Copyright (c) 2013 The GreenBox Development LLC, all rights reserved
  4. //
  5. // This file is a proprietary part of GreenBox3D, disclosing the content
  6. // of this file without the owner consent may lead to legal actions
  7. using System;
  8. using System.CodeDom.Compiler;
  9. using System.Collections.Generic;
  10. using System.Collections.Specialized;
  11. using System.ComponentModel;
  12. using System.Diagnostics;
  13. using System.Diagnostics.CodeAnalysis;
  14. using System.Globalization;
  15. using System.IO;
  16. using System.Linq;
  17. using System.Runtime.InteropServices;
  18. using System.Runtime.Versioning;
  19. using System.Text;
  20. using System.Xml;
  21. using EnvDTE;
  22. using Microsoft.Build.BackEnd;
  23. using Microsoft.Build.Evaluation;
  24. using Microsoft.Build.Execution;
  25. using Microsoft.Build.Framework;
  26. using Microsoft.Build.Utilities;
  27. using Microsoft.VisualStudio.OLE.Interop;
  28. using Microsoft.VisualStudio.Project.Automation;
  29. using Microsoft.VisualStudio.Shell;
  30. using Microsoft.VisualStudio.Shell.Interop;
  31. using Constants = EnvDTE.Constants;
  32. using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
  33. using IServiceProvider = System.IServiceProvider;
  34. using MSBuild = Microsoft.Build.Evaluation;
  35. using MSBuildConstruction = Microsoft.Build.Construction;
  36. using MSBuildExecution = Microsoft.Build.Execution;
  37. using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants;
  38. using Process = System.Diagnostics.Process;
  39. using ProjectItem = EnvDTE.ProjectItem;
  40. using VsCommands = Microsoft.VisualStudio.VSConstants.VSStd97CmdID;
  41. using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID;
  42. namespace Microsoft.VisualStudio.Project
  43. {
  44. /// <summary>
  45. /// Manages the persistent state of the project (References, options, files, etc.) and deals with user interaction via a GUI in the form a hierarchy.
  46. /// </summary>
  47. [CLSCompliant(false)]
  48. [ComVisible(true)]
  49. public abstract partial class ProjectNode : HierarchyNode,
  50. IVsGetCfgProvider,
  51. IVsProject3,
  52. IVsAggregatableProject,
  53. IVsProjectFlavorCfgProvider,
  54. IPersistFileFormat,
  55. IVsProjectBuildSystem,
  56. IVsBuildPropertyStorage,
  57. IVsComponentUser,
  58. IVsDependencyProvider,
  59. IVsSccProject2,
  60. IBuildDependencyUpdate,
  61. IProjectEventsListener,
  62. IProjectEventsProvider,
  63. IReferenceContainerProvider,
  64. IVsProjectSpecialFiles,
  65. IVsProjectUpgrade,
  66. IVsDesignTimeAssemblyResolution,
  67. IVsSetTargetFrameworkWorkerCallback
  68. {
  69. #region nested types
  70. public enum ImageName
  71. {
  72. OfflineWebApp = 0,
  73. WebReferencesFolder = 1,
  74. OpenReferenceFolder = 2,
  75. ReferenceFolder = 3,
  76. Reference = 4,
  77. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "SDL")]
  78. SDLWebReference = 5,
  79. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "DISCO")]
  80. DISCOWebReference = 6,
  81. Folder = 7,
  82. OpenFolder = 8,
  83. ExcludedFolder = 9,
  84. OpenExcludedFolder = 10,
  85. ExcludedFile = 11,
  86. DependentFile = 12,
  87. MissingFile = 13,
  88. WindowsForm = 14,
  89. WindowsUserControl = 15,
  90. WindowsComponent = 16,
  91. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "XML")]
  92. XMLSchema = 17,
  93. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "XML")]
  94. XMLFile = 18,
  95. WebForm = 19,
  96. WebService = 20,
  97. WebUserControl = 21,
  98. WebCustomUserControl = 22,
  99. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "ASP")]
  100. ASPPage = 23,
  101. GlobalApplicationClass = 24,
  102. WebConfig = 25,
  103. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "HTML")]
  104. HTMLPage = 26,
  105. StyleSheet = 27,
  106. ScriptFile = 28,
  107. TextFile = 29,
  108. SettingsFile = 30,
  109. Resources = 31,
  110. Bitmap = 32,
  111. Icon = 33,
  112. Image = 34,
  113. ImageMap = 35,
  114. XWorld = 36,
  115. Audio = 37,
  116. Video = 38,
  117. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "CAB")]
  118. CAB = 39,
  119. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "JAR")]
  120. JAR = 40,
  121. DataEnvironment = 41,
  122. PreviewFile = 42,
  123. DanglingReference = 43,
  124. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "XSLT")]
  125. XSLTFile = 44,
  126. Cursor = 45,
  127. AppDesignerFolder = 46,
  128. Data = 47,
  129. Application = 48,
  130. DataSet = 49,
  131. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "PFX")]
  132. PFX = 50,
  133. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "SNK")]
  134. SNK = 51,
  135. ImageLast = 51
  136. }
  137. /// <summary>
  138. /// Flags for specifying which events to stop triggering.
  139. /// </summary>
  140. [Flags]
  141. internal enum EventTriggering
  142. {
  143. TriggerAll = 0,
  144. DoNotTriggerHierarchyEvents = 1,
  145. DoNotTriggerTrackerEvents = 2
  146. }
  147. #endregion
  148. #region constants
  149. /// <summary>
  150. /// The user file extension.
  151. /// </summary>
  152. internal const string PerUserFileExtension = ".user";
  153. /// <summary>
  154. /// The VS command that allows projects to open Windows Explorer to the project directory.
  155. /// </summary>
  156. private const VsCommands2K ExploreFolderInWindowsCommand = (VsCommands2K)1635;
  157. private readonly Guid GUID_MruPage = new Guid("{19B97F03-9594-4c1c-BE28-25FF030113B3}");
  158. #endregion
  159. #region fields
  160. private static readonly FrameworkName DefaultTargetFrameworkMoniker = new FrameworkName(".NETFramework",
  161. new Version(4, 0));
  162. private static Guid addComponentLastActiveTab = VSConstants.GUID_SolutionPage;
  163. private static uint addComponentDialogSizeX = 0;
  164. private static uint addComponentDialogSizeY = 0;
  165. /// <summary>
  166. /// List of output groups names and their associated target
  167. /// </summary>
  168. private static readonly KeyValuePair<string, string>[] outputGroupNames =
  169. {
  170. // Name Target (MSBuild)
  171. new KeyValuePair<string, string>("Built", "BuiltProjectOutputGroup"),
  172. new KeyValuePair<string, string>("ContentFiles", "ContentFilesProjectOutputGroup"),
  173. new KeyValuePair<string, string>("LocalizedResourceDlls", "SatelliteDllsProjectOutputGroup"),
  174. new KeyValuePair<string, string>("Documentation", "DocumentationProjectOutputGroup"),
  175. new KeyValuePair<string, string>("Symbols", "DebugSymbolsProjectOutputGroup"),
  176. new KeyValuePair<string, string>("SourceFiles", "SourceFilesProjectOutputGroup"),
  177. new KeyValuePair<string, string>("XmlSerializer", "SGenFilesOutputGroup"),
  178. };
  179. /// <summary>A project will only try to build if it can obtain a lock on this object</summary>
  180. private static volatile object BuildLock = new object();
  181. /// <summary>
  182. /// The build dependency list passed to IVsDependencyProvider::EnumDependencies
  183. /// </summary>
  184. private readonly List<IVsBuildDependency> buildDependencyList = new List<IVsBuildDependency>();
  185. /// <summary>
  186. /// Used to map types to CATID. This provide a generic way for us to do this
  187. /// and make it simpler for a project to provide it's CATIDs for the different type of objects
  188. /// for which it wants to support extensibility. This also enables us to have multiple
  189. /// type mapping to the same CATID if we choose to.
  190. /// </summary>
  191. private readonly Dictionary<Type, Guid> catidMapping = new Dictionary<Type, Guid>();
  192. /// <summary>Maps integer ids to project item instances</summary>
  193. private readonly EventSinkCollection itemIdMap = new EventSinkCollection();
  194. private Url baseUri;
  195. /// <summary>
  196. /// MSBuild engine we are going to use
  197. /// </summary>
  198. private ProjectCollection buildEngine;
  199. private bool buildInProcess;
  200. private bool buildIsPrepared;
  201. private Logger buildLogger;
  202. private MSBuild.Project buildProject;
  203. private bool canFileNodesHaveChilds;
  204. /// <summary>
  205. /// Control if command with potential destructive behavior such as delete should
  206. /// be enabled for nodes of this project.
  207. /// </summary>
  208. private bool canProjectDeleteItems;
  209. private ConfigProvider configProvider;
  210. private ProjectInstance currentConfig;
  211. private DesignTimeAssemblyResolution designTimeAssemblyResolution;
  212. /// <summary>
  213. /// Flag for controling query edit should communicate with the scc manager.
  214. /// </summary>
  215. private bool disableQueryEdit;
  216. /// <summary>
  217. /// Field for determining whether sourcecontrol should be disabled.
  218. /// </summary>
  219. private bool disableScc;
  220. private string errorString;
  221. private EventTriggering eventTriggeringFlag = EventTriggering.TriggerAll;
  222. private string filename;
  223. private ImageHandler imageHandler;
  224. private bool invokeMSBuildWhenResumed;
  225. private bool isClosed;
  226. private bool isDirty;
  227. private bool isDisposed;
  228. private bool isNewProject;
  229. private bool isProjectEventsListener = true;
  230. /// <summary>
  231. /// Flag for controling how many times we register with the Scc manager.
  232. /// </summary>
  233. private bool isRegisteredWithScc;
  234. /// <summary>
  235. /// This property returns the time of the last change made to this project.
  236. /// It is not the time of the last change on the project file, but actually of
  237. /// the in memory project settings. In other words, it is the last time that
  238. /// SetProjectDirty was called.
  239. /// </summary>
  240. private DateTime lastModifiedTime;
  241. /// <summary>
  242. /// A cached copy of project options.
  243. /// </summary>
  244. private ProjectOptions options;
  245. /// <summary>
  246. /// Member to store output base relative path. Used by OutputBaseRelativePath property
  247. /// </summary>
  248. private string outputBaseRelativePath = "bin";
  249. /// <summary>
  250. /// The internal package implementation.
  251. /// </summary>
  252. private ProjectPackage package;
  253. private IProjectEvents projectEventsProvider;
  254. private Guid projectIdGuid;
  255. private bool projectOpened;
  256. private string sccAuxPath;
  257. private string sccLocalPath;
  258. private string sccProjectName;
  259. private string sccProvider;
  260. private bool showProjectInSolutionPage = true;
  261. /// <summary>A service provider call back object provided by the IDE hosting the project manager</summary>
  262. private ServiceProvider site;
  263. /// <summary>
  264. /// Defines if Project System supports Project Designer
  265. /// </summary>
  266. private bool supportsProjectDesigner;
  267. private uint suspendMSBuildCounter;
  268. private TaskProvider taskProvider;
  269. /// <summary>
  270. /// Token processor used by the project sample.
  271. /// </summary>
  272. private TokenProcessor tokenProcessor;
  273. private TrackDocumentsHelper tracker;
  274. private bool useProvidedLogger;
  275. private string warningString;
  276. /// <summary>
  277. /// Used for flavoring to hold the XML fragments
  278. /// </summary>
  279. private XmlDocument xmlFragments;
  280. public static ServiceProvider ServiceProvider { get; set; }
  281. #endregion
  282. #region abstract properties
  283. /// <summary>
  284. /// This Guid must match the Guid you registered under
  285. /// HKLM\Software\Microsoft\VisualStudio\%version%\Projects.
  286. /// Among other things, the Project framework uses this
  287. /// guid to find your project and item templates.
  288. /// </summary>
  289. public abstract Guid ProjectGuid { get; }
  290. /// <summary>
  291. /// Returns a caption for VSHPROPID_TypeName.
  292. /// </summary>
  293. /// <returns></returns>
  294. public abstract string ProjectType { get; }
  295. #endregion
  296. #region virtual properties
  297. /// <summary>
  298. /// This is the project instance guid that is peristed in the project file
  299. /// </summary>
  300. [Browsable(false)]
  301. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "ID")]
  302. public virtual Guid ProjectIDGuid
  303. {
  304. get { return projectIdGuid; }
  305. set
  306. {
  307. if (projectIdGuid != value)
  308. {
  309. projectIdGuid = value;
  310. if (buildProject != null)
  311. {
  312. SetProjectProperty("ProjectGuid", projectIdGuid.ToString("B"));
  313. }
  314. }
  315. }
  316. }
  317. #endregion
  318. #region properties
  319. #region overridden properties
  320. public override int MenuCommandId
  321. {
  322. get { return VsMenus.IDM_VS_CTXT_PROJNODE; }
  323. }
  324. public override string Url
  325. {
  326. get { return GetMkDocument(); }
  327. }
  328. public override string Caption
  329. {
  330. get
  331. {
  332. // Default to file name
  333. string caption = buildProject.FullPath;
  334. if (String.IsNullOrEmpty(caption))
  335. {
  336. if (buildProject.GetProperty(ProjectFileConstants.Name) != null)
  337. {
  338. caption = buildProject.GetProperty(ProjectFileConstants.Name).EvaluatedValue;
  339. if (caption == null || caption.Length == 0)
  340. {
  341. caption = ItemNode.GetMetadata(ProjectFileConstants.Include);
  342. }
  343. }
  344. }
  345. else
  346. {
  347. caption = Path.GetFileNameWithoutExtension(caption);
  348. }
  349. return caption;
  350. }
  351. }
  352. public override Guid ItemTypeGuid
  353. {
  354. get { return ProjectGuid; }
  355. }
  356. public override int ImageIndex
  357. {
  358. get { return (int)ImageName.Application; }
  359. }
  360. #endregion
  361. #region virtual properties
  362. public virtual string ErrorString
  363. {
  364. get
  365. {
  366. if (errorString == null)
  367. {
  368. errorString = SR.GetString(SR.Error, CultureInfo.CurrentUICulture);
  369. }
  370. return errorString;
  371. }
  372. }
  373. public virtual string WarningString
  374. {
  375. get
  376. {
  377. if (warningString == null)
  378. {
  379. warningString = SR.GetString(SR.Warning, CultureInfo.CurrentUICulture);
  380. }
  381. return warningString;
  382. }
  383. }
  384. /// <summary>
  385. /// The target name that will be used for evaluating the project file (i.e., pseudo-builds).
  386. /// This target is used to trigger a build with when the project system changes.
  387. /// Example: The language projrcts are triggering a build with the Compile target whenever
  388. /// the project system changes.
  389. /// </summary>
  390. [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "ReEvaluate")]
  391. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Re")]
  392. protected internal virtual string ReEvaluateProjectFileTargetName
  393. {
  394. get { return null; }
  395. }
  396. /// <summary>
  397. /// This is the object that will be returned by EnvDTE.Project.Object for this project
  398. /// </summary>
  399. protected internal virtual object ProjectObject
  400. {
  401. get { return null; }
  402. }
  403. /// <summary>
  404. /// Override this property to specify when the project file is dirty.
  405. /// </summary>
  406. protected virtual bool IsProjectFileDirty
  407. {
  408. get
  409. {
  410. string document = GetMkDocument();
  411. if (String.IsNullOrEmpty(document))
  412. {
  413. return isDirty;
  414. }
  415. return (isDirty || !File.Exists(document));
  416. }
  417. }
  418. /// <summary>
  419. /// True if the project uses the Project Designer Editor instead of the property page frame to edit project properties.
  420. /// </summary>
  421. protected virtual bool SupportsProjectDesigner
  422. {
  423. get { return supportsProjectDesigner; }
  424. set { supportsProjectDesigner = value; }
  425. }
  426. protected virtual Guid ProjectDesignerEditor
  427. {
  428. get { return VSConstants.GUID_ProjectDesignerEditor; }
  429. }
  430. /// <summary>
  431. /// Defines the flag that supports the VSHPROPID.ShowProjInSolutionPage
  432. /// </summary>
  433. protected virtual bool ShowProjectInSolutionPage
  434. {
  435. get { return showProjectInSolutionPage; }
  436. set { showProjectInSolutionPage = value; }
  437. }
  438. #endregion
  439. /// <summary>
  440. /// Gets or sets the ability of a project filenode to have child nodes (sub items).
  441. /// Example would be C#/VB forms having resx and designer files.
  442. /// </summary>
  443. protected internal bool CanFileNodesHaveChilds
  444. {
  445. get { return canFileNodesHaveChilds; }
  446. set { canFileNodesHaveChilds = value; }
  447. }
  448. /// <summary>
  449. /// Get and set the Token processor.
  450. /// </summary>
  451. public TokenProcessor FileTemplateProcessor
  452. {
  453. get
  454. {
  455. if (tokenProcessor == null)
  456. tokenProcessor = new TokenProcessor();
  457. return tokenProcessor;
  458. }
  459. set { tokenProcessor = value; }
  460. }
  461. /// <summary>
  462. /// Gets a service provider object provided by the IDE hosting the project
  463. /// </summary>
  464. [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")]
  465. public IServiceProvider Site
  466. {
  467. get { return site; }
  468. }
  469. /// <summary>
  470. /// Gets an ImageHandler for the project node.
  471. /// </summary>
  472. public ImageHandler ImageHandler
  473. {
  474. get
  475. {
  476. if (null == imageHandler)
  477. {
  478. imageHandler =
  479. new ImageHandler(
  480. typeof(ProjectNode).Assembly.GetManifestResourceStream(
  481. "Microsoft.VisualStudio.Project.Resources.imagelis.bmp"));
  482. }
  483. return imageHandler;
  484. }
  485. }
  486. /// <summary>
  487. /// This property returns the time of the last change made to this project.
  488. /// It is not the time of the last change on the project file, but actually of
  489. /// the in memory project settings. In other words, it is the last time that
  490. /// SetProjectDirty was called.
  491. /// </summary>
  492. public DateTime LastModifiedTime
  493. {
  494. get { return lastModifiedTime; }
  495. }
  496. /// <summary>
  497. /// Determines whether this project is a new project.
  498. /// </summary>
  499. public bool IsNewProject
  500. {
  501. get { return isNewProject; }
  502. }
  503. /// <summary>
  504. /// Gets the path to the folder containing the project.
  505. /// </summary>
  506. public string ProjectFolder
  507. {
  508. get { return Path.GetDirectoryName(filename); }
  509. }
  510. /// <summary>
  511. /// Gets or sets the project filename.
  512. /// </summary>
  513. public string ProjectFile
  514. {
  515. get { return Path.GetFileName(filename); }
  516. set { SetEditLabel(value); }
  517. }
  518. /// <summary>
  519. /// Gets the Base Uniform Resource Identifier (URI).
  520. /// </summary>
  521. [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "URI")]
  522. public Url BaseURI
  523. {
  524. get
  525. {
  526. if (baseUri == null && buildProject != null)
  527. {
  528. string path = Path.GetDirectoryName(buildProject.FullPath);
  529. // Uri/Url behave differently when you have trailing slash and when you dont
  530. if (!path.EndsWith("\\", StringComparison.Ordinal) && !path.EndsWith("/", StringComparison.Ordinal))
  531. path += "\\";
  532. baseUri = new Url(path);
  533. }
  534. Debug.Assert(baseUri != null,
  535. "Base URL should not be null. Did you call BaseURI before loading the project?");
  536. return baseUri;
  537. }
  538. }
  539. /// <summary>
  540. /// Gets whether or not the project is closed.
  541. /// </summary>
  542. public bool IsClosed
  543. {
  544. get { return isClosed; }
  545. }
  546. /// <summary>
  547. /// Gets whether or not the project is being built.
  548. /// </summary>
  549. public bool BuildInProgress
  550. {
  551. get { return buildInProcess; }
  552. }
  553. /// <summary>
  554. /// Gets or set the relative path to the folder containing the project ouput.
  555. /// </summary>
  556. public virtual string OutputBaseRelativePath
  557. {
  558. get { return outputBaseRelativePath; }
  559. set
  560. {
  561. if (Path.IsPathRooted(value))
  562. {
  563. throw new ArgumentException("Path must not be rooted.");
  564. }
  565. outputBaseRelativePath = value;
  566. }
  567. }
  568. public FrameworkName TargetFrameworkMoniker
  569. {
  570. get
  571. {
  572. if (options == null)
  573. {
  574. GetProjectOptions();
  575. }
  576. if (options != null)
  577. {
  578. return options.TargetFrameworkMoniker ?? DefaultTargetFrameworkMoniker;
  579. }
  580. else
  581. {
  582. return DefaultTargetFrameworkMoniker;
  583. }
  584. }
  585. set
  586. {
  587. if (options == null)
  588. {
  589. GetProjectOptions();
  590. }
  591. if (value == null)
  592. {
  593. value = DefaultTargetFrameworkMoniker;
  594. }
  595. if (options.TargetFrameworkMoniker != value)
  596. {
  597. OnTargetFrameworkMonikerChanged(options, options.TargetFrameworkMoniker, value);
  598. }
  599. }
  600. }
  601. /// <summary>
  602. /// Version of this node as an IVsHierarchy that can be safely passed to native code from a background thread.
  603. /// </summary>
  604. public IVsHierarchy InteropSafeIVsHierarchy { get; protected set; }
  605. /// <summary>
  606. /// Version of this node as an IVsUIHierarchy that can be safely passed to native code from a background thread.
  607. /// </summary>
  608. public IVsUIHierarchy InteropSafeIVsUIHierarchy { get; protected set; }
  609. /// <summary>
  610. /// Version of this node as an IVsProject3 that can be safely passed to native code from a background thread.
  611. /// </summary>
  612. public IVsProject3 InteropSafeIVsProject3 { get; protected set; }
  613. /// <summary>
  614. /// Version of this node as an IVsSccProject2 that can be safely passed to native code from a background thread.
  615. /// </summary>
  616. public IVsSccProject2 InteropSafeIVsSccProject2 { get; protected set; }
  617. /// <summary>
  618. /// Version of this node as an IVsUIHierWinClipboardHelperEvents that can be safely passed to native code from a background thread.
  619. /// </summary>
  620. public IVsUIHierWinClipboardHelperEvents InteropSafeIVsUIHierWinClipboardHelperEvents { get; protected set; }
  621. public IVsComponentUser InteropSafeIVsComponentUser { get; protected set; }
  622. /// <summary>
  623. /// Gets or sets the flag whether query edit should communicate with the scc manager.
  624. /// </summary>
  625. protected bool DisableQueryEdit
  626. {
  627. get { return disableQueryEdit; }
  628. set { disableQueryEdit = value; }
  629. }
  630. /// <summary>
  631. /// Gets a collection of integer ids that maps to project item instances
  632. /// </summary>
  633. internal EventSinkCollection ItemIdMap
  634. {
  635. get { return itemIdMap; }
  636. }
  637. /// <summary>
  638. /// Get the helper object that track document changes.
  639. /// </summary>
  640. internal TrackDocumentsHelper Tracker
  641. {
  642. get { return tracker; }
  643. }
  644. /// <summary>
  645. /// Gets or sets the build logger.
  646. /// </summary>
  647. protected Logger BuildLogger
  648. {
  649. get { return buildLogger; }
  650. set
  651. {
  652. buildLogger = value;
  653. useProvidedLogger = true;
  654. }
  655. }
  656. /// <summary>
  657. /// Gets the taskprovider.
  658. /// </summary>
  659. protected TaskProvider TaskProvider
  660. {
  661. get { return taskProvider; }
  662. }
  663. /// <summary>
  664. /// Gets the project file name.
  665. /// </summary>
  666. protected string FileName
  667. {
  668. get { return filename; }
  669. }
  670. protected bool IsIdeInCommandLineMode
  671. {
  672. get
  673. {
  674. bool cmdline = false;
  675. var shell = site.GetService(typeof(SVsShell)) as IVsShell;
  676. if (shell != null)
  677. {
  678. object obj;
  679. Marshal.ThrowExceptionForHR(shell.GetProperty((int)__VSSPROPID.VSSPROPID_IsInCommandLineMode,
  680. out obj));
  681. cmdline = (bool)obj;
  682. }
  683. return cmdline;
  684. }
  685. }
  686. /// <summary>
  687. /// Gets the configuration provider.
  688. /// </summary>
  689. protected ConfigProvider ConfigProvider
  690. {
  691. get
  692. {
  693. if (configProvider == null)
  694. {
  695. configProvider = CreateConfigProvider();
  696. }
  697. return configProvider;
  698. }
  699. }
  700. /// <summary>
  701. /// Gets or sets whether or not source code control is disabled for this project.
  702. /// </summary>
  703. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Scc")]
  704. protected bool IsSccDisabled
  705. {
  706. get { return disableScc; }
  707. set { disableScc = value; }
  708. }
  709. /// <summary>
  710. /// Gets or set whether items can be deleted for this project.
  711. /// Enabling this feature can have the potential destructive behavior such as deleting files from disk.
  712. /// </summary>
  713. protected internal bool CanProjectDeleteItems
  714. {
  715. get { return canProjectDeleteItems; }
  716. set { canProjectDeleteItems = value; }
  717. }
  718. /// <summary>
  719. /// Determines whether the project was fully opened. This is set when the OnAfterOpenProject has triggered.
  720. /// </summary>
  721. protected internal bool HasProjectOpened
  722. {
  723. get { return projectOpened; }
  724. }
  725. /// <summary>
  726. /// Gets or sets event triggering flags.
  727. /// </summary>
  728. internal EventTriggering EventTriggeringFlag
  729. {
  730. get { return eventTriggeringFlag; }
  731. set { eventTriggeringFlag = value; }
  732. }
  733. /// <summary>
  734. /// Defines the build project that has loaded the project file.
  735. /// </summary>
  736. protected internal MSBuild.Project BuildProject
  737. {
  738. get { return buildProject; }
  739. set { SetBuildProject(value); }
  740. }
  741. /// <summary>
  742. /// Gets the current config.
  743. /// </summary>
  744. /// <value>The current config.</value>
  745. protected internal ProjectInstance CurrentConfig
  746. {
  747. get { return currentConfig; }
  748. }
  749. /// <summary>
  750. /// Defines the build engine that is used to build the project file.
  751. /// </summary>
  752. internal ProjectCollection BuildEngine
  753. {
  754. get { return buildEngine; }
  755. set { buildEngine = value; }
  756. }
  757. /// <summary>
  758. /// The internal package implementation.
  759. /// </summary>
  760. [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
  761. internal ProjectPackage Package
  762. {
  763. get { return package; }
  764. set { package = value; }
  765. }
  766. #endregion
  767. #region ctor
  768. protected ProjectNode()
  769. {
  770. Initialize();
  771. }
  772. #endregion
  773. #region overridden methods
  774. protected override NodeProperties CreatePropertiesObject()
  775. {
  776. return new ProjectNodeProperties(this);
  777. }
  778. /// <summary>
  779. /// Sets the properties for the project node.
  780. /// </summary>
  781. /// <param name="propid">
  782. /// Identifier of the hierarchy property. For a list of propid values, <see cref="__VSHPROPID" />
  783. /// </param>
  784. /// <param name="value">The value to set. </param>
  785. /// <returns>A success or failure value.</returns>
  786. public override int SetProperty(int propid, object value)
  787. {
  788. __VSHPROPID id = (__VSHPROPID)propid;
  789. switch (id)
  790. {
  791. case __VSHPROPID.VSHPROPID_ShowProjInSolutionPage:
  792. ShowProjectInSolutionPage = (bool)value;
  793. return VSConstants.S_OK;
  794. }
  795. return base.SetProperty(propid, value);
  796. }
  797. /// <summary>
  798. /// Renames the project node.
  799. /// </summary>
  800. /// <param name="label">The new name</param>
  801. /// <returns>A success or failure value.</returns>
  802. public override int SetEditLabel(string label)
  803. {
  804. // Validate the filename.
  805. if (String.IsNullOrEmpty(label))
  806. {
  807. throw new InvalidOperationException(SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture));
  808. }
  809. else if (ProjectFolder.Length + label.Length + 1 > NativeMethods.MAX_PATH)
  810. {
  811. throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
  812. SR.GetString(SR.PathTooLong,
  813. CultureInfo.CurrentUICulture), label));
  814. }
  815. else if (Utilities.IsFileNameInvalid(label))
  816. {
  817. throw new InvalidOperationException(SR.GetString(SR.ErrorInvalidFileName, CultureInfo.CurrentUICulture));
  818. }
  819. string fileName = Path.GetFileNameWithoutExtension(label);
  820. // if there is no filename or it starts with a leading dot issue an error message and quit.
  821. if (String.IsNullOrEmpty(fileName) || fileName[0] == '.')
  822. {
  823. throw new InvalidOperationException(SR.GetString(SR.FileNameCannotContainALeadingPeriod,
  824. CultureInfo.CurrentUICulture));
  825. }
  826. // Nothing to do if the name is the same
  827. string oldFileName = Path.GetFileNameWithoutExtension(Url);
  828. if (String.Compare(oldFileName, label, StringComparison.Ordinal) == 0)
  829. {
  830. return VSConstants.S_FALSE;
  831. }
  832. // Now check whether the original file is still there. It could have been renamed.
  833. if (!File.Exists(Url))
  834. {
  835. throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
  836. SR.GetString(SR.FileOrFolderCannotBeFound,
  837. CultureInfo.CurrentUICulture),
  838. ProjectFile));
  839. }
  840. // Get the full file name and then rename the project file.
  841. string newFile = Path.Combine(ProjectFolder, label);
  842. string extension = Path.GetExtension(Url);
  843. // Make sure it has the correct extension
  844. if (String.Compare(Path.GetExtension(newFile), extension, StringComparison.OrdinalIgnoreCase) != 0)
  845. {
  846. newFile += extension;
  847. }
  848. RenameProjectFile(newFile);
  849. return VSConstants.S_OK;
  850. }
  851. /// <summary>
  852. /// Gets the automation object for the project node.
  853. /// </summary>
  854. /// <returns>An instance of an EnvDTE.Project implementation object representing the automation object for the project.</returns>
  855. public override object GetAutomationObject()
  856. {
  857. return new OAProject(this);
  858. }
  859. /// <summary>
  860. /// Closes the project node.
  861. /// </summary>
  862. /// <returns>A success or failure value.</returns>
  863. public override int Close()
  864. {
  865. int hr = VSConstants.S_OK;
  866. try
  867. {
  868. // Walk the tree and close all nodes.
  869. // This has to be done before the project closes, since we want still state available for the ProjectMgr on the nodes
  870. // when nodes are closing.
  871. try
  872. {
  873. CloseAllNodes(this);
  874. }
  875. finally
  876. {
  877. Dispose(true);
  878. }
  879. }
  880. catch (COMException e)
  881. {
  882. hr = e.ErrorCode;
  883. }
  884. finally
  885. {
  886. ErrorHandler.ThrowOnFailure(base.Close());
  887. }
  888. isClosed = true;
  889. return hr;
  890. }
  891. /// <summary>
  892. /// Sets the service provider from which to access the services.
  893. /// </summary>
  894. /// <param name="site">An instance to an Microsoft.VisualStudio.OLE.Interop object</param>
  895. /// <returns>A success or failure value.</returns>
  896. public override int SetSite(IOleServiceProvider site)
  897. {
  898. CCITracing.TraceCall();
  899. this.site = new ServiceProvider(site);
  900. ServiceProvider = this.site;
  901. if (taskProvider != null)
  902. {
  903. taskProvider.Dispose();
  904. }
  905. taskProvider = new TaskProvider(this.site);
  906. return VSConstants.S_OK;
  907. }
  908. /// <summary>
  909. /// Gets the properties of the project node.
  910. /// </summary>
  911. /// <param name="propId">The __VSHPROPID of the property.</param>
  912. /// <returns>
  913. /// A property dependent value. See: <see cref="__VSHPROPID" /> for details.
  914. /// </returns>
  915. public override object GetProperty(int propId)
  916. {
  917. switch ((__VSHPROPID)propId)
  918. {
  919. case __VSHPROPID.VSHPROPID_ConfigurationProvider:
  920. return ConfigProvider;
  921. case __VSHPROPID.VSHPROPID_ProjectName:
  922. return Caption;
  923. case __VSHPROPID.VSHPROPID_ProjectDir:
  924. return ProjectFolder;
  925. case __VSHPROPID.VSHPROPID_TypeName:
  926. return ProjectType;
  927. case __VSHPROPID.VSHPROPID_ShowProjInSolutionPage:
  928. return ShowProjectInSolutionPage;
  929. case __VSHPROPID.VSHPROPID_ExpandByDefault:
  930. return true;
  931. // Use the same icon as if the folder was closed
  932. case __VSHPROPID.VSHPROPID_OpenFolderIconIndex:
  933. return GetProperty((int)__VSHPROPID.VSHPROPID_IconIndex);
  934. }
  935. switch ((__VSHPROPID2)propId)
  936. {
  937. case __VSHPROPID2.VSHPROPID_SupportsProjectDesigner:
  938. return SupportsProjectDesigner;
  939. case __VSHPROPID2.VSHPROPID_PropertyPagesCLSIDList:
  940. return
  941. Utilities.CreateSemicolonDelimitedListOfStringFromGuids(
  942. GetConfigurationIndependentPropertyPages());
  943. case __VSHPROPID2.VSHPROPID_CfgPropertyPagesCLSIDList:
  944. return
  945. Utilities.CreateSemicolonDelimitedListOfStringFromGuids(GetConfigurationDependentPropertyPages());
  946. case __VSHPROPID2.VSHPROPID_PriorityPropertyPagesCLSIDList:
  947. return Utilities.CreateSemicolonDelimitedListOfStringFromGuids(GetPriorityProjectDesignerPages());
  948. case __VSHPROPID2.VSHPROPID_Container:
  949. return true;
  950. default:
  951. break;
  952. }
  953. return base.GetProperty(propId);
  954. }
  955. /// <summary>
  956. /// Gets the GUID value of the node.
  957. /// </summary>
  958. /// <param name="propid">A __VSHPROPID or __VSHPROPID2 value of the guid property</param>
  959. /// <param name="guid">The guid to return for the property.</param>
  960. /// <returns>A success or failure value.</returns>
  961. public override int GetGuidProperty(int propid, out Guid guid)
  962. {
  963. guid = Guid.Empty;
  964. if ((__VSHPROPID)propid == __VSHPROPID.VSHPROPID_ProjectIDGuid)
  965. {
  966. guid = ProjectIDGuid;
  967. }
  968. else if (propid == (int)__VSHPROPID.VSHPROPID_CmdUIGuid)
  969. {
  970. guid = ProjectGuid;
  971. }
  972. else if ((__VSHPROPID2)propid == __VSHPROPID2.VSHPROPID_ProjectDesignerEditor && SupportsProjectDesigner)
  973. {
  974. guid = ProjectDesignerEditor;
  975. }
  976. else
  977. {
  978. base.GetGuidProperty(propid, out guid);
  979. }
  980. if (guid.CompareTo(Guid.Empty) == 0)
  981. {
  982. return VSConstants.DISP_E_MEMBERNOTFOUND;
  983. }
  984. return VSConstants.S_OK;
  985. }
  986. /// <summary>
  987. /// Sets Guid properties for the project node.
  988. /// </summary>
  989. /// <param name="propid">A __VSHPROPID or __VSHPROPID2 value of the guid property</param>
  990. /// <param name="guid">The guid value to set.</param>
  991. /// <returns>A success or failure value.</returns>
  992. public override int SetGuidProperty(int propid, ref Guid guid)
  993. {
  994. switch ((__VSHPROPID)propid)
  995. {
  996. case __VSHPROPID.VSHPROPID_ProjectIDGuid:
  997. ProjectIDGuid = guid;
  998. return VSConstants.S_OK;
  999. }
  1000. CCITracing.TraceCall(String.Format(CultureInfo.CurrentCulture, "Property {0} not found", propid));
  1001. return VSConstants.DISP_E_MEMBERNOTFOUND;
  1002. }
  1003. /// <summary>
  1004. /// Removes items from the hierarchy.
  1005. /// </summary>
  1006. /// <devdoc>Project overwrites this.</devdoc>
  1007. public override void Remove(bool removeFromStorage)
  1008. {
  1009. // the project will not be deleted from disk, just removed
  1010. if (removeFromStorage)
  1011. {
  1012. return;
  1013. }
  1014. // Remove the entire project from the solution
  1015. IVsSolution solution = Site.GetService(typeof(SVsSolution)) as IVsSolution;
  1016. uint iOption = 1; // SLNSAVEOPT_PromptSave
  1017. ErrorHandler.ThrowOnFailure(solution.CloseSolutionElement(iOption, InteropSafeIVsHierarchy, 0));
  1018. }
  1019. /// <summary>
  1020. /// Gets the moniker for the project node. That is the full path of the project file.
  1021. /// </summary>
  1022. /// <returns>The moniker for the project file.</returns>
  1023. public override string GetMkDocument()
  1024. {
  1025. Debug.Assert(!String.IsNullOrEmpty(filename));
  1026. Debug.Assert(BaseURI != null && !String.IsNullOrEmpty(BaseURI.AbsoluteUrl));
  1027. return Path.Combine(BaseURI.AbsoluteUrl, filename);
  1028. }
  1029. /// <summary>
  1030. /// Disposes the project node object.
  1031. /// </summary>
  1032. /// <param name="disposing">Flag determining ehether it was deterministic or non deterministic clean up.</param>
  1033. protected override void Dispose(bool disposing)
  1034. {
  1035. if (isDisposed)
  1036. {
  1037. return;
  1038. }
  1039. try
  1040. {
  1041. try
  1042. {
  1043. UnRegisterProject();
  1044. }
  1045. finally
  1046. {
  1047. try
  1048. {
  1049. RegisterClipboardNotifications(false);
  1050. }
  1051. finally
  1052. {
  1053. try
  1054. {
  1055. if (projectEventsProvider != null)
  1056. {
  1057. projectEventsProvider.AfterProjectFileOpened -= OnAfterProjectOpen;
  1058. }
  1059. if (taskProvider != null)
  1060. {
  1061. taskProvider.Tasks.Clear();
  1062. taskProvider.Dispose();
  1063. taskProvider = null;
  1064. }
  1065. if (buildLogger != null)
  1066. {
  1067. buildLogger.Shutdown();
  1068. buildLogger = null;
  1069. }
  1070. if (site != null)
  1071. {
  1072. site.Dispose();
  1073. }
  1074. }
  1075. finally
  1076. {
  1077. buildEngine = null;
  1078. }
  1079. }
  1080. }
  1081. if (buildProject != null)
  1082. {
  1083. buildProject.ProjectCollection.UnloadProject(buildProject);
  1084. buildProject.ProjectCollection.UnloadProject(buildProject.Xml);
  1085. buildProject = null;
  1086. }
  1087. if (null != imageHandler)
  1088. {
  1089. imageHandler.Close();
  1090. imageHandler = null;
  1091. }
  1092. }
  1093. finally
  1094. {
  1095. base.Dispose(disposing);
  1096. isDisposed = true;
  1097. }
  1098. }
  1099. /// <summary>
  1100. /// Handles command status on the project node. If a command cannot be handled then the base should be called.
  1101. /// </summary>
  1102. /// <param name="cmdGroup">A unique identifier of the command group. The pguidCmdGroup parameter can be NULL to specify the standard group.</param>
  1103. /// <param name="cmd">The command to query status for.</param>
  1104. /// <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>
  1105. /// <param name="result">An out parameter specifying the QueryStatusResult of the command.</param>
  1106. /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns>
  1107. protected override int QueryStatusOnNode(Guid cmdGroup, uint cmd, IntPtr pCmdText, ref QueryStatusResult result)
  1108. {
  1109. if (cmdGroup == VsMenus.guidStandardCommandSet97)
  1110. {
  1111. switch ((VsCommands)cmd)
  1112. {
  1113. case VsCommands.Copy:
  1114. case VsCommands.Paste:
  1115. case VsCommands.Cut:
  1116. case VsCommands.Rename:
  1117. case VsCommands.Exit:
  1118. case VsCommands.ProjectSettings:
  1119. case VsCommands.BuildSln:
  1120. case VsCommands.UnloadProject:
  1121. result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED;
  1122. return VSConstants.S_OK;
  1123. case VsCommands.ViewForm:
  1124. if (HasDesigner)
  1125. {
  1126. result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED;
  1127. return VSConstants.S_OK;
  1128. }
  1129. break;
  1130. case VsCommands.CancelBuild:
  1131. result |= QueryStatusResult.SUPPORTED;
  1132. if (buildInProcess)
  1133. result |= QueryStatusResult.ENABLED;
  1134. else
  1135. result |= QueryStatusResult.INVISIBLE;
  1136. return VSConstants.S_OK;
  1137. case VsCommands.NewFolder:
  1138. case VsCommands.AddNewItem:
  1139. case VsCommands.AddExistingItem:
  1140. result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED;
  1141. return VSConstants.S_OK;
  1142. case VsCommands.SetStartupProject:
  1143. result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED;
  1144. return VSConstants.S_OK;
  1145. }
  1146. }
  1147. else if (cmdGroup == VsMenus.guidStandardCommandSet2K)
  1148. {
  1149. switch ((VsCommands2K)cmd)
  1150. {
  1151. case VsCommands2K.ADDREFERENCE:
  1152. result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED;
  1153. return VSConstants.S_OK;
  1154. case VsCommands2K.EXCLUDEFROMPROJECT:
  1155. result |= QueryStatusResult.SUPPORTED | QueryStatusResult.INVISIBLE;
  1156. return VSConstants.S_OK;
  1157. case ExploreFolderInWindowsCommand:
  1158. result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED;
  1159. return VSConstants.S_OK;
  1160. }
  1161. }
  1162. else
  1163. {
  1164. return (int)OleConstants.OLECMDERR_E_UNKNOWNGROUP;
  1165. }
  1166. return base.QueryStatusOnNode(cmdGroup, cmd, pCmdText, ref result);
  1167. }
  1168. /// <summary>
  1169. /// Handles command execution.
  1170. /// </summary>
  1171. /// <param name="cmdGroup">Unique identifier of the command group</param>
  1172. /// <param name="cmd">The command to be executed.</param>
  1173. /// <param name="nCmdexecopt">Values describe how the object should execute the command.</param>
  1174. /// <param name="pvaIn">Pointer to a VARIANTARG structure containing input arguments. Can be NULL</param>
  1175. /// <param name="pvaOut">VARIANTARG structure to receive command output. Can be NULL.</param>
  1176. /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns>
  1177. protected override int ExecCommandOnNode(Guid cmdGroup, uint cmd, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
  1178. {
  1179. if (cmdGroup == VsMenus.guidStandardCommandSet97)
  1180. {
  1181. switch ((VsCommands)cmd)
  1182. {
  1183. case VsCommands.UnloadProject:
  1184. return UnloadProject();
  1185. case VsCommands.CleanSel:
  1186. case VsCommands.CleanCtx:

Large files files are truncated, but you can click here to view the full file