Extensibility wrapper
Cats: Code
So i finally finished writing my visual studio extensibility wrapper. The idea was to insulate developers from some of the horrors of vs '05 by providing a translation mechanism. The wrapper supports two major things (plus some other, client-specific functionality) - the ability to add an item to any menu in vs declarativley, and the ability to create tracking objects for every project that is currently open.
The menu system works in two parts - first there is a class you have to subclass - MenuBarItem, and an attribute you have to decorate your class with - TargetBarsAttribute. The parent class defines two abstract methods InnerQueryStatus and InnerExec, which get called as a result of the system invoking query status on the IDTCommandTarget2 that it gets, and function the same way as those defined by the interface do. The attribute lets you pick from a number of predefined locations (Code Window context menu, Menu Bar and Solution Explorer Context Menu) , or specify a list of paths separated by ';'.
The interesting thing with vs is that there's not really a good way to identify a less common menu bar. They're all accessible by name, but the names aren't unique, and there isn't a reference of them. Microsoft actually recommends that if you want a list of command bars, you should write an app that will iterate through the DTE's CommandBars object at print them out, which is what I ended up having to do (i'll post the results and code for that later). As a result, what ends up happening is you have to come up with a better definition of what menu bar you're going after. I wanted to add an item to the menu that comes up when you right-click on an element in the web designer. I figured out that it's called "Context"... well so are 10 others - so i had to extend the path mechanism of the attribute a bit. What you can do is specify a parent, a target and a list of items the target should have - "Other Context Menus/Context[View Code|Show Smart Tag]". This will find the Other Context Menus command bar (thankfully a unique name), then iterate through its children to find a command bar that's called Context and has a view code and show smart tag option.
Whew. What a pain. The wonderful thing is that while i was writing all of this, i ran into the most idiotic issue. When an item gets added, the wrapper builds a list of command bars to add the item to. When it would iterate through that list, and add the item to the command bar, it would always fail on the second addition, with a "Catastrophic Failure". Useful. Very. Especially since the microsoft guys on their own forums decided to let me figure that one on my own (don't get me started on them - completely useless individuals; if you ask something that can't be looked up in the documentation, you're SOL). What was it, you ask? Well it was my mistake. I was passing in an index for the new menu item that was driven by the wrong thing - the item was added to the first bar into location 1, the second bar into location 2 and so on. Of course, since (for whatever reason) certain things in vs extensibility use 1-based indeces, the first worked, the second didn't. Why that couldn't have generated an IndexOutBounds exception, or something else a bit more useful that Catastrophic Failure is beyond me, and cost me about a week of banging my head against the wall.
Anyway... it's time for me to run, i'll post a follow up for this in a bit to talk about the other piece.