All for .net, .net for all!

LearnVSXNow! Part #41 – Toolbar Layout and Persistence

A very good friend of mine started to extend Visual Studio 2008. When writing his first few toolbars, he felt lost in the documentation treating the initial layout and persistence options. When I explained him the details and the rationale behind, I found, those are never summarized in one place. So I decided to share them.

If you often create your own tool windows, these options are probably quite clear for you, however, there might be a few details you do not know about…

Visual Studio uses well-organized windows to represent a developer workspace. To establish the visual functionality perceived when using the user interface of Visual Studio, there is an exact boundary of responsibilities between a window and the IDE. The IDE provides a mechanism to maintain the list of windows, takes care about positioning and moving them, saves the layout, and so on—without knowing at all what the window contains and how it is used. In contrast a window takes care about painting its client area, responding to repositioning and resizing events without knowing at all how the IDE implements windowing logic. The clear separation of these responsibilities is provided by distinguishing between two roles:

—  The IDE uses the concept of window frame that is responsible to host the client area of the window called window pane. This window frame connects the pane with the IDE and controls the visual properties and behavior of the pane.

—  The window provides a window pane object that can be hosted in a window frame delivered by the IDE. This pane works as a controller for implementing the interaction logic behind the UI.

—  The window frame also can provide a toolbar for commands understood by the pane. At initialization time the pane tells the frame which command should be displayed there. When a command is invoked, the frame notifies the pane to respond for that command.

The next figure helps illustrating the concepts above. There are a few windows highlighted with a border that represent how the frame and the pane form a functional window.

The frame not simply hosts the pane but also adds some extra decoration and behavior to it. For example the Find and Replace window uses a so-called floating frame that adds a caption with a close button, a resizable tool-window border around the pane, and a toolbar. Every control in the window from the “Find what” label and below including the pushbutton at the bottom are managed—painted and controlled—by the pane. The Quick Find button is drawn by the frame as it is a part of the toolbar.

The Solution Explorer at the right contains a pane with the tree view of the solution structure. The frame hosting this pane is docked at the right side of the main IDE window and so it provides a different border than the floating window. The frame also contains a pin button to turn on or off the auto-hide property of the window.

The Output window at the bottom is docked exactly at the same location as the Error List window, but the latter one is sent to the back. The window frame uses a small tab at the bottom in order to allow bringing a window to the front. Just as for the other windows, the toolbar here is also the part of the window frame.

The Toolbox window at the left demonstrates a window that is hidden at the moment. The small rectangle is the frame indicating the pane is automatically hidden. As the mouse is hovered over the frame the window pane flies in.

The largest part of the screen behind the Find and Replace window is covered by two windows representing the FirstLookPackage.cs and Guids.cs files. These are so-called tabbed document windows. The frame provides the tabs with the names of the files and all other parts of the editor window belong to the pane.

The frame provided by the IDE can natively host ActiveX Controls and ActiveX Documents. So, if we create an ActiveX wrapper around our windows it can be immediately “consumed” by the IDE. Fortunately, we are not obliged to do that. We can host any window having a Win32 window handle by creating a simple lightweight wrapper around our window implementing the IVsWindowPane interface. The main role of the interface is to retrieve a Win32 window handle to the frame so that it can embed the pane’s window and also provides methods to translate keyboard accelerator keys and pre-translation of messages.

The Managed Package Framework provides wrapper classes (we are going to see a few examples later in this chapter), so we do not have to implement IVsWindowPane by ourselves.

The Visual Studio IDE uses two types of windows: tool windows and document windows.

In Figure 5-1 all the highlighted windows are tool windows while the editors representing the FirstLookPackage.cs and Guids.cs files are document windows.

Tool Window Lifecycle

Tool windows are important parts of the development environment Visual Studio users leverage on when working with the IDE. They can position and size tool windows, tab them with other tool windows, dock them in order to establish a handy environment of their own. When the IDE is closed tool window positions are saved, so the next time when the IDE is launched these windows can be recreated and positioned to the saved location.

In order this mechanism could work, a tool window must be registered with a package owning the tool window. When it is time to create a tool window, the following steps are executed:

—  The IDE looks up the registry to find out which package owns that window. If the package has not been loaded, the IDE loads the package as described in Chapter 3: Visual Studio Packages in the On-demand Loading of Packages section.

—  Every package implements the IVsPackage interface which has a CreateTool method. The IDE invokes this method and from that point it is the responsibility of the package to create the tool window instance.

