Commit
This commit is contained in:
parent
8b61ca41fa
commit
17883e16e1
41 changed files with 3173 additions and 0 deletions
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue