Archive

Archive for the ‘VSX’ Category

The build process of an Integration Package (part I)

March 31, 2010 Leave a comment

This series of posts describe the inner workings of how a package is build with focus on the VSCT file. In this part we’ll ravel out the parts of the build process.

When building a package in Visual Studio, the project file is used as an input on which items to include in the build. When you open up a csproj file of a integration package project (unload the project and open for edit) you can find next items which are related to the package type project:

  • EmbeddedResource Include=”VSPackage.resx” with children MergeWithCTO and ManifestResourceName
  • None Include=”source.extension.vsixmanifest” with child SubType Designer
  • VSCTCompile Include”xxx.vsct” with children ResourceName and SubType Designer
  • A PropertyGroup with children TargetRegistryRoot, RegisterOutputPackage and RegisterWithCodebase
  • An Import tag with attribute Project=”…Microsoft.VsSDK.Targets”
    The VSPackage.resx is a resource for the package ;-) . You can find references to it in the InstalledProductRegistrationAttribute on the package class.

The source.extension.vsixmanifest is the designer for the VSIX manifest, it declares what type of extensions are provided by the content in the VSIX. For more info about VSIX files see Quan To’s post on VSIX.

The VSCT file is the source for the command table (see further). The <SubType>Designer</Subtype> on the vsct file tells VS to show a View Code/View Designer group in the context menu. In both cases it opens up a xml designer.

The PropertyGroup are options of the VSIX build process and can be found in the property page of the project in the VSIX tab.

All the previous items are used during the build process. This process is declared in the import tag pointing to a build targets file : “$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\VSSDK\Microsoft.VsSDK.targets”. This file can be found typically in the “C:\Program Files\MSBuild\Microsoft\VisualStudio\v10.0\VSSDK” folder. When you open this folder you can find the Microsoft.VsSDK.targets, Microsoft.VsSDK.Common.targets files and an assembly Microsoft.VsSDK.Build.Tasks. These are the key players of the build process.

If we take a look at the tasks, we could categorize them as in beneath image:

VSSDK Build steps

  1. Check On VsSDK installation: checks if VsSDK is installed
  2. Compile VSCT: compiles the VSCT file into a CTO file (command table)
  3. Deploy VSIX: prepares for the deployment of the package
  4. Merge CTO resource: check on resources (like MenuResource) to merge into the cto file
  5. Generate Code from LEX/YACC files: the language token and lexical classes used to enable syntax coloring (see Babel)
  6. Generate PkgDef file: generates the package definition file which represents registry values that are created when an application is installed on a computer and that are referenced by the Visual Studio Shell when it starts the application.
  7. Generate Zip file: generates the Zip file to be deployed

In next post we’ll take a closer look at the tasks related to the VSCT file.

Categories: VSX Tags:

Writing to the VS ErrorList

March 23, 2010 4 comments

The Shell provides a class to gain access to the ErrorList pane : ErrorListProvider. It implements the Add/Remove of ErrorList items in the ErrorList pane. To gain access to this provider it expects a ServiceProvider in the constructor. This provider can be the GlobalService of the Package class.

An ErrorList item is a class (called ErrorTask) where you can set all needed properties to navigate to the location in the document, categorize it and show the message.

So, it’s a quite simple and natural way of showing items in the ErrorList. I’ll show you the details now.

The simpliest approach is to create a helper class that implements the IServiceProvider interface; the implementation body of this interface (GetService(Type)) is a call to the Package.GetGlobalService(serviceType). Now we enabled the construction of the ErrorListProvider with this helper class.

public class ErrorListHelper : IServiceProvider
{
   public object GetService(Type serviceType)
    {
        return Package.GetGlobalService(serviceType);
    }
}

Now we can instantiate the ErrorListProvider: it is important here to give the provider a name and a new guid. Try to avoid making a new (= new guid and name) ErrorListProvider for each call. Consider making a singleton to access the helper class, if so make it scope the package only (for example by making the class generic).

