5,446,823 members and growing! (17,739 online)
Email Password   helpLost your password?
Languages » C# » Utilities     Beginner License: The Code Project Open License (CPOL)

Developing Visual Studio Add-in to enforce company’s standard modification history

By Rahil Jan Muhammad

Using Visual Studio.net to develop Add-in to enforce company’s standard modification history
C# (C# 1.0, C# 2.0, C# 3.0, C#), .NET, Visual Studio, Architect, Dev, Design

Posted: 21 May 2008
Updated: 21 Jun 2008
Views: 5,757
Bookmarked: 34 times
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
9 votes for this Article.
Popularity: 3.75 Rating: 3.93 out of 5
0 votes, 0.0%
1
1 vote, 11.1%
2
2 votes, 22.2%
3
1 vote, 11.1%
4
5 votes, 55.6%
5
Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report This Article

Introduction

Like many other features provided by visual studio.net, Add-in is also a very useful feature of visual studio but unfortunately only few users use this feature.
Through add-ins you can integrate extra functionalities directly into the visual studio IDE. In this article we will create an add-in that will help to implement
standard modification history at the top of you c# files.
please please do vote for my article weather you like it or not ;)

Using the Code

In this article initially we will use the wizard provided by the IDE then we will modify the generated code as per our requirements. Our target is to provide option
in the Tools menu to add standard modification history at the top of c# files (see fig 1a and 1b).


Fig 1a


Fig 1b

Create a new Visual studio Add-in project as displayed in the figure 2a. Click OK and select Next in the second step of wizard. Select the language you need to
use for your add-in in the third step of wizard; I am using C# for this article.


Fig 2a

Make sure that you have selected both options in the next step (fig 3a).


Fig 3a

Give your add-in a decent name in the next step. Since I will be using this add-in to enforce modification history standards therefore I am using
“Modification History” as a name and also as a description, I would suggest you to give more meaningful description (fig 4a).


Fig 4a

In the very next step I would recommend you to at-least select the first option. By selecting this option visual studio.net would generate a code to add a
command with default icon in the Tools menu, which we will be modifying later on (fig 5a).


Fig 5a

In the next screen if you select the given option then programmer will have the option of adding an about box and other technical support information. For now
I am not using this feature (Fig 6a). And in the next immediate screen click Finish


Fig 6a

Once you complete the wizard you would have auto generated code and if you run this auto generated project you would notice that you have a new menu item in Tools menu.
Now lets talk about the code, all we need to focus on is connect.cs class. Connect.cs class provides IDTExtensibility2 interface that allows the programmer to take
control of IDE’s user interface functionality. The main object we will be using is already generated by visual studio.net

private DTE2 _applicationObject;

In this article we will modify auto generated code of 3 functions of connect.cs class

public void Exec(…)
public void QueryStatus(…)
public void OnConnection(…)

In the auto generated code of OnConnecion(…) you would see that in the try block only one command option is created and that command button is added into the Tools menu but as per our need we need to create 2 commands (one for Created By modification history and other one is for Modified By modification history) in the submenu (see fig 1a). For this purpose we have modified the generated code within Try block on OnConnection(…) method.

public void OnConnection(object application, ext_ConnectMode connectMode,
    object addInInst, ref Array custom)
{
    _applicationObject = (DTE2)application;
    _addInInstance = (AddIn)addInInst;
    if(connectMode == ext_ConnectMode.ext_cm_UISetup)
    {
    object []contextGUIDS = new object[] { };
    Commands2 commands = (Commands2)_applicationObject.Commands;
    string toolsMenuName;

    try
    {
        //If you would like to move the command to a different menu, change the
        //  word "Tools" to the English version of the menu. This code will take
        //  the culture, append on the name of the menu then add the command to
        //  that menu. You can find a list of all the top-level menus in the file
        //  CommandBar.resx.
        ResourceManager resourceManager = new ResourceManager(
                                                           "ModificationHistory.CommandBar", 
                                                           Assembly.GetExecutingAssembly());
        CultureInfo cultureInfo = new System.Globalization.CultureInfo(
            _applicationObject.LocaleID);
        string resourceName = String.Concat(cultureInfo.TwoLetterISOLanguageName, "Tools");
        toolsMenuName = resourceManager.GetString(resourceName);
    }
    catch
    {
        //We tried to find a localized version of the word Tools, but one was not found.
        //  Default to the en-US word, which may work for the current culture.
        toolsMenuName = "Tools";
    }

    //Place the command on the tools menu.
    //Find the MenuBar command bar, which is the top-level command bar holding all
    //the main menu items:
    Microsoft.VisualStudio.CommandBars.CommandBar menuBarCommandBar = 
((Microsoft.VisualStudio.CommandBars.CommandBars)_applicationObject.CommandBars)["MenuBar"];

    //Find the Tools command bar on the MenuBar command bar:
    CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName];
    CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl;

