Tải bản đầy đủ (.pdf) (34 trang)

Visual Basic 2005 Design and Development - Chapter 8 ppsx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.32 MB, 34 trang )

Part II
Meta-Development
In this Part:
Chapter 8 Snippets, Macros, and Add-ins
Chapter 9 Scripting
Chapter 10 Custom Controls and Components
Chapter 11 Property Support
Chapter 12 Attributes and XML Comments
12_053416 pt02.qxd 1/2/07 6:31 PM Page 203
12_053416 pt02.qxd 1/2/07 6:31 PM Page 204
Snippets, Macros,
and Add-ins
Visual Studio provides many tools that make writing code easier. This chapter describes three
tools that you can use to automatically generate code: snippets, macros, and add-ins.
Snippets let you copy a piece of code into an application. After you insert the code, snippet-editing
tools let you make simple systematic replacements to customize the new code.
Macros let you record actions you perform in a code editor and replay them later. By itself, that
would only be useful if you needed to repeat the exact same series of operations. By editing the
recorded macro, however, you can generate new code in very complicated ways.
Like macros, add-ins let you generate complicated pieces of code. Add-ins have the additional
advantage that they are compiled, so you can write an add-in for developers while not allowing
them to view or modify it. Because an add-in is a Visual Studio project in its own right, it can take
advantage of the full power of the development environment.
Snippets
An IntelliSense code snippet (or just snippet) is a piece of code stored in a special XML format, so it is
easy to insert into your applications. Visual Studio comes with several hundreds of pre-built snip-
pets that you can use to generate code for such tasks as activating a running application, clearing
the console window, creating a sorted dictionary, or calculating the sine of an angle:
Many of the pre-built snippets are quite simple. For example, the following code shows the snip-
pet that calculates the sine of an angle:
Dim radians As Double = 120 * Math.PI / 180


Dim sin As Double = Math.Sin(radians)
13_053416 ch08.qxd 1/2/07 6:31 PM Page 205
When you insert this snippet, the code’s “120” is highlighted by a green box and the cursor is positioned
there. This is a replacement area. You should replace the default angle
120 with the angle you’re inter-
ested in. If you hover the mouse over the replacement area, a tooltip gives you a hint about what you are
supposed to do by saying, “Replace with the measurement in degrees.”
Snippets can help you remember how to write the code for common programming tasks. They can auto-
mate tedious, repetitive chores, and can help you remember the little details that are so easy to forget.
For example, they can automatically add the appropriate
Imports statements when you use routines
that require them. They build the pieces of property procedures, including the procedures themselves,
the private variables that store procedure values, attributes to give descriptions of the procedures and
categories in the Properties window, and even comments.
Snippets can even help you standardize your code. For example, suppose you have a standard comment
block that you want every developer on the project to use at the beginning of every file. This block might
include a copyright statement, the name of the module, the name of the developer who created the file,
and places for revision history. You can help developers follow the standard by creating a snippet that
contains the comment template. If developers insert the snippet into their modules, all of the files will
have module-level comments in exactly the same format. The snippet’s replacement areas even help the
developers insert the module’s name and the name of the developer who created the file.
The following section describes in greater detail how to insert snippets. The sections after that one
explain how to write your own snippets.
Using Snippets
To insert a snippet into your code, right-click where you want to insert and select the Insert Snippet com-
mand. Visual Studio displays a cascading pop-up list, similar to the one shown in Figure 8-1.
Figure 8-1: The Insert Snippet command lets you insert snippets from snippet folders.
206
Part II: Meta-Development
13_053416 ch08.qxd 1/2/07 6:31 PM Page 206

Scroll down to the folder that contains the snippet you want and double-click it. In some cases, the initial
snippet folder will contain subfolders. Continue delving into the snippet folders until you find a list of
actual snippets similar to the one shown in Figure 8-2. Then double-click the snippet you want to insert.
Figure 8-2: Double-click the snippet that you want to insert.
Figure 8-3 shows the code inserted by the Public Property snippet. Colored boxes indicate values that you
should replace. In this example, the replacement values include the strings
FirstName, String, and Misc.
They also include blank values inside the quotes in the code’s
Description and DefaultValue attributes.
Figure 8-3: Make replacements in the snippet as necessary.
207
Chapter 8: Snippets, Macros, and Add-ins
13_053416 ch08.qxd 1/2/07 6:31 PM Page 207
If you hover the mouse over a replacement area, a tooltip tells you what value you should put there.
Initially, the first replacement area for
FirstName is highlighted. Enter the name you want to give this
property. When you press the Tab key, the value you entered is copied to all of the
FirstName replace-
ment fields and the next replacement area is highlighted. Continue making replacements until you have
replaced all of the values.
If there is a shortcut assigned to a snippet, then you can use it to insert the snippet more quickly. Type
the first several letters in the shortcut, followed by a question mark (?), and press Tab. Visual Studio dis-
plays a pop-up list of snippets with the one matching the string you entered selected. Figure 8-4 shows
the list displayed when I typed “propertysn?”
Figure 8-4: Using snippet shortcuts you can insert snippets very quickly.
If you use a snippet frequently, it will be faster to insert it using its shortcut than by navigating through
the snippet folders.
Making Snippets
Snippets are stored in XML files with specific tags that identify the snippet’s name, code, replacement
values, and so forth.

