This commit is contained in:
vitaliiy@outlook.com 2014-03-12 20:32:09 -07:00
parent 8b61ca41fa
commit 17883e16e1
41 changed files with 3173 additions and 0 deletions

View file

@ -0,0 +1,359 @@

namespace Microsoft.VsSDK.IntegrationTestLibrary
{
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell;
/// <summary>
/// This class is responsible to close dialog boxes that pop up during different VS Calls
/// </summary>
internal class DialogBoxPurger : IDisposable
{
/// <summary>
/// The default number of milliseconds to wait for the threads to signal to terminate.
/// </summary>
private const int DefaultMillisecondsToWait = 3500;
/// <summary>
/// Object used for synchronization between thread calls.
/// </summary>
internal static volatile object Mutex = new object();
/// <summary>
/// The IVsUIShell. This cannot be queried on the working thread from the service provider. Must be done in the main thread.!!
/// </summary>
private IVsUIShell uiShell;
/// <summary>
/// The button to "press" on the dialog.
/// </summary>
private int buttonAction;
/// <summary>
/// Thread signales to the calling thread that it is done.
/// </summary>
private bool exitThread = false;
/// <summary>
/// Calling thread signales to this thread to die.
/// </summary>
private AutoResetEvent threadDone = new AutoResetEvent(false);
/// <summary>
/// The queued thread started.
/// </summary>
private AutoResetEvent threadStarted = new AutoResetEvent(false);
/// <summary>
/// The result of the dialogbox closing for all the dialog boxes. That is if there are two of them and one fails this will be false.
/// </summary>
private bool dialogBoxCloseResult = false;
/// <summary>
/// The expected text to see on the dialog box. If set the thread will continue finding the dialog box with this text.
/// </summary>
private string expectedDialogBoxText = String.Empty;
/// <summary>
/// The number of the same dialog boxes to wait for.
/// This is for scenarios when two dialog boxes with the same text are popping up.
/// </summary>
private int numberOfDialogsToWaitFor = 1;
/// <summary>
/// Has the object been disposed.
/// </summary>
private bool isDisposed;
/// <summary>
/// Overloaded ctor.
/// </summary>
/// <param name="buttonAction">The botton to "press" on the dialog box.</param>
/// <param name="numberOfDialogsToWaitFor">The number of dialog boxes with the same message to wait for. This is the situation when the same action pops up two of the same dialog boxes</param>
/// <param name="expectedDialogMesssage">The expected dialog box message to check for.</param>
internal DialogBoxPurger(int buttonAction, int numberOfDialogsToWaitFor, string expectedDialogMesssage)
{
this.buttonAction = buttonAction;
this.numberOfDialogsToWaitFor = numberOfDialogsToWaitFor;
this.expectedDialogBoxText = expectedDialogMesssage;
}
/// <summary>
/// Overloaded ctor.
/// </summary>
/// <param name="buttonAction">The botton to "press" on the dialog box.</param>
/// <param name="numberOfDialogsToWaitFor">The number of dialog boxes with the same message to wait for. This is the situation when the same action pops up two of the same dialog boxes</param>
internal DialogBoxPurger(int buttonAction, int numberOfDialogsToWaitFor)
{
this.buttonAction = buttonAction;
this.numberOfDialogsToWaitFor = numberOfDialogsToWaitFor;
}
/// <summary>
/// Overloaded ctor.
/// </summary>
/// <param name="buttonAction">The botton to "press" on the dialog box.</param>
/// <param name="expectedDialogMesssage">The expected dialog box message to check for.</param>
internal DialogBoxPurger(int buttonAction, string expectedDialogMesssage)
{
this.buttonAction = buttonAction;
this.expectedDialogBoxText = expectedDialogMesssage;
}
/// <summary>
/// Overloaded ctor.
/// </summary>
/// <param name="buttonAction">The botton to "press" on the dialog box.</param>
internal DialogBoxPurger(int buttonAction)
{
this.buttonAction = buttonAction;
}
/// <summary>
#region IDisposable Members
void IDisposable.Dispose()
{
if (this.isDisposed)
{
return;
}
this.WaitForDialogThreadToTerminate();
this.isDisposed = true;
}
/// <summary>
/// Spawns a thread that will start listening to dialog boxes.
/// </summary>
internal void Start()
{
// We ask for the uishell here since we cannot do that on the therad that we will spawn.
IVsUIShell uiShell = Package.GetGlobalService(typeof(SVsUIShell)) as IVsUIShell;
if (uiShell == null)
{
throw new InvalidOperationException("Could not get the uiShell from the serviceProvider");
}
this.uiShell = uiShell;
System.Threading.Thread thread = new System.Threading.Thread(new ThreadStart(this.HandleDialogBoxes));
thread.Start();
// We should never deadlock here, hence do not use the lock. Wait to be sure that the thread started.
this.threadStarted.WaitOne(3500, false);
}
/// <summary>
/// Waits for the dialog box close thread to terminate. If the thread does not signal back within millisecondsToWait that it is shutting down,
/// then it will tell to the thread to do it.
/// </summary>
internal bool WaitForDialogThreadToTerminate()
{
return this.WaitForDialogThreadToTerminate(DefaultMillisecondsToWait);
}
/// <summary>
/// Waits for the dialog box close thread to terminate. If the thread does not signal back within millisecondsToWait that it is shutting down,
/// then it will tell to the thread to do it.
/// </summary>
/// <param name="millisecondsToWait">The number milliseconds to wait for until the dialog purger thread is signaled to terminate. This is just for safe precaution that we do not hang. </param>
/// <returns>The result of the dialog boxes closing</returns>
internal bool WaitForDialogThreadToTerminate(int numberOfMillisecondsToWait)
{
bool signaled = false;
// We give millisecondsToWait sec to bring up and close the dialog box.
signaled = this.threadDone.WaitOne(numberOfMillisecondsToWait, false);
// Kill the thread since a timeout occured.
if (!signaled)
{
lock (Mutex)
{
// Set the exit thread to true. Next time the thread will kill itselfes if it sees
this.exitThread = true;
}
// Wait for the thread to finish. We should never deadlock here.
this.threadDone.WaitOne();
}
return this.dialogBoxCloseResult;
}
/// <summary>
/// This is the thread method.
/// </summary>
private void HandleDialogBoxes()
{
// No synchronization numberOfDialogsToWaitFor since it is readonly
IntPtr[] hwnds = new IntPtr[this.numberOfDialogsToWaitFor];
bool[] dialogBoxCloseResults = new bool[this.numberOfDialogsToWaitFor];
try
{
// Signal that we started
lock (Mutex)
{
this.threadStarted.Set();
}
// The loop will be exited either if a message is send by the caller thread or if we found the dialog. If a message box text is specified the loop will not exit until the dialog is found.
bool stayInLoop = true;
int dialogBoxesToWaitFor = 1;
while (stayInLoop)
{
int hwndIndex = dialogBoxesToWaitFor - 1;
// We need to lock since the caller might set context to null.
lock (Mutex)
{
if (this.exitThread)
{
break;
}
// We protect the shell too from reentrency.
this.uiShell.GetDialogOwnerHwnd(out hwnds[hwndIndex]);
}
if (hwnds[hwndIndex] != IntPtr.Zero)
{
StringBuilder windowClassName = new StringBuilder(256);
NativeMethods.GetClassName(hwnds[hwndIndex], windowClassName, windowClassName.Capacity);
// The #32770 is the class name of a messagebox dialog.
if (windowClassName.ToString().Contains("#32770"))
{
IntPtr unmanagedMemoryLocation = IntPtr.Zero;
string dialogBoxText = String.Empty;
try
{
unmanagedMemoryLocation = Marshal.AllocHGlobal(10 * 1024);
NativeMethods.EnumChildWindows(hwnds[hwndIndex], new NativeMethods.CallBack(FindMessageBoxString), unmanagedMemoryLocation);
dialogBoxText = Marshal.PtrToStringUni(unmanagedMemoryLocation);
}
finally
{
if (unmanagedMemoryLocation != IntPtr.Zero)
{
Marshal.FreeHGlobal(unmanagedMemoryLocation);
}
}
lock (Mutex)
{
// Since this is running on the main thread be sure that we close the dialog.
bool dialogCloseResult = false;
if (this.buttonAction != 0)
{
dialogCloseResult = NativeMethods.EndDialog(hwnds[hwndIndex], this.buttonAction);
}
// Check if we have found the right dialog box.
if (String.IsNullOrEmpty(this.expectedDialogBoxText) || (!String.IsNullOrEmpty(dialogBoxText) && String.Compare(this.expectedDialogBoxText, dialogBoxText.Trim(), StringComparison.OrdinalIgnoreCase) == 0))
{
dialogBoxCloseResults[hwndIndex] = dialogCloseResult;
if (dialogBoxesToWaitFor++ >= this.numberOfDialogsToWaitFor)
{
stayInLoop = false;
}
}
}
}
}
}
}
finally
{
//Let the main thread run a possible close command.
System.Threading.Thread.Sleep(2000);
foreach (IntPtr hwnd in hwnds)
{
// At this point the dialog should be closed, if not attempt to close it.
if (hwnd != IntPtr.Zero)
{
NativeMethods.SendMessage(hwnd, NativeMethods.WM_CLOSE, 0, new IntPtr(0));
}
}
lock (Mutex)
{
// Be optimistic.
this.dialogBoxCloseResult = true;
for (int i = 0; i < dialogBoxCloseResults.Length; i++)
{
if (!dialogBoxCloseResults[i])
{
this.dialogBoxCloseResult = false;
break;
}
}
this.threadDone.Set();
}
}
}
/// <summary>
/// Finds a messagebox string on a messagebox.
/// </summary>
/// <param name="hwnd">The windows handle of the dialog</param>
/// <param name="unmanagedMemoryLocation">A pointer to the memorylocation the string will be written to</param>
/// <returns>True if found.</returns>
private static bool FindMessageBoxString(IntPtr hwnd, IntPtr unmanagedMemoryLocation)
{
StringBuilder sb = new StringBuilder(512);
NativeMethods.GetClassName(hwnd, sb, sb.Capacity);
if (sb.ToString().ToLower().Contains("static"))
{
StringBuilder windowText = new StringBuilder(2048);
NativeMethods.GetWindowText(hwnd, windowText, windowText.Capacity);
if (windowText.Length > 0)
{
IntPtr stringAsPtr = IntPtr.Zero;
try
{
stringAsPtr = Marshal.StringToHGlobalAnsi(windowText.ToString());
char[] stringAsArray = windowText.ToString().ToCharArray();
// Since unicode characters are copied check if we are out of the allocated length.
// If not add the end terminating zero.
if ((2 * stringAsArray.Length) + 1 < 2048)
{
Marshal.Copy(stringAsArray, 0, unmanagedMemoryLocation, stringAsArray.Length);
Marshal.WriteInt32(unmanagedMemoryLocation, 2 * stringAsArray.Length, 0);
}
}
finally
{
if (stringAsPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(stringAsPtr);
}
}
return false;
}
}
return true;
}
#endregion
}
}

