locked
Get Selected Miscellaneous Files RRS feed

  • Question

  • I would like to get a list of the files selected in "Miscellaneous Files". For regular projects, I am able to use Microsoft.VisualStudio.Project.ProjectNode.GetSelectedNodes(), but "Miscellaneous Files" isn't a ProjectNode (right?). 

    Environment: VS 2010 Shell project using mpfproj10

    I'm able to get the uint itemID's of the selected items using IVsMonitorSelection. How do I get from itemID's to a file path?

    Wednesday, October 12, 2011 11:49 PM

Answers

  • Hi Cameron,

    The ISelectionContainer actually contains the automation object used to populate the properties dialog. It's useful when you want to retrieve the properties of a specific object, some toolwindows use this to populate the properties dialog as well, but it's not really useful for this particular scenario.

    Easiest way I can think of, would be to cast the IVsHierarchy you get back, to an IVsProject interface, then call IVsProject.GetMkDocument with the itemID. Just about every IVsHierarchy implementation I've ever seen also implement IVsProject, (at least the ones displayed in Solution Explorer, including the Misc Files project).

    For example:

    IVsMonitorSelection vsMonSel = (IVsMonitorSelection)serviceProvider.GetService(typeof(SVsShellMonitorSelection));
    IntPtr pHier, pSC;
    uint itemID;
    IVsMultiItemSelect vsMIS;
     
    int hr = vsMonSel.GetCurrentSelection(out pHier, out itemID, out vsMIS, out pSC);
    if (hr == 0)
    {
       if (vsMIS != null)
       {
          uint numItems; int fSingleHierarchy;
          hr = vsMIS.GetSelectionInfo(out numItems, out fSingleHierarchy);
     
          if (numItems > 0)
          {
             VSITEMSELECTION[] vsItemSel = new VSITEMSELECTION[numItems];
             hr = vsMIS.GetSelectedItems(0, numItems, vsItemSel);
             if (hr == 0)
             {
                for (uint i = 0; i < numItems; i++ )
                {
                   string fileName;
                   IVsProject vsProj = (IVsProject)vsItemSel[i].pHier;
                   hr = vsProj.GetMkDocument(vsItemSel[i].itemid, out fileName);
                   System.Diagnostics.Debug.WriteLine(fileName);
                }
             }
          }
       }
       else // only one item selected
       {
          string fileName;
          IVsProject vsProj = (IVsProject)Marshal.GetObjectForIUnknown(pHier);
          hr = vsProj.GetMkDocument(itemID, out fileName);
          System.Diagnostics.Debug.WriteLine(fileName);
       }
    }
    

     

    Sincerely,


    Ed Dore
    Thursday, October 13, 2011 3:41 AM

