views:

484

answers:

2

I wonder if anyone can tell me why does QueryStatus() method get called so many times when command is being evaluated for execution? In my case it gets called several times (at least 9) with at least one vsCommandStatusTextWantedName and many more vsCommandStatusTextWantedNone, but never with vsCommandStatusTextWantedStatus?

So lots of QueryStatus() calls for just one Exec(). Why?

Example details
I have only one Command and one CommandBarButton related to it, that resides in "Code Window" context menu. Whenever I left click within code window, QueryStatus() should be called (as I understand it) three times at most. For each vsCommandStatusTextWanted once. Why is this not the case in this situation?

+1  A: 

The one Exec() part is easy: that only gets called when a command is actually invoked. QueryStatus() will get called at different times to update UI elements like menu items, toolbar buttons. Since status can be different depending on state like: is text selected, is a project open, is a file open, etc, it needs to be queried for often.

Edit: And if you have multiple commands, then the status for each one needs to be queried for even if the user doesn't end up invoking any of them. If you have commands that are visible (on a menu or in a toolbar), the UI needs to query about their applicability to the current environment (which isn't static).

sean e
Exactly my thought. But I can't see where is the need for more than one QueryStatus() per vsCommandSTatusTestWantedXYZ... I have a context menu item in Code Window and when I left click within code it's natural that QueryStatus will first evaluate its name and status (which is not called, but vsCommandStatusTextWantedNone is called instead). But not more than these two... Why so many in this particular case?
Robert Koritnik
+1  A: 

VSPackages implement IOleCommandTarget to handle QueryStatus calls from the environment. Addins implement a similar interface - IDTCommandTarget. But IOleCommandTarget does not use the vsCommandStatusTextWanted enumeration that you have in IDTCommandTarget.

For a VSPackage command in the top menu, QueryStatus is called once per command for static commands: to see if command is enabled.
For dynamic commands, QueryStatus is called twice per command: once to see if the command should be visible and a second time to see if it is enabled.

Here's the native callstack for first call into a VSPackage IOleCommandTarget:QueryStatus:

msenv.dll!CVSCommandTarget::QueryStatusCmd()  + 0x9f9 bytes 
msenv.dll!CVSShellMenu::IsCommandVisible()  + 0x5f bytes 
msenv.dll!CVSShellMenu::IsCommandVisible()  + 0x10f bytes 
msenv.dll!CMsoButtonUser::FAutoVisible()  + 0x16 bytes 
msenv.dll!CVSShellMenu::IsMenuVisible()  + 0x21bf bytes 
msenv.dll!CMsoMenuUser::FAutoVisible()  + 0x3f bytes 
msenv.dll!TBC::FAutoVisible()  + 0x31 bytes 
msenv.dll!TB::CalcRectOrReflowToolbar()  + 0x351 bytes 
msenv.dll!TB::FSetBestRectEx()  - 0x5958d bytes 
msenv.dll!TB::FShowTbInternal()  + 0x13835a bytes 
msenv.dll!TB::FPlacePopup()  + 0x114 bytes 
msenv.dll!TBComponentPopup::ModalPopup()  + 0x93 bytes 
msenv.dll!TB::FPopup()  + 0x133 bytes 
msenv.dll!CVSShellMenu::ShowContextMenu()  + 0x172 bytes
 ....

And the callstack for the second call:

msenv.dll!CVSCommandTarget::QueryStatusCmd()  + 0x9f9 bytes 
msenv.dll!CVSShellMenu::IsCommandVisible()  + 0x5f bytes 
msenv.dll!CVSShellMenu::IsCommandVisible()  + 0x10f bytes 
msenv.dll!CMsoButtonUser::FAutoVisible()  + 0x16 bytes 
msenv.dll!CVSShellMenu::IsMenuVisible()  + 0x21bf bytes 
msenv.dll!CMsoMenuUser::FEnabled()  + 0xc5 bytes 
msenv.dll!TBC::FEnabled()  + 0x54 bytes 
msenv.dll!TBCM::FEnabled()  + 0x1b bytes 
msenv.dll!TBCM::FUpdate()  + 0x2e bytes 
msenv.dll!TB::CalcRectOrReflowToolbar()  + 0x689 bytes 
msenv.dll!TB::FSetBestRectEx()  - 0x5958d bytes 
msenv.dll!TB::FShowTbInternal()  + 0x13835a bytes 
msenv.dll!TB::FPlacePopup()  + 0x114 bytes 
msenv.dll!TBComponentPopup::ModalPopup()  + 0x93 bytes 
msenv.dll!TB::FPopup()  + 0x133 bytes 
msenv.dll!CVSShellMenu::ShowContextMenu()  + 0x172 bytes 
 ....

I suspect that your command (or Addin commands in general?) are treated as dynamic (with dynamic text), but can't guess as to why a single command would have QueryStatus called 9 consecutive times if it does not appear in a toolbar or top-level menu (only in the context menu). So I could see 3 QueryStatus calls: is visible, is enabled, get text. 9 being a multiple of 3 is interesting...

If you don't have the symbol server setup for your debugger, I would get it set up so that you can check out the msenv.dll calls to get any indication as I did above for the VSPackage QueryStatus calls.

sean e
This doesn't directly answer my question, because I'm not creating a VSPackage but an Add-in. I would only like to know when does QueryStatus get called and for what purpose. What could help in your answer is the setup of debugger symbol server.
Robert Koritnik
I understand that you are creating an addin. That is why I explained the difference between an addin and a package. The point of the post was to show how getting the symbol server set up could help you answer your own question.
sean e