namespace SolutionOpen { using System; using Microsoft.VisualStudio.CommandBars; using Extensibility; using EnvDTE; using EnvDTE80; using System.Windows.Forms; using System.Collections.Specialized; /// The object for implementing an Add-in. /// public class Connect : Object, IDTExtensibility2, IDTCommandTarget { /// Implements the constructor for the Add-in object. Place your initialization code within this method. public Connect() { } /// Implements the OnConnection method of the IDTExtensibility2 interface. Receives notification that the Add-in is being loaded. /// Root object of the host application. /// Describes how the Add-in is being loaded. /// Object representing this Add-in. /// public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom) { applicationObject = (DTE2)application; addInInstance = (AddIn)addInInst; if (connectMode == ext_ConnectMode.ext_cm_UISetup) { object[] contextGUIDS = new object[] { }; Commands2 commands = (Commands2)applicationObject.Commands; try { //Add a command to the Commands collection: Command command = commands.AddNamedCommand2(addInInstance, "SolutionOpen", "SolutionOpen", "Open files from anywhere within the solution", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton); Command command2 = commands.AddNamedCommand2(addInInstance, "HeaderFlip", "HeaderFlip", "Flips through all the files with the same base name", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton); Command command3 = commands.AddNamedCommand2(addInInstance, "RefreshFileList", "RefreshFileList", "Refreshes the list of files in the solution from the project files", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton); } catch (Exception) { } } } /// Implements the OnDisconnection method of the IDTExtensibility2 interface. Receives notification that the Add-in is being unloaded. /// Describes how the Add-in is being unloaded. /// Array of parameters that are host application specific. /// public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom) { } /// Implements the OnAddInsUpdate method of the IDTExtensibility2 interface. Receives notification when the collection of Add-ins has changed. /// Array of parameters that are host application specific. /// public void OnAddInsUpdate(ref Array custom) { } /// Implements the OnStartupComplete method of the IDTExtensibility2 interface. Receives notification that the host application has completed loading. /// Array of parameters that are host application specific. /// public void OnStartupComplete(ref Array custom) { } /// Implements the OnBeginShutdown method of the IDTExtensibility2 interface. Receives notification that the host application is being unloaded. /// Array of parameters that are host application specific. /// public void OnBeginShutdown(ref Array custom) { } /// Implements the QueryStatus method of the IDTCommandTarget interface. This is called when the command's availability is updated /// The name of the command to determine state for. /// Text that is needed for the command. /// The state of the command in the user interface. /// Text requested by the neededText parameter. /// public void QueryStatus(string commandName, vsCommandStatusTextWanted neededText, ref vsCommandStatus status, ref object commandText) { if (neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone) { if (commandName == "SolutionOpen.Connect.SolutionOpen" || commandName == "SolutionOpen.Connect.HeaderFlip" || commandName == "SolutionOpen.Connect.RefreshFileList") { status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled; } } } private String BaseName(string fullName) { int fileNameStart = fullName.LastIndexOfAny("\\/".ToCharArray()) + 1; int firstDot = fullName.IndexOf('.', fileNameStart); if (firstDot > 0) return fullName.Substring(fileNameStart, (firstDot - fileNameStart)); return fullName; } /// Implements the Exec method of the IDTCommandTarget interface. This is called when the command is invoked. /// The name of the command to execute. /// Describes how the command should be run. /// Parameters passed from the caller to the command handler. /// Parameters passed from the command handler to the caller. /// Informs the caller if the command was handled or not. /// public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled) { handled = false; if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault) { bool refreshFileList = false; if (commandName == "SolutionOpen.Connect.RefreshFileList") { handled = true; refreshFileList = true; } if (refreshFileList || filePaths.Count == 0) { // get the list of files in the project filePaths.Clear(); EnvDTE.Projects projects = applicationObject.Solution.Projects; for (int i = 1; i <= projects.Count; ++i) FindFiles(projects.Item(i).ProjectItems, ref filePaths); // return if all that was requested was a file list refresh if (handled) return; } if (commandName == "SolutionOpen.Connect.SolutionOpen") { // show the dialog box and handle what the user wants to do ChooseFile chooseFile = new ChooseFile(ref applicationObject, ref filePaths); if (chooseFile.ShowDialog() == DialogResult.OK) chooseFile.OpenSelectedFiles(); // clean up chooseFile.Dispose(); handled = true; return; } else if (commandName == "SolutionOpen.Connect.HeaderFlip") { // make sure there is an active document if (applicationObject.ActiveDocument != null) { // Get the current active document and its base name String activeDocumentFullName = applicationObject.ActiveDocument.FullName; String activeDocumentBaseName = BaseName(activeDocumentFullName); // find the files with the same base name StringCollection matchingFilePaths = new StringCollection(); foreach (String fullName in filePaths.Values) { String baseName = BaseName(fullName); if (String.Compare(activeDocumentBaseName, baseName, true) == 0) matchingFilePaths.Add(fullName); } // make sure that we have more than one of them open before we try to switch if (matchingFilePaths.Count > 1) { // figure out which document in the list (if any) is the current document int activeDocumentIndex = -1; for (int i = 0; activeDocumentIndex < 0 && i < matchingFilePaths.Count; ++i) { if (String.Compare(activeDocumentFullName, matchingFilePaths[i], true) == 0) activeDocumentIndex = i; } // make sure we found this document if (activeDocumentIndex >= 0) { // figure out which document comes next int nextDocument = activeDocumentIndex + 1; if (nextDocument >= matchingFilePaths.Count) nextDocument = 0; // open and display that document applicationObject.ItemOperations.OpenFile(matchingFilePaths[nextDocument], EnvDTE.Constants.vsViewKindAny); } } handled = true; return; } } } } private void FindFiles(EnvDTE.ProjectItems projectItems, ref StringDictionary filePaths) { foreach (EnvDTE.ProjectItem projectItem in projectItems) { // check all the files in this project item for (int i = 0; i < projectItem.FileCount; ++i) { // Make sure the project item is a physical file if (projectItem.Kind == "{6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}") { String fileName = projectItem.get_FileNames(1); if (fileName != null) filePaths[fileName] = fileName; } } // recurse into any project items within this project item if (projectItem.ProjectItems != null) FindFiles(projectItem.ProjectItems, ref filePaths); // handle sub-projects if (projectItem.SubProject != null) FindFiles(projectItem.SubProject.ProjectItems, ref filePaths); } } private DTE2 applicationObject; private AddIn addInInstance; private StringDictionary filePaths = new StringDictionary(); } }