Visual Studio Extension: Get the path of the current selected file in the Solution Explorer
Asked Answered
O

2

5

I'm trying to create my first extension for visual studio and so far I've been following this tutorial to get me started (http://www.diaryofaninja.com/blog/2014/02/18/who-said-building-visual-studio-extensions-was-hard). Now I have a custom menu item appearing when I click on a file in the solution explorer. What I need now for my small project is to get the path of the file selected in the solution explorer but I can't understand how can I do that. Any help?

---------------------------- EDIT ------------------------------

As matze said, the answer is in the link I posted. I just didn't notice it when I wrote it. In the meanwhile I also found another possible answer in this thread: How to get the details of the selected item in solution explorer using vs package

where I found this code:

foreach (UIHierarchyItem selItem in selectedItems)
            {
                ProjectItem prjItem = selItem.Object as ProjectItem;
                string filePath = prjItem.Properties.Item("FullPath").Value.ToString();
                //System.Windows.Forms.MessageBox.Show(selItem.Name + filePath);
                return filePath;
            }

So, here are two ways to get the path to the selected file(s) :)

Ormiston answered 8/1, 2016 at 12:35 Comment(0)
C
3

The article you mentioned already contains a solution for that.

Look for the menuCommand_BeforeQueryStatus method in the sample code. It uses the IsSingleProjectItemSelection method to obtain an IVsHierarchy object representing the project as well as the id of the selected item. It seems that you can safely cast the hierarchy to IVsProject and use it´s GetMkDocument function to query the item´s fullpath...

IVsHierarchy hierarchy = null;
uint itemid = VSConstants.VSITEMID_NIL;

if (IsSingleProjectItemSelection(out hierarchy, out itemid))
{
    IVsProject project;
    if ((project = hierarchy as IVsProject) != null)
    {
        string itemFullPath = null;
        project.GetMkDocument(itemid, out itemFullPath);
    }
}

I don´t want to copy the entire code from the article into this answer, but it might be of interest how the IsSingleProjectItemSelection function obtains the selected item; so I just add some notes instead which may guide into the right direction... The method uses the GetCurrentSelection method of the global IVsMonitorSelection service to query to the current selected item.

Chip answered 11/1, 2016 at 19:17 Comment(1)
you're right. I noticed this only a couple of days after. I've been doing it in the spare times so I completely forgot I even set up a class variable with that value. I'm editing the question and adding another possible solutionOrmiston
H
7

For future reference:

//In your async method load the DTE
var dte2 = await ServiceProvider.GetGlobalServiceAsync(typeof(SDTE)) as DTE2;
var selectedItems = dte2.SelectItems;
if(selectedItems.MultiSelect || selectedItems.Count > 1){ //Use either/or
     for(short i = 1; i <= selectedItems.Count; i++){
        //Get selected item
        var selectedItem = selectedItems[i];
        //Get associated project item (selectedItem.ProjectItem  
        //If selectedItem is a project, then selectedItem.ProjectItem will be null,
        //and selectedItem.Project will not be null.
        var projectItem = selectedItem.ProjectItem;
        //Get project for ProjectItem
        var project = projectItem.ContainingProject;
        // Or get project object if selectedItem is a project
        var sproject = selectedItem.Project;
        //Is selectedItem a physical folder?
        var isFolder = projectItem.Kind == EnvDTE.Constants.vsProjectItemKindPhysicalFolder;
        //Else, get item's folder
        var itemFolder = new FileInfo(projectItem.Properties.Item("FullPath").ToString()).Directory;
        //Find config file
        var configFiles itemFolder.GetFiles("web.config");
        var configfile = configFiles.length > 0 ? configFiles[0] : null;
        //Turn config file into ProjectItem object
        var configItem = dte2.solution.FindProjectItem(configFile.FullName);
        
     }
}

I hope someone finds this helpful...

Hasdrubal answered 27/10, 2020 at 16:1 Comment(4)
What is GetGlobalServiceAsync? My ServiceProvider does not offer that methodMallarme
Oh it's now just GetServiceAsyncMallarme
This (and others mentioning how to access the DTE) were a start for me. However, in VS 2022 "ServiceProvider" was null (in the context of an item click handler). Random search at VSIX Community produced an alternative (maybe newest?) way: "AsyncPackage.GetGlobalService(typeof(SDTE)) as DTE2". From there got ActiveDocument.Name and .Path.Lillalillard
github.com/VsixCommunity/Community.VisualStudio.Toolkit/…Lillalillard
C
3

The article you mentioned already contains a solution for that.

Look for the menuCommand_BeforeQueryStatus method in the sample code. It uses the IsSingleProjectItemSelection method to obtain an IVsHierarchy object representing the project as well as the id of the selected item. It seems that you can safely cast the hierarchy to IVsProject and use it´s GetMkDocument function to query the item´s fullpath...

IVsHierarchy hierarchy = null;
uint itemid = VSConstants.VSITEMID_NIL;

if (IsSingleProjectItemSelection(out hierarchy, out itemid))
{
    IVsProject project;
    if ((project = hierarchy as IVsProject) != null)
    {
        string itemFullPath = null;
        project.GetMkDocument(itemid, out itemFullPath);
    }
}

I don´t want to copy the entire code from the article into this answer, but it might be of interest how the IsSingleProjectItemSelection function obtains the selected item; so I just add some notes instead which may guide into the right direction... The method uses the GetCurrentSelection method of the global IVsMonitorSelection service to query to the current selected item.

Chip answered 11/1, 2016 at 19:17 Comment(1)
you're right. I noticed this only a couple of days after. I've been doing it in the spare times so I completely forgot I even set up a class variable with that value. I'm editing the question and adding another possible solutionOrmiston

© 2022 - 2024 — McMap. All rights reserved.