Sunday, October 25, 2009

Hack 89. Writing a Visual Studio Add-in











 < Day Day Up > 





Hack 89. Writing a Visual Studio Add-in





Although the automation model can be more fun

than a barrel of monkeys, add-ins let you really extend the

environment
.





In this book, you have

learned about a large number of different add-ins that you can

install to enhance the functionality of Visual Studio. In this hack,

you will learn how to write one of those add-ins. The topic of

writing Visual Studio add-ins can be, and has been, the topic of

entire books, so needless to say, this hack will simply be an

introduction to the topic.





Add-ins are installable extensions to the Visual Studio IDE. Through

add-ins, you can accomplish quite a bit with the IDE. An excellent

example of this is TestDriven.NET [Hack #93], an add-in that really adds

significant functionality to the IDE.





I am not going to attempt anything that grandiose for this hack.

Instead, you will learn how to create a simple add-in that adds an

item to the Tools menu and to the right-click menu that will allow

you to select text and then click the menu item to surround that code

with a try . . . catch block.







12.5.1. Create the Project





To get started, you will first need

to create a new add-in project by going to File New

Project and then selecting the add-in project from Other

Project Extensibility Projects. This dialog is shown in

Figure 12-4.







Figure 12-4. New add-in project







This launches the Extensibility Wizard shown in Figure 12-5.







Figure 12-5. Extensibility Wizard







Click Next to move to the first screen of the Extensibility Wizard,

shown in Figure 12-6.







Figure 12-6. Select a Programming Language screen







In the first screen of the wizard, you choose what language you want

to use to create this add-in. In this example, I will use C#, but you

can also use Visual Basic or Visual C++. After choosing the language,

click Next and you will see the Select an Application Host screen

(shown in Figure 12-7).







Figure 12-7. Select An Application Host screen







On the Select An Application Host screen, you choose what

application hosts you want your add-in to

be compatible with. The choices are the Microsoft



VSMacros IDE and the regular IDE. It is a

good idea to enable your add-in for the VSMacros IDE only if you

think users will really get value out of using your add-in in that

IDE. In this case, the add-in could indeed be useful from the macro

IDE, so I will leave both of these checked.





When you click Next, you will see the name and description screen

shown in Figure 12-8.







Figure 12-8. Enter a Name and Description screen







In the name and description screen, you get to name your add-in and

provide a brief description of the tool. Clicking Next will show you

the options screen shown in Figure 12-9.







Figure 12-9. Choose Add-in Options screen







The add-in options screen includes a number of options for how you

want your add-in to work. Here are the options you must decide upon

on this screen:






Would you like to create UI for the user to interact with your add-in?





This option decides whether a menu item will be added to the Tools

menu. Having this button on the Tools menu does not mean that you

will need to create a complex UI by any means. In this example, I am

going to check this box because I want users to be able to click a

button in the Tools menu to insert a TRy...catch

block.






My add-in will never put up modal UI





This option decides whether your add-in can be used during

command-line builds [Hack #78] . You

need to check this box only if your add-in will never show a modal UI

and if your add-in would benefit from being loaded during such a

build. Since this add-in is strictly a coding add-in, I will leave

this box unchecked.






I would like my add-in to load when the host application starts





This option decides if the add-in will be automatically loaded. This

can always be configured and changed by the user, so I am going to

uncheck it. There is no reason to force the user to load the add-in

every time.






Setting up access privileges





This option determines whether the add-in will be available to all

users or just the user who installs the add-in. Unfortunately, the

install program does not ask the user to make this choice during the

install process so it is usually a good idea to leave this unchecked.









After you have configured the add-in options for your add-in, you can

click Next to be shown the help about screen, which is shown in Figure 12-10.







Figure 12-10. Choosing 'Help About' Information screen







The help about screen lets you configure

whether an About box should be enabled for your add-in and, if so,

what should be included in that box. When you click Next, you will

see the Summary screen shown in Figure 12-11.







Figure 12-11. Add-in Summary screen







After completing the wizard, you will see two projects in

the Solution Explorer, a class library and a setup project. You will

also notice a file called

Connect.cs, as shown in Figure 12-12.







Figure 12-12. New projects in Solution Explorer







Visual Studio also adds a great deal of the boilerplate code to the

Connect.cs file for you. If you open it, you

will see all of the required methods already created with default

code. You could actually run this add-in already, and it would handle

the command�it just wouldn't do

anything.









12.5.2. Add Menu Item





Since you checked the Tools menu option in the

project wizard, Visual Studio will have already added the command for

your add-in to the Tools menu, but you usually want to also have a

menu item somewhere else. In this example, I want to have a menu item

also on the right-click menu. To do this, you will need to modify the

default code that the wizard generated.





When your add-in is loaded, Visual Studio calls the

OnConnection method�this is where you will

need to add commands. Here is the default code created by the wizard:





public void OnConnection(object application, 

Extensibility.ext_ConnectMode connectMode,

object addInInst, ref System.Array custom)

{

applicationObject = (_DTE)application;

addInInstance = (AddIn)addInInst;

if(connectMode = = Extensibility.ext_ConnectMode.ext_cm_UISetup)

{

object [ ]contextGUIDS = new object[ ] { };

Commands commands = applicationObject.Commands;

_CommandBars commandBars = applicationObject.CommandBars;



try

{

Command command = commands.AddNamedCommand(addInInstance,

"TryCatchMatic", "TryCatchMatic",

"Executes the command for TryCatchMatic", true,

59, ref contextGUIDS,

(int)vsCommandStatus.vsCommandStatusSupported

+(int)vsCommandStatus.vsCommandStatusEnabled);



CommandBar commandBar = (CommandBar)commandBars["Tools"];

CommandBarControl commandBarControl =

command.AddControl(commandBar, 1);

}

catch(System.Exception /*e*/)

{

}

}



}







The boldfaced code is the section that actually creates the command

and then adds it to the Tools command bar. Using the same

Command object, I am also going to add it to the

Code Window command bar, which represents the right-click menu when

inside the code window. First, you need to create a

CommandBar object and get a reference to the

correct command bar, then add your command to that command bar using

the AddControl method. You should insert these two

lines after the last line within the TRy block:





CommandBar commandBar2 = (CommandBar)commandBars["Code Window"];

CommandBarControl commandBarControl2 =

command.AddControl(commandBar2, 1);







This command will now show up on the Tools menu as well as the

right-click menu in the code window after the add-in is installed.

For information on how to find the various command bars in Visual

Studio, please refer to [Hack #90].





You will most likely also want to add something to the

catch block, since the code created by the wizard

simply "swallows" the error. You

can write the exception using Debug.WriteLine or

implement some other method of handling the exception.









12.5.3. Write the Code





The next step is to write the code that

will do the work of the add-in. In this example, I will be writing a

simple piece of code that surrounds the selected text with a

try . . . catch block. This code needs to be added

to the Exec method that was added for you by the

wizard. Here is a look at the default code:





public void Exec(string commandName, 

EnvDTE.vsCommandExecOption executeOption,

ref object varIn, ref object varOut, ref bool handled)

{

handled = false;

if(executeOption = =

EnvDTE.vsCommandExecOption.vsCommandExecOptionDoDefault)

{

if(commandName = = "TryCatchMatic.Connect.TryCatchMatic")

{

handled = true;

return;

}

}

}







This code first checks the executeOptions and then

checks to see if the command being called is the command for this

add-in. Inside the last if statement is where you

will write the code for what your add-in will actually do. Here is

the code I have added to get the currently selected text and then

surround it with a try...catch block:





if(commandName =  = "TryCatchMatic.Connect.TryCatchMatic")

{



string selectedText = textDoc.Selection.Text;



string newText = "try\n { \n" + selectedText

+ "\n}\ncatch\n{\n}";



textDoc.Selection.Text = newText;

handled = true;

return;

}







In this code, I get a reference to the

ActiveDocument and then get the selected text. I

can then replace the selected text with the new, surrounded text.









12.5.4. Installation





When you

are ready to install and test your add-in, it is pretty simple to do

so, since the wizard automatically added an installer to the project.









Before doing anything else, it is of the utmost importance that you

exclude any assemblies that are default Visual Studio assemblies.

This could include Extensibility.dll,

Office.dll
, VSLang.dll,

DTE.OLB
, EnvDTE.DLL,

stdole.DLL
, and others. If you leave these assemblies in

your installation project, then when a user uninstalls your add-in,

it could remove these assemblies, thus breaking Visual Studio and

requiring the user to either repair her installation or manually try

to re-add the assemblies your installer removed.








Next, you will need to build the installer, as it is not built by

default. You can do this by right-clicking on the project and

clicking Build. After the project has been built, you can right-click

on the installer and click Install. This will install your add-in on

your machine. Next, you will need to close and then reopen the IDE,

and you should see your menu items. If you do not see your menu

items, make sure that your add-in is enabled in the add-in manager

and then try running devenv

/setup [Hack #92] .





This hack has been a quick introduction to the development of

add-ins, but there is a lot more to learn. Here are some great

resources to help you learn more about add-in development:






Visual Studio Extensibility Center





http://msdn.microsoft.com/vstudio/extend






Visual Studio .NET Add-ins Yahoo Group





http://groups.yahoo.com/group/vsnetaddin






Visual Studio 2003 Automation Samples





http://www.microsoft.com/downloads/details.aspx?familyid=3ff9c915-30e5-430e-95b3-621dccd25150&displaylang=en






Craig Skibo's weblog (Developer of the Visual Studio Automation Object Model)





http://blogs.msdn.com/craigskibo






Dr. Extensibility's weblog





http://blogs.msdn.com/dr._ex























     < Day Day Up > 



    No comments:

    Post a Comment