anx.framework/Visual Studio/ANXVisualStudioPackage/Nodes/ContentProjectReferenceContainer.cs
Konstantin Koch 8287c54432 Included the Visual Studio extension and made the necessary changes to make it run.
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.
2015-04-08 14:50:03 +02:00

338 lines
14 KiB
C#

using ANX.Framework.Build;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Project;
using Microsoft.VisualStudio.Project.Automation;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using ANX.Framework.VisualStudio.Nodes;
using ANX.Framework.Content.Pipeline.Tasks.References;
namespace ANX.Framework.VisualStudio.Nodes
{
class ContentProjectReferenceContainer : ReferenceContainerNode
{
ContentProjectNode contentProjectNode;
public bool Loading
{
get;
set;
}
protected void SetProjectDirty()
{
if (Loading)
return;
this.ProjectMgr.SetProjectFileDirty(true);
}
public ContentProjectReferenceContainer(ContentProjectNode root)
: base(root)
{
this.contentProjectNode = root;
this.OnChildAdded += ContentProjectReferenceContainer_OnChildAdded;
this.OnChildRemoved += ContentProjectReferenceContainer_OnChildRemoved;
}
public void LoadReferencesFromContentProject()
{
Loading = true;
try
{
foreach (var item in contentProjectNode.ContentProject.References)
{
ReferenceNode node = null;
if (item is AssemblyReference)
{
/*var element = new MsBuildProjectElement(this.ProjectMgr, AssemblyName.GetAssemblyName(item.AssemblyPath).FullName, ProjectFileConstants.ProjectReference);
element.SetMetadata(ProjectFileConstants.Name, item.Name);
element.SetMetadata(ProjectFileConstants.HintPath, item.AssemblyPath);
element.SetMetadata(ProjectFileConstants.Private, false.ToString()); //By default, never copy the assembly to the output directory for content projects, even if it's not a framework assembly.
element.SetMetadata(ProjectFileConstants.AssemblyName, Path.GetFileName(item.AssemblyPath));
node = CreateReferenceNode(ProjectFileConstants.Reference, element);*/
var reference = (AssemblyReference)item;
string path = reference.AssemblyPath;
using (var buildAppDomain = contentProjectNode.BuildAppDomain.Aquire())
{
path = buildAppDomain.MakeAbsoluteFromSearchPaths(path);
}
node = CreateAssemblyReferenceNode(reference.Name, path);
}
else if (item is GACReference)
{
var reference = (GACReference)item;
node = CreateAssemblyReferenceNode(reference.Name, reference.AssemblyName);
}
else if (item is ProjectReference)
{
var reference = (ProjectReference)item;
/*var element = new MsBuildProjectElement(this.ProjectMgr, reference.Include, ProjectFileConstants.ProjectReference);
element.SetMetadata(ProjectFileConstants.Project, reference.Guid.ToString());
element.SetMetadata(ProjectFileConstants.Name, item.Name);
element.SetMetadata(ProjectFileConstants.Private, false.ToString()); //By default, never copy the assembly to the output directory for content projects, even if it's not a framework assembly.
node = CreateReferenceNode(ProjectFileConstants.ProjectReference, element);*/
string path = string.Empty;
string uniqueName = string.Empty;
try
{
path = CommonUtils.GetAbsoluteFilePath(Path.GetDirectoryName(this.ProjectMgr.Url), reference.Include);
}
catch { }
try
{
uniqueName = reference.Guid.ToString("B") + "|" + CommonUtils.TrimUpPaths(reference.Include);
}
catch { }
VSCOMPONENTSELECTORDATA selectorData = new VSCOMPONENTSELECTORDATA()
{
bstrTitle = reference.Name,
bstrFile = path,
bstrProjRef = uniqueName
};
node = CreateProjectReferenceNode(selectorData);
}
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);
}
}
}
//After all references have been added, we can load them.
this.LoadAssemblies(this.EnumReferences().ToArray());
}
finally
{
Loading = false;
}
}
void ContentProjectReferenceContainer_OnChildAdded(object sender, HierarchyNodeEventArgs e)
{
this.SetProjectDirty();
//Wait with loading the refernces until the project finished loading.
if (this.Loading)
return;
LoadReference((ReferenceNode)e.Child);
}
void LoadReference(ReferenceNode node)
{
if (node is AnxAssemblyReferenceNode)
{
var assemblyReference = (AnxAssemblyReferenceNode)node;
assemblyReference.ItemNode.SetMetadata(ProjectFileConstants.Private, false.ToString()); //By default, never copy the assembly to the output directory for content projects, even if it's not a framework assembly.
if (assemblyReference.IsValid)
{
//Keep the ui thread responsive while the tasks battle over the lock for the appDomain.
LoadAssemblies(assemblyReference);
}
}
else if (node is AnxProjectReferenceNode)
{
var projectReference = (AnxProjectReferenceNode)node;
projectReference.ItemNode.SetMetadata(ProjectFileConstants.Private, false.ToString()); //By default, never copy the assembly to the output directory for content projects, even if it's not a framework assembly.
if (File.Exists(projectReference.ReferencedProjectOutputPath))
{
LoadAssemblies(projectReference);
}
}
}
void ContentProjectReferenceContainer_OnChildRemoved(object sender, HierarchyNodeEventArgs e)
{
this.SetProjectDirty();
this.RefreshAssemblies(new List<HierarchyNode>(new [] { e.Child }));
}
public void RefreshAssemblies(IEnumerable<HierarchyNode> exclude = null)
{
using (var buildDomain = this.contentProjectNode.BuildAppDomain.Aquire())
{
buildDomain.Unload();
buildDomain.Initialize(this.contentProjectNode.ProjectGuid.ToString());
}
List<ReferenceNode> referencesToRefresh = new List<ReferenceNode>();
foreach (ReferenceNode reference in this.EnumReferences())
{
if (exclude != null && exclude.Contains(reference))
continue;
if (reference is AnxAssemblyReferenceNode)
{
var assemblyReference = (AnxAssemblyReferenceNode)reference;
assemblyReference.ItemNode.SetMetadata(ProjectFileConstants.Private, false.ToString()); //By default, never copy the assembly to the output directory for content projects, even if it's not a framework assembly.
if (assemblyReference.IsValid)
{
referencesToRefresh.Add(reference);
}
}
else if (reference is AnxProjectReferenceNode)
{
var projectReference = (AnxProjectReferenceNode)reference;
projectReference.ItemNode.SetMetadata(ProjectFileConstants.Private, false.ToString()); //By default, never copy the assembly to the output directory for content projects, even if it's not a framework assembly.
if (File.Exists(projectReference.ReferencedProjectOutputPath))
{
referencesToRefresh.Add(reference);
}
}
}
if (referencesToRefresh.Count > 0)
{
LoadAssemblies(referencesToRefresh.ToArray());
}
}
public Task LoadAssemblies(params ReferenceNode[] references)
{
return Task.Run(() =>
{
var allReferences = this.EnumNodesOfType<AnxAssemblyReferenceNode>().ToArray();
using (var buildDomain = this.contentProjectNode.BuildAppDomain.Aquire())
{
Dictionary<string, string> assemblyNamesAndPaths = new Dictionary<string, string>();
foreach (var reference in references)
{
string path = null;
string name = null;
if (reference is AnxAssemblyReferenceNode)
{
var assemblyReference = (AnxAssemblyReferenceNode)reference;
assemblyReference.RefreshReference();
path = assemblyReference.FullPath;
name = assemblyReference.AssemblyName.FullName;
if (string.IsNullOrEmpty(path))
path = name;
}
else if (reference is AnxProjectReferenceNode)
{
var projectReference = (AnxProjectReferenceNode)reference;
projectReference.RefreshReference();
path = projectReference.ReferencedProjectOutputPath;
if (File.Exists(path))
{
name = AssemblyName.GetAssemblyName(path).FullName;
}
}
if (name != null && path != null && File.Exists(path))
{
foreach (var assemblyName in buildDomain.Proxy.GetReferencedAssemblies(path))
{
if (!assemblyNamesAndPaths.ContainsKey(assemblyName.FullName))
{
string assemblyIdentifier = assemblyName.FullName;
foreach (var referenceEntry in allReferences)
{
if (referenceEntry.AssemblyName != null && referenceEntry.AssemblyName.FullName == assemblyName.FullName && File.Exists(referenceEntry.Url))
{
assemblyIdentifier = referenceEntry.Url;
break;
}
}
assemblyNamesAndPaths[assemblyName.FullName] = assemblyIdentifier;
}
}
assemblyNamesAndPaths[name] = path;
}
}
var callback = new LoadAssembliesCallback(this);
buildDomain.Proxy.LoadProjectAssemblies(assemblyNamesAndPaths.Values, buildDomain.SearchPaths, buildDomain.Redirects, callback.ErrorCallback);
}
}
);
}
class LoadAssembliesCallback : MarshalByRefObject
{
ContentProjectReferenceContainer parent;
internal LoadAssembliesCallback(ContentProjectReferenceContainer parent)
{
this.parent = parent;
}
public void ErrorCallback(string assembly, Exception exc)
{
ErrorLoggingHelper loggingHelper = new ErrorLoggingHelper(parent.contentProjectNode, parent.contentProjectNode.ErrorListProvider);
loggingHelper.LogWarning(null, null, null, assembly, -1, -1, exc.Message);
}
}
protected override AssemblyReferenceNode CreateAssemblyReferenceNode(ProjectElement element)
{
throw new NotSupportedException();
}
protected override AssemblyReferenceNode CreateAssemblyReferenceNode(string name, string fileName)
{
return new AnxAssemblyReferenceNode(this.contentProjectNode, name, fileName);
}
protected override ProjectReferenceNode CreateProjectReferenceNode(ProjectElement element)
{
throw new NotSupportedException();
}
protected override ProjectReferenceNode CreateProjectReferenceNode(VSCOMPONENTSELECTORDATA selectorData)
{
return new AnxProjectReferenceNode(this.contentProjectNode, selectorData.bstrTitle, selectorData.bstrFile, selectorData.bstrProjRef);
}
}
}