—  The package somewhere inside the CreateTool method uses the SVsUIShell service to instantiate the tool window. This service holds methods providing access to basic windowing functionality, including access to and creation of tool windows and document windows. At the end of the day its CreateToolWindow method is called to carry out all creation tasks. CreateToolWindow hosts the tool window in a window frame and also returns an IVsWindowFrame instance representing the frame.

—  The package executes the final initialization steps of the tool window.

The steps above are carried out independently of whether the tool window is created as a result of a user interaction or restoring the saved Visual Studio IDE window layout.

From this point the user can work with the tool window instance. The IDE uses the window frame to show, hide, position the tool window. Independently of the tool window is visible or hidden, the instance representing it stays alive while it is not closed explicitly.

Through its frame the tool window can respond to events like showing, hiding, resizing the tool window and other changes in its state. Catching these event can help in resource management of the tool window, for example expensive resources can be released when the window frame gets hidden and reclaimed when the frame is shown again.

Closing a tool window can be initiated either by the Visual Studio IDE when it is about to be closed, or as a result of user interaction. Before the tool window gets closed it has the opportunity to respond this event (for example save its state). When the tool window is closed, the instance representing it is destroyed.

Creating a sample Tool Window

We are going to create a sample tool window displaying operating system process information similar to the Task Manager window’s Processes tab.

We use the VSPackage wizard to create a tool window package with the name ProcessInfoToolWindow. You can also create the package with the wizard using the ordinary steps; fill the basic package information and the tool window options according to next figures:

After the wizard generated the default tool window, add new ProcessList.cs file to the project to declare the ProcessInfo and ProcessList classes holding process information as shown here:

using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;


namespace DeepDiver.ProcessInfoToolWindow


  public sealed class ProcessInfo


    public ProcessInfo(Process process)


      if (process == null) throw new ArgumentNullException("process");

      Name = process.ProcessName;

      Id = process.Id;

      Priority = process.BasePriority;

      ThreadCount = process.Threads.Count;



    public string Name { get; private set; }

    public int Id { get; set; }

    public int Priority { get; private set; }

    public int ThreadCount { get; set; }



  public static class ProcessList


    public static List<ProcessInfo> GetProcesses()


      var result = new List<ProcessInfo>();

      foreach (var process in Process.GetProcesses().OrderBy(p => p.ProcessName))


        result.Add(new ProcessInfo(process));


      return result;




The VSPackage wizard creates a UserControl named MyControl with a simple button as the tool window’s default user interface. To display the process information, the simple button will be changed to a ListView instance named ProcessListView the next figure illustrates:

The name of the control has been changed to ProcessInfoControl and its code is quite simple as the following code extract shows it:

using System.Windows.Forms;


