Replaced the old VS templates with ones that offer more flexiblity. Started replacing the Content Project for the samples with our custom project type. Inlcuded a basic not yet working AssimpImporter.
650 lines
23 KiB
C#
650 lines
23 KiB
C#
/* ****************************************************************************
|
|
*
|
|
* Copyright (c) Microsoft Corporation.
|
|
*
|
|
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
|
* copy of the license can be found in the License.html file at the root of this distribution. If
|
|
* you cannot locate the Apache License, Version 2.0, please send an email to
|
|
* vspython@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
|
* by the terms of the Apache License, Version 2.0.
|
|
*
|
|
* You must not remove this notice, or any other, from this software.
|
|
*
|
|
* ***************************************************************************/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Linq;
|
|
using Microsoft.VisualStudio;
|
|
using Microsoft.VisualStudio.Shell.Interop;
|
|
using MSBuild = Microsoft.Build.Evaluation;
|
|
using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants;
|
|
using VsCommands = Microsoft.VisualStudio.VSConstants.VSStd97CmdID;
|
|
using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID;
|
|
using System.Runtime.Versioning;
|
|
using System.ComponentModel.Composition;
|
|
|
|
namespace Microsoft.VisualStudio.Project
|
|
{
|
|
public class ReferenceContainerNode : HierarchyNode, IReferenceContainer
|
|
{
|
|
private EventHandler<HierarchyNodeEventArgs> onChildAdded;
|
|
private EventHandler<HierarchyNodeEventArgs> onChildRemoved;
|
|
|
|
#region ctor
|
|
public ReferenceContainerNode(ProjectNode root)
|
|
: base(root)
|
|
{
|
|
this.ExcludeNodeFromScc = true;
|
|
}
|
|
#endregion
|
|
|
|
#region Properties
|
|
private static string[] supportedReferenceTypes = new string[] {
|
|
ProjectFileConstants.ProjectReference,
|
|
ProjectFileConstants.Reference,
|
|
ProjectFileConstants.COMReference,
|
|
ProjectFileConstants.WebPiReference
|
|
};
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
|
protected virtual string[] SupportedReferenceTypes
|
|
{
|
|
get { return supportedReferenceTypes; }
|
|
}
|
|
#endregion
|
|
|
|
#region overridden properties
|
|
public override int SortPriority
|
|
{
|
|
get
|
|
{
|
|
return DefaultSortOrderNode.ReferenceContainerNode;
|
|
}
|
|
}
|
|
|
|
public override int MenuCommandId
|
|
{
|
|
get { return VsMenus.IDM_VS_CTXT_REFERENCEROOT; }
|
|
}
|
|
|
|
|
|
public override Guid ItemTypeGuid
|
|
{
|
|
get { return VSConstants.GUID_ItemType_VirtualFolder; }
|
|
}
|
|
|
|
|
|
public override string Url
|
|
{
|
|
get { return "References"; }
|
|
}
|
|
|
|
public override string Caption
|
|
{
|
|
get
|
|
{
|
|
return SR.GetString(SR.ReferencesNodeName, CultureInfo.CurrentUICulture);
|
|
}
|
|
}
|
|
|
|
|
|
private Automation.OAReferences references;
|
|
public override object Object
|
|
{
|
|
get
|
|
{
|
|
if (null == references)
|
|
{
|
|
references = new Automation.OAReferences(this);
|
|
}
|
|
return references;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region overridden methods
|
|
|
|
public override void RemoveChild(HierarchyNode node)
|
|
{
|
|
base.RemoveChild(node);
|
|
|
|
if (node is ReferenceNode)
|
|
{
|
|
FireChildRemoved((ReferenceNode)node);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns an instance of the automation object for ReferenceContainerNode
|
|
/// </summary>
|
|
/// <returns>An intance of the Automation.OAReferenceFolderItem type if succeeeded</returns>
|
|
public override object GetAutomationObject()
|
|
{
|
|
if (this.ProjectMgr == null || this.ProjectMgr.IsClosed)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return new Automation.OAReferenceFolderItem(this.ProjectMgr.GetAutomationObject() as Automation.OAProject, this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disable inline editing of Caption of a ReferendeContainerNode
|
|
/// </summary>
|
|
/// <returns>null</returns>
|
|
public override string GetEditLabel()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
|
|
public override object GetIconHandle(bool open)
|
|
{
|
|
return this.ProjectMgr.ImageHandler.GetIconHandle(open ? (int)ProjectNode.ImageName.OpenReferenceFolder : (int)ProjectNode.ImageName.ReferenceFolder);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// References node cannot be dragged.
|
|
/// </summary>
|
|
/// <returns>A stringbuilder.</returns>
|
|
public override string PrepareSelectedNodesForClipBoard()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Not supported.
|
|
/// </summary>
|
|
public override int ExcludeFromProject()
|
|
{
|
|
return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
|
|
}
|
|
|
|
public override int QueryStatusOnNode(Guid cmdGroup, uint cmd, IntPtr pCmdText, ref QueryStatusResult result)
|
|
{
|
|
if (cmdGroup == VsMenus.guidStandardCommandSet97)
|
|
{
|
|
switch ((VsCommands)cmd)
|
|
{
|
|
case VsCommands.AddNewItem:
|
|
case VsCommands.AddExistingItem:
|
|
result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED;
|
|
return VSConstants.S_OK;
|
|
}
|
|
}
|
|
else if (cmdGroup == VsMenus.guidStandardCommandSet2K)
|
|
{
|
|
if ((VsCommands2K)cmd == VsCommands2K.ADDREFERENCE)
|
|
{
|
|
result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED;
|
|
return VSConstants.S_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return (int)OleConstants.OLECMDERR_E_UNKNOWNGROUP;
|
|
}
|
|
return base.QueryStatusOnNode(cmdGroup, cmd, pCmdText, ref result);
|
|
}
|
|
|
|
public override int ExecCommandOnNode(Guid cmdGroup, uint cmd, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
|
|
{
|
|
if (cmdGroup == VsMenus.guidStandardCommandSet2K)
|
|
{
|
|
switch ((VsCommands2K)cmd)
|
|
{
|
|
case VsCommands2K.ADDREFERENCE:
|
|
return this.ProjectMgr.AddProjectReference();
|
|
#if FALSE
|
|
case VsCommands2K.ADDWEBREFERENCE:
|
|
return this.ProjectMgr.AddWebReference();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return base.ExecCommandOnNode(cmdGroup, cmd, nCmdexecopt, pvaIn, pvaOut);
|
|
}
|
|
|
|
public override bool CanDeleteItem(__VSDELETEITEMOPERATION deleteOperation)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Defines whether this node is valid node for painting the refererences icon.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
protected override bool CanShowDefaultIcon()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IReferenceContainer
|
|
|
|
public IList<ReferenceNode> EnumReferences()
|
|
{
|
|
List<ReferenceNode> refs = new List<ReferenceNode>();
|
|
for (HierarchyNode node = this.FirstChild; node != null; node = node.NextSibling)
|
|
{
|
|
ReferenceNode refNode = node as ReferenceNode;
|
|
if (refNode != null)
|
|
{
|
|
refs.Add(refNode);
|
|
}
|
|
}
|
|
|
|
return refs;
|
|
}
|
|
/// <summary>
|
|
/// Adds references to this container from a MSBuild project.
|
|
/// </summary>
|
|
public void LoadReferencesFromBuildProject(MSBuild.Project buildProject)
|
|
{
|
|
foreach (string referenceType in SupportedReferenceTypes)
|
|
{
|
|
IEnumerable<MSBuild.ProjectItem> refererncesGroup = this.ProjectMgr.BuildProject.GetItems(referenceType);
|
|
|
|
bool isAssemblyReference = referenceType == ProjectFileConstants.Reference;
|
|
// If the project was loaded for browsing we should still create the nodes but as not resolved.
|
|
if (isAssemblyReference &&
|
|
(!ProjectMgr.BuildProject.Targets.ContainsKey(MsBuildTarget.ResolveAssemblyReferences) || this.ProjectMgr.Build(MsBuildTarget.ResolveAssemblyReferences) != MSBuildResult.Successful))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
foreach (MSBuild.ProjectItem item in refererncesGroup)
|
|
{
|
|
ProjectElement element = new MsBuildProjectElement(this.ProjectMgr, item);
|
|
|
|
ReferenceNode node = CreateReferenceNode(referenceType, element);
|
|
|
|
if (node != null)
|
|
{
|
|
// Make sure that we do not want to add the item twice to the ui hierarchy
|
|
// We are using here the UI representation of the Node namely the Caption to find that out, in order to
|
|
// avoid different representation problems.
|
|
// Example :<Reference Include="EnvDTE80, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
|
// <Reference Include="EnvDTE80" />
|
|
bool found = false;
|
|
for (HierarchyNode n = this.FirstChild; n != null && !found; n = n.NextSibling)
|
|
{
|
|
if (String.Compare(n.Caption, node.Caption, StringComparison.OrdinalIgnoreCase) == 0)
|
|
{
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
this.AddChild(node);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a reference to this container using the selector data structure to identify it.
|
|
/// </summary>
|
|
/// <param name="selectorData">data describing selected component</param>
|
|
/// <returns>Reference in case of a valid reference node has been created. Otherwise null</returns>
|
|
public ReferenceNode AddReferenceFromSelectorData(VSCOMPONENTSELECTORDATA selectorData)
|
|
{
|
|
//Make sure we can edit the project file
|
|
if (!this.ProjectMgr.QueryEditProjectFile(false))
|
|
{
|
|
throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED);
|
|
}
|
|
|
|
//Create the reference node
|
|
ReferenceNode node = null;
|
|
try
|
|
{
|
|
node = CreateReferenceNode(selectorData);
|
|
}
|
|
catch (ArgumentException)
|
|
{
|
|
// Some selector data was not valid.
|
|
}
|
|
|
|
//Add the reference node to the project if we have a valid reference node
|
|
if (node != null)
|
|
{
|
|
// This call will find if the reference is in the project and, in this case
|
|
// will not add it again, so the parent node will not be set.
|
|
node.AddReference();
|
|
if (null == node.Parent)
|
|
{
|
|
// The reference was not added, so we can not return this item because it
|
|
// is not inside the project.
|
|
return null;
|
|
}
|
|
var added = onChildAdded;
|
|
if (added != null) {
|
|
onChildAdded(this, new HierarchyNodeEventArgs(node));
|
|
}
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
public override void AddChild(HierarchyNode node)
|
|
{
|
|
if (node is ReferenceNode)
|
|
{
|
|
((ReferenceNode)node).RefreshReference();
|
|
}
|
|
|
|
base.AddChild(node);
|
|
|
|
var added = onChildAdded;
|
|
if (added != null)
|
|
{
|
|
onChildAdded(this, new HierarchyNodeEventArgs(node));
|
|
}
|
|
}
|
|
|
|
#if DEV11_OR_LATER
|
|
|
|
public void AddReference(IVsReference pReference)
|
|
{
|
|
if (pReference.AlreadyReferenced == false)
|
|
return;
|
|
|
|
ReferenceNode node = null;
|
|
if (pReference is IVsAssemblyReference)
|
|
{
|
|
IVsAssemblyReference assemblyReference = (IVsAssemblyReference)pReference;
|
|
|
|
node = CreateAssemblyReferenceNode(assemblyReference.Name, assemblyReference.FullPath);
|
|
}
|
|
else if (pReference is IVsFileReference)
|
|
{
|
|
IVsFileReference fileReference = (IVsFileReference)pReference;
|
|
|
|
node = CreateAssemblyReferenceNode(fileReference.Name, fileReference.FullPath);
|
|
}
|
|
else if (pReference is IVsProjectReference)
|
|
{
|
|
IVsProjectReference projectReference = (IVsProjectReference)pReference;
|
|
|
|
//ReferenceSpecification must be relative to the current project.
|
|
EnvDTE.DTE dte = (EnvDTE.DTE)this.ProjectMgr.GetService(typeof(EnvDTE.DTE));
|
|
string relativePath = CommonUtils.GetRelativeFilePath(Path.GetDirectoryName(this.ProjectMgr.Url), Path.Combine(dte.Solution.FullName, projectReference.FullPath));
|
|
|
|
VSCOMPONENTSELECTORDATA selectorData = new VSCOMPONENTSELECTORDATA()
|
|
{
|
|
bstrTitle = projectReference.Name,
|
|
bstrFile = projectReference.FullPath,
|
|
bstrProjRef = projectReference.Identity + "|" + relativePath
|
|
};
|
|
|
|
node = CreateProjectReferenceNode(selectorData); ;
|
|
}
|
|
|
|
if (node != null && !this.ContainsReference(node))
|
|
{
|
|
this.AddChild(node);
|
|
}
|
|
}
|
|
|
|
public bool ContainsReference(IVsReference node)
|
|
{
|
|
if (node == null)
|
|
throw new ArgumentNullException("node");
|
|
|
|
for (HierarchyNode hierarchyNode = this.FirstChild; hierarchyNode != null; hierarchyNode = hierarchyNode.NextSibling)
|
|
{
|
|
ReferenceNode refNode = hierarchyNode as ReferenceNode;
|
|
if (refNode != null && refNode.Equals(node))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public bool RemoveReference(IVsReference reference)
|
|
{
|
|
for (HierarchyNode hierarchyNode = this.FirstChild; hierarchyNode != null; hierarchyNode = hierarchyNode.NextSibling)
|
|
{
|
|
ReferenceNode refNode = hierarchyNode as ReferenceNode;
|
|
if (refNode != null && refNode.Equals(reference))
|
|
{
|
|
refNode.Remove(false);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
#endif
|
|
#endregion
|
|
|
|
#region virtual methods
|
|
protected virtual ReferenceNode CreateReferenceNode(string referenceType, ProjectElement element)
|
|
{
|
|
ReferenceNode node = null;
|
|
#if FALSE
|
|
if(referenceType == ProjectFileConstants.COMReference)
|
|
{
|
|
node = this.CreateComReferenceNode(element);
|
|
}
|
|
else
|
|
#endif
|
|
if (referenceType == ProjectFileConstants.Reference)
|
|
{
|
|
node = this.CreateAssemblyReferenceNode(element);
|
|
}
|
|
else if (referenceType == ProjectFileConstants.ProjectReference)
|
|
{
|
|
node = this.CreateProjectReferenceNode(element);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
protected virtual ReferenceNode CreateReferenceNode(VSCOMPONENTSELECTORDATA selectorData)
|
|
{
|
|
ReferenceNode node = null;
|
|
switch (selectorData.type)
|
|
{
|
|
case VSCOMPONENTTYPE.VSCOMPONENTTYPE_Project:
|
|
node = this.CreateProjectReferenceNode(selectorData);
|
|
break;
|
|
case VSCOMPONENTTYPE.VSCOMPONENTTYPE_File:
|
|
// This is the case for managed assembly
|
|
case VSCOMPONENTTYPE.VSCOMPONENTTYPE_ComPlus:
|
|
node = this.CreateFileComponent(selectorData);
|
|
break;
|
|
#if FALSE
|
|
case VSCOMPONENTTYPE.VSCOMPONENTTYPE_Com2:
|
|
node = this.CreateComReferenceNode(selectorData);
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
return node;
|
|
}
|
|
#endregion
|
|
|
|
#region Helper functions to add references
|
|
/// <summary>
|
|
/// Creates a project reference node given an existing project element.
|
|
/// </summary>
|
|
protected virtual ProjectReferenceNode CreateProjectReferenceNode(ProjectElement element)
|
|
{
|
|
return new ProjectReferenceNode(this.ProjectMgr, element);
|
|
}
|
|
/// <summary>
|
|
/// Create a Project to Project reference given a VSCOMPONENTSELECTORDATA structure
|
|
/// </summary>
|
|
protected virtual ProjectReferenceNode CreateProjectReferenceNode(VSCOMPONENTSELECTORDATA selectorData)
|
|
{
|
|
return new ProjectReferenceNode(this.ProjectMgr, selectorData.bstrTitle, selectorData.bstrFile, selectorData.bstrProjRef);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates an assemby or com reference node given a selector data.
|
|
/// </summary>
|
|
protected virtual ReferenceNode CreateFileComponent(VSCOMPONENTSELECTORDATA selectorData)
|
|
{
|
|
if (null == selectorData.bstrFile)
|
|
{
|
|
throw new ArgumentNullException("selectorData");
|
|
}
|
|
|
|
// We have a path to a file, it could be anything
|
|
// First see if it is a managed assembly
|
|
bool tryToCreateAnAssemblyReference = true;
|
|
if (File.Exists(selectorData.bstrFile))
|
|
{
|
|
try
|
|
{
|
|
// We should not load the assembly in the current appdomain.
|
|
// If we do not do it like that and we load the assembly in the current appdomain then the assembly cannot be unloaded again.
|
|
// The following problems might arose in that case.
|
|
// 1. Assume that a user is extending the MPF and his project is creating a managed assembly dll.
|
|
// 2. The user opens VS and creates a project and builds it.
|
|
// 3. Then the user opens VS creates another project and adds a reference to the previously built assembly. This will load the assembly in the appdomain had we been using Assembly.ReflectionOnlyLoadFrom.
|
|
// 4. Then he goes back to the first project modifies it an builds it. A build error is issued that the assembly is used.
|
|
|
|
// GetAssemblyName is assured not to load the assembly.
|
|
tryToCreateAnAssemblyReference = (AssemblyName.GetAssemblyName(selectorData.bstrFile) != null);
|
|
}
|
|
catch (BadImageFormatException)
|
|
{
|
|
// We have found the file and it is not a .NET assembly; no need to try to
|
|
// load it again.
|
|
tryToCreateAnAssemblyReference = false;
|
|
}
|
|
catch (FileLoadException)
|
|
{
|
|
// We must still try to load from here because this exception is thrown if we want
|
|
// to add the same assembly refererence from different locations.
|
|
tryToCreateAnAssemblyReference = true;
|
|
}
|
|
}
|
|
|
|
ReferenceNode node = null;
|
|
|
|
if (tryToCreateAnAssemblyReference)
|
|
{
|
|
// This might be a candidate for an assembly reference node. Try to load it.
|
|
// CreateAssemblyReferenceNode will suppress BadImageFormatException if the node cannot be created.
|
|
node = this.CreateAssemblyReferenceNode(selectorData.bstrTitle, selectorData.bstrFile);
|
|
}
|
|
|
|
// If no node has been created try to create a com reference node.
|
|
if (node == null)
|
|
{
|
|
if (!File.Exists(selectorData.bstrFile))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
node = ProjectMgr.CreateReferenceNodeForFile(selectorData.bstrFile);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates an assembly refernce node from a project element.
|
|
/// </summary>
|
|
protected virtual AssemblyReferenceNode CreateAssemblyReferenceNode(ProjectElement element)
|
|
{
|
|
AssemblyReferenceNode node = null;
|
|
try
|
|
{
|
|
node = new AssemblyReferenceNode(this.ProjectMgr, element);
|
|
}
|
|
catch (ArgumentNullException e)
|
|
{
|
|
Trace.WriteLine("Exception : " + e.Message);
|
|
}
|
|
catch (FileNotFoundException e)
|
|
{
|
|
Trace.WriteLine("Exception : " + e.Message);
|
|
}
|
|
catch (BadImageFormatException e)
|
|
{
|
|
Trace.WriteLine("Exception : " + e.Message);
|
|
}
|
|
catch (FileLoadException e)
|
|
{
|
|
Trace.WriteLine("Exception : " + e.Message);
|
|
}
|
|
catch (System.Security.SecurityException e)
|
|
{
|
|
Trace.WriteLine("Exception : " + e.Message);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates an assembly reference node from a file path.
|
|
/// </summary>
|
|
protected virtual AssemblyReferenceNode CreateAssemblyReferenceNode(string name, string fileName)
|
|
{
|
|
AssemblyReferenceNode node = null;
|
|
try
|
|
{
|
|
node = new AssemblyReferenceNode(this.ProjectMgr, name, fileName);
|
|
}
|
|
catch (ArgumentNullException e)
|
|
{
|
|
Trace.WriteLine("Exception : " + e.Message);
|
|
}
|
|
catch (FileNotFoundException e)
|
|
{
|
|
Trace.WriteLine("Exception : " + e.Message);
|
|
}
|
|
catch (BadImageFormatException e)
|
|
{
|
|
Trace.WriteLine("Exception : " + e.Message);
|
|
}
|
|
catch (FileLoadException e)
|
|
{
|
|
Trace.WriteLine("Exception : " + e.Message);
|
|
}
|
|
catch (System.Security.SecurityException e)
|
|
{
|
|
Trace.WriteLine("Exception : " + e.Message);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
#endregion
|
|
|
|
public event EventHandler<HierarchyNodeEventArgs> OnChildAdded {
|
|
add { onChildAdded += value; }
|
|
remove { onChildAdded -= value; }
|
|
}
|
|
public event EventHandler<HierarchyNodeEventArgs> OnChildRemoved {
|
|
add { onChildRemoved += value; }
|
|
remove { onChildRemoved -= value; }
|
|
}
|
|
|
|
public void FireChildRemoved(ReferenceNode referenceNode) {
|
|
var removed = onChildRemoved;
|
|
if (removed != null) {
|
|
removed(this, new HierarchyNodeEventArgs(referenceNode));
|
|
}
|
|
}
|
|
}
|
|
}
|