且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Visual Studio 扩展:如何获取“路径"选择的解决方案文件夹?

更新时间:2023-10-05 12:20:40

最后,探索(更多)另一个回答我之前问题的人的网站,我终于找到了.所以我将分享一个我用来知道在解决方案资源管理器中选择什么类型的项目的方法.

applicationObject = await ServiceProvider.GetGlobalServiceAsync(typeof(SDTE)) as DTE2;//在一个方法中启动私有枚举 SelectionTypes{其他 = 0,子模块 = 1,IsAFolder = 2,IsAProject = 4,项目中 = 8}私有静态列表获取选择类型(){ThreadHelper.ThrowIfNotOnUIThread();var selectionTypes = new List();EnvDTE.UIHierarchy solutionExplorer = applicationObject.ToolWindows.SolutionExplorer;object[] items = solutionExplorer.SelectedItems as object[];//{ Name = "WindowBase" FullName = "Microsoft.VisualStudio.Platform.WindowManagement.DTE.WindowBase"}if (items.Length > 0){for (int i = 0; i < items.Length; i++){var selectionType = SelectionTypes.Other;var selectedItem = items[0] as EnvDTE.UIHierarchyItem;var currentItem = selectedItem;var subModulesParentsCount = 0;var countingSubModulesParents = false;var nbParents = -1;if (currentItem.Object.GetType().FullName == "Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAProject") selectionType |= SelectionTypes.IsAProject;if (currentItem.Object.GetType().FullName == "Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAFolderItem") selectionType |= SelectionTypes.IsAFolder;while (currentItem != null){nbParents++;if (countingSubModulesParents) subModulesParentsCount++;if (currentItem.Name == "SubModules"){subModulesParentsCount = 0;计数SubModulesParents = true;}if (currentItem.Object.GetType().FullName == "Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAProject") selectionType |= SelectionTypes.InAProject;currentItem = currentItem.Collection.Parent as EnvDTE.UIHierarchyItem;}if (selectionType == SelectionTypes.Other && nbParents != 0) selectionType |= SelectionTypes.IsAFolder;if (subModulesParentsCount == 1){selectionType |= SelectionTypes.InSubModules;}selectionTypes.Add(selectionType);}}返回选择类型;}

Previous question: Visual Studio Extension: How to disable native command?

I build an extension that manages correctly Git Modules and, to do so, I have a folder in the solution called SubModules.

I managed to add my context menu to the solution file and to the project files, but I would like to disable some native commands when right-clicking on my SubModules folder (i.e. Remove, Add).

I now know how to disable the native commands I want, but to do so, I need to get the "path" of the selected Solution Folder.

I tried to implement IVsSelectionEvents, but no luck (o is not null before casting):

public int OnSelectionChanged(IVsHierarchy pHierOld, uint itemidOld, IVsMultiItemSelect pMISOld, ISelectionContainer pSCOld, IVsHierarchy pHierNew, uint itemidNew, IVsMultiItemSelect pMISNew, ISelectionContainer pSCNew)
{
    var o = GetProjectItem(pHierNew, itemidNew);
    return VSConstants.S_OK;
}

private static ProjectItem GetProjectItem(IVsHierarchy hierarchy, uint itemId)
{
    object o;
    if (hierarchy.GetProperty(itemId, (int)__VSHPROPID.VSHPROPID_ExtObject, out o) == VSConstants.S_OK)
    {
        var t = o as SolutionFolder; // ==> null

        return o as ProjectItem; // ==> null
    }
    return null;
}

Using the code I had (from the other question) (where I want to find the "path", but I could have managed with the above "solution"), I tried to cast to SolutionFolder or to FileProperties... still no luck; even though MSDN tells the returned objects are supposed to be of type FileProperties. Exploring with QuickWatch on (Marshal.GetObjectForIUnknown(selectionContainerPtr) as ISelectionContainer), I can go in the see the private property _nodes and there, I can see my SolutionFolder node and go up using its Parent property to ensure it is a folder I want to block commands. Here is the actual code:

private static void CommandEvents_BeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
{
    string name = GetCommandName(Guid, ID);

    if (name == "Project.AddNewSolutionFolder")
    {
        CancelDefault = true;
    }
    if (name == "Edit.Delete")
    {
        CancelDefault = true;

        IVsMultiItemSelect multiItemSelect = null;
        IntPtr hierarchyPtr = IntPtr.Zero;
        IntPtr selectionContainerPtr = IntPtr.Zero;
        uint itemid = 0;

        int hr = monitorSelection.GetCurrentSelection(out hierarchyPtr, out itemid, out multiItemSelect, out selectionContainerPtr);
        object[] selected = new object[2];
        (Marshal.GetObjectForIUnknown(selectionContainerPtr) as ISelectionContainer).GetObjects(2, 1, selected);


        var t = selected[0] as VSLangProj.FileProperties; // ==> null
        var t2 = selected[0] as SolutionFolder; // ==> null
        var b = 1;
    }

    if (name == "View.Branch")
    {
        //TODO: Could disable this command if not able to find the branch changing command (that would be cancelled and launch ours)
        menuBranchOpened = true;
    }

    if (menuBranchOpened)
    {
        var a = 1;
    }

}

I was inspired by and tried (none worked except the above one seems to be really near) :

Finally, exploring (more) the website of the other person who answered me for my previous question, I finally found it. So I will share a method I made to know what type of items are selected in the Solution Explorer.

applicationObject = await ServiceProvider.GetGlobalServiceAsync(typeof(SDTE)) as DTE2; // Was initiate in a method

private enum SelectionTypes
{
    Other = 0,
    InSubModules = 1,
    IsAFolder = 2,
    IsAProject = 4,
    InAProject = 8
}

private static List<SelectionTypes> GetSelectionTypes()
{
    ThreadHelper.ThrowIfNotOnUIThread();
    var selectionTypes = new List<SelectionTypes>();

    EnvDTE.UIHierarchy solutionExplorer = applicationObject.ToolWindows.SolutionExplorer;
    object[] items = solutionExplorer.SelectedItems as object[];
    //{ Name = "WindowBase" FullName = "Microsoft.VisualStudio.Platform.WindowManagement.DTE.WindowBase"}
    if (items.Length > 0)
    {
        for (int i = 0; i < items.Length; i++)
        {
            var selectionType = SelectionTypes.Other;
            var selectedItem = items[0] as EnvDTE.UIHierarchyItem;
            var currentItem = selectedItem;
            var subModulesParentsCount = 0;
            var countingSubModulesParents = false;
            var nbParents = -1;

            if (currentItem.Object.GetType().FullName == "Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAProject") selectionType |= SelectionTypes.IsAProject;
            if (currentItem.Object.GetType().FullName == "Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAFolderItem") selectionType |= SelectionTypes.IsAFolder;

            while (currentItem != null)
            {
                nbParents++;
                if (countingSubModulesParents) subModulesParentsCount++;

                if (currentItem.Name == "SubModules")
                {
                    subModulesParentsCount = 0;
                    countingSubModulesParents = true;
                }

                if (currentItem.Object.GetType().FullName == "Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAProject") selectionType |= SelectionTypes.InAProject;

                currentItem = currentItem.Collection.Parent as EnvDTE.UIHierarchyItem;
            }

            if (selectionType == SelectionTypes.Other && nbParents != 0) selectionType |= SelectionTypes.IsAFolder;

            if (subModulesParentsCount == 1)
            {
                selectionType |= SelectionTypes.InSubModules;
            }

            selectionTypes.Add(selectionType);
        }
    }

    return selectionTypes;
}