    //This try/catch block can be duplicated if you wish to add multiple commands
    //  to be handled by your Add-in, just make sure you also update the
    //  QueryStatus/Exec method to include the new command names.
    try
    {
        //User Code Start
        //searhing if submenu already exists
        for (int iloop = 1; iloop <= toolsPopup.CommandBar.Controls.Count; iloop++)
        {
             if (toolsPopup.CommandBar.Controls[iloop].Caption == "Modification History")
             {
                 CommandBarPopup op = 
                     (CommandBarPopup)toolsPopup.CommandBar.Controls[iloop];
                 oBar = op.CommandBar;
                 break;
             }
        }
                   
        //Add a command to the Commands collection:
        Command cmdCreatedBy = commands.AddNamedCommand2(_addInInstance, "CreatedBy", 
            "Created By", "Executes the command for Created By", true, 10, 
            ref contextGUIDS,  (int)vsCommandStatus.vsCommandStatusSupported + 
            (int)vsCommandStatus.vsCommandStatusEnabled,
            (int)vsCommandStyle.vsCommandStylePictAndText, 
            vsCommandControlType.vsCommandControlTypeButton);
        Command cmdModifiedBy = commands.AddNamedCommand2(_addInInstance, "ModifiedBy", 
            "Modified By", "Executes the command for ModificationHistory", true, 13, 
            ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + 
            (int)vsCommandStatus.vsCommandStatusEnabled,
            (int)vsCommandStyle.vsCommandStylePictAndText, 
            vsCommandControlType.vsCommandControlTypeButton);

        //if required submenu doesn't exist create a new one
        if (oBar == null)
              oBar = (CommandBar)commands.AddCommandBar("Modification History", 
                        vsCommandBarType.vsCommandBarTypeMenu, toolsPopup.CommandBar, 1);


        //Add a control for the command to the tools menu:
        if ((cmdModifiedBy != null) && (toolsPopup != null))
            cmdModifiedBy.AddControl(oBar, 1);

        //Add a control for the command to the tools menu:
        if ((cmdCreatedBy != null) && (toolsPopup != null))
                cmdCreatedBy.AddControl(oBar, 1);

        //User Code End
        }
    catch(System.ArgumentException )
    {
    //If we are here, then the exception is probably because a command with that name
    //  already exists. If so there is no need to recreate the command and we can 
                    //  safely ignore the exception.
    }
}
}

At the beginning of the Try block we are checking that if submenu with the name of “Modification History” already exists or not. If exists then we will use the same Command Bar (submenu) to add our 2 new commands

After that we have created 2 Command object instead of one. Just keep one thing in mind that you should not have any spaces in the second parameter i.e. name of the Command button menu. You can also change the icon by changing the value of 6th parameter. In this case we are using 10 and 13 which are reserved icons provided by Visual Studio.NET. You can also use your own icons from the resource file instead.

Immediately after that we have created Command Bar (submenu) if not already exists. And finally we are adding both our newly created Commands in Command Bar

Since we have now two Commands therefore it is also necessary to change the code of QueryStatus(…) method. See the modified clause of IF condition in the code below.

