locked
Visual Studio Extensibility: Breakpoint validation RRS feed

  • Question

  • Hi,

    we implemented method ValidateBreakpointLocation of the LanguageService class (from package Microsoft.VisualStudio.Package) to perform breakpoint validation for our custom debug engine.

    Question 1: is ValidateBreakpointLocation the most recent way to do this or is there something newer (e.g. in MEF)? Background: we are implementing an IsolatedShell based on .NET4 with Visual Studio 2010.

    Question 2: consider this scenario using ValidateBreakpointLocation: add a breakpoint to a valid line and afterwards uncomment the line. After uncommenting, ValidateBreakpointLocation is called. When returning FALSE here, the breakpoint is removed from the editor window. This is not what we want as it's not very nice from a usability point of view (it's also not done by Visual Studio). So what we need is a way to determine if the current line already contains a breakpoint (in that case we would return TRUE in ValidateBreakpointLocation to prevent automatic breakpoint deletion).

    How can we do this?

    Please note: this should also work when initially opening a solution (similar to Visual Studio that allows to safe breakpoints in commented lines and is able to recreate them when a solution is opened again).

    Thanks and best regards,

    Bernhard


    • Edited by Bernhard005 Monday, July 9, 2012 2:40 PM
    • Moved by Robert Breitenhofer Tuesday, July 31, 2012 8:21 AM English instead German (From:Visual Studio)
    Monday, July 9, 2012 2:40 PM

Answers

  • Hi Bernhard,

    Regarding question #1, the answer is no. BP validation still happens through the legacy language service stuff.

    Regarding question #2, testing this scenario on a C# app, it looks like the BP gets moved to the next valid line of code when you start a debug session. Not sure if that's the debugger or the langauge service doing that.

    Those marker type ID's are entirely undocumented, and they can change from release to release. Ran into a problem a while back trying to figure out what some of these were. Turns out the debugger uses some markers to simply track text spans. To figure out what was what, I built the following add-in to dump all the marker types. Figured I'd post it here in the hopes someone else finds it useful. :-)

    using System;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Text;
    using Extensibility;
    using EnvDTE;
    using EnvDTE80;
    using Microsoft.VisualStudio.CommandBars;
     
    using Microsoft.VisualStudio.TextManager.Interop;
    using Microsoft.VisualStudio.Shell;
    using Microsoft.VisualStudio.Shell.Settings;
    using Microsoft.VisualStudio.Settings;
     
    using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
     
    namespace DumpDebugMarkers
    {
          public class Connect : IDTExtensibility2
          {
           private DTE2 applicationObject;
           private AddIn addInInstance;
           private ServiceProvider serviceProvider;
           private CommandBarButton cmdBarBtn;
     
           public Connect() {}
     
           private void OnCmdBarButtonClick(CommandBarButton Ctrl, ref bool CancelDefault)
           {
             IVsTextManager vsTextMgr = (IVsTextManager)Package.GetGlobalService(typeof(SVsTextManager));
     
             StringBuilder sb = new StringBuilder();
             int markerCount=0;
             vsTextMgr.GetMarkerTypeCount(out markerCount);
             for (int i = 0; i < markerCount; i++)
             {
                IVsTextMarkerType markerType = null;
                vsTextMgr.GetMarkerTypeInterface(i, out markerType);
                if (markerType != null)
                {
                   string displayName;
                   markerType.GetDisplayName(out displayName);
                   //sb.AppendFormat("{0} : {1}\r\n", i.ToString(), displayName);
     
                   IVsMergeableUIItem mergableUI = markerType as IVsMergeableUIItem;
                   if (mergableUI != null)
                   {
                      string canonicalName;
                      string description;
                      string name;
     
                      mergableUI.GetCanonicalName(out canonicalName);
                      mergableUI.GetDescription(out description);
                      mergableUI.GetDisplayName(out name);
                      sb.AppendFormat("{0} : {1} : {2} : {3}\r\n", i.ToString(), name, canonicalName, description);
                   }
                }
             }
             // print text marker info to debugger's outputwindow pane.
             System.Diagnostics.Debug.WriteLine("===============================================");
             System.Diagnostics.Debug.WriteLine(sb.ToString());
             System.Diagnostics.Debug.WriteLine("===============================================");
     
             //ShellSettingsManager settingsMgr = new ShellSettingsManager((System.IServiceProvider)serviceProvider);
             //SettingsStore settingsStore = settingsMgr.GetReadOnlySettingsStore(SettingsScope.Configuration);
             //foreach (var marker in settingsStore.GetSubCollectionNames("Text Editor\\External Markers"))
             //{
             //    //System.Diagnostics.Debug.WriteLine(marker.ToString());
     
             //    Guid guidMarker = new Guid(marker);
             //    IVsTextMarkerType markerType;
             //    int markerID;
                    
             //    if (0 == vsTextMgr.GetRegisteredMarkerTypeID(ref guidMarker, out markerID))
             //    {
             //        if (0 == vsTextMgr.GetMarkerTypeInterface(markerID, out markerType))
             //        {
             //            string displayName, description;
             //            IVsMergeableUIItem vsMergableUItem = markerType as IVsMergeableUIItem;
             //            if (vsMergableUItem != null)
             //            {
             //                vsMergableUItem.GetDisplayName(out displayName);
             //                vsMergableUItem.GetDescription(out description);
             //                System.Diagnostics.Debug.WriteLine(markerID.ToString() + " : " + displayName + " : " + description);
             //            }
             //        }
             //    }
             //}
          }
     
          public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
          {
             applicationObject = (DTE2)application;
             addInInstance = (AddIn)addInInst;
             serviceProvider = new ServiceProvider((IOleServiceProvider)application, true);
     
             CommandBar menuBar = ((CommandBars)applicationObject.CommandBars)["MenuBar"];
             CommandBarPopup toolsPopup = (CommandBarPopup)menuBar.Controls["Tools"];
             cmdBarBtn = (CommandBarButton)toolsPopup.Controls.Add(MsoControlType.msoControlButton, Missing.Value, Missing.Value, 1, true);
             cmdBarBtn.Caption = "Dump Debug Markers";
             cmdBarBtn.Style = MsoButtonStyle.msoButtonCaption;
             cmdBarBtn.Click += new _CommandBarButtonEvents_ClickEventHandler(OnCmdBarButtonClick); 			
          }
     
          public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
          {
             if (cmdBarBtn != null)
             {
                cmdBarBtn.Click -= new _CommandBarButtonEvents_ClickEventHandler(OnCmdBarButtonClick);
                cmdBarBtn.Delete(true);
                cmdBarBtn = null;
             }
          }
     
          public void OnAddInsUpdate(ref Array custom) {}
          public void OnStartupComplete(ref Array custom) {}
          public void OnBeginShutdown(ref Array custom) {}		
       }
    }


    Ed Dore

    Wednesday, August 8, 2012 6:47 PM