All replies

  • Here is some code with comments that I've been working with derived from GetSelectedNodes():

     

    internal IEnumerable<string> GetSelectedFiles()
    {
        var files = new List<string>();
    
        // Retrieve shell interface in order to get current selection
        var monitorSelection = this.GetService(typeof(IVsMonitorSelection)) as IVsMonitorSelection;
        if (monitorSelection == null)
            throw new InvalidOperationException();
    
        var selected = new List<uint>();
        IntPtr hierarchyPtr = IntPtr.Zero;
        IntPtr selectionContainerPtr = IntPtr.Zero;
        try
        {
            // Get the current project hierarchy, project item, and selection container for the current selection
            // If the selection spans multiple hierachies, hierarchyPtr is Zero
            uint itemid;
            IVsMultiItemSelect multiItemSelect = null;
            ErrorHandler.ThrowOnFailure(monitorSelection.GetCurrentSelection(out hierarchyPtr, out itemid, out multiItemSelect, out selectionContainerPtr));
    
            // Option #1 - get the objects
            // What do I do with the ComObject's?
    
            if (selectionContainerPtr != IntPtr.Zero)
            {
                var selectionContainer = Marshal.GetObjectForIUnknown(selectionContainerPtr) as ISelectionContainer;
                uint count;
                ErrorHandler.ThrowOnFailure(selectionContainer.CountObjects((uint)Microsoft.VisualStudio.Shell.Interop.Constants.GETOBJS_SELECTED, out count));
    
                if (count > 0)
                {
                    var objects = new object[count];
                    selectionContainer.GetObjects((uint)Microsoft.VisualStudio.Shell.Interop.Constants.GETOBJS_SELECTED, count, objects);
                    foreach (var o in objects)
                    {
                        // the objects are of type System.__ComObject
                        // What do I do with them?
                        //var file = ???
                        //files.Add(file);
                    }
                }
            }
    
            // Option #2 - get the item ID
            // What do I do with the item ID's?
    
            // We only care if there are one ore more nodes selected in the tree
            if (itemid != VSConstants.VSITEMID_NIL && hierarchyPtr != IntPtr.Zero)
            {
                var hierarchy = Marshal.GetObjectForIUnknown(hierarchyPtr) as IVsHierarchy;
                if (itemid != VSConstants.VSITEMID_SELECTION)
                {
                    selected.Add(itemid);
                }
                else if (multiItemSelect != null)
                {
                    // This is a multiple item selection.
                    //Get number of items selected and also determine if the items are located in more than one hierarchy
                    uint numberOfSelectedItems;
                    int isSingleHierarchyInt;
                    ErrorHandler.ThrowOnFailure(multiItemSelect.GetSelectionInfo(out numberOfSelectedItems, out isSingleHierarchyInt));
                    bool isSingleHierarchy = (isSingleHierarchyInt != 0);
    
                    VSITEMSELECTION[] vsItemSelections = new VSITEMSELECTION[numberOfSelectedItems];
                    uint flags = (isSingleHierarchy) ? (uint)__VSGSIFLAGS.GSI_fOmitHierPtrs : 0;
                    ErrorHandler.ThrowOnFailure(multiItemSelect.GetSelectedItems(flags, numberOfSelectedItems, vsItemSelections));
                    foreach (VSITEMSELECTION vsItemSelection in vsItemSelections)
                    {
                        selected.Add(vsItemSelection.itemid);
                    }
                }
            }
        }
        finally
        {
            if (hierarchyPtr != IntPtr.Zero)
            {
                Marshal.Release(hierarchyPtr);
            }
            if (selectionContainerPtr != IntPtr.Zero)
            {
                Marshal.Release(selectionContainerPtr);
            }
        }
    
        // Umm... This is wrong, but what do I do with the itemid's?
        //foreach(var itemid in selected)
        //{
        //    object o = Marshal.GetObjectForIUnknown((IntPtr)itemid);
        //    var file = ???
        //    files.Add(file);
        //}
    
        return files;
    }
    


     

     

     

     


    Thursday, October 13, 2011 12:16 AM
  • Hi Cameron,

    The ISelectionContainer actually contains the automation object used to populate the properties dialog. It's useful when you want to retrieve the properties of a specific object, some toolwindows use this to populate the properties dialog as well, but it's not really useful for this particular scenario.

    Easiest way I can think of, would be to cast the IVsHierarchy you get back, to an IVsProject interface, then call IVsProject.GetMkDocument with the itemID. Just about every IVsHierarchy implementation I've ever seen also implement IVsProject, (at least the ones displayed in Solution Explorer, including the Misc Files project).

    For example:

    IVsMonitorSelection vsMonSel = (IVsMonitorSelection)serviceProvider.GetService(typeof(SVsShellMonitorSelection));
    IntPtr pHier, pSC;
    uint itemID;
    IVsMultiItemSelect vsMIS;
     
    int hr = vsMonSel.GetCurrentSelection(out pHier, out itemID, out vsMIS, out pSC);
    if (hr == 0)
    {
       if (vsMIS != null)
       {
          uint numItems; int fSingleHierarchy;
          hr = vsMIS.GetSelectionInfo(out numItems, out fSingleHierarchy);
     
          if (numItems > 0)
          {
             VSITEMSELECTION[] vsItemSel = new VSITEMSELECTION[numItems];
             hr = vsMIS.GetSelectedItems(0, numItems, vsItemSel);
             if (hr == 0)
             {
                for (uint i = 0; i < numItems; i++ )
                {
                   string fileName;
                   IVsProject vsProj = (IVsProject)vsItemSel[i].pHier;
                   hr = vsProj.GetMkDocument(vsItemSel[i].itemid, out fileName);
                   System.Diagnostics.Debug.WriteLine(fileName);
                }
             }
          }
       }
       else // only one item selected
       {
          string fileName;
          IVsProject vsProj = (IVsProject)Marshal.GetObjectForIUnknown(pHier);
          hr = vsProj.GetMkDocument(itemID, out fileName);
          System.Diagnostics.Debug.WriteLine(fileName);
       }
    }
    

     

    Sincerely,


    Ed Dore
    Thursday, October 13, 2011 3:41 AM
  • Hello,

    Would you mind letting me know the result of the suggestions? If you need further assistance, feel free to let me know. I will be more than happy to be of assistance.

    Yi


    Yi Feng Li [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Monday, October 17, 2011 5:46 AM
  • Hi

    1. I need to implement "save all" feature. when user will click on SaveAll button of visual studio. all open editor save successfully. I know that "DTE.Dcoument.Saveall()" function can help but It is not working in case of Custom Editor (IEditor)

    Is there any events which i can right the code and handle my problem.

    • Edited by Mr Vibhu Thursday, December 27, 2012 1:33 PM
    Thursday, December 27, 2012 1:32 PM