locked
Customizing a main Visual Studio context menu and getting the changes automatically applied to its sons RRS feed

  • Question

  • Hi to all,
    I'm new to the Visual Studio Extensions and therefore my apologies if I'm asking something very stupid.
    I need to add my own command along with the other default breakpoint commands like "Location...", "Condition...", "Hit Count..." and so on.
    Thanks to VSCTPowerToy and EnableVSIPLogging I've discovered that VS shows these commands in three different places: IDM_BREAKPOINT_CONTEXT, IDM_BREAKPOINTS_WINDOW_CONTEXT and IDM_BREAKPOINT_SUBMENU. All of them seem to be parented to IDG_BREAKPOINT_CONTEXT_MODIFY.
    I want to directly modify this last one and get the changes applied also to its three sons instead of going to work separately with every son.
    Below is my custom vsct, it works but I'm not sure if my implementation is right:

    <Commands package="guidMyPkg">
     <Buttons>
      <Button guid="guidMyCmdSet" id="MyBtnID" priority="0x0000" type="Button">
    	<Parent guid="guidVSDebugGroup" id="IDG_BREAKPOINT_CONTEXT_MODIFY"/>
    	<Strings>
              <ButtonText>My command text</ButtonText>
            </Strings>
      </Button>
     </Buttons>
    </Commands>

    1- I've read in more places that I should always include a group and that my control should be a son of this group. The group should then be a son of the target VS element. I tried to follow this pattern with the below code, but I only got unexpected behaviours...

    <Commands package="guidMyPkg">
     <Groups>
       <Group guid="guidMyCmdSet" id="MyMenuGroup" priority="0x0000">
          <Parent guid="guidVSDebugGroup" id="IDG_BREAKPOINT_CONTEXT_MODIFY"/>
       </Group>
     </Groups>
     <Buttons>
      <Button guid="guidMyCmdSet" id="MyBtnID" priority="0x0000" type="Button">
          <Parent guid="guidMyCmdSet" id="MyMenuGroup"/>
          <Strings>
             <ButtonText>My command text</ButtonText>
          </Strings>
      </Button>
     </Buttons>
    </Commands>

    ...my button is no more visibile and in order to display it, I have to assign a CommandPlacement for every son of IDG_BREAKPOINT_CONTEXT_MODIFY. In addition to that, since VS recognize a different group, it automatically assigns a line separator (BeginGroup) which is not what I want.
    Therefore, without the creation of a group and the direct connection of my button with the target control, gives me the desired result with less code, but is this really the way to go or I'm doing something that will cause future issues?

    2-  Is there a way for my button to inherit the visibility/behaviours of the other buttons like "Location...", "Condition..." and so on. I ask this because, apart for the code executed on the click event, for the rest my button acts exactly in the same way as these buttons.

    3 - My initial idea was to add my custom options on "When Hit..." dialog window, but I've deduced that it is not possible to override and customize VS dialog windows and I've decided to directly implement my button linked to my own dialog.
    Is that right or I'm missing an important feature that allow to do something similar?

    4 - The order of the commands it is configured through the priority field, but I'm not been able to find a priority level schema. I only see hexadecimal numbers as 0x100, 0x0305, 0x0600. It is not straightforward as 0,1,2,3.
    Is there an online reference where I can find a table along with the meaning of every available priority number?

    5 - Regarding the symbols element, the GuidSymbol/IDSymbol pair is something that it is generated from the compiler by following special patterns or can also be random values entered manually by the programmer?

    Thanks to all in advance

    • Edited by clarkxx Wednesday, April 17, 2013 3:19 PM Made corrections
    Wednesday, April 17, 2013 3:13 PM

Answers

  • Yes, without running code or using UI contexts you only have two possibilites for your command in terms of visiblity / enabled state. The defaults are visible and enabled, you can also add DefaultDisabled and/or DefaultInvisible to your VSCT to switch that around.

    When you ask MPF for IOleCommandTarget you will get back the IOleCommandTarget for your window or package (depending on which context you call it from), that won't work because the only handlers that will be there will be the ones you registered. What you want is to get the shell's command target, which encapsulates the entire command route. You want something like this

    IOleCommandTarget shellCmdTarget = (IOleCommandTarget)GetService(typeof(SUIHostCommandDispatcher));
    var WhenHitBtn = new Guid("{C9DD4A59-47FB-11D2-83E7-00C04F9902C1}");
    OLECMD cmd = new OLECMD { cmdID = 0x146 };
    OLECMD[] cmdArray = { cmd };
    int res = shellCmdTarget.QueryStatus(ref WhenHitBtn, 1, cmdArray, IntPtr.Zero);
    if (ErrorHandler.Succeeded(res))
    {
        bool isEnabled = (cmdArray[0].cmdf & (uint)OLECMDF.OLECMDF_ENABLED) == (uint)OLECMDF.OLECMDF_ENABLED;
        bool isVisible = (cmdArray[0].cmdf & (uint)OLECMDF.OLECMDF_INVISIBLE) == 0;
    }

    IDTCommandTarget is something related to DTE and doesn't come in to play here, IOleCommandTarget is an interface that a bunch of people (basically every toolwindow, every package, every project, etc..) implement, it isn't a service interface, that is where SUIHostCommandDispatcher comes in, which is the service interface that represents the entire VS command route. Do note that the command route includes your window, so don't forward a QS to it for a command you handle, if in handling it you simply forward it to the SUIHostCommandDispatcher, otherwise you will be in an infinite loop and overflow the stack.


    Friday, April 19, 2013 11:51 PM

