One of the most important considerations to increase the performance of Visual Studio .NET is to delay the loading of VSPackages. Loading a VSPackage DLL is expensive from a file I/O point of view, adding extra memory pressure to the working set, and execution time of running more code. There are many delay loading techniques employed by VSPackages depending on the features that the VSPackage provides. For VSPackages that provide global commands, the goal is that the commands are displayed in the UI (on menus, toolbars, and context menus) without loading the VSPackage DLL. Only when the user executes one of the commands is the VSPackage DLL loaded. In many cases the commands are always available statically. This case is easy. The commands are defined in the .CTC file of the VSPackage without specifying the DYNAMICVISIBILITY flag. The following example shows an always available “View.HelloWorldTool” command (guidToolWnCmdSet:icmdHelloWorld ) that is owned by a VSPackage (guidToolWnPkg).
// GUID:CMDID GROUP:ID PRIORITY ICON TYPE FLAGS
// BUTTON_TEXT MENU_TEXT TOOLTIP_TEXT COMMAND_NAME
guidToolWnCmdSet:icmdHelloWorld, guidSHLMainMenu:IDG_VS_VIEW_BROWSER, 0x0100, guidOfficeIcon:msotcidNoIcon, BUTTON, , "&Hello World Tool";
// This icmdHelloWorld is not defined as a shared
// command, so it uses a custom guidToolWnCmdSet
// as the command set GUID. Also, by specifying
// blank for the FLAGS, this command is
// default visible and enabled. Other valid values
// for FLAGS are the following:
// DEFAULTDISABLED, DEFAULTINVISIBLE,
// DYNAMICVISIBILITY, TEXTCHANGES
// These values for FLAGS can be or'ed together,
// e.g. "DEFAULTINVISIBLE | DYNAMICVISIBILITY"
In many cases, the visibility of the command needs to be dynamic; it depends on the current context/selection of the UI. The ideal visibility of a command may be tied to many different factors. The perfect showing of the command is most easily managed by implementing IOleCommandTarget::QueryStatus, but this requires that the VSPackage DLL is loaded in order to get a chance to execute code. The preferred strategy is to allow the IDE to manage the visibility of the VSPackage commands without loading the VSPackage. In order to do this, the visibility of a command can be declared in the .CTC file as being tied to one or more special UI Contexts that are identified by a GUID called a “CmdUI Context GUID”. The IDE automatically tracks some UI Contexts:
In addition there are other modes that are identified by active CmdUI GUIDS:
A VSPackage can arrange to have a command visibility automatically managed by the IDE without loading their VSPackage DLL by defining the command in its CTC file with “DEFAULTDISABLED | DEFAULTINVISIBLE | DYNAMICVISIBILITY” flags and also adding one or more entries in the VISIBILITY_SECTION. When one of the specified CmdUI Context GUID’s is turned on then the command will be made visible and enabled automatically without actually loading the VSPackage and calling its QueryStatus implementation. In many cases, it is not possible to get the perfect visibility/enabling of a command in the manner. It is still better tradeoff to have reasonably good dynamic enabling of the command that may sometimes show the command when it should not be, then to force the early loading of the VSPackage so that it can handle QueryStatus. In some cases the use may get an error message saying that the command really did not apply. But from then on, the command enabling will be perfect because the VSPackage will then be loaded. The overall performance increase by only loading VSPackages when the user really needs them is more important than sometimes showing a command when it really does not apply. In some cases if an appropriate CmdUI Context is not already defined, it is better to add code to an already loaded VSPackage to turn on a new CmdUI Context GUID so that other VSPackages can avoid being loaded early. The SID_SVsShellMonitorSelection/IID_IVsMonitorSelection service can be used to turn CmdUIContext GUID’s on and off (see GetCmdUIContextCookie, IsCmdUIContextActive, and SetCmdUIContext methods).
The following is an example of a VSPackage command taken from the SlnExt sample that has dynamic visibility of a command managed by CmdUI Contexts without loading the VSPackage. In this case the command is the “Project.AddNewSolutionNote command that is set to be enabled and visible whenever a Solution exits (i.e. when one of the following CmdUI Context GUID’s is on: UICONTEXT_EmptySolution, UICONTEXT_SolutionHasMultipleProjects, or UICONTEXT_SolutionHasSingleProject).
Using VISIBILITY Section
0x0100, guidOfficeIcon:msotcidNoIcon, BUTTON,
DEFAULTDISABLED | DEFAULTINVISIBLE | DYNAMICVISIBILITY,
"Add New &Solution Note";
// Command GUID when visible
The following is an excerpt from the VSIP documentation on the VISIBILITY_SECTION:
The VISIBILITY_SECTION – VISIBILITY_END section determines the dynamic visibility of commands. Each entry identifies a command and an associated command UI context. A command listed in the VISIBILITY_SECTION – VISIBILITY_END section will appear only with the associated context. This section only applies to commands and toolbars, not to groups. Commands not included in this section are visible whenever their parent menu is active. A command may be associated with multiple command UI contexts by including an entry for each command/context combination.
VISIBILITY_SECTION – VISIBILITY_END
Each entry in the VISIBILITY_SECTION – VISIBILITY_END section contains two fields. They are, in order:
The GUID:CmdId field identifies the command or menu for which you want to control static visibility.
The GUID field identifies the command UI context to associate with the GUID:CmdId field. When this command UI context has focus, the command or menu is visible.
Commands must have the DEFAULT_INVISIBLE and DYNAMIC VISIBILITY flags set in order for entries in the VISIBILITY_SECTION – VISIBILITY_END section to take effect. Toolbars have DYNAMIC_VISIBILITY by default.