I'm creating a VSIX that contains a Tool Window. I would like to move the menu item that opens it into Debug > Windows, instead of View > Other Windows. I would also like to show it only when the target project is in debug mode (for example like the Call Stack menu item).
I managed to show the menu item in the Debug menu, but not in Debug > Windows. In my .vsct I've used:
<!-- ... -->
<Extern href="VSDbgCmd.h"/>
<Extern href="VsDebugGuids.h"/>
<!-- ... -->
<Parent guid="guidVSDebugGroup" id="IDM_DEBUG_WINDOWS"/>
<!-- ... -->
Regarding showing it only in debug mode, I don't have any idea and I couldn't find anything useful.
So my question is: how do I make my menu item behave like Call Stack menu item (in Debug > Window and shown only in debug mode)?
While there is a UIContext for "debugging", there doesn't appear to be one for when the debugger actually enteres break mode. (Hint, I used https://marketplace.visualstudio.com/items?itemName=PaulHarrington.ComponentDiagnostics extension to monitor the active UI Contexts)
So you'll need to add DynamicVisibility and DefaultInvisible command flags to your button:
<Extern href="stdidcmd.h"/>
<Extern href="vsshlids.h"/>
<Extern href="VSDbgCmd.h"/>
<Extern href="VsDebugGuids.h"/>
<Commands package="guidIaxToolWindowPackage">
<Buttons>
<Button guid="guidIaxToolWindowPackageCmdSet" id="IaxToolWindowCommandId" priority="0x0002" type="Button">
<Parent guid="guidVSDebugGroup" id="IDG_DEBUG_WINDOWS_GENERAL"/>
<Icon guid="guidImages" id="bmpPic1" />
<CommandFlag>DynamicVisibility</CommandFlag>
<CommandFlag>DefaultInvisible</CommandFlag>
<Strings>
<ButtonText>Show IaxToolWindow</ButtonText>
</Strings>
</Button>
</Buttons>
Then ensure your package is loaded whenever the debugger attaches to or launches a process, by decorating your AsyncPackage class with the ProvideAutoLoad attribute below:
namespace IaxToolwindow
{
// use Debugging UI Context to ensure package get loaded when debugging starts
[ProvideAutoLoad(VSConstants.UICONTEXT.Debugging_string, PackageAutoLoadFlags.BackgroundLoad)]
[PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] // Info on this package for Help/About
[ProvideMenuResource("Menus.ctmenu", 1)]
[ProvideToolWindow(typeof(IaxToolWindow))]
[Guid(IaxToolWindowPackage.PackageGuidString)]
public sealed class IaxToolWindowPackage : AsyncPackage
{
public const string PackageGuidString = "256ca1a6-6b6d-4329-a7f9-15ee5bbf8114";
Then add a BeforeQueryStatus command handler for your menu command, to make the menu item visible when IVSDebugger.GetMode returns DBGMODE_BREAK. For example:
private IaxToolWindowCommand(AsyncPackage package, OleMenuCommandService commandService)
{
this.package = package ?? throw new ArgumentNullException(nameof(package));
commandService = commandService ?? throw new ArgumentNullException(nameof(commandService));
var menuCommandID = new CommandID(CommandSet, CommandId);
var menuItem = new OleMenuCommand(this.Execute, menuCommandID);
menuItem.BeforeQueryStatus += IAxToolWindowCommand_BeforeQueryStatus;
commandService.AddCommand(menuItem);
}
private void IAxToolWindowCommand_BeforeQueryStatus(object sender, EventArgs e)
{
ThreadHelper.JoinableTaskFactory.Run(async delegate
{
await Microsoft.VisualStudio.Shell.ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
OleMenuCommand menuItem = (OleMenuCommand)sender;
IVsDebugger vsDebugger = await ServiceProvider.GetServiceAsync(typeof(IVsDebugger)) as IVsDebugger;
Assumes.Present(vsDebugger);
DBGMODE[] dbgmode = new DBGMODE[1];
int hr = vsDebugger.GetMode(dbgmode);
// show menu item when debugger is in break mode
menuItem.Visible = (dbgmode[0] == DBGMODE.DBGMODE_Break);
});
}
This was built off a wizard generated AsyncToolwindow project. But note I changed up the MenuCommand to OleMenuCommand, so we can add and use a BeforeQueryStatus handler to control the visibility of the menu item.
The ProvideAutoLoad is used to ensure the package is loaded whenever a debug session is started, so it's started in time to make the menu item visible (when the debugger is in break mode).
If there had been a UIContext guid activated when the debugger entered break mode, we could have just added a VisbilityConstraint to the .vsct. But given the absence of a UIContext specific to break mode, you'll need to do something similar to the above, to make the menu item visible only when in break mode.
Sincerely,