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.
896 lines
39 KiB
C#
896 lines
39 KiB
C#
/********************************************************************************************
|
||
|
||
Copyright (c) Microsoft Corporation
|
||
All rights reserved.
|
||
|
||
Microsoft Public License:
|
||
|
||
This license governs use of the accompanying software. If you use the software, you
|
||
accept this license. If you do not accept the license, do not use the software.
|
||
|
||
1. Definitions
|
||
The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
|
||
same meaning here as under U.S. copyright law.
|
||
A "contribution" is the original software, or any additions or changes to the software.
|
||
A "contributor" is any person that distributes its contribution under this license.
|
||
"Licensed patents" are a contributor's patent claims that read directly on its contribution.
|
||
|
||
2. Grant of Rights
|
||
(A) Copyright Grant- Subject to the terms of this license, including the license conditions
|
||
and limitations in section 3, each contributor grants you a non-exclusive, worldwide,
|
||
royalty-free copyright license to reproduce its contribution, prepare derivative works of
|
||
its contribution, and distribute its contribution or any derivative works that you create.
|
||
(B) Patent Grant- Subject to the terms of this license, including the license conditions
|
||
and limitations in section 3, each contributor grants you a non-exclusive, worldwide,
|
||
royalty-free license under its licensed patents to make, have made, use, sell, offer for
|
||
sale, import, and/or otherwise dispose of its contribution in the software or derivative
|
||
works of the contribution in the software.
|
||
|
||
3. Conditions and Limitations
|
||
(A) No Trademark License- This license does not grant you rights to use any contributors'
|
||
name, logo, or trademarks.
|
||
(B) If you bring a patent claim against any contributor over patents that you claim are
|
||
infringed by the software, your patent license from such contributor to the software ends
|
||
automatically.
|
||
(C) If you distribute any portion of the software, you must retain all copyright, patent,
|
||
trademark, and attribution notices that are present in the software.
|
||
(D) If you distribute any portion of the software in source code form, you may do so only
|
||
under this license by including a complete copy of this license with your distribution.
|
||
If you distribute any portion of the software in compiled or object code form, you may only
|
||
do so under a license that complies with this license.
|
||
(E) The software is licensed "as-is." You bear the risk of using it. The contributors give
|
||
no express warranties, guarantees or conditions. You may have additional consumer rights
|
||
under your local laws which this license cannot change. To the extent permitted under your
|
||
local laws, the contributors exclude the implied warranties of merchantability, fitness for
|
||
a particular purpose and non-infringement.
|
||
|
||
********************************************************************************************/
|
||
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel.Design;
|
||
using System.Diagnostics;
|
||
using System.Globalization;
|
||
using System.IO;
|
||
using System.Reflection;
|
||
using System.Text;
|
||
using EnvDTE;
|
||
using Microsoft.VisualStudio;
|
||
using Microsoft.VisualStudio.Shell;
|
||
using Microsoft.VisualStudio.Shell.Interop;
|
||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||
using Microsoft.VisualStudio.Project.Automation;
|
||
|
||
namespace Microsoft.VisualStudio.Project.IntegrationTests
|
||
{
|
||
public class Utilities
|
||
{
|
||
internal static string[] BadFileNames = new string[] { "#<23>&%\"<22>&\"%", "c:\\temp\\?&&&", "c:\\temp\\CON", "c:\\temp\\AUX", "c:\\temp\\LPT1", "c:\\temp\\LPT5", "c:\\temp\\COM1", "c:\\temp\\COM5", "c:\\temp\\PRN", "c:\\temp\\NUL", "c:\\temp\\CLOCK$",
|
||
"c:\\temp\\LPT0.txt","c:\\temp\\CON.txt", "c:\\temp\\AUX.txt", "c:\\temp\\LPT1.txt", "c:\\temp\\LPT5.txt", "c:\\temp\\COM1.txt", "c:\\temp\\COM5.txt", "c:\\temp\\PRN.txt", "c:\\temp\\NUL.txt", "c:\\temp\\CLOCK$.txt",
|
||
"c:\\temp\\fieNam.??t", "c:\\temp\\FileName.#xt" };
|
||
internal static string[] FileNamesThatShouldPass = new string[] { "MyLPT1", "LPT1My", "Auxiliary", "MYNULL", "NULLMY" };
|
||
internal static string LongFileName = "123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_1";
|
||
|
||
internal static Guid NestedProjectGuid = new Guid("1CFCDD29-C8A2-4556-9C2E-5ABBD9952B20");
|
||
internal static Guid SampleLanguageProjectGuid = new Guid("B6207E59-9758-4e9c-8AE3-AE4FACF71C82");
|
||
|
||
public static Guid CsProjectGuid
|
||
{
|
||
get { return new Guid("FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"); }
|
||
}
|
||
public static Guid VbProjectGuid
|
||
{
|
||
get { return new Guid("F184B08F-C81C-45F6-A57F-5ABD9991F28F"); }
|
||
}
|
||
public static Guid VcProjectGuid
|
||
{
|
||
get { return new Guid("8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"); }
|
||
}
|
||
|
||
public static HierarchyNode GetChildItem(ProjectNode project, string url)
|
||
{
|
||
HierarchyNode node = null;
|
||
MethodInfo findChildMethod = project.GetType().GetMethod("FindChild", BindingFlags.NonPublic | BindingFlags.Instance);
|
||
node = (HierarchyNode)findChildMethod.Invoke(project, new object[] { url });
|
||
|
||
return node;
|
||
|
||
}
|
||
|
||
public static ProjectNode CreateMyNestedProject(IServiceProvider sp, DTE dte, string projectName, string destination, bool exclusive)
|
||
{
|
||
CreateSampleProject(dte, "Application.nestedproj", destination, projectName, NestedProjectGuid, exclusive);
|
||
|
||
OAProject automation = Utilities.FindExtObject(sp, Utilities.NestedProjectGuid, projectName) as OAProject;
|
||
Assert.IsNotNull(automation, "Failed to create a project using automation");
|
||
|
||
return automation.Project;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Creates a new sample project
|
||
/// </summary>
|
||
public static void CreateSampleProject(DTE dte, string relTemplateLocation, string destination, string projectName, Guid projectType, bool exclusive)
|
||
{
|
||
Assert.IsNotNull(dte, "invalid value of dte");
|
||
Assert.IsFalse(String.IsNullOrEmpty(projectName), "Project name is not set for creating a new project.");
|
||
Assert.IsFalse(String.IsNullOrEmpty(relTemplateLocation), "The template location is invalid.");
|
||
Assert.IsFalse(String.IsNullOrEmpty(projectName), "Invalid project name");
|
||
Assert.IsFalse(Guid.Empty == projectType, "Invalid project type");
|
||
|
||
//create new project from template
|
||
Solution solution = dte.Solution;
|
||
string templatePath = solution.get_TemplatePath(projectType.ToString("B"));
|
||
templatePath = Path.Combine(templatePath, relTemplateLocation);
|
||
Assert.IsTrue(File.Exists(templatePath), "Could not find templateFile");
|
||
solution.AddFromTemplate(templatePath, destination, projectName, exclusive);
|
||
}
|
||
|
||
public static EnvDTE.Project FindExtObject(IServiceProvider sp, Guid guid, string projectName)
|
||
{
|
||
IVsSolution solutionService = sp.GetService(typeof(SVsSolution)) as IVsSolution;
|
||
IEnumHierarchies enumHierarchies;
|
||
uint enumFlags = (uint)(__VSENUMPROJFLAGS.EPF_ALLINSOLUTION | __VSENUMPROJFLAGS.EPF_MATCHTYPE);
|
||
solutionService.GetProjectEnum(enumFlags, ref guid, out enumHierarchies);
|
||
if(enumHierarchies != null)
|
||
{
|
||
// Loop projects found
|
||
IVsHierarchy[] hierarchy = new IVsHierarchy[1];
|
||
uint fetched = 0;
|
||
while(enumHierarchies.Next(1, hierarchy, out fetched) == VSConstants.S_OK && fetched == 1)
|
||
{
|
||
object name;
|
||
hierarchy[0].GetProperty((uint)VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_Name, out name);
|
||
if(string.Compare(projectName, (string)name) == 0)
|
||
{
|
||
object extObject;
|
||
hierarchy[0].GetProperty((uint)VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ExtObject, out extObject);
|
||
return extObject as EnvDTE.Project;
|
||
}
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
public static IVsHierarchy GetHierarchyOfUniqueName(IServiceProvider serviceProvider, string uniqueName)
|
||
{
|
||
IVsSolution solutionService = serviceProvider.GetService(typeof(SVsSolution)) as IVsSolution;
|
||
IVsHierarchy hierarchy;
|
||
solutionService.GetProjectOfUniqueName(uniqueName, out hierarchy);
|
||
return hierarchy;
|
||
}
|
||
|
||
public static string GetResourceStringFromTheProjectAssembly(string resourceID)
|
||
{
|
||
Type type = typeof(ProjectNode).Assembly.GetType(typeof(ProjectNode).Namespace + ".SR", true, true);
|
||
MethodInfo getString = type.GetMethod("GetString", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(string), typeof(CultureInfo) }, new ParameterModifier[] { });
|
||
|
||
return getString.Invoke(null, new object[] { resourceID, CultureInfo.CurrentUICulture }) as string;
|
||
}
|
||
|
||
|
||
internal static FileNode AddFile(ProjectNode project, string fileNameWithoutExtension, string extension)
|
||
{
|
||
string newModelFilePath = TestUtils.GetNewFileName(project.ProjectFolder, fileNameWithoutExtension, extension);
|
||
|
||
VSADDRESULT[] result = new VSADDRESULT[1];
|
||
project.AddItem(VSConstants.VSITEMID_ROOT, VSADDITEMOPERATION.VSADDITEMOP_OPENFILE, String.Empty, 1, new string[] { newModelFilePath }, IntPtr.Zero, result);
|
||
|
||
string fileName = Path.GetFileName(newModelFilePath);
|
||
|
||
for(HierarchyNode n = project.FirstChild; n != null; n = n.NextSibling)
|
||
{
|
||
if(n is FileNode)
|
||
{
|
||
string nodeFileName = Path.GetFileName(n.GetMkDocument());
|
||
|
||
if(nodeFileName == fileName)
|
||
{
|
||
return n as FileNode;
|
||
}
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Selects all nodes of type T in the project.
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <param name="project"></param>
|
||
/// <returns>The id's of the selected nodes.</returns>
|
||
internal static List<uint> SelectOrUnselectNodes<T>(ProjectNode project, bool select)
|
||
where T : HierarchyNode
|
||
{
|
||
List<uint> selectedNodeIds = new List<uint>();
|
||
IVsUIHierarchyWindow uiHierarchy = VsShellUtilities.GetUIHierarchyWindow(project.Site, HierarchyNode.SolutionExplorer);
|
||
if(uiHierarchy == null)
|
||
{
|
||
return selectedNodeIds;
|
||
}
|
||
|
||
List<T> nodes = GetNodesOfType<T>(project);
|
||
if(nodes.Count > 0)
|
||
{
|
||
foreach(T node in nodes)
|
||
{
|
||
uiHierarchy.ExpandItem(project.InteropSafeIVsUIHierarchy, node.ID, (select) ? EXPANDFLAGS.EXPF_SelectItem : EXPANDFLAGS.EXPF_UnSelectItem);
|
||
selectedNodeIds.Add(node.ID);
|
||
}
|
||
}
|
||
|
||
return selectedNodeIds;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Selects all nodes of type T in the project.
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <param name="project"></param>
|
||
/// <returns>The id's of the selected nodes.</returns>
|
||
internal static T SelectAnyNodeOfType<T>(ProjectNode project)
|
||
where T : HierarchyNode
|
||
{
|
||
IVsUIHierarchyWindow uiHierarchy = VsShellUtilities.GetUIHierarchyWindow(project.Site, HierarchyNode.SolutionExplorer);
|
||
if(uiHierarchy == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
List<T> nodes = GetNodesOfType<T>(project);
|
||
if(nodes.Count > 0)
|
||
{
|
||
uiHierarchy.ExpandItem(project.InteropSafeIVsUIHierarchy, nodes[0].ID, EXPANDFLAGS.EXPF_SelectItem);
|
||
return nodes[0];
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Performs the EXPANDFLAGS action on a node with nodeID.
|
||
/// </summary>
|
||
internal static void ManipulateNode(ProjectNode project, uint nodeID, EXPANDFLAGS flag)
|
||
{
|
||
IVsUIHierarchyWindow uiHierarchy = VsShellUtilities.GetUIHierarchyWindow(project.Site, HierarchyNode.SolutionExplorer);
|
||
if(uiHierarchy == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
uiHierarchy.ExpandItem(project.InteropSafeIVsUIHierarchy, nodeID, flag);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get the nodes of type T
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <param name="parent"></param>
|
||
/// <param name="T"></param>
|
||
/// <returns></returns>
|
||
internal static List<T> GetNodesOfType<T>(HierarchyNode parent)
|
||
where T : HierarchyNode
|
||
{
|
||
List<T> nodes = new List<T>();
|
||
|
||
FindNodesOfType<T>(parent, nodes);
|
||
|
||
return nodes;
|
||
}
|
||
|
||
internal static ProjectReferenceNode AddProjectReference(ProjectNode project, ProjectNode projectReference)
|
||
{
|
||
VSCOMPONENTSELECTORDATA selectorData = new VSCOMPONENTSELECTORDATA();
|
||
|
||
selectorData.bstrFile = projectReference.ProjectFolder;
|
||
IVsSolution solution = (IVsSolution)project.Site.GetService(typeof(IVsSolution));
|
||
solution.GetProjrefOfItem(projectReference.InteropSafeIVsHierarchy, VSConstants.VSITEMID_ROOT, out selectorData.bstrProjRef);
|
||
selectorData.bstrTitle = projectReference.Caption;
|
||
selectorData.type = VSCOMPONENTTYPE.VSCOMPONENTTYPE_Project;
|
||
|
||
// Get the ReferenceContainerNode for this project.
|
||
IReferenceContainer container = project.GetReferenceContainer();
|
||
container.AddReferenceFromSelectorData(selectorData);
|
||
|
||
MethodInfo mi = typeof(ReferenceContainerNode).GetMethod("FindChild", BindingFlags.NonPublic | BindingFlags.Instance);
|
||
|
||
return mi.Invoke(container, new object[] { projectReference.GetMkDocument() }) as ProjectReferenceNode;
|
||
}
|
||
|
||
internal static AssemblyReferenceNode AddAssemblyReference(ProjectNode project, string assemblyReference)
|
||
{
|
||
VSCOMPONENTSELECTORDATA selectorData = new VSCOMPONENTSELECTORDATA();
|
||
|
||
selectorData.bstrFile = assemblyReference;
|
||
selectorData.bstrTitle = Path.GetFileNameWithoutExtension(assemblyReference);
|
||
selectorData.type = VSCOMPONENTTYPE.VSCOMPONENTTYPE_File;
|
||
|
||
// Get the ReferenceContainerNode for this project.
|
||
IReferenceContainer container = project.GetReferenceContainer();
|
||
container.AddReferenceFromSelectorData(selectorData);
|
||
|
||
MethodInfo mi = typeof(ReferenceContainerNode).GetMethod("FindChild", BindingFlags.NonPublic | BindingFlags.Instance);
|
||
|
||
return mi.Invoke(container, new object[] { assemblyReference }) as AssemblyReferenceNode;
|
||
}
|
||
|
||
internal static ComReferenceNode AddComReference(ProjectNode project, VSCOMPONENTSELECTORDATA selectorData)
|
||
{
|
||
|
||
// Get the ReferenceContainerNode for this project.
|
||
IReferenceContainer container = project.GetReferenceContainer();
|
||
container.AddReferenceFromSelectorData(selectorData);
|
||
|
||
// Now find the refererence added.
|
||
ReferenceContainerNode containerNode = container as ReferenceContainerNode;
|
||
for(HierarchyNode n = containerNode.FirstChild; n != null; n = n.NextSibling)
|
||
{
|
||
if(n is ComReferenceNode)
|
||
{
|
||
ComReferenceNode refererenceNode = n as ComReferenceNode;
|
||
|
||
// We check if the name is the same and the type guid is the same
|
||
if(refererenceNode.TypeGuid == selectorData.guidTypeLibrary && String.Compare(refererenceNode.Caption, selectorData.bstrTitle, StringComparison.OrdinalIgnoreCase) == 0)
|
||
{
|
||
return refererenceNode;
|
||
}
|
||
}
|
||
}
|
||
|
||
throw new InvalidOperationException("The Com Refererence added cannot be found");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Retrives the nested hierarchy.
|
||
/// </summary>
|
||
/// <param name="project"></param>
|
||
/// <returns></returns>
|
||
internal static IVsHierarchy GetNestedHierarchy(ProjectNode node, string nestedProjectName)
|
||
{
|
||
EnvDTE.Project project = node.GetAutomationObject() as EnvDTE.Project;
|
||
EnvDTE.ProjectItem nestedProjectItem = project.ProjectItems.Item(nestedProjectName);
|
||
EnvDTE.Project nestedProject = nestedProjectItem.SubProject;
|
||
|
||
IServiceProvider serviceProvider = node.Site;
|
||
IVsSolution ivsSolution = (IVsSolution)serviceProvider.GetService(typeof(IVsSolution));
|
||
IVsHierarchy nestedHierarchy = null;
|
||
ErrorHandler.ThrowOnFailure(ivsSolution.GetProjectOfUniqueName(nestedProject.UniqueName, out nestedHierarchy));
|
||
|
||
return nestedHierarchy;
|
||
|
||
}
|
||
|
||
internal static EnvDTE.Project GetAutomationObject(IVsHierarchy hierarchy)
|
||
{
|
||
object extensibility;
|
||
ErrorHandler.ThrowOnFailure(hierarchy.GetProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ExtObject, out extensibility));
|
||
return extensibility as EnvDTE.Project;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Invokes SetEditLabel and checkes if the exception with the error message is caught.
|
||
/// </summary>
|
||
internal static bool CheckForSetEditLabelBadFileName<T>(HierarchyNode node, string badFileName, string expectedMessage)
|
||
where T : Exception
|
||
{
|
||
bool badFileNameCaught = false;
|
||
IVsExtensibility extensibility = node.GetService(typeof(IVsExtensibility)) as IVsExtensibility;
|
||
extensibility.EnterAutomationFunction();
|
||
try
|
||
{
|
||
node.SetEditLabel(badFileName);
|
||
}
|
||
catch(Exception e)
|
||
{
|
||
if((e is T) && (e.Message == expectedMessage || e.Message.Contains(expectedMessage)))
|
||
{
|
||
badFileNameCaught = true;
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
extensibility.ExitAutomationFunction();
|
||
}
|
||
|
||
return badFileNameCaught;
|
||
}
|
||
|
||
private static void FindNodesOfType<T>(HierarchyNode parent, List<T> nodes)
|
||
where T : HierarchyNode
|
||
{
|
||
for(HierarchyNode n = parent.FirstChild; n != null; n = n.NextSibling)
|
||
{
|
||
if(n is T)
|
||
{
|
||
T nodeAsT = (T)n;
|
||
nodes.Add(nodeAsT);
|
||
}
|
||
|
||
FindNodesOfType<T>(n, nodes);
|
||
}
|
||
}
|
||
|
||
internal static DirectoryInfo GetWinDir()
|
||
{
|
||
// Get the value of the environment variable windir
|
||
string windir = System.Environment.GetEnvironmentVariable("windir");
|
||
return new DirectoryInfo(windir);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Create a new folderNode as a child node to a containernode (folder or project)
|
||
/// </summary>
|
||
/// <param name="project"></param>
|
||
/// <param name="folderPath"></param>
|
||
/// <returns></returns>
|
||
internal static FolderNode CreateFolder(ProjectNode project, string folderPath, HierarchyNode containerNode)
|
||
{
|
||
MethodInfo createFolder = typeof(ProjectNode).GetMethod("CreateFolderNode", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(string) }, null);
|
||
FolderNode folderNode = createFolder.Invoke(project, new object[] { folderPath }) as FolderNode;
|
||
containerNode.AddChild(folderNode);
|
||
//Create Directory associated to this FolderNode
|
||
folderNode.CreateDirectory();
|
||
|
||
return folderNode;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Returns the full path of the assembly a project builds.
|
||
/// </summary>
|
||
/// <param name="project">The project whose build asembly to retrive.</param>
|
||
/// <returns>The full path of the assembly this project builds.</returns>
|
||
internal static string GetOutputPath(EnvDTE.Project automationProjectObject)
|
||
{
|
||
// Get the configuration manager from the project.
|
||
EnvDTE.ConfigurationManager confManager = automationProjectObject.ConfigurationManager;
|
||
if(null == confManager)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
// Get the active configuration.
|
||
EnvDTE.Configuration config = confManager.ActiveConfiguration;
|
||
if(null == config)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
// Get the output path for the current configuration.
|
||
EnvDTE.Property outputPathProperty = config.Properties.Item("OutputPath");
|
||
if(null == outputPathProperty)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
string outputPath = outputPathProperty.Value.ToString();
|
||
|
||
// Ususally the output path is relative to the project path, but it is possible
|
||
// to set it as an absolute path. If it is not absolute, then evaluate its value
|
||
// based on the project directory.
|
||
if(!System.IO.Path.IsPathRooted(outputPath))
|
||
{
|
||
string projectDir = System.IO.Path.GetDirectoryName(automationProjectObject.FullName);
|
||
outputPath = System.IO.Path.Combine(projectDir, outputPath);
|
||
}
|
||
|
||
// Now get the name of the assembly from the project.
|
||
// Some project system throw if the property does not exist. We expect an ArgumentException.
|
||
EnvDTE.Property assemblyNameProperty = null;
|
||
try
|
||
{
|
||
assemblyNameProperty = automationProjectObject.Properties.Item("OutputFileName");
|
||
}
|
||
catch(ArgumentException)
|
||
{
|
||
}
|
||
|
||
if(null == assemblyNameProperty)
|
||
{
|
||
return null;
|
||
}
|
||
else
|
||
{
|
||
outputPath = System.IO.Path.Combine(outputPath, assemblyNameProperty.Value.ToString());
|
||
}
|
||
|
||
// build the full path adding the name of the assembly to the output path.
|
||
|
||
return outputPath;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Creates a new C# class library project.
|
||
/// </summary>
|
||
/// <param name="projectName">Name of new project.</param>
|
||
/// <returns>New project.</returns>
|
||
public static EnvDTE.Project CreateCSharpLibraryProject(DTE dte, string projectName)
|
||
{
|
||
// - get template file
|
||
string templateFile = ((EnvDTE80.Solution2)dte.Solution).GetProjectTemplate("ClassLibrary.zip", "CSharp");
|
||
|
||
// - project name and directory
|
||
string solutionDirectory = Directory.GetParent(dte.Solution.FullName).FullName;
|
||
string projectDirectory = TestUtils.GetNewDirectoryName(solutionDirectory, projectName);
|
||
|
||
// - create the C# project
|
||
EnvDTE.Project returnedProject = dte.Solution.AddFromTemplate(templateFile, projectDirectory, projectName, false);
|
||
|
||
// - find the newly created project (for some reason, AddFromTemplate doesn't return the project)
|
||
string simpleProjectDirectory = Path.GetFileName(projectDirectory);
|
||
string relativeProjectFileName = simpleProjectDirectory + @"\" + projectName + ".csproj";
|
||
|
||
EnvDTE.Project csharpProject = null;
|
||
try
|
||
{
|
||
csharpProject = dte.Solution.Projects.Item(relativeProjectFileName);
|
||
}
|
||
catch(ArgumentException)
|
||
{
|
||
}
|
||
Assert.IsTrue(csharpProject != null, string.Format("Failed to find newly created project. Relative project name: {0}. Solution.Projects.Count: {1}", relativeProjectFileName, dte.Solution.Projects.Count));
|
||
return csharpProject;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get reference to IVsOutputWindowPane interface from pane guid. The method will create the pane if it is not already created.
|
||
/// </summary>
|
||
/// <param name="guidPane">A guid for the pane.</param>
|
||
/// <param name="paneName">The name of the pane.</param>
|
||
/// <param name="visible">Set the visibility state of the pane.</param>
|
||
/// <param name="clearWithSolution">Should the pane be cleared with solution. It is used if the pane will be created by this method.</param>
|
||
/// <returns>A reference to an IVsOutputWindowPane interface.</returns>
|
||
public static IVsOutputWindowPane GetOutputWindowpane(IServiceProvider serviceProvider, Guid guidPane, string paneName, bool visible, bool clearWithSolution)
|
||
{
|
||
IVsOutputWindow outputWindow = serviceProvider.GetService(typeof(IVsOutputWindow)) as IVsOutputWindow;
|
||
if(outputWindow == null)
|
||
{
|
||
throw new InvalidOperationException("Could not get the IVsOutputWindow");
|
||
}
|
||
|
||
IVsOutputWindowPane outputWindowPane = null;
|
||
int hr = outputWindow.GetPane(ref guidPane, out outputWindowPane);
|
||
|
||
if(ErrorHandler.Failed(hr) && outputWindowPane == null)
|
||
{
|
||
if(ErrorHandler.Succeeded(outputWindow.CreatePane(ref guidPane, paneName, visible ? 1 : 0, clearWithSolution ? 1 : 0)))
|
||
{
|
||
outputWindow.GetPane(ref guidPane, out outputWindowPane);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if(!visible)
|
||
{
|
||
outputWindowPane.Hide();
|
||
}
|
||
else
|
||
{
|
||
outputWindowPane.Activate();
|
||
}
|
||
}
|
||
|
||
return outputWindowPane;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// </summary>
|
||
public static partial class TestUtils
|
||
{
|
||
#region Constants
|
||
private const int cmdIdAddFirst = 4609; //0x1201;
|
||
#endregion
|
||
|
||
#region Methods: Handling embedded resources
|
||
/// <summary>
|
||
/// Gets the embedded file identified by the resource name, and converts the
|
||
/// file into a string.
|
||
/// </summary>
|
||
/// <param name="resourceName">In VS, is DefaultNamespace.FileName?</param>
|
||
/// <returns></returns>
|
||
public static string GetEmbeddedStringResource(Assembly assembly, string resourceName)
|
||
{
|
||
string result = null;
|
||
|
||
// Use the .NET procedure for loading a file embedded in the assembly
|
||
Stream stream = assembly.GetManifestResourceStream(resourceName);
|
||
if(stream != null)
|
||
{
|
||
// Convert bytes to string
|
||
byte[] fileContentsAsBytes = new byte[stream.Length];
|
||
stream.Read(fileContentsAsBytes, 0, (int)stream.Length);
|
||
result = Encoding.Default.GetString(fileContentsAsBytes);
|
||
}
|
||
else
|
||
{
|
||
// Embedded resource not found - list available resources
|
||
Debug.WriteLine("Unable to find the embedded resource file '" + resourceName + "'.");
|
||
Debug.WriteLine(" Available resources:");
|
||
foreach(string aResourceName in assembly.GetManifestResourceNames())
|
||
{
|
||
Debug.WriteLine(" " + aResourceName);
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
/// <param name="embeddedResourceName"></param>
|
||
/// <param name="baseFileName"></param>
|
||
/// <param name="fileExtension"></param>
|
||
/// <returns></returns>
|
||
public static void WriteEmbeddedResourceToFile(Assembly assembly, string embeddedResourceName, string fileName)
|
||
{
|
||
// Get file contents
|
||
string fileContents = GetEmbeddedStringResource(assembly, embeddedResourceName);
|
||
if(fileContents == null)
|
||
throw new ApplicationException("Failed to get embedded resource '" + embeddedResourceName + "' from assembly '" + assembly.FullName);
|
||
|
||
// Write to file
|
||
StreamWriter sw = new StreamWriter(fileName);
|
||
sw.Write(fileContents);
|
||
sw.Close();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Writes an embedded resource to a file.
|
||
/// </summary>
|
||
/// <param name="assembly">The name of the assembly that the embedded resource is defined.</param>
|
||
/// <param name="embeddedResourceName">The name of the embedded resource.</param>
|
||
/// <param name="fileName">The file to write the embedded resource's content.</param>
|
||
public static void WriteEmbeddedResourceToBinaryFile(Assembly assembly, string embeddedResourceName, string fileName)
|
||
{
|
||
// Get file contents
|
||
Stream stream = assembly.GetManifestResourceStream(embeddedResourceName);
|
||
if(stream == null)
|
||
throw new InvalidOperationException("Failed to get embedded resource '" + embeddedResourceName + "' from assembly '" + assembly.FullName);
|
||
|
||
// Write to file
|
||
BinaryWriter sw = null;
|
||
FileStream fs = null;
|
||
try
|
||
{
|
||
byte[] fileContentsAsBytes = new byte[stream.Length];
|
||
stream.Read(fileContentsAsBytes, 0, (int)stream.Length);
|
||
|
||
FileMode mode = FileMode.CreateNew;
|
||
if(File.Exists(fileName))
|
||
{
|
||
mode = FileMode.Truncate;
|
||
}
|
||
|
||
fs = new FileStream(fileName, mode);
|
||
|
||
sw = new BinaryWriter(fs);
|
||
sw.Write(fileContentsAsBytes);
|
||
}
|
||
finally
|
||
{
|
||
if(fs != null)
|
||
{
|
||
fs.Close();
|
||
}
|
||
if(sw != null)
|
||
{
|
||
sw.Close();
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Methods: Handling temporary files and directories
|
||
/// <summary>
|
||
/// Returns the first available file name on the form
|
||
/// [baseFileName]i.[extension]
|
||
/// where [i] starts at 1 and increases until there is an available file name
|
||
/// in the given directory. Also creates an empty file with that name to mark
|
||
/// that file as occupied.
|
||
/// </summary>
|
||
/// <param name="directory">Directory that the file should live in.</param>
|
||
/// <param name="baseFileName"></param>
|
||
/// <param name="extension">may be null, in which case the .[extension] part
|
||
/// is not added.</param>
|
||
/// <returns>Full file name.</returns>
|
||
public static string GetNewFileName(string directory, string baseFileName, string extension)
|
||
{
|
||
// Get the new file name
|
||
string fileName = GetNewFileOrDirectoryNameWithoutCreatingAnything(directory, baseFileName, extension);
|
||
|
||
// Create an empty file to mark it as taken
|
||
StreamWriter sw = new StreamWriter(fileName);
|
||
|
||
sw.Write("");
|
||
sw.Close();
|
||
return fileName;
|
||
}
|
||
/// <summary>
|
||
/// Returns the first available directory name on the form
|
||
/// [baseDirectoryName]i
|
||
/// where [i] starts at 1 and increases until there is an available directory name
|
||
/// in the given directory. Also creates the directory to mark it as occupied.
|
||
/// </summary>
|
||
/// <param name="directory">Directory that the file should live in.</param>
|
||
/// <param name="baseDirectoryName"></param>
|
||
/// <returns>Full directory name.</returns>
|
||
public static string GetNewDirectoryName(string directory, string baseDirectoryName)
|
||
{
|
||
// Get the new file name
|
||
string directoryName = GetNewFileOrDirectoryNameWithoutCreatingAnything(directory, baseDirectoryName, null);
|
||
|
||
// Create an empty directory to make it as occupied
|
||
Directory.CreateDirectory(directoryName);
|
||
|
||
return directoryName;
|
||
}
|
||
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
/// <param name="directory"></param>
|
||
/// <param name="baseFileName"></param>
|
||
/// <param name="extension"></param>
|
||
/// <returns></returns>
|
||
private static string GetNewFileOrDirectoryNameWithoutCreatingAnything(string directory, string baseFileName, string extension)
|
||
{
|
||
// - get a file name that we can use
|
||
string fileName;
|
||
int i = 1;
|
||
|
||
string fullFileName = null;
|
||
while(true)
|
||
{
|
||
// construct next file name
|
||
fileName = baseFileName + i;
|
||
if(extension != null)
|
||
fileName += '.' + extension;
|
||
|
||
// check if that file exists in the directory
|
||
fullFileName = Path.Combine(directory, fileName);
|
||
|
||
if(!File.Exists(fullFileName) && !Directory.Exists(fullFileName))
|
||
break;
|
||
else
|
||
i++;
|
||
}
|
||
|
||
return fullFileName;
|
||
}
|
||
#endregion
|
||
|
||
#region Methods: Handling solutions
|
||
/// <summary>
|
||
/// Closes the currently open solution (if any), and creates a new solution with the given name.
|
||
/// </summary>
|
||
/// <param name="solutionName">Name of new solution.</param>
|
||
public static void CreateEmptySolution(IServiceProvider serviceProvider, string destination, string solutionName)
|
||
{
|
||
IVsSolution solutionService = CloseCurrentSolution(serviceProvider);
|
||
|
||
// Create solution
|
||
solutionService.CreateSolution(destination, solutionName, (uint)__VSCREATESOLUTIONFLAGS.CSF_SILENT);
|
||
solutionService.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, null, 0);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Closes the currently open solution
|
||
/// </summary>
|
||
public static IVsSolution CloseCurrentSolution(IServiceProvider serviceProvider)
|
||
{
|
||
// Get solution service
|
||
IVsSolution solutionService = (IVsSolution)serviceProvider.GetService(typeof(IVsSolution));
|
||
|
||
// Close already open solution
|
||
solutionService.CloseSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_NoSave, null, 0);
|
||
|
||
return solutionService;
|
||
}
|
||
|
||
public static void ForceSaveSolution(IServiceProvider serviceProvider)
|
||
{
|
||
// Get solution service
|
||
IVsSolution solutionService = (IVsSolution)serviceProvider.GetService(typeof(IVsSolution));
|
||
|
||
// Force-save the solution
|
||
solutionService.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, null, 0);
|
||
}
|
||
#endregion
|
||
|
||
#region Methods: Handling project items
|
||
/// <summary>
|
||
/// Saves the file for an open document.
|
||
/// </summary>
|
||
/// <param name="fileName"></param>
|
||
public static void SaveDocument(IServiceProvider serviceProvider, string fileName)
|
||
{
|
||
// Get document cookie and hierarchy for the file
|
||
IVsRunningDocumentTable runningDocumentTableService = (IVsRunningDocumentTable)serviceProvider.GetService(typeof(IVsRunningDocumentTable));
|
||
uint docCookie;
|
||
IntPtr docData;
|
||
IVsHierarchy hierarchy;
|
||
uint itemId;
|
||
runningDocumentTableService.FindAndLockDocument(
|
||
(uint)Microsoft.VisualStudio.Shell.Interop._VSRDTFLAGS.RDT_NoLock,
|
||
fileName,
|
||
out hierarchy,
|
||
out itemId,
|
||
out docData,
|
||
out docCookie);
|
||
|
||
// Save the document
|
||
IVsSolution solutionService = (IVsSolution)serviceProvider.GetService(typeof(IVsSolution));
|
||
solutionService.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, hierarchy, docCookie);
|
||
}
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
/// <param name="fullFileName"></param>
|
||
public static void CloseInEditorWithoutSaving(IServiceProvider serviceProvider, string fullFileName)
|
||
{
|
||
#region Input validation
|
||
Debug.Assert(serviceProvider != null, "ServiceProvider cannot be null");
|
||
Debug.Assert(fullFileName != null && fullFileName.Length > 0, "fullFileName cannot be empty");
|
||
#endregion
|
||
|
||
// Get the RDT service
|
||
IVsRunningDocumentTable runningDocumentTableService = (IVsRunningDocumentTable)serviceProvider.GetService(typeof(IVsRunningDocumentTable));
|
||
Debug.Assert(runningDocumentTableService != null, "Failed to get the Running Document Table Service");
|
||
|
||
// Get our document cookie and hierarchy for the file
|
||
uint docCookie;
|
||
IntPtr docData;
|
||
IVsHierarchy hierarchy;
|
||
uint itemId;
|
||
runningDocumentTableService.FindAndLockDocument(
|
||
(uint)Microsoft.VisualStudio.Shell.Interop._VSRDTFLAGS.RDT_NoLock,
|
||
fullFileName,
|
||
out hierarchy,
|
||
out itemId,
|
||
out docData,
|
||
out docCookie);
|
||
|
||
// Get the SolutionService
|
||
IVsSolution solutionService = serviceProvider.GetService(typeof(IVsSolution)) as IVsSolution;
|
||
Debug.Assert(solutionService != null, "Failed to get IVsSolution service");
|
||
|
||
// Close the document
|
||
solutionService.CloseSolutionElement(
|
||
(uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_NoSave,
|
||
hierarchy,
|
||
docCookie);
|
||
}
|
||
#endregion
|
||
|
||
#region Methods: Handling commands
|
||
/// <summary>
|
||
/// Executes a Command (menu item) in the given context
|
||
/// </summary>
|
||
/// <param name="dte"></param>
|
||
/// <param name="cmd"></param>
|
||
public static void ExecuteCommand(EnvDTE.DTE dte, CommandID cmd)
|
||
{
|
||
object Customin = null;
|
||
object Customout = null;
|
||
string guidString = cmd.Guid.ToString("B").ToUpper();
|
||
int cmdId = cmd.ID;
|
||
dte.Commands.Raise(guidString, cmdId, ref Customin, ref Customout);
|
||
}
|
||
#endregion
|
||
|
||
#region Methods: Loading packages
|
||
public static IVsPackage LoadPackage(IServiceProvider serviceProvider, Guid packageGuid)
|
||
{
|
||
IVsShell shellService = (IVsShell)serviceProvider.GetService(typeof(SVsShell));
|
||
IVsPackage package;
|
||
shellService.LoadPackage(ref packageGuid, out package);
|
||
Assert.IsNotNull(package, "Failed to load package");
|
||
return package;
|
||
}
|
||
#endregion
|
||
}
|
||
}
|