public void QueryStatus(string commandName, vsCommandStatusTextWanted neededText, 
                        ref vsCommandStatus status, ref object commandText)
{
    if(neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
    {
        if (commandName == "ModificationHistory.Connect.CreatedBy" || 
             commandName == "ModificationHistory.Connect.ModifiedBy")
        {
            status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported|
                                      vsCommandStatus.vsCommandStatusEnabled;
            return;
        }
    }
}

UI has been completed now we need to add functionality to newly added Commands for that we will modify Exec(…) method of conncet.cs class. Every time you click newly added Commands; Exec(…) function would be called and that is why we need to identify the invoker through parameter “commandName”. In this tutorial we are only generating modification history for C# files only. After that we are simply placing are standard text of modification history (Created By/Modified By) at the appropriate position of C# file. In this article we are using member variable to store text (template) of modification history, you can also store these texts in the separate text file.

string sCSCreatedByText =
            "/*************************************************************" +
            "************************\n" +
            "\n" +
            "Author                        :  [USERNAME]\n" +
            "Development Environment    :  [ENVIROMENT]\n" +
            "Name of the File           :  [FILENAME]\n" +
            " \n" +
            "Overview:\n" +
            "Write description of file here \n" +
            " \n" +
            "\n" +
            "Creation/Modification History      :\n" +
            "--------------------------------------------------------------" +
            "------------------------\n" +
            "Date            user                    Description\n" +
            "------------      ------------------    ----------------------" +
            "--------------------------\n" +
            "[DATE]     [USERNAME]\n" +
            "***************************************************************" +
            "***********************/\n";

        string sCSModifiedByText =
            "[DATE]     [USERNAME]\n" +
            "***************************************************************" +
            "***********************/\n";

        string sCSModifiedReplacedText =
            "***************************************************************" +
            "***********************/\n";


public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, 
                  ref object varOut, ref bool handled)
        {
            handled = false;
            if(executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
            {
                if (commandName == "ModificationHistory.Connect.CreatedBy")
                {
                    if (_applicationObject.ActiveDocument.Language.ToString() == "CSharp")
                    { 
                        TextDocument objTextDoc = 
                    (TextDocument)_applicationObject.ActiveDocument.Object("TextDocument");
                        sCSCreatedByText = sCSCreatedByText.Replace("[USERNAME]",
                                                                    Environment.UserName);
                        sCSCreatedByText = sCSCreatedByText.Replace("[ENVIROMENT]",
                                             _applicationObject.Application.Name + 
                                             " " + _applicationObject.Application.Version );
                        sCSCreatedByText = sCSCreatedByText.Replace("[FILENAME]",
                                             _applicationObject.ActiveDocument.Name);
                        sCSCreatedByText = sCSCreatedByText.Replace("[DATE]",
                                             DateTime.Now.ToShortDateString());
                        
                        objTextDoc.StartPoint.CreateEditPoint().Insert(sCSCreatedByText);
                    }

                    handled = true;
                    return;
                }

                if (commandName == "ModificationHistory.Connect.ModifiedBy")
                {
                    if (_applicationObject.ActiveDocument.Language.ToString() == "CSharp")
                    {
                        TextDocument objTextDoc = 
                    (TextDocument)_applicationObject.ActiveDocument.Object("TextDocument");
                        sCSModifiedByText = sCSModifiedByText.Replace("[USERNAME]",
                            Environment.UserName);
                        sCSModifiedByText = sCSModifiedByText.Replace("[DATE]",
                            DateTime.Now.ToShortDateString());

                        objTextDoc.ReplaceText(sCSModifiedReplacedText, sCSModifiedByText,
                                                (int)vsFindOptions.vsFindOptionsFromStart  );
                    }

                    handled = true;
                    return;
                }
            }
            
            handled = true;
            return;
        }

Conclusion

This is just a single use of Add-ins, you can use this functionality of visual studio.net for many other purposes like to add personal checklist, contact info of your client you are developing software for. Even you can also implement spell checker for you code.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Rahil Jan Muhammad


I have completed my MS in Data Engineering and AI system and have a vast experience in software development using .NET, Oracle and SQL Server
Currently I am working with TRG TECH. TRG TECH is a division of TRG bpo and is the technology provider for TRG bpo’s international clients and companies
Occupation: Software Developer (Senior)
Company: TRG Tech (www.trgworld.com/trgtech)
Location: Pakistan Pakistan

Other popular C# articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 7 of 7 (Total in Forum: 7) (Refresh)FirstPrevNext
Subject  Author Date 
Generaldoes not work for .vb filesmemberrippo7:26 22 Jun '08  
GeneralA job for source controlmemberSnakefoot20:25 26 May '08  
GeneralRe: A job for source controlmemberdragoshilbert23:59 26 May '08  
GeneralRe: A job for source controlmemberRahil Manasia11:41 28 May '08  
GeneralRe: A job for source controlmemberSnakefoot21:51 28 May '08  
GeneralHow do I install this in VS?supporterMarc Clifton9:55 21 May '08  
GeneralRe: How do I install this in VS?memberErnest Laurentin11:44 21 May '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 21 Jun 2008
Editor: Sean Ewington
Copyright 2008 by Rahil Jan Muhammad
Everything else Copyright © CodeProject, 1999-2008
Web12 | Advertise on the Code Project