All replies

  • >I've read in more places that I should always include a group and that my control should be a son of this group. 

    This is incorrect. It is true that for a command to be visible in the UI it needs to be parented to some group which is itself parented to some menu/toolbar, but that doesn't mean you have to introduce a group locally, you are free to use an existing one like you did, and in fact it is the entire point of the command system design (i.e. to allow a single group to be placed in multiple locations, and for people to show up in all locations simply by adding their items to that group).

    >2-  Is there a way for my button to inherit the visibility/behaviours of the other buttons like "Location...", "Condition..." and so on. I ask this because, apart for the code executed on the click event, for the rest my button acts exactly in the same way as these buttons.

    No, the command system is designed for the common case, which is individual commands that have their own logic to determine visibily/enabled state. The idea of tying one command to another isn't explicitly supported, but you could do it fairly easily by simply running a QueryStatus for the command you want your state tied to, while inside your own QueryStatus, and then simply copying that commands status (enabled, visible, etc..) to your command and returning that as the result of the QueryStatus.

    >My initial idea was to add my custom options on "When Hit..." dialog window, but I've deduced that it is not possible to override and customize VS dialog windows and I've decided to directly implement my button linked to my own dialog.
    Is that right or I'm missing an important feature that allow to do something similar?

    I suspect that it is correct. VS is extensible but not infinitely extensible (i.e. it isn't the case that every single window / dialog is extensible in every possible way you might want).

    >The order of the commands it is configured through the priority field, but I'm not been able to find a priority level schema. I only see hexadecimal numbers as 0x100, 0x0305, 0x0600. It is not straightforward as 0,1,2,3.
    Is there an online reference where I can find a table along with the meaning of every available priority number?

    Not sure how 0, 1, 2, 3 is more or less meaningful than hex values. You could make your priorities 1, 2, 3 if you wanted, for whatever reason they have been historically specified as hex values. The semantics are identical, i.e. order is simply sort or based on priority. If you command has a priority of 0x100 it will appear before every other command in that same group whose priority is > 0x100. We give no guarantees about sort order of two items with the same priority.

    >Regarding the symbols element, the GuidSymbol/IDSymbol pair is something that it is generated from the compiler by following special patterns or can also be random values entered manually by the programmer?

    They exist only for convenience of the programmer. Internally VS deals only with GUIDs and DWORDs (int) for command identifiers, it has no idea of the symbolic names. You can view the GuidSymbol as akin to a namespace, IDs are elements in that namespace. That means that IDSymbol Foo with value 100 does not need to be globally unique (there can be other symbols with the value of 100), it simply needs to be unique vis-a-vis all other ids that are 'under' the top level GuidSymbol.

    Wednesday, April 17, 2013 4:36 PM
  • Hi Ryan and thanks for your fast and very professional support.
    I'm glad to see that there's nothing wrong to link my button directly to a group which is part of an external package. This way things are much more easy.
    Yes, It would have been really too much the possibility to customize even VS dialogs. Priority and symbols are much more easier than I was thinking.

    Regarding the visibility/State, I was hoping to avoid any QueryStatus, but with your solution I can at least avoid writing conditional code and tie the state directly to a target command. I'm not sure if the execution of two queries is good for performance, but for sure will make things really easy.
    I would like to attempt one last possible option, even If I already know that I will end up with your suggested solution: VisibilityConstraints
    It appears to be that I can associate the visibility of a command to a particular context. I tried with the following code which in theory should hide my button when I'm not in source code mode, but unfortunately, when I close the source code tab, the button is still visible. I missed something?

    <Button guid="guidMyCmdSet" id="MyBtnID" priority="0x0000" type="Button">
    	<Parent guid="guidVSDebugGroup" id="IDG_BREAKPOINT_CONTEXT_MODIFY"/>
    	<CommandFlag>DefaultInvisible</CommandFlag>
            <CommandFlag>DynamicVisibility</CommandFlag>
    	<Strings>
              <ButtonText>My command text</ButtonText>
            </Strings>
    </Button>
    
    <VisibilityConstraints>
        <VisibilityItem guid="guidMyCmdSet" id="MyBtnID" context="guidNotViewSourceMode"></VisibilityItem>  
    </VisibilityConstraints>

    Thanks again

    Wednesday, April 17, 2013 5:36 PM
  • >Regarding the visibility/State, I was hoping to avoid any QueryStatus, but with your solution I can at least avoid writing conditional code and tie the state directly to a target command.

    It is unlikely for most interesting commands that you can avoid QueryStatus.

    >I'm not sure if the execution of two queries is good for performance, but for sure will make things really easy.

    The shell has a QueryStatus caching mechanism, worst case scenario your QueryStatus will skip the cache and do a full QS pass for the command, that is not terribly expensive and I suspect the difference would be on the order of a few milliseconds.

    >
    I would like to attempt one last possible option, even If I already know that I will end up with your suggested solution: VisibilityConstraints

    Visibility constraints rely on someone (or you) setting the UI context at the appropriate times. I have never seen the guidNotViewSourceMode, but I also don't see anyone that unsets it, the app stub appears to set it (which is really strange) and I see no one ever clearing it. This doesn't look like a useful UI context for command visibility and its name appears to have nothing to do with what it is actually doing (which I can't really understand, because as I said, it is set on startup and never cleared, so it seems it will be forever active). This approach would be usable only if the other commands you care about have their visibility determined by a visibility context that you could also use. They do not, they all have QueryStatus handlers.


    Wednesday, April 17, 2013 6:34 PM
  • After looking the UI context mechanism I fully understand what you're saying at the point that I've already started the implementation of your solution.
    The only problem that I'm facing is that, in order to enable BeforeQueryStatus notifications, I'm forced everytime to autoload the package through the ProvideAutoLoadAttribute, even for sessions where the custom command remains hidden and unused.

    I can load the package only by specific context, but looking through VSConstants there are not too many choices. There is SolutionExist (I've never worked with VS without a solution/project loaded), CodeWindow which doesn't work due to an old bug never fixed , Debugging which loads the package only during debugging phase and a few other ones.
    May be that by mixing several attributes I can get it to work for a specific command, but I can already imagine the collateral effects that such hardcoding can cause with multiple commands of different categories, unless every command has its own package (an approach too much heavy just to handle a simple thing like visibility/state).

    Is there an easy and reliable way to load the package only when really needed and without recurring to the above dirty tricks?

    Wednesday, April 17, 2013 11:59 PM
  • The supported mechanism is auto load or wait until a service you offer is requested. VS delay loads packages and couldn't possibly know when 'the right time' to load them would be, and we wouldn't want to load to do QueryStatus or we would be loading a lot of packages on startup.

    If your command can be only used during debugging I would image you want something like SolutionExists. People can launch VS with no solution/project open, but they can't ever start debugging that way. 

    I haven't looked at the debugger package but I suspect it loads either when someone (like the project system) asks for a service it provides, or, more likely, on something like SolutionExists.
    Thursday, April 18, 2013 12:45 AM
  • Unfortunately my command can be used also in edit mode. Is part of the same list of the breakpoint edit commands (Location, When hit, Condition etc). Just like the default commands, my command should only be available when the user has already placed a breakpoint with a right-click on the red point in the left margin, with a right-click on the text highlighted in red and also with a right-click in a breakpoint available in the Breakpoints window.
    The breakpoint window does not represent a problem since the context menu showing my command only appear if the list contains breakpoints.
    The same apply to margin of the ide: no cliccable breakpoint mean not context menu.
    The problem is when I click on the source code panel: my command is showed even if no breakpoint is available while the default commands are only displayed if the underline text is in red color (=breakpoint placed).
    The SolutionExist context is miles away from this kind of detection.
    I've looked deeper at the debugger package and I have discovered (VsDbgCmdUsed.vsct and VsDbgCmdPlace.vsct) how the visibility is handled (I only show one command for better readability):

    <CommandPlacement guid="guidVSDebugCommand" id="cmdidBreakpointLocation" priority="0x0300">
          <Parent guid="guidVSDebugGroup" id="IDG_BREAKPOINT_CONTEXT_MODIFY"/>
    </CommandPlacement>
    <!-- Make conditional for the items in this block -->
        <!-- #if !defined(No_BreakpointEdit) -->
        <UsedCommands Condition="!defined(No_BreakpointEdit)" >
          <UsedCommand guid="guidVSDebugCommand" id="cmdidBreakpointLocation"/>
        </UsedCommands>
    <!-- #endif -->

    Basically it checks for "No_BreakpointEdit" definition. If the breakpoint is not in Edit mode, then it is not displayed.
    Also my command must only be displayed with the same expression.
    I've tried, but without success (my command is not shown):

    <UsedCommands Condition="!defined(No_BreakpointEdit)" >
         <UsedCommand guid="guidMyCmdSet" id="MyBtnID"/>
    </UsedCommands>
    
    <CommandPlacements>
       <CommandPlacement guid="guidMyCmdSet" id="MyBtnID" priority="0x100">
         <Parent guid="guidVSDebugGroup" id="IDG_BREAKPOINT_CONTEXT_MODIFY"/>
       </CommandPlacement>
    </CommandPlacements>
    Thursday, April 18, 2013 4:19 AM
  • You are misunderstanding what the VSCT is doing there, it is NOT influencing visibility in any way. It is a mechanism used so that isolated shell authors can eliminate the command from their shells, it won't help you in any way.

    >The problem is when I click on the source code panel: my command is showed even if no breakpoint is available while the default commands are only displayed if the underline text is in red color (=breakpoint placed).

    You need a QueryStatus handler to control your visibility, and your package needs to be loaded for your QueryStatus handler to be applicable. Those commands aren't doing anything magic, they have QueryStatus handlers and their package is loaded.

    >The SolutionExist context is miles away from this kind of detection.

    The point of SolutionExists is simply to have your package AutoLoad on that context, it has nothing to do with your command visibility, you will need QueryStatus handlers for that, there is no way around that.


    Thursday, April 18, 2013 5:02 PM
  • Thanks for letting me know this detail. At this point my only option remains a QueryStatus handler and the max I can do is to limit the autoload on some contexts.
    Unfortunately the generic contexts does not help at all:
    SolutionBuilding, Debugging, Dragging, FullScreenMode, DesignMode, NoSolution, SolutionExists, EmptySolution, SolutionHasSingleProject, SolutionHasMultipleProjects, CodeWindow.
    Is this the full list of available contexts or I can hope that somewhere else there is something closest to my needs?

    Anyway, the only reason I'm trying to load the package when really needed is for saving resources and for avoid possible startup delay of VS.

    I've measured the time that my package needs to be fully loaded (from the constructor until the end of the initialization) and it only takes 5-10 ms.
    I was wondering if I'm doing all of this only for saving VS from a few ms of startup delay or if, under the hood, there's much more involved.

    Thanks

    Thursday, April 18, 2013 9:22 PM
  • We discourage load at startup as it takes VM space, causes disk I/O above and beyond anything you actually do your initialization path. Measuring is somewhat futile as it can vary WILDLY based on disk I/O, which is entirely outside of your control.

    That said, if you need to be available anytime a document is open, for instance, you would auto load on something like SolutionHasSingleProject and SolutionHasMultipleProjects. That should indicate anytime someone has a project open, which is required to debug, if you want your commands to not be visible if you aren't loaded mark them DefaultInvisible in your VSCT. 

    VS when it loads your package will site it and that is exposed in MPF via the Initilize method. If you request services there you could cause rippling package loads if the providers of the services aren't yet loaded.

    Thursday, April 18, 2013 10:40 PM
  • Basically my command is an additional feature for the breakpoints: it allow to set the next statement and during the debug process, the instructions between my custom breakpoint and the target statement, are skipped. It acts exactly like the default "Set next statement" command of VS, but in an automatic way. It can be configured during the debug process and in normal mode as well, but only if there is already a breakpoint where the current cursor is located (just like "Location...", "Condition..." etc).

    It's a kind of command that sometimes may be used from the user, other times not.
    There is not a programmatic logic that allows to determine when the service is needed unless VS exposes a context like "InstructionLocatedOnCurrentCursorHasAbreakpoint".
    In this case I can handle visibility directly with VisibilityConstraints and load the package only when the user click the command.
    Unfortunately does not exist such context.

    I agree that load at startup should be avoided expecially, like my case, just for hiding/showing a button and with the concrete possibility that the real service will not even called.

    I really don't like this pattern, but now that you know exactly what my command does and when needs to be showed or not, do you see any valid alternative?

    Friday, April 19, 2013 12:01 AM
  • No, the UI context system is fairly course grained, having a context as you suggest would be ridiculously chatty, i.e. it could change on every cursor move. Considering that UI context changes can drive package loads and other things it would be a terrible idea to have a rapidly changing UI context, in general.

    I am baffled as to why you don't want a QueryStatus handler. There are 4000+ commands in VS, at least 95% of them have QueryStatus handlers. The debugger, for all the commands you mention, utilize QueryStatus.

    Friday, April 19, 2013 12:21 AM
  • Maybe we are talking of differents QueryStatus methods because seems to be that the one you are talking about allow to manage visibility with the package not yet loaded.
    The one I tried is "OleMenuCommand.BeforeQueryStatus". It sends me a callback before my command is displayed so that I can change the visibility state.
    Unless I'm doing something wrong, I can only get notification when the package is being loaded (through AutoLoad attribute).
    Do you mean to bypass the initialization of the package (in the initialize method) and only call Package.Initialize() in the ItemClickedCallback ?

    You said that you always discourage load at startup and that's what's I'm trying to follow, but based on the above described above, it seems to be that there's no way to avoid this unless there's something that I'm doing wrong.

    Friday, April 19, 2013 2:38 AM
  • No, QueryStatus only would run if your package has been loaded, this is true for pretty much any code in VS, you can't run code unless some part of your dll (a package or a MEF component) has been loaded. No, I don't mean calling Initialize (you never call that method, VS does). What I am saying is your package should auto load on SolutionExists and register its command handlers in Initialize.

    We discourage loading at startup for people that don't have a legitimate need to do so (lots of people just want to eagerly load their code even though there is no need to), if you have a need to then use the mechanisms that are there for that purpose, i.e. the AutoLoad stuff.
    Friday, April 19, 2013 5:04 PM
  • I understand and mine is the classic case where I'm forced to autoload the package only for hide/show the command, unless I decide to leave the command always visible and enabled even when there is no service that can be called.

    You talked about running a second QueryStatus from inside my own MyCmdBeforeQueryStatus for the command I want the state tied to. I'm not sure if you was referring to IDTCommandTarget or IOleCommandTarget.
    I've tried both, but without success. With the first one I can't even get the service while the second one doesn't fill the cmdf member and returns error -2147221248.
    I don't know what I'm doing wrong.
    If I implement IOleCommandTarget as callback, I only receive one notification, but only related to my own command, just like MyCmdBeforeQueryStatus.
    The command I want the state tied to is "When Hit.." that VS show by default (= guidVSDebugCommand:cmdidBreakpointAction).
    Thanks for your help, you're really a nice person and very patient.

    void MyCmdBeforeQueryStatus(object sender, EventArgs e)
    {
       //IOleCommandTarget test
       var serv = GetService(typeof(IOleCommandTarget)) as IOleCommandTarget;
       var WhenHitBtn = new Guid("{C9DD4A59-47FB-11D2-83E7-00C04F9902C1}");
       OLECMD cmd = new OLECMD { cmdID = 0x146 };
       OLECMD[] cmdArray = { cmd };
       var suc = serv.QueryStatus(ref WhenHitBtn, 1, cmdArray, IntPtr.Zero); //Returns -2147221248
    
       //IDTCommandTarget test
       var serv2 = GetService(typeof(IDTCommandTarget)) as IDTCommandTarget; //returns null
       var h = new vsCommandStatus();
       object obj = null;
       serv2.QueryStatus("&When Hit...", vsCommandStatusTextWanted.vsCommandStatusTextWantedNone, ref h, ref obj);
    }
    Friday, April 19, 2013 11:20 PM
  • Yes, without running code or using UI contexts you only have two possibilites for your command in terms of visiblity / enabled state. The defaults are visible and enabled, you can also add DefaultDisabled and/or DefaultInvisible to your VSCT to switch that around.

    When you ask MPF for IOleCommandTarget you will get back the IOleCommandTarget for your window or package (depending on which context you call it from), that won't work because the only handlers that will be there will be the ones you registered. What you want is to get the shell's command target, which encapsulates the entire command route. You want something like this

    IOleCommandTarget shellCmdTarget = (IOleCommandTarget)GetService(typeof(SUIHostCommandDispatcher));
    var WhenHitBtn = new Guid("{C9DD4A59-47FB-11D2-83E7-00C04F9902C1}");
    OLECMD cmd = new OLECMD { cmdID = 0x146 };
    OLECMD[] cmdArray = { cmd };
    int res = shellCmdTarget.QueryStatus(ref WhenHitBtn, 1, cmdArray, IntPtr.Zero);
    if (ErrorHandler.Succeeded(res))
    {
        bool isEnabled = (cmdArray[0].cmdf & (uint)OLECMDF.OLECMDF_ENABLED) == (uint)OLECMDF.OLECMDF_ENABLED;
        bool isVisible = (cmdArray[0].cmdf & (uint)OLECMDF.OLECMDF_INVISIBLE) == 0;
    }

    IDTCommandTarget is something related to DTE and doesn't come in to play here, IOleCommandTarget is an interface that a bunch of people (basically every toolwindow, every package, every project, etc..) implement, it isn't a service interface, that is where SUIHostCommandDispatcher comes in, which is the service interface that represents the entire VS command route. Do note that the command route includes your window, so don't forward a QS to it for a command you handle, if in handling it you simply forward it to the SUIHostCommandDispatcher, otherwise you will be in an infinite loop and overflow the stack.


    Friday, April 19, 2013 11:51 PM
  • Thanks for the code, Ryan! It works and finally I'm able to hide/show my button in conformity with the others VS breakpoints commands.

    However, loading the package only to handle the visibility of this button is something very hard to digest expecially because I don't always need to call the related service. Leaving the button always visible is not an option since it can only create confusion and I'm the kind of person that only want to work in a clean working layout.

    Before I mark this thread as solved, can I ask you some final suggestions?

    What I can do to keep system resources just to the minimum required to change visibility of my command? Do you think is really a bad idea to initialize the package only when the user click the button to request the service instead of doing initialization immediately ? If I don't call "base.initialize()" immediately I should save some system resources, isn't true?

    Just to be sure that I've not forgot anything and tried everything, I was wondering if it could work If I find a way to make my button a member of the "guidVSDebugGroup" instead of just being a parent. May be that being a member, the visibility will be handled directly from VS as already does for the others commands of the list for which my command is parented.
    I know it's not possible, just want to be sure of that.

    The BeforeQueryStatus returns an OleMenuCommand representing my command. Is there a way to determine the parent of the command? I need this detail because if the parent of the command firing the event is the breakpoint window or the editor margin, then I really don't need to execute a QS since visibility is handled directly from VS. I've checked the OleMenuCommand details, but found nothing (the property list is not even filled). It also lacks of the very basic information of a command.
    Few days ago I tested a possible "addin" version of my package and found that CommandBars provides a big list of details related to a command, included the parent property that I need. How I can access the same details in a VSPackage?

    Before starting playing with extensibility, I was undecided between "package" or "addin" and finally decided for package because I was told it was a new and better technology that allow a more deep level of extensibility.
    From what I have experienced in these first days, working with packages is not straightforward like addins and I've found less things available to programmer (as stated above with OleMenuCommand).

    Thanks again

    • Edited by clarkxx Saturday, April 20, 2013 3:39 AM added details
    Saturday, April 20, 2013 3:09 AM
  • >Do you think is really a bad idea to initialize the package only when the user click the button to request the service instead of doing initialization immediately ? 

    base.Initialize does nothing, the shell calls Initialize when your package is sited.

    >Just to be sure that I've not forgot anything and tried everything, I was wondering if it could work If I find a way to make my button a member of the "guidVSDebugGroup" instead of just being a parent. May be that being a member, the visibility will be handled directly from VS as already does for the others commands of the list for which my command is parented.
    I know it's not possible, just want to be sure of that.

    No, this is not how the VS command system works. Visibility isn't controlled at a group level, it is controlled per item, the debugger has a QueryStatus handler for every command they own, not just a single one that does all of them in one shot.

    >The BeforeQueryStatus returns an OleMenuCommand representing my command. Is there a way to determine the parent of the command? I need this detail because if the parent of the command firing the event is the breakpoint window or the editor margin, then I really don't need to execute a QS since visibility is handled directly from VS. I've checked the OleMenuCommand details, but found nothing (the property list is not even filled). It also lacks of the very basic information of a command.

    I don't understand your question, if the shell is asking for your status then it needs to know your status, not just 'sometimes'.

    >From what I have experienced in these first days, working with packages is not straightforward like addins and I've found less things available to programmer (as stated above with OleMenuCommand).

    Yes, Packages are better than AddIns, they allow deeper integration and allow for lazier interaction, generally. Creating commands via an AddIn means you have to run code (no VSCT), changing their status also means you have to run code. You seem to be searching for something which simply doesn't exist, i.e. a way to have VS magically infer the right state for your commands all while running 0 code and taking 0 memory.

    Also, saying there are 'less things available' is just false, both people can query any services they wish. I believe you mean an AddIn is handed a DTE instance, but your package can say DTE dte = (DTE)GetService(typeof(SDTE)) and you to can get at DTE, though for the most part I try to avoid DTE and if given how concerned you seem to be about bloat and overhead it is humorous that you want to use DTE, which is nothing but overhead.
    Saturday, April 20, 2013 3:32 PM
  • Ok, I will leave the code generated from VS as is, since after adding your suggested code everything works flawlessly.
    I was pretty sure it was not possible to handle visibility at group level, just wanted your confirmation.

    My button is parented to "guidVSDebugGroup:IDG_BREAKPOINT_CONTEXT_MODIFY". This mean that VS will put my button in three different places (IDM_BREAKPOINT_CONTEXT, IDM_BREAKPOINTS_WINDOW_CONTEXT and IDM_BREAKPOINT_SUBMENU). Only in IDM_BREAKPOINT_SUBMENU I really need to handle the visibility of my command (for the first two, visibility is already handled automatically from VS), but I receive a BeforeQueryStatus from all of the three places. My idea was to identify the exact place from where the status is requested and only run the second QueryStatus (for the command I want the state tied to) if the request comes from IDM_BREAKPOINT_SUBMENU.
    Something like "If (MyCommand.Parent == IDM_BREAKPOINT_SUBMENU) RunQuery else return;" or much more better, limit the BeforeQueryStatus callback only to IDM_BREAKPOINT_SUBMENU.
    I'm always talking about the querystatus dedicated to handle the visibility of my command, not the callbacks related to the click (for these ones, it doesn't matter the place that originated the request since the action and the code to run is always the same independently from the origin).
    Anyway, I can leave QS free to run even in the two contexts where they are not needed. After all, every query only requires a few ms.

    I thought that DTE were only a feature available for addins and I was not aware of its overhead. Since you recommend to avoid DTE, I will follow your suggestion even if it could be the easy way (from a DTE instance, all of the things I need to access, active document, active window, debugger, commands and so on, are immediately available!).
    I'm glad of having chosen packages for VS extensibility. It is clear that, since I'm at the beginning, I tend to see addins as more powerfull and easier. I'm sure that when I will become more confident with packages, I will be able to get all of the benefits not available in addins.

    More than trying to search for something that a particular technology does not offer, I try more to avoid the discouraged practices like for example the autoload of a package only for handling the visibility of a command. Unfortunately, as in my case, there are times where, in order to get things working as expected, one is forced to break the golden rules.
    Many thanks

    Saturday, April 20, 2013 7:17 PM
  • >I really need to handle the visibility of my command (for the first two, visibility is already handled automatically from VS)

    No, there is no 'automatic' handling, unless you mean the menu isn't visible until you right click, but as soon as you do that VS needs to know your state, which means it will QueryStatus you.

    >I tend to see addins as more powerfull and easier.

    They are probably easier if you develop just using intellisense, but they are definitely not 'more powerful', and they definitely don't have the same performance characteristics or deployment story (i.e. no VSIX deployment for AddIns).

    >More than trying to search for something that a particular technology does not offer, I try more to avoid the discouraged practices like for example the autoload of a package only for handling the visibility of a command.

    There really are no hard and fast 'don't ever do X' in VS, everything has its reasons. If you see 'don't do X' it generally means 'you don't normally need to do X', sometimes you do, as in your case, but most times you don't (i.e. most times simply saying DefaultDisabled or having default enabled is sufficient, it isn't normal to be tying your status to the status of another command that you don't own).

    Monday, April 22, 2013 5:25 AM
  • Yes, It seems that there's no way to filter/limit QueryStatus only to specific CommandPlacements. Whenever VS encounters my command it will send a QueryStatus even if there's no need to handle the status for PlacementA and PlacementB.
    The only solution is to remove the command from the main group and implement a command for each placement. Then, only subscribe events for the command bound to the desired CP. May be some sort of shortcut instead of three multiple commands.
    Does not look like a good idea. I think it's more cleaner to leave things as is, one only command tied to the main group, even if I'll receive query status for unneeded placements.

    Yes, it is not normal to be tying my command status to the status of another command that I don't own. I can easily avoid this by checking if the current line of the code window contains a breakpoint. If true, I can enable/show my command, otherwise not. This is what the foreign command is supposed to do.
    Even if I write the required code, this will not help with the visibility management of my command. I will still have to autoload the package in order to change visibility.
    At least, in this way I can save me from writing code and, in theory, it should be less overhead, too.

    Yes, you're right, at the beginning addins may seems easier because there are no vsct files. I must admit it took time to understand the vsct thing, but now that I have more confidence, I must say that it's really something powerfull.
    It has been a panic with the visibility thing expecially because at the end I had to renounce to an OnDemand version of my package, but what really matter is that the behaviour of my command is exactly as I want.

    For the rest I can say that it's fun to work on VSPackages, the implementation of new functionalities is fast and pretty easy. This as long as I can keep a DTE instance where I can access the various elements of the ide in no time.
    Without dte it's a total different story or, better, a different thread...

    Bryan, I want to say thousands of thanks for your help. You're really a nice person and a great value for this forum. Not only you provide professional answers, you also enter into details and this is something that I really appreciate.

    Thanks

    Monday, April 22, 2013 10:47 PM
  • >Whenever VS encounters my command it will send a QueryStatus even if there's no need to handle the status for PlacementA and PlacementB.

    VS does QueryStatus when necessary, so I don't understand what you mean 'even if there's no need to handle the status for PlacementA and PlacementB'. Difference placements can entail different command handlers, and VS doesn't track this (it would be a massive amount of effort as handlers can change dynamically at anytime with no notification), so expecting VS to somehow 'know' it doesn't 'need' to call QueryStatus is not realistic.

    >This is what the foreign command is supposed to do.
    Even if I write the required code, this will not help with the visibility management of my command. I will still have to autoload the package in order to change visibility.
    At least, in this way I can save me from writing code and, in theory, it should be less overhead, too.

    Yes, but, as with all things in software engineering, not everything that COULD be done is done, it is based on common need. You don't just shove every possible feature into the platform that someone MIGHT need. I can see in your case it would be handy to say 'my visibility is the same as this other command' in VSCT in a way such that we could automatically manage this without loading your package. However I would argue the number of people that would want/need that is very small, and with all things whether or not it is worth doing is ranked against all the other proposals in a given ship cycle. I suspect this request would rank very, very low.

    >Yes, you're right, at the beginning addins may seems easier because there are no vsct files. I must admit it took time to understand the vsct thing, but now that I have more confidence, I must say that it's really something powerfull.

    The important difference is VSCT allows declarative command contribution, i.e. VS can build command UI without loading every single package and running code in all of them. If it had to do that it would have horrendouse perf on startup. With AddIns the ONLY way to create a command is to run code. Declarative specification of command contributions scales a hundred times better than imperative.
    >This as long as I can keep a DTE instance where I can access the various elements of the ide in no time.

    One important thing to understand when doing VS extensibility is that most all objects you get (DTE or otherwise) are COM objects. COM has very specific threading semantics and the CLR (generally) won't allow you to break them. This means if you do something like try to iterate over all command bars (from DTE) from a background thread your perf will be TERRIBLE. The reason is every single item fetch will be a synchronous RPC transition to the UI thread. Every property you touch, also a transition to the UI thread. There is a balance to strike between explicitly transiting to the UI thread and letting RPC do it for you. Generally, if you are making just one or two calls, using RPC is likely better (though that is a can of worms), if you are doing a loop and calling methods or fetching properties (which are really method calls) or just running a bunch of code that touches lots of objects, transiting once to the UI thread and running all the code there will save you a ton of time.

    >Bryan, I want to say thousands of thanks for your help. You're really a nice person and a great value for this forum. Not only you provide professional answers, you also enter into details and this is something that I really appreciate.

    Thanks, I try to help where I can, as you can see I have strong opinions (say on DTE), but they are mostly loosely held (i.e. I know reasonable people can and do disagree, and I am not so set in my opinon as to allow no exceptions). Feel free to ask questions here, I try to answer when I can and rope in other people from various teams when needed (though that sometimes doesn't work, not everyone seems to take time to answer questions here, and all I can really do is ask them to, not force them to).

    Wednesday, April 24, 2013 5:10 PM
  • Ryan, your responses never stops to surprise me. It's really a pleasure to talk with you. A good amount of things you talk about are not available in documentation or elsewhere and have really a great value.

    It's reasonable that VS doesn't track at placement level since would be a massive amount of effort. It will be fine even if I get a query status for all of the three placements while only one really requires the management of the state.
    I'm not sure how many people could like a feature like 'my visibility is the same as this other command' in VSCT. For sure not the people that implement a feature that works alone and without any relationship with the built-in ones. However, in cases like mine where I add a command to the built-in group "IDG_BREAKPOINT_CONTEXT_MODIFY", it is reasonable think that I want visibility tied to this group, otherwise I would have created and added my own group.
    I don't know the amount of work which could be required for such feature, but if it's something easy, the VS team should do this without too much doubts.

    Regarding DTE, I agree with what you said in this response, but there are much more things to consider. It's better that we continue discussion in the thread  dedicated to DTE which I recently opened.

    Thanks

    • Edited by clarkxx Wednesday, April 24, 2013 7:36 PM type
    Wednesday, April 24, 2013 7:33 PM