スキップしてメイン コンテンツへ

 none
vsixを使った拡張機能の作成(ソリューションエクスプローラで選択しているファイルのパス取得)について RRS feed

  • 質問

  • Visual Studio 2015 を用いて、vsixを使った機能拡張の作成を行っています。

    ソリューションエクスプローラに1つメニューを追加したのですが、C#プロジェクト配下のファイルであれば、フルパスを取得できます。

    しかし、ソリューションフォルダ以下(C#プロジェクト等に属さない)のファイルの場合は取得できません。

    一般的に公開されている 「copy as path 」(以下パス参照)でもエラーになります。

    https://marketplace.visualstudio.com/items?itemName=AlexEyler.CopyasPath

    これをモデル化されていないプロジェクトというのかと思いますが、

    選択しているファイルのフルパスは取得できないのでしょうか?

    コードはサンプルで以下のように記載しています。

    -----------------------------------------------------------------------

           private void MenuItemCallback(object sender, EventArgs e)
            {
                try
                {
                    Object selectedObject = null;
                    var monitorSelection = Package.GetGlobalService(typeof(SVsShellMonitorSelection)) as IVsMonitorSelection;
    
                    IntPtr hierarchyPointer;
                    uint projectItemId;
                    IVsMultiItemSelect multiItemSelect;
                    IntPtr selectionContainerPointer;
                    monitorSelection.GetCurrentSelection
                    (
                        out hierarchyPointer,
                        out projectItemId,
                        out multiItemSelect,
                        out selectionContainerPointer
                    );
    
                    IVsHierarchy selectedHierarchy = (IVsHierarchy)Marshal.GetTypedObjectForIUnknown(hierarchyPointer, typeof(IVsHierarchy));
                    if (selectedHierarchy != null )
                    {
                        Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure
                        (
                            selectedHierarchy.GetProperty
                            (
                                projectItemId,
                                (int)__VSHPROPID.VSHPROPID_ExtObject,
                                out selectedObject
                            )
                        );
                    }
                    if (selectedHierarchy != null)
                    {
                        Marshal.ReleaseComObject(selectedHierarchy);
                    }
    
                    var selectedProjectItem = selectedObject as ProjectItem;
                    // ↓ここでプルジェクト配下のアイテムではなく、ソリューション配下のアイテムの場合はFullPathがとってこない
                    //   
                    string fullPath = selectedProjectItem.Properties.Item("FullPath").Value.ToString();
    
    ・・・・・

    ご存じの方がいらっしゃいましたら、よろしくお願い致します。
    • 編集済み coco2014 2019年10月11日 2:54
    2019年10月11日 2:53

回答

  • PropertiesではなくFileNamesを使えば取れます

    //string fullPath = selectedProjectItem.Properties.Item("FullPath").Value.ToString();
    
    for (short i = 1; i <= selectedProjectItem.FileCount; i++)
    {
        string path = selectedProjectItem.FileNames[i];
        System.Diagnostics.Debug.WriteLine(path);
    }

    あと、面倒なインターフェースから掘り出すよりもEnvDTEからとったほうが楽です。

    var dte = Package.GetGlobalService(typeof(EnvDTE.DTE)) as EnvDTE80.DTE2;
    if (dte != null)
    {
        foreach (object osel in (object[])dte.ToolWindows.SolutionExplorer.SelectedItems)
        {
            EnvDTE.UIHierarchyItem node = osel as EnvDTE.UIHierarchyItem;
            if (node != null)
            {
                string type = "";
                string name = null;
                string filePath = null;
    
                if (node.Object is EnvDTE.ProjectItem)
                {
                    var pitem = node.Object as EnvDTE.ProjectItem;
                    for (short i = 1; i <= pitem.FileCount; i++)
                    {
                        type = "プロジェクトアイテム";
                        name = pitem.Name;
                        filePath = pitem.FileNames[i];
                    }
                    if (pitem.Kind == Microsoft.VisualStudio.VSConstants.ItemTypeGuid.PhysicalFile_string)
                    {
                        type += "(物理ファイル)";
                    }
                    else if (pitem.Kind == Microsoft.VisualStudio.VSConstants.ItemTypeGuid.PhysicalFolder_string)
                    {
                        type += "(物理フォルダ)";
                    }
                    else if (pitem.Kind == Microsoft.VisualStudio.VSConstants.ItemTypeGuid.VirtualFolder_string)
                    {
                        filePath = "<<仮想フォルダ>>";//C言語のフィルタとか
                    }
    
                    EnvDTE.Properties properties = pitem.Properties;
                    if (properties != null)
                    {
                        for (int i = 1; i < pitem.Properties.Count; i++)
                        {
                            EnvDTE.Property prop = pitem.Properties.Item(i);
                            if (prop != null)
                            {
                                System.Diagnostics.Debug.WriteLine(prop.Name + "=" + prop.Value);
                            }
                        }
                    }
                }
                else if (node.Object is EnvDTE.Project)
                {
                    var proj = (EnvDTE.Project)node.Object;
                    type = "プロジェクト";
                    name = proj.Name;
                    filePath = proj.FileName;
                    if (proj.Kind == "{66A26720-8FB5-11D2-AA7E-00C04F688DDE}")//フォルダ
                    {
                        filePath = "<<ソリューションフォルダ>>";
                    }
                }
                else if (node.Object is EnvDTE.Solution)
                {
                    var sol = (EnvDTE.Solution)node.Object;
                    type = "ソリューション";
                    name = sol.FullName;
                    filePath = sol.FileName;
    
                }
    
    #if VSLangProjを参照追加している場合
                else if (node.Object is VSLangProj.Reference)
                {
    
                    VSLangProj.Reference @ref = node.Object as VSLangProj.Reference;
                    type = "参照";
                    name = @ref.Name;
                    filePath = @ref.Path;
    
                }
    #endif
                else
                {
                    type = "<<不明>>";
                    name = node.Name;
                    filePath = "<<不明>>";
                }
    
                string msg
                = "TYPE= " + type + "\r\n"
                + "NAME= " + name + "\r\n"
                + "FILE= " + filePath;
                VsShellUtilities.ShowMessageBox(this.package, msg, "選択しているアイテムの情報", OLEMSGICON.OLEMSGICON_NOICON, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
    
            }
    
        }
    }

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 編集済み gekkaMVP 2019年10月11日 13:28
    • 回答としてマーク coco2014 2019年10月14日 5:02
    2019年10月11日 10:33

すべての返信

  • PropertiesではなくFileNamesを使えば取れます

    //string fullPath = selectedProjectItem.Properties.Item("FullPath").Value.ToString();
    
    for (short i = 1; i <= selectedProjectItem.FileCount; i++)
    {
        string path = selectedProjectItem.FileNames[i];
        System.Diagnostics.Debug.WriteLine(path);
    }

    あと、面倒なインターフェースから掘り出すよりもEnvDTEからとったほうが楽です。

    var dte = Package.GetGlobalService(typeof(EnvDTE.DTE)) as EnvDTE80.DTE2;
    if (dte != null)
    {
        foreach (object osel in (object[])dte.ToolWindows.SolutionExplorer.SelectedItems)
        {
            EnvDTE.UIHierarchyItem node = osel as EnvDTE.UIHierarchyItem;
            if (node != null)
            {
                string type = "";
                string name = null;
                string filePath = null;
    
                if (node.Object is EnvDTE.ProjectItem)
                {
                    var pitem = node.Object as EnvDTE.ProjectItem;
                    for (short i = 1; i <= pitem.FileCount; i++)
                    {
                        type = "プロジェクトアイテム";
                        name = pitem.Name;
                        filePath = pitem.FileNames[i];
                    }
                    if (pitem.Kind == Microsoft.VisualStudio.VSConstants.ItemTypeGuid.PhysicalFile_string)
                    {
                        type += "(物理ファイル)";
                    }
                    else if (pitem.Kind == Microsoft.VisualStudio.VSConstants.ItemTypeGuid.PhysicalFolder_string)
                    {
                        type += "(物理フォルダ)";
                    }
                    else if (pitem.Kind == Microsoft.VisualStudio.VSConstants.ItemTypeGuid.VirtualFolder_string)
                    {
                        filePath = "<<仮想フォルダ>>";//C言語のフィルタとか
                    }
    
                    EnvDTE.Properties properties = pitem.Properties;
                    if (properties != null)
                    {
                        for (int i = 1; i < pitem.Properties.Count; i++)
                        {
                            EnvDTE.Property prop = pitem.Properties.Item(i);
                            if (prop != null)
                            {
                                System.Diagnostics.Debug.WriteLine(prop.Name + "=" + prop.Value);
                            }
                        }
                    }
                }
                else if (node.Object is EnvDTE.Project)
                {
                    var proj = (EnvDTE.Project)node.Object;
                    type = "プロジェクト";
                    name = proj.Name;
                    filePath = proj.FileName;
                    if (proj.Kind == "{66A26720-8FB5-11D2-AA7E-00C04F688DDE}")//フォルダ
                    {
                        filePath = "<<ソリューションフォルダ>>";
                    }
                }
                else if (node.Object is EnvDTE.Solution)
                {
                    var sol = (EnvDTE.Solution)node.Object;
                    type = "ソリューション";
                    name = sol.FullName;
                    filePath = sol.FileName;
    
                }
    
    #if VSLangProjを参照追加している場合
                else if (node.Object is VSLangProj.Reference)
                {
    
                    VSLangProj.Reference @ref = node.Object as VSLangProj.Reference;
                    type = "参照";
                    name = @ref.Name;
                    filePath = @ref.Path;
    
                }
    #endif
                else
                {
                    type = "<<不明>>";
                    name = node.Name;
                    filePath = "<<不明>>";
                }
    
                string msg
                = "TYPE= " + type + "\r\n"
                + "NAME= " + name + "\r\n"
                + "FILE= " + filePath;
                VsShellUtilities.ShowMessageBox(this.package, msg, "選択しているアイテムの情報", OLEMSGICON.OLEMSGICON_NOICON, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
    
            }
    
        }
    }

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 編集済み gekkaMVP 2019年10月11日 13:28
    • 回答としてマーク coco2014 2019年10月14日 5:02
    2019年10月11日 10:33
  • gekkaさん

    ご回答ありがとうございます!

    FileNames

    でできました!まさか、FileNamesとは。

    ファイル名が取得できるものだと思ってましたが、パスが取得できるんですね。

    ありがとうございました!

    これで前へ進めそうです。

    助かりました!

    2019年10月14日 1:15