To create a snippet, make a Visual Studio project. Open the Project menu and select Add New Item. Pick
the XML File template, give the file a descriptive name with a
.snippet extension, and click OK. For
example, you might name a property snippet’s file
Property.snippet.
Actually, snippets are just text files in XML format, so you could write them using any text editor.
However, when the Visual Studio IDE opens a snippet, it uses a special XML editor that makes editing
the files easier. For example, it knows which tags should be allowed at different points. If you type “<”
208
Part II: Meta-Development
13_053416 ch08.qxd 1/2/07 6:31 PM Page 208
inside a Literal element, the editor displays a pop-up that lists the allowed sub-items: ! (for com-
ments),
? (for XML processor instructions), Default, Function, ID, ToolTip, and Type. The edi-
tor also flags XML errors such as unclosed tags, mismatched open and close tags, and so forth.
Double-click the file to open it. Initially, the file only contains an XML declaration. After the declaration,
you must add a series of XML tags to define the snippet. Rather than wading through all of the ugly
details, take a look at the following example. The text that follows describes the key sections that you
need to modify:
<CodeSnippets>
<CodeSnippet>
<Header>
<Title>Public Property</Title>
<Shortcut>PropertySnippet</Shortcut>
</Header>
<Snippet>
<Imports>
<Import>
<Namespace>System.ComponentModel</Namespace>
</Import>