namespace DeepDiver.ProcessInfoToolWindow


  public partial class ProcessInfoControl : UserControl


    public ProcessInfoControl()





    public void RefreshData()



      foreach (var processInfo in ProcessList.GetProcesses())


        var item = new ListViewItem(

















The only public member of the control is RefreshData that simply populates the ProcessListView control with the process information. This is where the ProcessList and ProcessInfo helper types are used. The ProcessInfoToolWindow class implements the window pane functionality; it is very simple as the code here illustrates:

using System.Windows.Forms;

using System.Runtime.InteropServices;

using Microsoft.VisualStudio.Shell;


namespace DeepDiver.ProcessInfoToolWindow



  public class ProcessInfoToolWindow : ToolWindowPane


    private readonly ProcessInfoControl control;


    public ProcessInfoToolWindow() :



      Caption = Resources.ToolWindowTitle;

      BitmapResourceID = 301;

      BitmapIndex = 1;

      control = new ProcessInfoControl();



    override public IWin32Window Window


      get { return control; }



    protected override void OnCreate()







ProcessInfoToolWindow follows the pattern I used in the LearnVSXNow! - #4: Creating a package with a tool window post.  The only addition is that the OnCreate method of the ToolWindowPane class is overridden to initialize the tool window. This method is called directly after the window pane has been instantiated and sited into its frame; this is the place for any initialization activities that require access to the UI or the window frame. This implementation simply calls the RefreshData method of the UI to populate the process list.

As you can see, the OnCreate method of the base class is also called. You should keep this practice; otherwise your tool window initialization may not work as expected.

There is nothing special in the package hosting our tool window:

using System;

using System.ComponentModel.Design;

using System.Runtime.InteropServices;

using Microsoft.VisualStudio;

using Microsoft.VisualStudio.Shell;

using Microsoft.VisualStudio.Shell.Interop;


namespace DeepDiver.ProcessInfoToolWindow


  [PackageRegistration(UseManagedResourcesOnly = true)]


  [InstalledProductRegistration(false, "#110", "#112", "1.0",

    IconResourceID = 400)]

  [ProvideLoadKey("Standard", "1.0", "ProcessInfoToolWindow", "DeepDiver", 1)]

  [ProvideMenuResource(1000, 1)]

  [ProvideToolWindow(typeof (ProcessInfoToolWindow))]


  public sealed class ProcessInfoToolWindowPackage : Package


    protected override void Initialize()



      var mcs = GetService(typeof (IMenuCommandService)) as OleMenuCommandService;

      if (null != mcs)


        var toolwndCommandID = new CommandID(GuidList.guidProcessInfoToolWindowCmdSet,

           (int) PkgCmdIDList.ShowProcessInfoWindow);

        var menuToolWin = new MenuCommand(ShowToolWindow, toolwndCommandID);





    private void ShowToolWindow(object sender, EventArgs e)


      ToolWindowPane window = FindToolWindow(typeof (ProcessInfoToolWindow),

        0, true);

      if ((null == window) || (null == window.Frame))


        throw new NotSupportedException(Resources.CanNotCreateWindow);


      var windowFrame = (IVsWindowFrame) window.Frame;





When you build the package and run with Ctrl+F5 (Start Without Debugging), you can access the tool window through the ViewðOther WindowsðProcess Information. The tool window appears with a list of processes similarly to following figure:

Initial Layout and Persistence

In the package definition we used the simplest form of the ProvideToolWindow attribute:


We can control the initial layout and behavior of any tool windows by customizing ProvideToolWindow through its attribute properties. The following table summarizes them with a short description:




This flag indicates if the tool window should be displayed when the IDE restarts if it was displayed last time when the IDE was closed. The value of false causes the IDE to display the tool window, the value of true hides it even if it was hidden when the IDE was closed.

The default value of this property is false.



These attributes set the top-left corner coordinates for the tool window. The first time the tool window is instantiated this position is applied to set the window location. Coordinates are absolute screen coordinates where (0, 0) is the top left corner of the screen.



Sets the initial width and height of the tool window. The first time the tool window is instantiated this size is applied. Width and height is specified in pixels.


The tool window can be positioned relatively to other windows. This property uses the values of the VsDockStyle enumerated type in the Microsoft.VisualStudio.Shell namespace to set up this initial relation. This property is used together with the Window and Orientation properties. The enumeration has the following values:

—  MDI: The tool window is linked to the multiple-document interface area. This is the area where the editor and designer documents are displayed. When this value is used, the Window and Orientation property values are ignored.

—  Float: The tool window will float initially, but can be docked by dragging its title bar to the wished dock position. If Orientation and Window properties are set, the tool window can be docked by double clicking on its title bar.

—  AlwaysFloat: The tool window will float initially and cannot be docked unless it is manually set to dockable.

—  Tabbed: The tool window is tabbed together with another window identified with the Window property. In this case Orientation can be set to Left or Right.


The string form of the GUID of the window on which the tool window is docked or tabbed. You can use the GUID string with or without curly braces.


The default orientation for the tool window relative to the window specified by the Window property.


Determines whether multiple instances of the tool window are allowed or not.

As it was mentioned before, closing the IDE will save the layout of the windows into the application data folder under the current user’s profile and also puts some information system registry under the current Visual Studio registry key. Setting the Transient property to true will not prevent the IDE to save the tool window layout information, however when starting the IDE next time the window will not be automatically displayed. When you display it with the appropriate menu function, it will put the window to its previous location where it had been placed just before the IDE was closed. The initial ProvideToolWindow attribute sets the initial position of the tool window only at the first time the tool window is displayed. If it is moved or resized, the next time it will be displayed at the saved position.

This behavior can lead to unexpected behavior during development. Even if you change the ProvideToolWindow properties and rebuild your package, the tool window seems not obeying you and always be displayed on its saved position. It is because the IDE uses the initial tool window position only if it does not find saved layout information. The very first time the tool window is instantiated this is the case, but not for any subsequent instantiation.

You can remove the persisted window layout information by deleting the windows.prf and windowsidx.prf files from the application data folder of your user profile (its location varies according to your operating system, group policy and profile settings).

Here are a few samples to help you better understand how these properties contribute in settings the initial layout of a tool window. I suggest trying them and looking for their visual effect. Do not forget to delete the window layout information files before trying the effect of samples!

Sample 1: The window is set to initially put its top-left corner to the (100, 200) on the screen with the size of (100, 300). The window will be set to float. You can drag the tool window by its caption and dock to the selected position.


  PositionX = 100, PositionY = 200,

  Width = 100, Height = 300,

  Style = VsDockStyle.Float)]

Sample 2: We place the window just like in Sample 1. When double-clicking on its caption it gets docked to the right of Property window.


  Style = VsDockStyle.Float,

  Orientation = ToolWindowOrientation.Right,

  Window = "{EEFA5220-E298-11D0-8F78-00A0C9110057}")]

Sample 3: We position the window just like in Sample 1, but docking is disabled. We cannot drag it to any dock position.


  PositionX = 100, PositionY = 200,

  Width = 100, Height = 300,

  Style = VsDockStyle.AlwaysFloat)]

Sample 4: We place the tool window into the document are and set it up so that Visual Studio does not display it after restart even if the tool window was displayed last time when the IDE was closed:


  Style = VsDockStyle.MDI,

  Transient = true)]

Sample 5: The tool window is set tabbed to the right of the Solution Explorer. The GUID string value of the Window property represents Solution Explorer.


  Style = VsDockStyle.Tabbed,

  Orientation = ToolWindowOrientation.Right,

  Window = "3ae79031-e1bc-11d0-8f78-00a0c9110057")]

The following table gives you a short list about GUIDs of the most frequently used tool windows.

Tool Window

Related GUID

Main IDE Window


Code Window


Error List


Task List




Call Stack








Solution Explorer




Object Browser


Macro Explorer


Dynamic Help


Class View


Resource View


Server Explorer


Command Window


Find Symbol


Find Symbol Results


Find Results #1


Find Results #2


In LearnVSXNow! #13 - Menus and comands in VS IDE I have already treated the relation of visibility contexts and commands. When we assigned a specific context to particular command it became visible when the environment got into the context.

We can assign visibility contexts to the tool windows as well: when the environment gets into the context, the tool window is displayed without any explicit user interaction. Visibility contexts are assigned to tool windows by the ProvideToolWindowVisibility attribute. One or more instance of this attribute can be added to the package class, each represents one context. When the IDE enters to one of these contexts, the tool window is displayed. When the IDE leaves any of those contexts, the tool window is hidden.

The best way to get familiar with this registration attribute is to try it with the ProcessInfoToolWindow sample. Add the highlighted lines to the ProcessInfoToolWindowPackage class:

// --- Tab the tool window with Output window

[ProvideToolWindow(typeof(ProcessInfoToolWindow), Style = VsDockStyle.Tabbed,

  Window = "{34E76E81-EE4A-11D0-AE2E-00A0C90FFFC3}")]

// --- Assign it to the "SolutionExists" context



// --- Assign it to the "FullScreenMode" context




public sealed class ProcessInfoToolWindowPackage : Package


  // ...


The ProvideToolWindow attribute sets docks the Process Information tool window to the output window. Because we do not use the Transient property, it defaults to false and so we can expect the tool window to be re-displayed after restarting the IDE—assuming it was shown when the IDE is closed. We added two decorating ProvideToolWindowVisibility attributes to the package class. Each of them has two constructor parameters: the first defines the type of tool window, the second the GUID of the visibility context is assigned to. The two GUIDs represent the SolutionExists and FullScreenMode context. When the package is rebuilt is run, we can follow the tool window behavior determined by the contexts with the following steps:

—  Original state: There is no open solution in the Visual Studio IDE, and so the Process Information tool window is not displayed.

—  Step 1: Open the Output window (ViewðOutput)

—  Step 2: Create a new text file with the FileðNewðFile function. The text file forces to create an unsaved solution, so the IDE enters into the SolutionExists context and the Process Information tool window is displayed; it is tabbed to the Output window.

—  Step 3: Close the IDE and start the package again. As the Process Information tool window is not transient, normally (without visibility context constraints) it would be displayed. However, the IDE has no open solution and so have not entered into the SolutionExists (or into the FullScreenMode) context, so the tool window is hidden.

—  Step 4: Create a new text file just like in Step 2. Again, the IDE gets into the SolutionExists context and Process Information is displayed again.

—  Step 5: Close the solution. The IDE leaves the SolutionExists context and so Process Information gets hidden.

—  Step 6: Use the ViewðFull Screen function to enter the IDE into the FullScreenMode context. As you expect, the Process Information is displayed, because it is assigned with this context.