public class ErrorListHelper : IServiceProvider
{
    public ErrorListProvider GetErrorListProvider()
    {
        ErrorListProvider provider = new ErrorListProvider(this);//this implementing IServiceProvider
        provider.ProviderName = {name scoping package};
        provider.ProviderGuid = {guid scoping package};
        return provider;
    }
}

Now that we have the ErrorListProvider in place, we have to make the helper class to add and remove items from the list: this includes, creating a ErrorTask object and handle the event to navigate to the context document’s position.

Lets start taking a look on how to create a ErrorTask object:

public void Write(
            TaskCategory category,
            TaskErrorCategory errorCategory,
            string context, //used as an indicator when removing
            string text,
            string document,
            int line,
            int column)
{
    ErrorTask task = new ErrorTask();
    task.Text = text;
    task.ErrorCategory = errorCategory;
    //The task list does +1 before showing this numbers
    task.Line = line - 1;
    task.Column = column - 1;
    task.Document = document;
    task.Category = category;

    if(! string.IsNullOrEmpty(document))
    {
        //attach to the navigate event
        task.Navigate += NavigateDocument;
    }   
    GetErrorListProvider().Tasks.Add(task);//add it to the errorlistprovider

}

Now that we have the ErrorTask in place, we can take a look at the handling of the Navigate event. This is a bit of code that I have centralized in another helper class to be reusable.

void NavigateDocument(object sender, EventArgs e)
{
    Task task = sender as Task;
    if (task == null)
    {
        throw new ArgumentException("sender");
    }
    //use the helper class to handle the navigation
    ShellContext.OpenDocumentAndNavigateTo(task.Document, task.Line, task.Column);
}

What it must cover:

  • get the VS service to open the document (IVsShellOpenDocument)
  • open the document via the OpenDocumentViaProject; this gives you a pointer to the frame (IVsWindowFrame) hosting the document
  • use the frame to get the VsTextBuffer
  • get the VS service that manages the textbuffer (VsTextManager) and use it to navigate to the position in the document

Here is the peace of code that does this:

    public static void OpenDocumentAndNavigateTo(
                                    string path, int line, int column)
    {
        IVsUIShellOpenDocument openDoc =
            Package.GetGlobalService(typeof(IVsUIShellOpenDocument))
                    as IVsUIShellOpenDocument;
        if (openDoc == null)
        {
            return ;
        }
        IVsWindowFrame frame;
        Microsoft.VisualStudio.OLE.Interop.IServiceProvider sp;
        IVsUIHierarchy hier;
        uint itemid;
        Guid logicalView = VSConstants.LOGVIEWID_Code;
        if (ErrorHandler.Failed(
            openDoc.OpenDocumentViaProject(path, ref logicalView, out sp, out hier, out itemid, out frame))
            || frame == null)
        {
            return ;
        }  
        object docData;  
        frame.GetProperty((int)__VSFPROPID.VSFPROPID_DocData, out docData);  

        // Get the VsTextBuffer  
        VsTextBuffer buffer = docData as VsTextBuffer;  
        if (buffer == null )  
        {  
            IVsTextBufferProvider bufferProvider = docData as IVsTextBufferProvider;  
            if (bufferProvider != null )  
            {  
                IVsTextLines lines;  
                ErrorHandler.ThrowOnFailure(bufferProvider.GetTextBuffer(out lines));  
                buffer = lines as VsTextBuffer;  
                Debug.Assert(buffer != null, "IVsTextLines does not implement IVsTextBuffer");  
                if (buffer == null)  
                {  
                   return ;  
                }  
            }  
        } 
        // Finally, perform the navigation.  
        IVsTextManager mgr = Package.GetGlobalService(typeof(VsTextManagerClass))
             as IVsTextManager;  
        if (mgr == null)  
        {  
            return;  
        }  
        mgr.NavigateToLineAndColumn(buffer, ref logicalView, line, column, line, column);  
    }