View file

@ -0,0 +1,154 @@
/***************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
This code is licensed under the Visual Studio SDK license terms.
THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
***************************************************************************/
namespace Microsoft.VsSDK.IntegrationTestLibrary
{
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.VisualStudio.Shell.Interop;
/// <summary>
/// Defines pinvoked utility methods and internal VS Constants
/// </summary>
internal static class NativeMethods
{
internal delegate bool CallBack(IntPtr hwnd, IntPtr lParam);
// Declare two overloaded SendMessage functions
[DllImport("user32.dll")]
internal static extern UInt32 SendMessage(IntPtr hWnd, UInt32 Msg,
UInt32 wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
internal static extern bool PeekMessage([In, Out] ref Microsoft.VisualStudio.OLE.Interop.MSG msg, HandleRef hwnd, int msgMin, int msgMax, int remove);
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
internal static extern bool TranslateMessage([In, Out] ref Microsoft.VisualStudio.OLE.Interop.MSG msg);
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
internal static extern int DispatchMessage([In] ref Microsoft.VisualStudio.OLE.Interop.MSG msg);
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
internal static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool attach);
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
internal static extern uint GetCurrentThreadId();
[DllImport("user32")]
internal static extern int EnumChildWindows(IntPtr hwnd, CallBack x, IntPtr y);
[DllImport("user32")]
internal static extern bool IsWindowVisible(IntPtr hDlg);
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
internal static extern IntPtr SetFocus(IntPtr hWnd);
[DllImport("user32")]
internal static extern int GetClassName(IntPtr hWnd,
StringBuilder className,
int stringLength);
[DllImport("user32")]
internal static extern int GetWindowText(IntPtr hWnd, StringBuilder className, int stringLength);
[DllImport("user32")]
internal static extern bool EndDialog(IntPtr hDlg, int result);
[DllImport("Kernel32")]
internal static extern long GetLastError();
internal const int QS_KEY = 0x0001,
QS_MOUSEMOVE = 0x0002,
QS_MOUSEBUTTON = 0x0004,
QS_POSTMESSAGE = 0x0008,
QS_TIMER = 0x0010,
QS_PAINT = 0x0020,
QS_SENDMESSAGE = 0x0040,
QS_HOTKEY = 0x0080,
QS_ALLPOSTMESSAGE = 0x0100,
QS_MOUSE = QS_MOUSEMOVE | QS_MOUSEBUTTON,
QS_INPUT = QS_MOUSE | QS_KEY,
QS_ALLEVENTS = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY,
QS_ALLINPUT = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE;
internal const int Facility_Win32 = 7;
internal const int WM_CLOSE = 0x0010;
internal const int
S_FALSE = 0x00000001,
S_OK = 0x00000000,
IDOK = 1,
IDCANCEL = 2,
IDABORT = 3,
IDRETRY = 4,
IDIGNORE = 5,
IDYES = 6,
IDNO = 7,
IDCLOSE = 8,
IDHELP = 9,
IDTRYAGAIN = 10,
IDCONTINUE = 11;
internal static long HResultFromWin32(long error)
{
if (error <= 0)
{
return error;
}
return ((error & 0x0000FFFF) | (Facility_Win32 << 16) | 0x80000000);
}
/// <devdoc>
/// Please use this "approved" method to compare file names.
/// </devdoc>
public static bool IsSamePath(string file1, string file2)
{
if (file1 == null || file1.Length == 0)
{
return (file2 == null || file2.Length == 0);
}
Uri uri1 = null;
Uri uri2 = null;
try
{
if (!Uri.TryCreate(file1, UriKind.Absolute, out uri1) || !Uri.TryCreate(file2, UriKind.Absolute, out uri2))
{
return false;
}
if (uri1 != null && uri1.IsFile && uri2 != null && uri2.IsFile)
{
return 0 == String.Compare(uri1.LocalPath, uri2.LocalPath, StringComparison.OrdinalIgnoreCase);
}
return file1 == file2;
}
catch (UriFormatException e)
{
System.Diagnostics.Trace.WriteLine("Exception " + e.Message);
}
return false;
}
}
}