—  Step 7: Do not leave the full screen mode and close Visual Studio with the FileðExit function.

—  Step 8: Start the package again. Now, Visual Studio opens in full screen mode—when we closed the IDE, this mode had been saved—, and so Process Information is displayed again. Not because of the IDE layout was saved, but due to the FullScreenMode visibility constraint!

To make the life a bit spicier you can “override” this visibility constraint behavior during runtime by showing or hiding tool windows manually:

—  If the tool window is displayed when the IDE enters into a specific context, even if you leave the context, the tool window does not get hidden. For example, carry out Step 1 and 2 above and leave Step 3. At this point there is an open solution and so Process Information is visible. Now, when you turn to full screen mode and then back to normal mode, the Process Information stays visible.

—  If the tool window is hidden when you leave a specific context, even if the IDE enters next time to that context the tool window stays hidden. For example, carry out Step 1 and Step 2 again. Now, close the Process Information window. If at this point you close the solution and then create a new text file again, the IDE enters into the SolutionExists context however, Process Information is not displayed.

This behavior is not a bug, it is intentional. If it would not be so, handling more than one visibility constraint were weird. For example, if we had an open solution and we were in full screen mode, Process Information would be shown. At this point turning off the full screen mode meant leaving the FullScreenMode context, but did not mean entering into the SolutionExists context! So at this point Process Information would be hidden that were against our intention to display this tool window if there was a solution open.

The following table summarizes the GUIDs belonging to the visibility contexts:

Context name

Related GUID





















Very often it is useful to bind the visibility of our tool window to other windows within the IDE. The architects of Visual Studio also had this idea in their mind: using the GUIDs in summarizing window GUIDs solves this wish. When a tool window is displayed, the IDE enters into that tool window’s context that is identified by the same GUID as the window itself.

Posted Feb 02 2009, 05:33 AM by inovak
Filed under:


Laurie Hannon wrote re: LearnVSXNow! Part #41 – Toolbar Layout and Persistence
on Mon, Feb 2 2009 19:09

I am working on an isolated shell app, and already have a working tool window pane and toolbar (and am using VSXtra).  I'm trying to change the visibility of the toolbar so it is visible by default, as soon as the IDE launches, just like the Standard toolbar.  Right now, after installing and launching the IDE, the user has to right click on the toolbars and turn on the new toolbar.  I've looked through your posts on this, as well as other sources, but I haven't seen any documentation that says how to turn a toolbar on by default.  Can you help?



DiveDeeper's blog wrote LVN! Sidebar #7 - Showing a toolbar at Visual Studio startup
on Tue, Feb 3 2009 15:21

After publishing LearnVSXNow! Part #41 – Toolbar Layout and Persistence I got a letter from Laurie

Visual Studio Hacks wrote Visual Studio Links #106
on Fri, Feb 6 2009 14:03

My latest in a series of the weekly, or more often, summary of interesting links I come across related to Visual Studio. John Kilmister has created a XAML for WPF Cheat Sheet and it is available for download (.pdf). Greg Duncan posted a link to the WPF

Abe wrote re: LearnVSXNow! Part #41 – Toolbar Layout and Persistence
on Tue, Jul 7 2009 15:53


I have problem related to Tool Windows.

I want to get the actual selected item from Solution Explorer or Class View (depends on witch is the active), but i don't know how to reach these windows.

Can you help me too :) ?



Visual Studio Search Results, Programmatically | Nin Labs wrote Visual Studio Search Results, Programmatically | Nin Labs
on Mon, Nov 8 2010 7:00

Pingback from  Visual Studio Search Results, Programmatically | Nin Labs

tweet wrote re: LearnVSXNow! Part #41 – Toolbar Layout and Persistence
on Mon, Feb 11 2013 9:09

I really liked your post. Keep writing.

Topsoil Supplies wrote re: LearnVSXNow! Part #41 – Toolbar Layout and Persistence
on Sat, Feb 16 2013 13:37

Appreciate you sharing, great blog post.Really looking forward to read more. Cool.

clomid no prescription wrote re: LearnVSXNow! Part #41 – Toolbar Layout and Persistence
on Mon, Feb 25 2013 15:50

I am so grateful for your blog article.Really looking forward to read more. Really Cool.

buy clomid wrote re: LearnVSXNow! Part #41 – Toolbar Layout and Persistence
on Fri, Mar 1 2013 5:25

WwxXep Fantastic article.Thanks Again. Keep writing.