All replies

  • We now found a solution regarding question 2: we call method EnumMarkers of IVsTextLines and check if the markerType is 62 (enabled breakpoint), 55 (disabled breakpoint) or 58 (warning breakpoint) by calling method GetType of IVsTextLineMarker. Luckily, this also works when initially opening a solution. Nevertheless, this approach is somewhat dirty as constants 55, 58 and 62 are not included in enum Microsoft.VisualStudio.TextManager.Interop.MARKERTYPE.

    Wednesday, August 1, 2012 9:48 AM
  • Hi Bernhard005,

    Thank you for posting in the MSDN Forum.

    I will involve some experts into this issue to see whether they can help you out. There might be some time delay, appreciate for your patience.

    Thank you for your understanding and support.

    Best regards,

       

    Ego [MSFT]
    MSDN Community Support | Feedback to us

    Friday, August 3, 2012 9:55 AM
  • Hi Bernhard,

    Regarding question #1, the answer is no. BP validation still happens through the legacy language service stuff.

    Regarding question #2, testing this scenario on a C# app, it looks like the BP gets moved to the next valid line of code when you start a debug session. Not sure if that's the debugger or the langauge service doing that.

    Those marker type ID's are entirely undocumented, and they can change from release to release. Ran into a problem a while back trying to figure out what some of these were. Turns out the debugger uses some markers to simply track text spans. To figure out what was what, I built the following add-in to dump all the marker types. Figured I'd post it here in the hopes someone else finds it useful. :-)

    using System;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Text;
    using Extensibility;
    using EnvDTE;
    using EnvDTE80;
    using Microsoft.VisualStudio.CommandBars;
     
    using Microsoft.VisualStudio.TextManager.Interop;
    using Microsoft.VisualStudio.Shell;
    using Microsoft.VisualStudio.Shell.Settings;
    using Microsoft.VisualStudio.Settings;
     
    using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
     
    namespace DumpDebugMarkers
    {
          public class Connect : IDTExtensibility2
          {
           private DTE2 applicationObject;
           private AddIn addInInstance;
           private ServiceProvider serviceProvider;
           private CommandBarButton cmdBarBtn;
     
           public Connect() {}
     
           private void OnCmdBarButtonClick(CommandBarButton Ctrl, ref bool CancelDefault)
           {
             IVsTextManager vsTextMgr = (IVsTextManager)Package.GetGlobalService(typeof(SVsTextManager));
     
             StringBuilder sb = new StringBuilder();
             int markerCount=0;
             vsTextMgr.GetMarkerTypeCount(out markerCount);
             for (int i = 0; i < markerCount; i++)
             {
                IVsTextMarkerType markerType = null;
                vsTextMgr.GetMarkerTypeInterface(i, out markerType);
                if (markerType != null)
                {
                   string displayName;
                   markerType.GetDisplayName(out displayName);
                   //sb.AppendFormat("{0} : {1}\r\n", i.ToString(), displayName);
     
                   IVsMergeableUIItem mergableUI = markerType as IVsMergeableUIItem;
                   if (mergableUI != null)
                   {
                      string canonicalName;
                      string description;
                      string name;
     
                      mergableUI.GetCanonicalName(out canonicalName);
                      mergableUI.GetDescription(out description);
                      mergableUI.GetDisplayName(out name);
                      sb.AppendFormat("{0} : {1} : {2} : {3}\r\n", i.ToString(), name, canonicalName, description);
                   }
                }
             }
             // print text marker info to debugger's outputwindow pane.
             System.Diagnostics.Debug.WriteLine("===============================================");
             System.Diagnostics.Debug.WriteLine(sb.ToString());
             System.Diagnostics.Debug.WriteLine("===============================================");
     
             //ShellSettingsManager settingsMgr = new ShellSettingsManager((System.IServiceProvider)serviceProvider);
             //SettingsStore settingsStore = settingsMgr.GetReadOnlySettingsStore(SettingsScope.Configuration);
             //foreach (var marker in settingsStore.GetSubCollectionNames("Text Editor\\External Markers"))
             //{
             //    //System.Diagnostics.Debug.WriteLine(marker.ToString());
     
             //    Guid guidMarker = new Guid(marker);
             //    IVsTextMarkerType markerType;
             //    int markerID;
                    
             //    if (0 == vsTextMgr.GetRegisteredMarkerTypeID(ref guidMarker, out markerID))
             //    {
             //        if (0 == vsTextMgr.GetMarkerTypeInterface(markerID, out markerType))
             //        {
             //            string displayName, description;
             //            IVsMergeableUIItem vsMergableUItem = markerType as IVsMergeableUIItem;
             //            if (vsMergableUItem != null)
             //            {
             //                vsMergableUItem.GetDisplayName(out displayName);
             //                vsMergableUItem.GetDescription(out description);
             //                System.Diagnostics.Debug.WriteLine(markerID.ToString() + " : " + displayName + " : " + description);
             //            }
             //        }
             //    }
             //}
          }
     
          public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
          {
             applicationObject = (DTE2)application;
             addInInstance = (AddIn)addInInst;
             serviceProvider = new ServiceProvider((IOleServiceProvider)application, true);
     
             CommandBar menuBar = ((CommandBars)applicationObject.CommandBars)["MenuBar"];
             CommandBarPopup toolsPopup = (CommandBarPopup)menuBar.Controls["Tools"];
             cmdBarBtn = (CommandBarButton)toolsPopup.Controls.Add(MsoControlType.msoControlButton, Missing.Value, Missing.Value, 1, true);
             cmdBarBtn.Caption = "Dump Debug Markers";
             cmdBarBtn.Style = MsoButtonStyle.msoButtonCaption;
             cmdBarBtn.Click += new _CommandBarButtonEvents_ClickEventHandler(OnCmdBarButtonClick); 			
          }
     
          public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
          {
             if (cmdBarBtn != null)
             {
                cmdBarBtn.Click -= new _CommandBarButtonEvents_ClickEventHandler(OnCmdBarButtonClick);
                cmdBarBtn.Delete(true);
                cmdBarBtn = null;
             }
          }
     
          public void OnAddInsUpdate(ref Array custom) {}
          public void OnStartupComplete(ref Array custom) {}
          public void OnBeginShutdown(ref Array custom) {}		
       }
    }


    Ed Dore

    Wednesday, August 8, 2012 6:47 PM