Managing Project Loading in a Solution

Visual Studio solutions can contain a large number of projects. The default Visual Studio behavior is to load all the projects in a solution at the time the solution is opened, and not to allow the user to access any of the projects until all of them have finished loading. When the process of project loading will last more than two minutes, a progress bar is displayed showing the number of projects loaded and the total number of projects. The user can unload projects while working in a solution with multiple projects, but this procedure has some disadvantages: the unloaded projects are not built as part of a Rebuild Solution command, and IntelliSense descriptions of types and members of closed projects are not displayed.

Developers can reduce solution load times and manage project loading behavior by creating a solution load manager. The solution load manager can set different project loading priorities for specific projects or project types, make sure that projects are loaded before starting a background build, delay background loading until other background tasks are complete, and perform other project load management tasks.

Project loading priorities

Visual Studio defines four different project loading priorities:

  • PLP_DemandLoad (the default): when a solution is opened, projects are loaded asynchronously. If this priority is set on an unloaded project after the solution is already open, the project will be loaded at the next idle point.

  • PLP_BackgroundLoad: when a solution is opened, projects are loaded in the background, allowing the user to access the projects as they are loaded without having to wait until all the projects are loaded.

  • PLP_LoadIfNeeded: projects are loaded when they are accessed. A project is accessed when the user expands the project node in the Solution Explorer, when a file belonging to the project is opened when the solution opens because it is in the open document list (persisted in the solution's user options file), or when another project that is being loaded has a dependency on the project. This type of project is not automatically loaded before starting a build process; the Solution Load Manager is responsible for ensuring that all the necessary projects are loaded. These projects should also be loaded before starting a Find/Replace in Files across the entire solution.

  • PLP_ExplicitLoadOnly: projects are not to be loaded unless the user explicitly requests it. This is the case when projects are explicitly unloaded.

Creating a solution load manager

Developers can create a solution load manager by implementing IVsSolutionLoadManager and advising Visual Studio that the solution load manager is active.

Activating a solution load manager

Visual Studio allows only one solution load manager at a given time, so you must advise Visual Studio when you want to activate your solution load manager. If a second solution load manager is activated later on, your solution load manager will be disconnected.

You must get the SVsSolutionService and set the VSPROPID_ActiveSolutionLoadManager property:

IVsSolution pSolution = GetService(typeof(SVsSolution)) as IVsSolution;
object objLoadMgr = this;   //the class that implements IVsSolutionManager
pSolution.SetProperty((int)__VSPROPID4.VSPROPID_ActiveSolutionLoadManager, objLoadMgr);

Implementing IVsSolutionLoadManager

The OnBeforeOpenProject method is called during the process of opening the solution. To implement this method, you use the IVsSolutionLoadManagerSupport service to set the load priority for the type of project you wish to manage. For example, the following code sets C# project types to load in the background:

Guid guidCSProjectType = new Guid("{FAE04EC0-301F-11d3-BF4B-00C04F79EFBC}");
pSLMgrSupport.SetProjectLoadPriority(guidProjectID, (uint)_VSProjectLoadPriority.PLP_BackgroundLoad);

The OnDisconnect method is called either when Visual Studio is being shut down or when a different package has taken over as the active solution load manager by calling SetProperty with the VSPROPID_ActiveSolutionLoadManager property.

Strategies for different kinds of solution load manager

You can implement solution load managers in different ways, depending on the types of solutions they are meant to manage.

If the solution load manager is meant to manage solution loading in general, it can be implemented as part of a VSPackage. The package should be set to autoload by adding the ProvideAutoloadAttribute on the VSPackage with a value of SolutionOpening(). The solution load manager can then be activated in the Initialize method.

Note

For more information about autoloading packages, see How to: Autoload a VSPackage.

Since Visual Studio recognizes only the last solution load manager to be activated, general solution load managers should always detect whether there is an existing load manager before activating themselves. If calling GetProperty() on the solution service for VSPROPID_ActiveSolutionLoadManager returns null, there is no active solution load manager. If it does not return null, check whether the object is the same as your solution load manager.

If the solution load manager is meant to manage only a few types of solution, the VSPackage can subscribe to solution load events (by calling AdviseSolutionEvents), and use the event handler for OnBeforeOpenSolution to activate the solution load manager.

If the solution load manager is meant to manage only specific solutions, the activation information can be persisted as part of the solution file. To do this, call WriteSolutionProps for the pre-solution section.

Specific solution load managers should deactivate themselves in the OnAfterCloseSolution event handler, in order not to conflict with other solution load managers.

If you need a solution load manager only to persist global project load priorities (for example, properties set on an Options page), you can activate the solution load manager in the OnAfterOpenSolution event handler, persist the setting in the solution properties, then deactivate the solution load manager.

Handling solution load events

To subscribe to solution load events, call AdviseSolutionEvents when you activate your solution load manager. If you implement IVsSolutionLoadEvents, you can respond to events that relate to different project loading priorities.

  • OnBeforeOpenSolution: This is fired before a solution is opened. You can use it to change the project loading priority for the projects in the solution.

  • OnBeforeBackgroundSolutionLoadBegins: This is fired after the solution is completely loaded, but before background project loading begins again. For example, a user might have accessed a project whose load priority is LoadIfNeeded, or the solution load manager might have changed a project load priority to BackgroundLoad, which would start a background load of that project.

  • OnAfterBackgroundSolutionLoadComplete: This is fired after a solution is initially fully loaded, whether or not there is a solution load manager. It is also fired after background load or demand load whenever the solution becomes fully loaded. At the same time, SolutionExistsAndFullyLoaded() is reactivated.

  • OnQueryBackgroundLoadProjectBatch: This is fired before the loading of a project (or projects). To ensure that other background processes are completed before the projects are loaded, set pfShouldDelayLoadToNextIdle to true.

  • OnBeforeLoadProjectBatch: This is fired when a batch of projects is about to be loaded. If fIsBackgroundIdleBatch is true, the projects are to be loaded in the background; if fIsBackgroundIdleBatch is false, the projects are to be loaded synchronously as a result of a user request, for example if the user expands a pending project in Solution Explorer. You can implement this to do expensive work that otherwise would need to be done in OnAfterOpenProject().

  • OnAfterLoadProjectBatch: This is fired after a batch of projects has been loaded.

Detecting and managing solution and project loading

In order to detect the load state of projects and solutions, call GetProperty with the following values:

You can also ensure that projects and solutions are loaded (no matter what the project load priorities are) by calling one of the following methods:

  • EnsureSolutionIsLoaded: calling this method forces the projects in a solution to load before the method returns.

  • EnsureProjectIsLoaded: calling this method forces the projects in guidProject to load before the method returns.

  • EnsureProjectsAreLoaded: calling this method forces the project in guidProjectID to load before the method returns.

Note

. By default only the projects that have the demand load and background load priorities are loaded, but if the VSBSLFLAGS_LoadAllPendingProjects flag is passed in to the method, all projects will be loaded except for the ones that are marked to load explicitly.