In this topic I’ll try to point out the barriers to achieve my goal. All the topics are written with writing an integration package for VSX integration package in mind.
The offered project when creating a new VSX integration package doesn’t make it simple to extract some functionality that could be automated. Consider next case:
“Add a command named ‘MyCommand’. When the context menu in the solution explorer is shown for a file with extension ‘.cs’, show the command in the menu. Make the command’s click event visible to the developer so that he can subscribe on it (only allowing one subscription on the event).“
Now, let’s try to develop this. I’ll approach this from a developer stand of view (DX).
A DX story
Open Visual Studio and create an new project, select ‘Other Project Types/Extensibility’ node and choose Visual Studio Integration Package as template and click ‘OK’.

New integration package
A project wizard is shown.
Click ‘Next’. Select Visual c# as a language option and generate a new key file.
Click ‘Next’. Add some package information (not important for this example).
Click ‘Next’. Now the VSPackage options are shown. Select ‘Menu Command’.
Click ‘Next”. Provide a command name, say ‘My Command’, and a command id. If you’ve never done this before you will probably wonder why to provide a name for an Id. ”When I’m using a Winforms project and add a button, then an Id is the name, isn’t it ? Probably the labels are wrong, and the command name should be ‘Text’ or ‘Caption’ and the command id the ‘Name’.“. Welcome to the world of Package syntax. To continue, leave the proposed name.
Click ‘Next’. Uncheck the unit test projects.
Click ‘Finish’. The solution is now created.

Outcome
Let’s take a look to the outcome.
So, I would expect to have a command (somewhere). Ok, let’s look for it. I named it ‘MyCommand’, so intiutivily I look for a file named ‘MyCommand.cs’. Nope, no such file. Aah, I found a file PkgCmdId.cs. Maybe they messed up the naming. No luck here. Ok, then use Find to find ’MyCommand’. Yeah, found it ! 2 files: VSPackage1.vsct and VSPackage1Package.cs. Vsct, what’s ? If you do some lookup you’ll see it stands for ’visual studio command table’ (I’ll get back on this in another blog item). Let’s open this file. Hey, I can find ‘MyCommand’ as a Button. Seems like a lot of generated stuff, so I’ll leave it. I can see here some literals : CommandName and ButtonText. Euh, didn’t I just entered ‘My Command’ as command name ? But now it uses the CommandId I just entered as CommandName and the ‘MyCommand’ as ButtonText . Bit confusing… I’ve seen enough from this file. Let’s open op the other file, the VSPackage1Package.cs.
Aha, c# code, I feel familiair. Base class…blabla… override Initialize(), yes. I see a OleCommandServive, so probably uses a ServiceProvider. Why does the baseclass exposes a GetService ? I’m used to call ServiceProvider.Instance.GetService() alike method ? So, I need this service to add my command to, most likely to expose it to VS. It seems it first needs an identifier ‘CommandID’ identified with 2 guids: a PackageCmdSet id, being the menuGroup identifier (Intellisence) and the commandID. Hey, the commandID’s name entered in the wizard pops up here ! So now it’s called commandID again. Nice, I think… Now, the MenuCommand is constructed with an eventhandler and the commandid object.
Strange, wouldn’t it be easier to: create a (custom) command with the identifiers as an attribute and subscribe to an event on the instance of the command ? They added a implementation for the eventhandling. It seems it only shows a messagebox with message “Inside MyCommand.MenuItemCallBack()”. Wierd syntax for a messagebox. Probably all has to do with COM. I recognize some stuff from Win32 unmanaged MessageBox.
Ok, now that I’ve explored the code, let’s try run it. Oh, I didn’t figger out yet where my command is shown. Nothing in the Package.cs file, must be in the vsct file. Back to the ‘Button’-tag, there is a child node named ‘Parent’ with id=’MyMenuGroup’. Found it in the Groups section. It also has a Parent-tag with id=’IDM_VS_MENU_TOOLS’. Won’t ask where this value comes from (will be covered in future blogs), but it state Tools, so probably the tools menu. Correct, found it.

My Command
Let’s click it. Alright, I have a working command !

Command Result
Now I have a command working, but I’d like it to be associated with a ‘.cs’ file. Euhm, where to start ? Google to the rescue !
To enable a menu when a context menu item is selected on a project item I have to write a listener and register it in VS’s MonitorSelection eventbroker. In that way I’ll be notified each time an item is selected and query if this is the item of interest for me. To achieve this I have to implement IVsSelectionEvents (OnCmdUIContextChanged, OnElementValueChanged, OnSelectionChanged).
Shouldn’t this be integrated in a Command like class ? Could be done on registration of the command (see previous). The custom command could be decorated with an attribute telling which file extension should be associated with the command.
I will not go any furthur here. I think I made my point. This is only a scenario started from a blank project. What if you want to extend it with a second command ? You have to do it all by hand, this time.
If we move this way of working to UX, what user interface would you prefer?

Bad and Good UX
Where did it go wrong ?
To understand what is going on, we have to take a brief look to the VS architecture.

VSX Components
On the top you see the target application type. In this context we are only interested in the managed package pilar.
Before we reach the core components of visual studio we pass the package API, the .Net interop Assemblies and the Managed Package Framework (MPF). Visual studio is build upon COM. To enable extensibility a set of interfaces are provided (package API) . Because this is unmanaged, a MPF is created using .Net Interop Assemblies to enable to work in a managed fashion.
The MPF is a nice job on wrapping the COMInterop, making the VS Core more accessable from managed code. Unfortunately, they seemed to forget it had to be used by developers using VS to develop packages.
Secondly, the Integration Package Template seems to be a quick, on the side, solution for package development. I suspect that the money was spent after they reached the wizard implementation.
Conclusion
There are 2 jobs to be done : refactor the MPF in context of usability, whilst maintaining the COM wrapping and write a genuine Integration Package project template (or extend the current package with a new package).
This is what I’ll be focussing on in future blogs.
Recent Comments