To remove the ErrorTask from the list, make use of the same Guid/Name to re-instantiate the ErrorListProvider.  The context argument in the write method can be used to remove all ErrorTasks for this context. The handling with the context is not covered here, because this post is focussed on the element to make this work.

When removing you should use the SuspendRefresh() before removing and ResumeRefresh() after the items are removed to avoid flickering.

 With all this parts paste together it should do the job, for me it did ;-)

Categories: VSX Tags: ,

VS Menu CommandId’s listed

February 18, 2010 5 comments

Isn’t it hard, each time you want to attach your menuitem to a VS menu, to find the correct guid of that menu ? You can search in the vsshlids.h header file or set the EnableVSIPLogging registrykey to debug the VS (see Dr. eX’s Blog ). Second option is very helpfull but you have to write down the Id’s, no copy/past available here. You can imagine that this is very error proun. To avoid this repetitive handling, I decided to keep track of all the Id’s I found so far. This means this post will regulary be updated.

Following sections are covered:

Considerations

Attaching your menu to a VS menu

When you have found out the id of the VS Menu you want to attach to, you have to:

1. Define the id in the Symbols section of the vsct file.

The Guid is the GuidSymbol id, the Id the IDSymbol (listed in this post)

<!-- This is the guid used to group the Team Explorer’s My Favorits together -->
<GuidSymbol name="guidTE_MyFavoritesCmdSet" value="{7DD170F4-0855-4A2D-B3AA-7FB59A79D27D}">
      <IDSymbol name="MyFavorites" value="256" />
</GuidSymbol>

2. Use it as a parent in your Group

<!—Your command group attaching to the context menu of the MyFavorits tag in the Team Explorer window-->
<Group guid="guidMyPackageCmdSet" id="MyMenuGroup" priority="0x0600">
   <Parent guid="guidTE_MyFavoritesCmdSet" id="MyFavorites"/>
</Group>

Using dymamic visibility

When using dymamic visibility (= setting CommandFlag DynamicVisibility on your button in the vsct file and subscribing on the OnBeforeQueryStatus of the OleMenuCommand) you have to set the ProvideAutoLoadAttibute on your Package class to enable the querying.

[ProvideAutoLoad("{adfc4e64-0397-11d1-9f4e-00a0c911004f}")] //NoSolution
public sealed class MyPackage: Package
{
}

You can find the UIContext id’s in the vsshlid.h header file ({SDK directory} \VisualStudioIntegration\Common\Inc). For completeness I’ll state them here too.

UIContext Guid
SolutionBuilding {adfc4e60-0397-11d1-9f4e-00a0c911004f}
Debugging {adfc4e61-0397-11d1-9f4e-00a0c911004f}
FullScreenMode {adfc4e62-0397-11d1-9f4e-00a0c911004f}
DesignMode {adfc4e63-0397-11d1-9f4e-00a0c911004f}
NoSolution {adfc4e64-0397-11d1-9f4e-00a0c911004f}
SolutionExists {f1536ef8-92ec-443c-9ed7-fdadf150da82}
EmptySolution {adfc4e65-0397-11d1-9f4e-00a0c911004f}
SolutionHasSingleProject {adfc4e66-0397-11d1-9f4e-00a0c911004f}
SolutionHasMultipleProjects {93694fa0-0397-11d1-9f4e-00a0c911004f}
CodeWindow {8fe2df1d-e0da-4ebe-9d5c-415d40e487b5}
NotBuildingAndNotDebugging {48ea4a80-f14e-4107-88fa-8d0016f30b9c}
SolutionExistsAndNotBuildingAndNotDebugging {d0e4deec-1b53-4cda-8559-d454583ad23b}

Tip: you could place them in a separate class and use them as constants.

Lists

