Logo
HOWTO: Use the Browse for Folder dialog of Visual Studio from a package

Author: Carlos J. Quintero (Microsoft MVP) Applies to: Microsoft Visual Studio 2010
Date: April 2015   Microsoft Visual Studio 2012
      Microsoft Visual Studio 2013
      Microsoft Visual Studio 2015
Introduction

The .Net Framework provides the FolderBrowserDialog class, which allows you to select a folder in the file system in a treeview. However, you may want to use a dialog similar to the one used to open or save a file, which not only offers a treeview (to the left of the dialog) but also a listview (to the right of the dialog). Visual Studio provides the GetDirectoryViaBrowseDlg method in the IVsUIShell interface to show such dialog.

More Information

The following package creates a menu command that, when clicked, shows the Folder Browse dialog of Visual Studio:

Language: C#   Copy Code Copy Code (IE only)
using System;
using System.Runtime.InteropServices;
using System.ComponentModel.Design;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell;

namespace MyCompany.VSFolderBrowserPackage
{
   [PackageRegistration(UseManagedResourcesOnly = true)]
   [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
   [ProvideMenuResource("Menus.ctmenu", 1)]
   [Guid(GuidList.guidVSFolderBrowserPackagePkgString)]
   public sealed class VSFolderBrowserPackagePackage : Package
   {
      public VSFolderBrowserPackagePackage()
      {
      }

      protected override void Initialize()
      {
         base.Initialize();

         // Add our command handlers for menu (commands must exist in the .vsct file)
         OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
         if (null != mcs)
         {
            // Create the command for the menu item.
            CommandID menuCommandID = new CommandID(GuidList.guidVSFolderBrowserPackageCmdSet, (int)PkgCmdIDList.cmdidBrowseFolderCommand);
            MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID);
            mcs.AddCommand(menuItem);
         }
      }

      private void MenuItemCallback(object sender, EventArgs e)
      {
         const uint BIF_RETURNONLYFSDIRS = 1;

         IVsUIShell uiShell;
         VSBROWSEINFOW[] browseInfoArray;
         IntPtr windowHandle;
         IntPtr dirNameHandle = IntPtr.Zero;
         int hr;
         string selectedDir = "";

         try
         {
            uiShell = base.GetService(typeof(SVsUIShell)) as IVsUIShell;

            hr = uiShell.GetDialogOwnerHwnd(out windowHandle);
            ErrorHandler.ThrowOnFailure(hr);

            browseInfoArray = new VSBROWSEINFOW[1];

            browseInfoArray[0].lStructSize = (uint)Marshal.SizeOf(browseInfoArray[0]);
            browseInfoArray[0].hwndOwner = windowHandle;
            browseInfoArray[0].nMaxDirName = 260;
            browseInfoArray[0].pwzDlgTitle = "My title";
            browseInfoArray[0].pwzInitialDir = null;
            dirNameHandle = Marshal.AllocCoTaskMem(2 * (int)browseInfoArray[0].nMaxDirName);
            browseInfoArray[0].pwzDirName = dirNameHandle;

            // See flags: https://msdn.microsoft.com/en-us/library/windows/desktop/bb773205.aspx
            browseInfoArray[0].dwFlags = BIF_RETURNONLYFSDIRS;
            hr = uiShell.GetDirectoryViaBrowseDlg(browseInfoArray);

            switch (hr)
            {
               case VSConstants.S_OK:

                  selectedDir = Marshal.PtrToStringAuto(dirNameHandle);
                  System.Windows.Forms.MessageBox.Show(selectedDir);
                  break;

               case VSConstants.OLE_E_PROMPTSAVECANCELLED:

                  // Cancelled
                  break;

               default:

                  ErrorHandler.ThrowOnFailure(hr);
                  break;
            }
         }
         catch (Exception ex)
         {
            System.Windows.Forms.MessageBox.Show(ex.ToString());
         }
         finally
         {
            if (dirNameHandle != IntPtr.Zero)
            {
               Marshal.FreeCoTaskMem(dirNameHandle);
            }
         }
      }
   }
}


Go to the 'Visual Studio Extensibility (VSX)' web site for more articles like this (Articles section)