View file

@ -0,0 +1,401 @@
using System;
using System.IO;
using System.Text;
using System.Reflection;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell;
using EnvDTE;
using EnvDTE80;
using Microsoft.Win32;
using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VSSDK.Tools.VsIdeTesting;
using Microsoft.VisualStudio;
namespace Microsoft.VsSDK.IntegrationTestLibrary
{
/// <summary>
/// </summary>
public class TestUtils
{
#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 void CreateEmptySolution(string directory, string solutionName)
{
CloseCurrentSolution(__VSSLNSAVEOPTIONS.SLNSAVEOPT_NoSave);
string solutionDirectory = GetNewDirectoryName(directory, solutionName);
// Create and force save solution
IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution));
solutionService.CreateSolution(solutionDirectory, solutionName, (uint)__VSCREATESOLUTIONFLAGS.CSF_SILENT);
solutionService.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, null, 0);
DTE dte = VsIdeTestHostContext.Dte;
Assert.AreEqual(solutionName + ".sln", Path.GetFileName(dte.Solution.FileName), "Newly created solution has wrong Filename");
}
public void CloseCurrentSolution(__VSSLNSAVEOPTIONS saveoptions)
{
// Get solution service
IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution));
// Close already open solution
solutionService.CloseSolutionElement((uint)saveoptions, null, 0);
}
public void ForceSaveSolution()
{
// Get solution service
IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution));
// Force-save the solution
solutionService.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, null, 0);
}
/// <summary>
/// Get current number of open project in solution
/// </summary>
/// <returns></returns>
public int ProjectCount()
{
// Get solution service
IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution));
object projectCount;
solutionService.GetProperty((int)__VSPROPID.VSPROPID_ProjectCount, out projectCount);
return (int)projectCount;
}
#endregion
#region Methods: Handling projects
/// <summary>
/// Creates a project.
/// </summary>
/// <param name="projectName">Name of new project.</param>
/// <param name="templateName">Name of project template to use</param>
/// <param name="language">language</param>
/// <returns>New project.</returns>
public void CreateProjectFromTemplate(string projectName, string templateName, string language, bool exclusive)
{
DTE dte = (DTE)VsIdeTestHostContext.ServiceProvider.GetService(typeof(DTE));
Solution2 sol = dte.Solution as Solution2;
string projectTemplate = sol.GetProjectTemplate(templateName, language);
// - project name and directory
string solutionDirectory = Directory.GetParent(dte.Solution.FullName).FullName;
string projectDirectory = GetNewDirectoryName(solutionDirectory, projectName);
dte.Solution.AddFromTemplate(projectTemplate, projectDirectory, projectName, false);
}
#endregion
#region Methods: Handling project items
/// <summary>
/// Create a new item in the project
/// </summary>
/// <param name="parent">the parent collection for the new item</param>
/// <param name="templateName"></param>
/// <param name="language"></param>
/// <param name="name"></param>
/// <returns></returns>
public ProjectItem AddNewItemFromVsTemplate(ProjectItems parent, string templateName, string language, string name)
{
if (parent == null)
throw new ArgumentException("project");
if (name == null)
throw new ArgumentException("name");
DTE dte = (DTE)VsIdeTestHostContext.ServiceProvider.GetService(typeof(DTE));
Solution2 sol = dte.Solution as Solution2;
string filename = sol.GetProjectItemTemplate(templateName, language);
parent.AddFromTemplate(filename, name);
return parent.Item(name);
}
/// <summary>
/// Save an open document.
/// </summary>
/// <param name="documentMoniker">for filebased documents this is the full path to the document</param>
public void SaveDocument(string documentMoniker)
{
// Get document cookie and hierarchy for the file
IVsRunningDocumentTable runningDocumentTableService = (IVsRunningDocumentTable)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsRunningDocumentTable));
uint docCookie;
IntPtr docData;
IVsHierarchy hierarchy;
uint itemId;
runningDocumentTableService.FindAndLockDocument(
(uint)Microsoft.VisualStudio.Shell.Interop._VSRDTFLAGS.RDT_NoLock,
documentMoniker,
out hierarchy,
out itemId,
out docData,
out docCookie);
// Save the document
IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution));
solutionService.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, hierarchy, docCookie);
}
public void CloseInEditorWithoutSaving(string fullFileName)
{
// Get the RDT service
IVsRunningDocumentTable runningDocumentTableService = (IVsRunningDocumentTable)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsRunningDocumentTable));
Assert.IsNotNull(runningDocumentTableService, "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 = VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution)) as IVsSolution;
Assert.IsNotNull(solutionService, "Failed to get IVsSolution service");
// Close the document
solutionService.CloseSolutionElement(
(uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_NoSave,
hierarchy,
docCookie);
}
#endregion
#region Methods: Handling Toolwindows
public bool CanFindToolwindow(Guid persistenceGuid)
{
IVsUIShell uiShellService = VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsUIShell)) as IVsUIShell;
Assert.IsNotNull(uiShellService);
IVsWindowFrame windowFrame;
int hr = uiShellService.FindToolWindow((uint)__VSFINDTOOLWIN.FTW_fFindFirst, ref persistenceGuid, out windowFrame);
Assert.IsTrue(hr == VSConstants.S_OK);
return (windowFrame != null);
}
#endregion
#region Methods: Loading packages
public IVsPackage LoadPackage(Guid packageGuid)
{
IVsShell shellService = (IVsShell)VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsShell));
IVsPackage package;
shellService.LoadPackage(ref packageGuid, out package);
Assert.IsNotNull(package, "Failed to load package");
return package;
}
#endregion
/// <summary>
/// Executes a Command (menu item) in the given context
/// </summary>
public void ExecuteCommand(CommandID cmd)
{
object Customin = null;
object Customout = null;
string guidString = cmd.Guid.ToString("B").ToUpper();
int cmdId = cmd.ID;
DTE dte = VsIdeTestHostContext.Dte;
dte.Commands.Raise(guidString, cmdId, ref Customin, ref Customout);
}
}
}