Team Explorer
Group: guidTE_TeamProjectServerCmdSet – GUIDSymbol: {23D49123-60AC-4D7E-939A-E01A4E176BEE}

Context IDSymbol
Team Foundation Server 256
Group: guidTE_MyFavoritesCmdSet – GUIDSymbol: {7DD170F4-0855-4A2D-B3AA-7FB59A79D27D}

Context IDSymbol
My Favorites 256
Group: guidTE_TeamProjectCmdSet - GUIDSymbol: {D309F791-903F-11D0-9EFC-00A0C911004F}

Context IDSymbol
Team Project 1799
Group: guidTE_WorkItemsCmdSet – GUIDSymbol: {2DC8D6BB-916C-4B80-9C52-FD8FC371ACC2}

Context IDSymbol
Work Items 513
Query Folder (*1) 514
Query (*2) 515

(*1): My Queries, Team Queries, Workbook Queries
(*2): MyBugs, MyTasks, OpenIssues, Product Backlog (Workbook Queries)…

Group: guidTE_BuildsCmdSet – GUIDSymbol: {34586048-8400-472E-BBBF-3AE30AF8046E}

Context IDSymbol
Builds 256
Build Definition 258
All Build Definitions 259
Categories: VSX Tags: , ,

VSXL 1 – Tackling commands and menus.

January 12, 2010 Leave a comment

This part will explain how we can reorganize the menus and commands to enable usage of an extension package.

To get around the workings of menus and commands I can recommend this blog by Inovak. Though it is written to build his VSXtra tool, it explains the inner workings of VS in context of menus and commands.

There is another blog by Inovak that explains the vsct file, which is a key part in the menus and commands workings (see below).

Next picture gives an overview of the parts that contribute in the menus and commands, based upon Inovak’s blog items.

Goal

We want the ability to add a (menu) command from a context menu when project is selected.

Let us take a look on what tasks should be automated when we use the current VSX approach:

  1. Update the vsct file and let the user give input on how and where the menu is displayed
  2. When dynamic menu, a BeforeQueryStatus eventhandler is needed
  3. Update the initialize method of the custom ‘Package.cs’ file to add the menucommand to the menucommand service

The first problem here is, there is no physical file for the command. All coding is done in the ‘package.cs’ file. So, let’s try to migrate the code from the package file to a separate command file.

The Command file.

These are the things that are directly related to the command and can be put in a separate class:

-          The Id of the command: a uint

-          The id of the commandset the command is belonging to : a guid

-          The implementation of execution of the command

-          [Optional] Visibility handling: via BeforeQueryStatus

Regarding the command id; in the MS solution they are gathered in the ‘PkgCmdId.cs’ file. This is not a bad idea since they are a range of id’s and no guids. For example, 0×100 is the first, 0×101 is the second, and so on. Otherwise, it would be nice to have them tightly coupled to the command file itself. So a reference to the id is the preferable solution.

Regarding the commandset id; in the MS solution they are gathered in the ‘GuidList.cs’ file. Since this is a guid and if we make use of a CommandGroup class as a holder of the id, I don’t see the benefit of using this.

Since a command is bound to its package, a reference to this package is also needed.

The CommandGroup itself is merely a representation of the Id. If we want to query which commands are attached, we can either use the VSCT file or query the Commands in the package that point to a specific CommandGroupClass.

The ‘CustomCommand’ is a set of 2 partial classes. One is generated by our integration package (storing the id’s and reference to the type of CommandGroup), another is presented to the developer to implement the base methods. This is called the double-derived pattern. In that way we can regenerate the custom command without removing the implementation.

A second task is to be done when generating a command class: managing the ‘PkgCmdId.cs’ file. Before loading our integration package command, we could load this class into memory and keep it there for the lifetime of the command execution. It should be presented as a package service so we could call something like ‘CreateNewCmdId(string commandName)’. The management and synchronization should be handled by this service. We’ll tackle this issue in a future blog, which will probably be: tackling the services.  