<Import>
<Namespace>System.Windows.Forms</Namespace>
</Import>
</Imports>
<References>
<Reference>
<Assembly>System.Windows.Forms.dll</Assembly>
</Reference>
</References>
<Declarations>
<Literal>
<ID>name</ID>
<ToolTip>The property’s name.</ToolTip>
<Default>FirstName</Default>
</Literal>
<Literal>
<ID>data_type</ID>
<ToolTip>The property’s data type.</ToolTip>
<Default>String</Default>
</Literal>
</Declarations>
<Code Language=”VB”>
<![CDATA[
‘’’ <summary>
‘’’ The $name$ property.
‘’’ </summary>
‘’’ <remarks>This property is implemented with property procedures.</remarks>
Private m_$name$ As $data_type$ = “$default$”
<Browsable(True)> _
Public Property $name$() As $data_type$

Get
MessageBox.Show(“In $name$.Get”)
Return m_$name$
End Get
Set(ByVal value As $data_type$)
209
Chapter 8: Snippets, Macros, and Add-ins
13_053416 ch08.qxd 1/2/07 6:31 PM Page 209
MessageBox.Show(“In $name$.Set”)
m_$name$ = value
End Set
End Property
]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
Within the Header section, the Title value gives the title displayed in the cascading snippet menus
shown in Figure 8-2. The
Shortcut value gives the snippet’s shortcut. If you type the first several letters
from the shortcut followed by a question mark and a tab, Visual Studio displays a list of snippets with
this one selected.
The
Snippet section contains several key subsections. The Imports section contains information about
imports that the code in the snippet requires. This example contains one import:
System.ComponentModel.
When you use this snippet, if the module does not already have an
Imports statement for this namespace,
the snippet adds it at the top of the module. In this example, the statements would be as follows:
Imports System.ComponentModel

Imports System.Windows.Forms
This example needs the System.ComponentModel namespace because it uses the Browsable attribute.
It needs the
Systems.Windows.Forms namespace to use the MessageBox class.
The
References section contains references that the snippet’s code needs. If the project doesn’t already
have a reference to the indicated assembly, the snippet adds it. This example requires a reference to
System.Windows.Forms.dll because that library contains the MessageBox class.
The
Declarations section defines replacement variables. Each Literal tag defines a word in the snip-
pet code that the developer can replace. This example’s first
Literal defines a token called “name.” The
snippet code indicates a replacement value by enclosing the token’s ID in dollar signs, as in
$name$.
Tags within the
Literal give the tooltip to display and the item’s default value. You should give a
Literal a default value whenever possible, because it makes the value easier for the developer to see.
The
Declarations section can also contain Object tags to define replacements representing objects
that are usually defined outside of the snippet’s code.
Finally, the
Code tag contains the snippet’s actual code. In this example, the tag’s Language attribute
indicates that this is a Visual Basic snippet. The
<![CDATA[ string allows an XML file to contain just
about any text, including white spaces and carriage returns, until reaching the corresponding
]]>.
Microsoft has produced a free snippet editor that lets you avoid the details of writing an XML file.
Download it at
/>210
Part II: Meta-Development

13_053416 ch08.qxd 1/2/07 6:31 PM Page 210
Installing Snippets
After you create a snippet file, put it in a directory where you want to store snippets. The cascading
snippet menus shown in Figures 8-1 and 8-2 display the directory’s name, so give the directory a mean-
ingful name.
Next, open Visual Studio’s Tools menu and select the Code Snippets Manager command to display the
tool shown in Figure 8-5. Click the Add button, browse to your snippets directory, and click Open. Back
in the Code Snippets Manager, click OK.
Figure 8-5: Use the Code Snippets Manager to add and remove snippet directories.
Now, Visual Studio is ready to use the snippets in that directory. When you right-click in a code editor
and select the Insert Snippet command, you should see the directory and any snippets defined in
.snippet files within the directory.
Sharing Snippets
Because snippets are plain old text files, they are easy to share. You can email them to other developers,
or post them on your Web site. You can put them in a shared snippet directory to ensure that every
developer on your project uses the same snippets so that they get the benefit of consistency.
You can also search the Web for snippets. You can download code snippets for Visual Studio at
As of this writing, these are the
snippets that come with Visual Studio 2005, so they should already be installed on your system. This is
probably a good place to check for updates, however.
211
Chapter 8: Snippets, Macros, and Add-ins
13_053416 ch08.qxd 1/2/07 6:31 PM Page 211
You can search this book’s snippet library at www.vb-helper.com/snippets.html. If you come up
with a good snippet that you’d like to share, send it to me at
and I’ll
add it to the library.
Macros
Snippets are a fantastic way to automate building certain chunks of code in a fixed format, while allow-
ing you to make simple replacements. By using snippets, you can simplify moderately complicated tasks

and add some useful consistency to a development project.
Although snippets are easy, they are fairly limited. They use a “design by example” approach, where
you write code and then turn it into a snippet. This approach is extremely simple, but it’s not very flexi-
ble. For example, the previous example that creates property procedures won’t work if you want to add
a parameter to the property, as shown in the following code:
‘ Get or set a test score.
Private m_Scores(0 To 9) As Double
Public Property Score(ByVal test_number As Integer) As Double
Get
Return m_Scores(test_number)
End Get
Set(ByVal value As Double)
m_Scores(test_number) = value
End Set
End Property
Snippets also only create code; they don’t modify it or the Visual Studio IDE.
Macros give you much greater flexibility. They let you write new code, modify existing code, and control
the development environment.
Visual Studio lets you record, write, edit, debug, and play back macros later, much as the Microsoft
Office applications do (although the Microsoft Office applications use VBA as their macro language,
whereas Visual Basic 2005 uses Visual Basic 2005 for macros). You can use macros to automate tasks that
you need to perform frequently, such as the following:
❑ Writing a series of Visual Basic statements that are mostly the same
❑ Performing an action on similar code entities (for example, commenting functions or printing
code documents)
❑ Altering the project’s structure (for example, adding files to it)
❑ Modifying the Visual Studio environment
The following sections briefly describe how to record, edit, and use macros in Visual Studio.
212
Part II: Meta-Development

13_053416 ch08.qxd 1/2/07 6:31 PM Page 212
Recording Macros
To record a macro, open the Tools menu, go to the Macros submenu, and select the Record
TemporaryMacro command. Visual Studio displays the Macro Recorder shown in Figure 8-6, and starts
recording a macro.
Figure 8-6: The Macro Recorder
lets you pause, stop, or cancel
macro recording.
While the Macro Recorder is running, you can add, edit, and delete code. Unfortunately, the Macro
Recorder does not capture any changes to a form’s properties and controls, so you may as well stay in a
code editor.
When you have finished recording, click the Stop Recording button in the middle of the Macro Recorder.
Visual Studio stores the new macro in a macro module. To see the macro, open the Tools menu, go to the
Macros submenu, and the select the Macro Explorer command to display the Macro Explorer shown in
Figure 8-7.
Figure 8-7: The Macro Explorer lets you view,
edit, and run macros.
The new macro is the
RecordingModule and is named TemporaryMacro. To execute the macro, double-
click it, or right-click it and select Run from the context menu.
If you record a new temporary macro, the previous one is overwritten. If you want to save a temporary
macro for later use, right-click it in Macro Explorer, select Rename, and give the macro a new name.
Now, if you record a new macro, it is named
TemporaryMacro and your old macro is saved.
213
Chapter 8: Snippets, Macros, and Add-ins
13_053416 ch08.qxd 1/2/07 6:31 PM Page 213
Editing Macros
To edit a macro, right-click it in Macro Explorer, and select Edit to make Visual Studio open the Macro
IDE shown in Figure 8-8.

Figure 8-8: Visual Studio lets you edit macros much as it lets you edit Visual Basic projects.
You can modify the macro’s code in the code editor shown in Figure 8-8 much as you can modify Visual
Basic code in the Visual Studio IDE. You can even set breakpoints in the editor, and step through the
code to debug it.
To organize your macros, you can use the Project Explorer shown on the left in Figure 8-8. Right-click
and add folders and modules to the projects. Then you can copy the renamed temporary macro into one
of those modules.
Modifying Macros
Unfortunately, recorded macros are often not very useful because they perform exactly the same steps
that you performed already. If you need to perform an extremely repetitive and mechanical task, you
might get some mileage out of repeating the same sequence of commands again and again.
Usually, it’s more useful to do something similar to the recorded macro, and not repeat exactly the same
steps each time. Start by recording a macro that is as similar as possible to what you need to do. Then
edit the macro to suit your needs.
For example, suppose you have 16
TextBox controls named TextBox0, TextBox1, , TextBox15
arranged in a grid on a form, and you want to set references to them in a two-dimensional array. You
could record a macro while typing the following code:
m_TextBoxes(0, 0) = TextBox0
214
Part II: Meta-Development
13_053416 ch08.qxd 1/2/07 6:31 PM Page 214
The following code shows the recorded macro:
Sub TemporaryMacro()
DTE.ActiveDocument.Selection.Text = “m_TextBoxes(0, 0) = TextBox0”
DTE.ActiveDocument.Selection.NewLine()
End Sub
DTE stands for “development tools environment.” The DTE object sits at the top of the Visual Studio
extensibility object model. It is similar to the
Application object used by some other programs such

as the Microsoft Office applications.
ActiveDocument is an object that represents the currently active editor document, in this case the
code in the code editor.
Selection is a property of the ActiveDocument that represents the cur-
rently selected text. The previous code sets this text and then adds a new line to it.
The extensibility object model is enormous, so there will barely be time to introduce it here. Look in the
online help for “DTE” for more information.
You don’t want to repeat exactly this statement 16 times, but it’s easy to modify the recorded code. The
following code loops through the four rows and columns, adding code for each control. Notice how it
adds to the code the values of the row and column variables and the number in the control’s name.
Sub SaveTextBoxes()
For r As Integer = 0 To 3
For c As Integer = 0 To 3
DTE.ActiveDocument.Selection.Text = “m_TextBoxes(“ & _
r.ToString() & “, “ & c.ToString() & _
“) = TextBox” & (r * 4 + c).ToString()
DTE.ActiveDocument.Selection.NewLine()
Next c
Next r
End Sub
The following code shows the result added to the form’s Load event handler, plus the code that defines
the
m_TextBoxes array:
Public Class Form1
Private m_TextBoxes(0 To 4, 0 To 4) As TextBox
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
m_TextBoxes(0, 0) = TextBox0
m_TextBoxes(0, 1) = TextBox1
m_TextBoxes(0, 2) = TextBox2

m_TextBoxes(0, 3) = TextBox3
m_TextBoxes(1, 0) = TextBox4
m_TextBoxes(1, 1) = TextBox5
m_TextBoxes(1, 2) = TextBox6
m_TextBoxes(1, 3) = TextBox7
m_TextBoxes(2, 0) = TextBox8
m_TextBoxes(2, 1) = TextBox9
m_TextBoxes(2, 2) = TextBox10
m_TextBoxes(2, 3) = TextBox11
m_TextBoxes(3, 0) = TextBox12
215
Chapter 8: Snippets, Macros, and Add-ins
13_053416 ch08.qxd 1/2/07 6:31 PM Page 215
m_TextBoxes(3, 1) = TextBox13
m_TextBoxes(3, 2) = TextBox14
m_TextBoxes(3, 3) = TextBox15
End Sub
End Class
You could certainly type all of this code by hand. If you use copy and paste judiciously, it might even be
faster than recording and modifying a macro, although it would still be a lot of work if you had a 10 by
10 grid of controls.
Although this example can save you a little work, you can get some serious power out of macros if you
edit them to take advantage of the other capabilities offered by the extensibility object model — the
classes that represent the IDE and the project you are editing.
For example, the following code comments out a selected section of code by placing it in an
#If
#End If
block. It first prompts you for the name of the variable to use in the #If statement. It composes
the block by concatenating the
#If statement, the currently selected text, and the #End If statement. It

then uses the current selection object’s
Insert method to replace the selected text with the block.
‘ Surround the selected code with an #If #End If block.
Public Sub PoundIfOut()
‘ Get the variable name.
Dim variable_name As String = InputBox(“Variable Name”, “Variable Name”, “”)
If variable_name.Length < 1 Then Exit Sub
Dim sel As EnvDTE.TextSelection = DTE.ActiveDocument.Selection
Dim txt As String = “#If “ & variable_name & “ Then” & vbCrLf & sel.Text
If Not txt.EndsWith(vbCrLf) Then txt &= vbCrLf
txt &= “#End If ‘ “ & variable_name & vbCrLf
‘ Replace the selected text with the result.
sel.Insert(txt, vsInsertFlags.vsInsertFlagsContainNewText)
End Sub
The following code shows a sample result. Here I selected the two lines used by the MessageBox state-
ment, ran the macro, and entered the variable name
SHOW_MESSAGES when prompted.
#If SHOW_MESSAGES Then
MessageBox.Show(“I’ve been commented out!”, “Commented”, _
MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
#End If ‘ SHOW_MESSAGES
In this example, it wouldn’t have been hard to just type in the #If and #End If statements, but this is a
handy macro when you want to quickly comment out a large block of code. Simply select the code, run
the macro, and enter a variable name.
The following macro uses a similar technique to place code in a new region. It starts by prompting you
for the region’s name. It concatenates a
#Region statement, the selected code, and an #End Region state-
ment, and then inserts the result into the code.
‘ Put the selected code in a region.
Public Sub MakeRegion()

216
Part II: Meta-Development
13_053416 ch08.qxd 1/2/07 6:31 PM Page 216
‘ Get the region name.
Dim region_name As String = InputBox(“Region Name”, “Region Name”, “”)
If region_name.Length < 1 Then Exit Sub
‘ Compose the new text.
Dim sel As EnvDTE.TextSelection = DTE.ActiveDocument.Selection
Dim txt As String = _
“#Region “”” & region_name & “””” & vbCrLf & _
sel.Text
If Not txt.EndsWith(vbCrLf) Then txt &= vbCrLf
txt &= “#End Region ‘ “ & region_name
‘ Replace the selected text with the result.
sel.Insert(txt, vsInsertFlags.vsInsertFlagsContainNewText)
End Sub
The following macro shows how you can loop through an array of names to make property procedures
for each. Writing each of these by hand, even using copy and paste or code snippets, would be tiresome.
‘ Make a series of property procedures for contact information.
Public Sub MakeContactInfoProperties()
Dim property_names() As String = { _
“FirstName”, “LastName”, “Street”, “Street2”, “City”, “State”, “Zip”, _
“WorkPhone”, “HomePhone”, “Email”, “WebPage”}
Dim txt As String = “”
For Each property_name As String In property_names
txt &= “Private m_” & property_name & “ As String = “”””” & vbCrLf
txt &= “Public Property “ & property_name & “() As String” & vbCrLf
txt &= vbTab & “Get” & vbCrLf
txt &= vbTab & vbTab & “Return m_” & property_name & vbCrLf
txt &= vbTab & “End Get” & vbCrLf

txt &= vbTab & “Set(ByVal value As String)” & vbCrLf
txt &= vbTab & vbTab & “m_” & property_name & “ = value” & vbCrLf
txt &= vbTab & “End Set” & vbCrLf
txt &= “End Property” & vbCrLf & vbCrLf
Next property_name
‘ Replace the selected text with the result.
Dim sel As EnvDTE.TextSelection = DTE.ActiveDocument.Selection
sel.Insert(txt, vsInsertFlags.vsInsertFlagsContainNewText)
End Sub
When a macro inserts code, the code editor does not automatically reformat the code to fix its indenta-
tion. These macros finish with the new code selected. If you press the Tab key immediately after running
the macros, the code editor will fix the code’s indentation.
Unfortunately, the extensibility object model is enormous (too big to cover here), extremely complicated,
and not very well-documented. Look in the online help’s index for “extensibility” for information about
the classes that represent the IDE and the loaded project.
Though the documentation isn’t great, Microsoft has provided a large number of sample macros that
you can study when designing your own macros.
217
Chapter 8: Snippets, Macros, and Add-ins
13_053416 ch08.qxd 1/2/07 6:31 PM Page 217
Using Sample Macros
Notice the Samples project in the Project Explorer shown in Figure 8-8 and in the Macro Explorer shown
in Figure 8-7. That project contains sample macros provided by Microsoft that demonstrate rather
advanced techniques. The samples demonstrate various techniques for manipulating the development
environment. For example, they show how to:
❑ Change the code editor’s font size
❑ Change the code editor’s colors
❑ Add the files in a directory sub-tree to a solution
❑ Print all open documents
❑ Comment out C++ code with

#ifdef statements
❑ Save and restore window layouts
❑ Turn line numbers and word wrap on and off
❑ Catch events raised by the project, documents, windows, the task list, and so forth
❑ Convert a macro project into an add-in
❑ Add comments to all functions in a file
❑ List macros, breakpoints, modified files, and so forth
❑ Evaluate an expression
❑ Dump all threads’ stacks
❑ List the languages that the debugger supports (Visual Basic, C#, C++, VJ#, and so on)
❑ Save a backup of the current document
To learn more about the samples in the online help, look in the index for “macros [Visual Studio
Macros]” and select the sub-topic “samples.”
Customizing Visual Studio
Special-purpose macros (such as MakeContactInfoProperties shown earlier in this chapter) are
macros you will probably run only once or twice. In those cases, it’s easy enough to run the macro by
double-clicking it in the Macro Explorer, or by opening it in the Macro IDE and selecting the Debug
menu’s Run command.
Other macros (such as
PoundIfOut and MakeRegion) can be useful on many occasions. In those cases,
you may want to make the macro more accessible by customizing Visual Studio.
In Visual Studio, select the Tools menu’s Customize command to display the Customize dialog shown in
Figure 8-9. On the Toolbars tab, you can click the New button to make a toolbar to hold buttons for
launching your macros.
218
Part II: Meta-Development
13_053416 ch08.qxd 1/2/07 6:31 PM Page 218
Figure 8-9: You can use the Toolbars tab’s New button to make a new toolbar to
provide easy access to macros.
On the Commands tab shown in Figure 8-10, scroll the list on the left down and select the Macros entry.

Then, click and drag macros from the list on the right onto menus and toolbars.
Figure 8-10: The Commands tab lets you drag commands (including macros) onto
menus and toolbars.
219
Chapter 8: Snippets, Macros, and Add-ins
13_053416 ch08.qxd 1/2/07 6:31 PM Page 219
Initially, the new menu or toolbar item is labeled with the full name of the macro. For example, the
MakeRegion macro is given the unwieldy name Macros.MyMacros.CommentMacros.MakeRegion. You
can right-click the new item and use the context menu to change the item’s name to something more rea-
sonable such as
Region.
You can also right-click the item and make it display text, text and an icon, or just an icon. Figure 8-11
shows the context menu selecting the Text Only (Always) style. That style, which is the default, makes
the item only display a textual label.
Figure 8-11: The context menu lets you determine
whether the item displays text, an icon, or both.
The Text Only (in Menus) option makes the item display a text label only if it’s in a menu, and an icon
only if it’s in a toolbar. The Image and Text option makes the item display both an icon and text in either
a menu or toolbar. Finally, the Default style (which ironically isn’t the default) displays an icon in tool-
bars and an icon plus text in menus.
You can use other commands in the context menu shown in Figure 8-11 to select, copy, and edit the
item’s icon.
To assign a shortcut to the macro, open the Customize dialog shown in Figure 8-10 and click the
Keyboard button to display the Options dialog shown in Figure 8-12.
Initially, the list of macros in the middle right contains all of the hundreds of available macros. To nar-
row the list down a bit, enter text that forms part of the name of the macro you want to use. In Figure
8-12, I entered Region and the list narrowed down to the two macros
MakeRegion and CommentRegion.
Select the macro you want to assign, click the text box below the label “Press shortcut keys,” and press
the keys that you want to assign to the macro. In this example, I pressed Alt+R.

220
Part II: Meta-Development
13_053416 ch08.qxd 1/2/07 6:31 PM Page 220
Figure 8-12: Use the Options dialog to assign keyboard shortcuts to macros.
The drop-down list below the “Shortcut currently used by” label lists any conflicts with existing shortcut
assignments. Visual Studio assigns a huge number of key combinations, so you are likely to find colli-
sions. In this example, the drop-down only lists the single conflict shown here. I don’t need to run the
MakeRegion macro while editing images, so this isn’t a problem.
If you want a general scheme to keep all of your macro shortcuts separate from pre-assigned shortcuts,
you’ll need to use a more complicated key combination such as Ctrl+Shift+Alt+R or Alt+M, Alt+R. Then
you can replace the final key R with other keys for other macros.
Sharing Macros
Sharing macros is relatively straightforward. To save a macro module in a text file, open the Macro IDE
and find the module that you want to export in the Project Explorer. Right-click the module and select
the Export command. Enter the name of the file you want to save and click Save.
Having saved the macro code into a file, you can share it with other developers, just as you can share
any other file. You can email the file to other developers, put them in a shared library, or post them on
the Web.
To use a macro module that someone sent you, open the Macro IDE. In the Project Explorer, right-click
the project that you want to contain the new module, open the Add submenu, and select the Add
Existing Item command. Select the new macro file and click Add.
Before you execute any macro, you should open it in a text editor and take a look at it to verify that it is
safe and doesn’t contain viruses or other nasty surprises. Use WordPad or another text editor to exam-
ine the module before you add it to your project.
221
Chapter 8: Snippets, Macros, and Add-ins
13_053416 ch08.qxd 1/2/07 6:31 PM Page 221
Add-ins
Macros have greater flexibility than code snippets, but they still have some restrictions. The Macro IDE
doesn’t provide the full power of Visual Studio, and you cannot add as many different kinds of objects

to a macro project. In particular, a macro module cannot contain forms.
Add-ins let you combine the ability to manipulate the Visual Studio IDE provided by macros with the
power of Visual Studio itself.
An add-in is a compiled DLL that runs in the Visual Studio IDE. Like a macro, the add-in’s code has access to
all of the extensibility objects that control the Visual Studio session and the project that is currently loaded.
Because an add-in is compiled, you have more control over how the add-in’s code is modified. You can
distribute an add-in that contains proprietary code without giving away the details to users. The fact
that the add-in is compiled also makes it more difficult for developers to modify the add-in. This is use-
ful if you want to use the add-in to help bring consistency to your project.
Of course, the fact that the add-in is compiled also means that you cannot look at its code. If you receive
an add-in from someone else, you must trust that it does not contain damaging code (such as a virus or
code that damages your system).
Because the code is compiled into IL, it’s fairly easy to read, even in its compiled form. Any determined
developer can read the IL to see what the macro does. Compiling it will stop casual snoopers and those
who might make careless changes, but if you really want to hide the details, you need to use an obfusca-
tor to make the compiled code more difficult to read.
Making an Add-in
To make an add-in, open Visual Studio and select the File menu’s New Project command. In the Project
Types tree view, open the Other Project Types branch and select Extensibility. Select the Visual Studio
Add-in template, as shown in Figure 8-13. Enter a meaningful name for the template project and click OK.
Figure 8-13: To make an add-in, select the Visual Studio Add-in template.
222
Part II: Meta-Development
13_053416 ch08.qxd 1/2/07 6:31 PM Page 222
When you start a new add-in project, Visual Studio displays the Add-in Wizard shown in Figure 8-14.
The wizard gathers basic information about the add-in you want to build, and then creates a lot of
important (but tedious) code for connecting the add-in to the Visual Studio environment and interacting
with the IDE.
When you click Next, the wizard displays the page shown in Figure 8-15 to let you specify the language
you want to use to write the add-in. Select the Visual Basic option and click Next.

Figure 8-14: The Add-in Wizard helps.
Figure 8-15: Select Visual Basic to write the add-in using Visual Basic.
223
Chapter 8: Snippets, Macros, and Add-ins
13_053416 ch08.qxd 1/2/07 6:31 PM Page 223
The wizard’s next page, shown in Figure 8-16, lets you pick the applications that will run the add-in.
Your choices include the Visual Studio IDE and the Macro IDE. Unless you really get into writing
macros, you will normally build add-ins for the Visual Studio IDE.
Check the IDEs that should run the add-in and click Next to display the page shown in Figure 8-17.
Enter a name and description for your add-in. These are displayed by the Add-in Manager described
shortly.
Figure 8-16: Check the IDEs that should run the add-in.
Figure 8-17: Enter the name and description that the Add-in Manager
should use for your add-in.
224
Part II: Meta-Development
13_053416 ch08.qxd 1/2/07 6:31 PM Page 224
When you click Next, the wizard displays the page shown in Figure 8-18. Check the first box if you want
the wizard to automatically add a button for your add-in to the Tools menu. If you don’t do this, then
you’ll need to use the Add-in Manager to add the button. You’ll also need to add extra code manually to
the add-in’s
OnConnection method. It’s easier to just check the box.
Figure 8-18: Select options for creating the add-in’s toolbar button and
loading the add-in.
If you check the second box, the add-in is loaded when the environment starts. The third checkbox indi-
cates that the add-in never displays a modal dialog to prompt the user for input. If the add-in doesn’t
display any modal dialogs, then it can run unattended from the command line.
Click Next to display the page shown in Figure 8-19. If you want to include information about the
add-in, check the checkbox and enter support information in the text box. The wizard stores this infor-
mation (along with other information gathered by the wizard) in a file named after the add-in with

an
.AddIn extension. For example, if your add-in is named MakeProperty, then this file is called
MakeProperty.AddIn.
If you check the box on this page and enter About information, Visual Studio displays this information
in its About dialog. Open Visual Studio’s Help menu and select the About Microsoft Visual Studio com-
mand to display the dialog shown in Figure 8-20. If you scroll down and select your add-in, you should
see the About information in the “Product details” section.
225
Chapter 8: Snippets, Macros, and Add-ins
13_053416 ch08.qxd 1/2/07 6:31 PM Page 225
Figure 8-19: Enter About information.
Figure 8-20: Visual Studio displays add-in information in its About dialog.
When you click the Next button, the Add-in Wizard displays a final page summarizing your selections.
Verify the settings that the wizard will use, and click Finish to create the add-in project.
226
Part II: Meta-Development
13_053416 ch08.qxd 1/2/07 6:31 PM Page 226
Adding Add-in Code
The Add-in Wizard generates a bunch of code that performs tasks such as connecting the add-in to the
Tools menu, responding to events, and accessing the IDE object hierarchy. Most of this work is done in
the module
Connect.vb.
To modify the add-in, open
Connect.vb and find the OnConnection subroutine. Inside the Try Catch
block, find the AddNamedCommand2 statement that is similar to the following. In Connect.vb, this state-
ment is all on one line, but I’ve broken it here into multiple lines to make it easier to read:
‘Add a command to the Commands collection:
Dim command As Command = commands.AddNamedCommand2(_addInInstance, _
“PropertyProcedureAddIn”, “PropertyProcedureAddIn”, _
“Executes the command for PropertyProcedureAddIn”, True, 59, _

Nothing, CType(vsCommandStatus.vsCommandStatusSupported, Integer) + _
CType(vsCommandStatus.vsCommandStatusEnabled, Integer), _
vsCommandStyle.vsCommandStylePictAndText, _
vsCommandControlType.vsCommandControlTypeButton)
This statement creates the button that appears on the Tools menu when Visual Studio displays the add-
in. Change the statement to give the button a better display name and tooltip, as shown in the second
and third lines of the following statement:
Dim command As Command = commands.AddNamedCommand2(_addInInstance, _
“PropertyProcedureAddIn”, “Add Property”, _
“Add a property using a private variable and property procedures”, True, 59, _
Nothing, CType(vsCommandStatus.vsCommandStatusSupported, Integer) + _
CType(vsCommandStatus.vsCommandStatusEnabled, Integer), _
vsCommandStyle.vsCommandStylePictAndText, _
vsCommandControlType.vsCommandControlTypeButton)
Next, find the Exec subroutine. Inside the If statement, place the code that the add-in should execute.
To keep the automatically generated parts of the code as simple as possible, just place a call here to
another subroutine that does all of the work. The following code shows how the
PropertyProcedure
AddIn
project calls subroutine MakeProperty:
Public Sub Exec(ByVal commandName As String, _
ByVal executeOption As vsCommandExecOption, ByRef varIn As Object, _
ByRef varOut As Object, ByRef handled As Boolean) Implements IDTCommandTarget.Exec
handled = False
If executeOption = vsCommandExecOption.vsCommandExecOptionDoDefault Then
If commandName = “PropertyProcedureAddIn.Connect.PropertyProcedureAddIn” _
Then
‘*** Make the property.
MakeProperty()
handled = True

Exit Sub
End If
End If
End Sub
227
Chapter 8: Snippets, Macros, and Add-ins
13_053416 ch08.qxd 1/2/07 6:31 PM Page 227

×