using System; using System.ComponentModel.Design; using System.Globalization; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System.Collections.Generic; using EnvDTE; using EnvDTE80; using Microsoft.VisualStudio; using System.Linq; using TestStack.White.UIItems.Finders; using TestStack.White.InputDevices; using TestStack.White.UIItems; using VSLangProj; using System.Runtime.InteropServices; using TestStack.White.WindowsAPI; using System.IO; using Microsoft.VisualStudio.Threading; namespace Tango.BuildExtensions { public class VSIXBase { private IVsThreadedWaitDialog2 _vsProgress = null; public IServiceProvider BaseServiceProvider { get; private set; } public DTE2 DTE { get; private set; } public VSIXBase(IServiceProvider serviceProvider) { BaseServiceProvider = serviceProvider; DTE = GetActiveIDE(); } #region Solution & Projects private DTE2 GetActiveIDE() { // Get an instance of currently running Visual Studio IDE. DTE2 dte2 = Package.GetGlobalService(typeof(DTE)) as DTE2; return dte2; } public IList GetSolutionProjects() { Projects projects = GetActiveIDE().Solution.Projects; List list = new List(); var item = projects.GetEnumerator(); while (item.MoveNext()) { var project = item.Current as Project; if (project == null) { continue; } if (project.Kind == ProjectKinds.vsProjectKindSolutionFolder) { list.AddRange(GetSolutionFolderProjects(project)); } else { list.Add(project); } } return list; } private IEnumerable GetSolutionFolderProjects(Project solutionFolder) { List list = new List(); for (var i = 1; i <= solutionFolder.ProjectItems.Count; i++) { var subProject = solutionFolder.ProjectItems.Item(i).SubProject; if (subProject == null) { continue; } // If this is another solution folder, do a recursive call, otherwise add if (subProject.Kind == ProjectKinds.vsProjectKindSolutionFolder) { list.AddRange(GetSolutionFolderProjects(subProject)); } else { list.Add(subProject); } } return list; } public List GetProjectItems(Project project) { List results = new List(); FillProjectItems(project.ProjectItems.OfType().ToList(), results); return results; } private void FillProjectItems(List rootItems, List results) { foreach (var item in rootItems) { results.Add(item); if (item.ProjectItems.Count > 0) { FillProjectItems(item.ProjectItems.OfType().ToList(), results); } } } protected String GetProjectOutputFilePath(EnvDTE.Project vsProject) { string fullPath = vsProject.Properties.Item("FullPath").Value.ToString(); string outputPath = vsProject.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath").Value.ToString(); string outputDir = Path.Combine(fullPath, outputPath); string outputFileName = vsProject.Properties.Item("OutputFileName").Value.ToString(); string assemblyPath = Path.Combine(outputDir, outputFileName); return assemblyPath; } protected void SelectSolutionExplorerNode(string nodePath) { EnvDTE.UIHierarchyItem item; try { item = DTE.ToolWindows.SolutionExplorer.GetItem(nodePath); item.Select(vsUISelectionType.vsUISelectionTypeSelect); } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.ToString()); } } protected void ExpandSolutionExplorerNode(string nodePath) { EnvDTE.UIHierarchyItem item; try { var explorer = DTE.ToolWindows.SolutionExplorer; item = explorer.GetItem(nodePath); item.Select(vsUISelectionType.vsUISelectionTypeSelect); if (!item.UIHierarchyItems.Expanded) { explorer.DoDefaultAction(); } } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.ToString()); } } #endregion #region Notifications public void WriteToConsole(String text) { ThreadHelper.ThrowIfNotOnUIThread(); // Get the output window var outputWindow = Package.GetGlobalService(typeof(SVsOutputWindow)) as IVsOutputWindow; // Ensure that the desired pane is visible var paneGuid = Microsoft.VisualStudio.VSConstants.OutputWindowPaneGuid.GeneralPane_guid; IVsOutputWindowPane pane; outputWindow.CreatePane(paneGuid, "General", 1, 0); outputWindow.GetPane(paneGuid, out pane); // Output the message pane.OutputString(text + Environment.NewLine); } public void ShowMessage(String text) { // Show a message box to prove we were here VsShellUtilities.ShowMessageBox( BaseServiceProvider, text, "Tango", OLEMSGICON.OLEMSGICON_INFO, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } #endregion #region Windows API protected WindowInfo WaitForWindowOpen(String title) { WindowInfo window = null; do { window = WindowInfo.GetAllWindows().SelectMany(x => x.Children).FirstOrDefault(x => x.Caption == title); } while (window == null); return window; } protected void WaitForWindowClose(String title) { while (WindowInfo.GetAllWindows().SelectMany(x => x.Children).ToList().Exists(x => x.Caption == title)) { System.Threading.Thread.Sleep(100); } } #endregion #region Threading protected void Wait(int milli) { System.Threading.Thread.Sleep(milli); } #endregion #region Status Form protected void OpenVSProgress(String title, String message, bool intermediate) { #pragma warning disable VSTHRD001 // Avoid legacy thread switching APIs ThreadHelper.Generic.Invoke(() => #pragma warning restore VSTHRD001 // Avoid legacy thread switching APIs { _vsProgress = null; ThreadHelper.ThrowIfNotOnUIThread(); IVsThreadedWaitDialogFactory dialogFactory = BaseServiceProvider.GetService(typeof(SVsThreadedWaitDialogFactory)) as IVsThreadedWaitDialogFactory; dialogFactory.CreateInstance(out _vsProgress); if (intermediate) { _vsProgress.StartWaitDialog(title, message, "", null, null, 0, false, true); } else { _vsProgress.StartWaitDialogWithPercentageProgress(title, message, "", null, null, false, 0, 0, 100); } }); } protected void SetVSProgress(String message, String progressText = null, int current = 0, int total = 0) { #pragma warning disable VSTHRD001 // Avoid legacy thread switching APIs ThreadHelper.Generic.Invoke(() => #pragma warning restore VSTHRD001 // Avoid legacy thread switching APIs { ThreadHelper.ThrowIfNotOnUIThread(); bool c; _vsProgress.UpdateProgress(message, progressText, null, current, total, true, out c); }); } protected void CloseVSProgress() { #pragma warning disable VSTHRD001 // Avoid legacy thread switching APIs ThreadHelper.Generic.Invoke(() => #pragma warning restore VSTHRD001 // Avoid legacy thread switching APIs { _vsProgress.EndWaitDialog(); }); } #endregion #region Content protected string GetFullPathToContentFile(String fileName) { return Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase), fileName).Replace("file:\\", ""); } #endregion #region IO /// /// Copies the specified directory source path to the specified destination. /// /// The source path. /// The destination path. /// if set to true will copy sub directories. /// Source directory does not exist or could not be found: " /// + sourcePath protected void CopyDirectory(string sourcePath, string destinationPath, bool copySubDirs, Action progress = null) { // Get the subdirectories for the specified directory. DirectoryInfo dir = new DirectoryInfo(sourcePath); if (!dir.Exists) { throw new DirectoryNotFoundException( "Source directory does not exist or could not be found: " + sourcePath); } DirectoryInfo[] dirs = dir.GetDirectories(); // If the destination directory doesn't exist, create it. if (!Directory.Exists(destinationPath)) { Directory.CreateDirectory(destinationPath); } // Get the files in the directory and copy them to the new location. FileInfo[] files = dir.GetFiles(); foreach (FileInfo file in files) { string temppath = Path.Combine(destinationPath, file.Name); progress?.Invoke(temppath); file.CopyTo(temppath, true); } // If copying subdirectories, copy them and their contents to new location. if (copySubDirs) { foreach (DirectoryInfo subdir in dirs) { string temppath = Path.Combine(destinationPath, subdir.Name); CopyDirectory(subdir.FullName, temppath, copySubDirs); } } } #endregion } }