Notice, that to be able to register the command we need to call the IMenuCommandService.  Since the called method ‘GetService’ is declared on the Package class, we can only access it from there. For now, we’ll use a utility to retrieve all the Command classes that need to be registered. Likewise, it will be refactored when tackling the services.

A last task is to keep in sync with the VSCT file. We can make use of XDocument to readout and write to. It should not allow making any changes to the command ids. To make things a little bit easier we can make use of the VS internal RDT (running document table).  To keep in scope, we’ll dedicate this in a separate blog.

VSCT revised

There are a few things that one could change about the way the VSCT file is used. Since it is only a declarative way of showing the command table definitions, it is possible to handle the building of the resources ourselves and create a resource per command. But this would mean that a custom postbuild tool should be made to create this resource. Since the added value of this is minor, I don’t think it’s a good idea.

On the other hand, creating a custom editor for managing the VSCT file looks like a better idea. Of course, I’m not the only one who thought of that: VSCT PowerToy, available at the MSDN code gallery [http://code.msdn.microsoft.com/VSCTPowerToy]. With this tool you cannot only manage your own command table but also look at other packages’ command tables!  It’s a nice way to learn on how to build your own ones.

In the next blog we will show you the coding of this all.

Categories: VSX, VSXL Tags: , ,

Part 2 : Decide Approach

January 2, 2010 Leave a comment

In previous post I pointed out where I would be focussing on to achieve a better DX with VSX integration package:

  • Refactoring MPF in context of usability
  • Writing a new integration package project

Now, after some considerations made, I’ve decided to change my approach. What I realy want to achieve is to be able to present tools to fasten up the development and lower the threshold. Herefore I only need a integration package for the VSX integration package to automate common tasks.

Refactoring the MPF is a good plan, but actually, the only thing that should be refactored is the top-layer, the way MPF organizes itself. I’ve looked into refactoring it and notice that it tantamounts to change the way it registers components (commands, toolwindows, services). Also, the core of all is enclosed in one file, namely the Package class.

Refactoring would take a massive part of my time, so I looked around to see if someone else would have made the effort. I found a need project, http://vsxtra.codeplex.com/. This project does all the refactoring. I considered to use it as a base to create my own integration package. I will not use it because of an extra dependency into my package.

It is still my intention to write a new integration package project. I can start with an Integration package to later migrate to a seperate project template.

So to conclude: I will focus on wrap the most of the MPF with a thin layer to automate small pieces of functionality. This way of working allows me to gradually increase the scope and leverage very fast small pieces of automated task without impacting existing VSX packages.

I also named the project VSXL. So from now on I’ll will use this to address the Visual Studio Integration Package Integration Package.

Part1: A first Developer Experience (DX)

December 31, 2009 Leave a comment

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

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

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

My Command

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

Command Result

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

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

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.

 

Categories: VSX Tags: , ,

First Post on VSX Experience

December 30, 2009 Leave a comment

As an early on developer, the VSX (former VSIP) always intreged me. Creating your own project template and extensions felt like a massive advandage in developer productivity. Reading around on the possibilities on extensibility encourage me several times to start developing packages and work out ideas that were buggling around in my head. Unfortunately,  each time, the learning curve was to big and time inhibited me to finialize the projects in mind.

Again, this year (2009), I was confronted with the same situation. Only this time I bogged down in VSX and started to free-up some time. On the way, I saw myself spending the most of the time creating registrationkeys and configuring vsct (command tables). This wasn’t very encouraging, especially considering building automation packages with a tool that actually doen’t do any automation except on creation of a package.

Out of this frustration, I took the intention to create me a VSX  package to extend the VS integration Package project with automated task. That’s what this blog will be about (in the first instance): how to achieve an integration package to support VSX automation.

Hope you’ll enjoy !

Oh yes, and a happy 2010 !

Follow

Get every new post delivered to your Inbox.