March 2008 - Posts
I have updated a quite old but useful article (Feb 2005) to document the new /ResetAddin command-line flag of Visual Studio 2005/2008 and how to do it correctly:
HOWTO: Removing commands and UI elements during Visual Studio .NET add-in uninstallation
http://www.mztools.com/articles/2005/MZ2005002.aspx
It is important to note that the /ResetAddin command-line flag will remove permanent controls but not permanent commandbars (another reason to not use them).
Just a curious difference in behavior between Visual Studio 2005 and Visual Studio 2008 that the MSDN documentation doesn't cover very well:
According to the MSDN documentation of VS 2005, "This switch prevents all third-party VSPackages from loading when Visual Studio starts, thus ensuring stable execution." One would expect that if third-party VSPackages are not loaded, add-ins would be also excluded from loading, but they aren't, they are loaded.
Visual Studio 2008 works as expected and the whole Add-in Manager is disabled.
Some days ago I posted a simple RichTextBox-based source code colorizer, but after testing with big code snippets it happened that it didn't perform very well (it took several seconds), so I rewrote it from scratch. This time I use a low level approach and I compose the RTF text directly. The result algorithm performs very well (less than a second) for big code snippets and it works with the RichTextBox of .NET Framework which didn't support the SelectionBackColor property. Here is the code:
Public Class FormCodeColorizer
Private Sub ButtonColorize_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonColorize.Click
Dim objDTE As EnvDTE.DTE
Dim objType As Type
objType = System.Type.GetTypeFromProgID("VisualStudio.DTE")
objDTE = CType(System.Activator.CreateInstance(objType), EnvDTE.DTE)
ColorizeRichText(objDTE, Me.RichTextBoxCode, "'", GetVBKeywords())
objDTE.Quit()
End Sub
Public Sub ColorizeRichText(ByVal objDTE As EnvDTE.DTE, ByVal ctlRichTextBox As RichTextBox, ByVal sCommentLinePrefix As String, ByVal colKeywords As Collections.Specialized.StringCollection)
Const DISPLAY_ITEM_PLAIN_TEXT As String = "Plain Text"
Const DISPLAY_ITEM_KEYWORD As String = "Keyword"
Const DISPLAY_ITEM_STRING As String = "String"
#If VS_8_0 Then
' PATCH: The Comment default color is wrong. We use the CSS Comment color instead
Const DISPLAY_ITEM_COMMENT As String = "CSS Comment"
#Else
Const DISPLAY_ITEM_COMMENT As String = "Comment"
#End If
Dim iSelectionStart As Integer
Dim iSelectionLength As Integer
Dim colFontsAndColorsItems As EnvDTE.FontsAndColorsItems = Nothing
Dim sFontFamily As String = ""
Dim sngFontSize As Single = 0.0
Dim objRtfHeaderStringBuilder As New System.Text.StringBuilder()
Dim objRtfBodyStringBuilder As New System.Text.StringBuilder()
Dim sLine As String
Dim sHeaderRtf As String
Dim sBodyRtf As String
Dim sPlainTextBackColorIndex As String = "1"
Dim sPlainTextForeColorIndex As String = "2"
Dim sKeywordBackColorIndex As String = "3"
Dim sKeywordForeColorIndex As String = "4"
Dim sCommentBackColorIndex As String = "5"
Dim sCommentForeColorIndex As String = "6"
Dim sStringBackColorIndex As String = "7"
Dim sStringForeColorIndex As String = "8"
Dim objPlainTextBackColor As Color
Dim objPlainTextForeColor As Color
Dim objKeywordBackColor As Color
Dim objKeywordForeColor As Color
Dim objCommentBackColor As Color
Dim objCommentForeColor As Color
Dim objStringBackColor As Color
Dim objStringForeColor As Color
Dim bPlainTextBold As Boolean
Dim bKeywordBold As Boolean
Dim bCommentBold As Boolean
Dim bStringBold As Boolean
Dim sKeyword As String
Dim sRtfKeywordBefore As String = ""
Dim sRtfKeywordAfter As String = ""
Dim sRtfBefore As String = ""
Dim sRtfAfter As String = ""
Dim sRtf As String
If GetTextEditorFontAndColorsItems(objDTE, sFontFamily, sngFontSize, colFontsAndColorsItems) Then
Try
' Cache selection position and length
iSelectionStart = ctlRichTextBox.SelectionStart
iSelectionLength = ctlRichTextBox.SelectionLength
GetColorsFromFontsAndColorsItems(colFontsAndColorsItems, DISPLAY_ITEM_PLAIN_TEXT, objPlainTextBackColor, objPlainTextForeColor, bPlainTextBold)
ctlRichTextBox.BackColor = objPlainTextBackColor
objRtfHeaderStringBuilder.Append("\rtf1") ' RTF Version 1.x
objRtfHeaderStringBuilder.Append("\ansi") ' ANSI
objRtfHeaderStringBuilder.Append("\deff0") ' Use font 0 as default
objRtfHeaderStringBuilder.Append("{\fonttbl") ' Font table group
objRtfHeaderStringBuilder.Append("{\f0") ' Font 0
objRtfHeaderStringBuilder.Append("\fnil") ' Use default font if specified font is not installed on the system
objRtfHeaderStringBuilder.Append("\fcharset0 ") ' Charset 0
objRtfHeaderStringBuilder.Append(sFontFamily) ' Font family name
objRtfHeaderStringBuilder.Append(";}") ' End font 0 definition
objRtfHeaderStringBuilder.Append("}") ' End font table group
objRtfHeaderStringBuilder.Append("{\colortbl ;") ' Color table group
' Add colors to table
AddColorsToRtfHeader(objRtfHeaderStringBuilder, colFontsAndColorsItems, DISPLAY_ITEM_PLAIN_TEXT, objPlainTextBackColor, objPlainTextForeColor, bPlainTextBold)
AddColorsToRtfHeader(objRtfHeaderStringBuilder, colFontsAndColorsItems, DISPLAY_ITEM_KEYWORD, objKeywordBackColor, objKeywordForeColor, bKeywordBold)
AddColorsToRtfHeader(objRtfHeaderStringBuilder, colFontsAndColorsItems, DISPLAY_ITEM_COMMENT, objCommentBackColor, objCommentForeColor, bCommentBold)
AddColorsToRtfHeader(objRtfHeaderStringBuilder, colFontsAndColorsItems, DISPLAY_ITEM_STRING, objStringBackColor, objStringForeColor, bStringBold)
objRtfHeaderStringBuilder.Append("}") ' ' End Color table group
objRtfHeaderStringBuilder.Append("\viewkind4") ' View Kind: Normal
objRtfHeaderStringBuilder.Append("\uc1") ' Unicode information
objRtfHeaderStringBuilder.Append("\pard") '
objRtfHeaderStringBuilder.Append("\tx270\tx540\tx810\tx1080\tx1350\tx1620\tx1890\tx2160\tx2430\tx2700") ' Tabulations
objRtfBodyStringBuilder.Append("\f0 ") ' Font 0
objRtfBodyStringBuilder.Append("\fs" & CType(sngFontSize * 2, Integer).ToString & " ") ' Font size in half points
If bPlainTextBold Then
objRtfBodyStringBuilder.Append("\b ")
End If
If ctlRichTextBox.Text = "" Then
objRtfBodyStringBuilder.Append("\par")
sBodyRtf = objRtfBodyStringBuilder.ToString
Else
For Each sLine In ctlRichTextBox.Lines
sLine = EscapeSpecialRTFCharacters(sLine)
objRtfBodyStringBuilder.Append(sLine) '
objRtfBodyStringBuilder.Append("\par") '
objRtfBodyStringBuilder.Append(ControlChars.Cr)
Next
sBodyRtf = objRtfBodyStringBuilder.ToString
' Colorize keywords
GetRtfBeforeAndAfter(objPlainTextBackColor, objPlainTextForeColor, bPlainTextBold, sPlainTextBackColorIndex, sPlainTextForeColorIndex, _
objKeywordBackColor, objKeywordForeColor, bKeywordBold, sKeywordBackColorIndex, sKeywordForeColorIndex, sRtfKeywordBefore, sRtfKeywordAfter)
If sRtfKeywordBefore <> "" Then
For Each sKeyword In colKeywords
' The \b regular expression means word boundary
sBodyRtf = System.Text.RegularExpressions.Regex.Replace(sBodyRtf, "\b" & sKeyword & "\b", sRtfKeywordBefore & sKeyword & sRtfKeywordAfter)
Next
End If
' Colorize strings
GetRtfBeforeAndAfter(objPlainTextBackColor, objPlainTextForeColor, bPlainTextBold, sPlainTextBackColorIndex, sPlainTextForeColorIndex, _
objStringBackColor, objStringForeColor, bStringBold, sStringBackColorIndex, sStringForeColorIndex, sRtfBefore, sRtfAfter)
If sRtfBefore <> "" Then
sBodyRtf = ColorizeTokenBetweenDelimiters(sBodyRtf, ControlChars.Quote, ControlChars.Quote, sRtfBefore, sRtfAfter, sRtfKeywordBefore, sRtfKeywordAfter)
End If
' Colorize comments
If sCommentLinePrefix <> "" Then
GetRtfBeforeAndAfter(objPlainTextBackColor, objPlainTextForeColor, bPlainTextBold, sPlainTextBackColorIndex, sPlainTextForeColorIndex, _
objCommentBackColor, objCommentForeColor, bCommentBold, sCommentBackColorIndex, sCommentForeColorIndex, sRtfBefore, sRtfAfter)
If sRtfBefore <> "" Then
sBodyRtf = ColorizeTokenBetweenDelimiters(sBodyRtf, sCommentLinePrefix, ControlChars.Cr, sRtfBefore, sRtfAfter, sRtfKeywordBefore, sRtfKeywordAfter)
End If
End If
End If
sHeaderRtf = objRtfHeaderStringBuilder.ToString
sRtf = "{" & sHeaderRtf & sBodyRtf & "}"
ctlRichTextBox.Rtf = sRtf
' Restore selection position and length
ctlRichTextBox.SelectionStart = iSelectionStart
ctlRichTextBox.SelectionLength = iSelectionLength
Catch objException As Exception
MessageBox.Show(objException.ToString)
End Try
End If
End Sub
Public Function GetVBKeywords() As System.Collections.Specialized.StringCollection
Dim colVBKeywords As New System.Collections.Specialized.StringCollection
colVBKeywords.Add("AddHandler")
colVBKeywords.Add("AddressOf")
colVBKeywords.Add("Alias")
colVBKeywords.Add("And")
colVBKeywords.Add("AndAlso")
colVBKeywords.Add("As")
colVBKeywords.Add("Boolean")
colVBKeywords.Add("ByRef")
colVBKeywords.Add("Byte")
colVBKeywords.Add("ByVal")
colVBKeywords.Add("Call")
colVBKeywords.Add("Case")
colVBKeywords.Add("Catch")
colVBKeywords.Add("CBool")
colVBKeywords.Add("CByte")
colVBKeywords.Add("CChar")
colVBKeywords.Add("CDate")
colVBKeywords.Add("CDec")
colVBKeywords.Add("CDbl")
colVBKeywords.Add("Char")
colVBKeywords.Add("CInt")
colVBKeywords.Add("Class")
colVBKeywords.Add("CLng")
colVBKeywords.Add("CObj")
colVBKeywords.Add("Const")
colVBKeywords.Add("Continue")
colVBKeywords.Add("CSByte")
colVBKeywords.Add("CShort")
colVBKeywords.Add("CSng")
colVBKeywords.Add("CStr")
colVBKeywords.Add("CType")
colVBKeywords.Add("CUInt")
colVBKeywords.Add("CULng")
colVBKeywords.Add("CUShort")
colVBKeywords.Add("Date")
colVBKeywords.Add("Decimal")
colVBKeywords.Add("Declare")
colVBKeywords.Add("Default")
colVBKeywords.Add("Delegate")
colVBKeywords.Add("Dim")
colVBKeywords.Add("DirectCast")
colVBKeywords.Add("Do")
colVBKeywords.Add("Double")
colVBKeywords.Add("Each")
colVBKeywords.Add("Else")
colVBKeywords.Add("ElseIf")
colVBKeywords.Add("End")
colVBKeywords.Add("EndIf")
colVBKeywords.Add("Enum")
colVBKeywords.Add("Erase")
colVBKeywords.Add("Error")
colVBKeywords.Add("Event")
colVBKeywords.Add("Exit")
colVBKeywords.Add("False")
colVBKeywords.Add("Finally")
colVBKeywords.Add("For")
colVBKeywords.Add("Friend")
colVBKeywords.Add("Function")
colVBKeywords.Add("Get")
colVBKeywords.Add("GetType")
colVBKeywords.Add("GetXMLNamespace")
colVBKeywords.Add("Global")
colVBKeywords.Add("GoSub")
colVBKeywords.Add("GoTo")
colVBKeywords.Add("Handles")
colVBKeywords.Add("If")
colVBKeywords.Add("Implements")
colVBKeywords.Add("Imports")
colVBKeywords.Add("In")
colVBKeywords.Add("Inherits")
colVBKeywords.Add("Integer")
colVBKeywords.Add("Interface")
colVBKeywords.Add("Is")
colVBKeywords.Add("IsNot")
colVBKeywords.Add("Let")
colVBKeywords.Add("Lib")
colVBKeywords.Add("Like")
colVBKeywords.Add("Long")
colVBKeywords.Add("Loop")
colVBKeywords.Add("Me")
colVBKeywords.Add("Mod")
colVBKeywords.Add("Module")
colVBKeywords.Add("MustInherit")
colVBKeywords.Add("MustOverride")
colVBKeywords.Add("MyBase")
colVBKeywords.Add("MyClass")
colVBKeywords.Add("Namespace")
colVBKeywords.Add("Narrowing")
colVBKeywords.Add("New")
colVBKeywords.Add("Next")
colVBKeywords.Add("Not")
colVBKeywords.Add("Nothing")
colVBKeywords.Add("NotInheritable")
colVBKeywords.Add("NotOverridable")
colVBKeywords.Add("Object")
colVBKeywords.Add("Of")
colVBKeywords.Add("On")
colVBKeywords.Add("Operator")
colVBKeywords.Add("Option")
colVBKeywords.Add("Optional")
colVBKeywords.Add("Or")
colVBKeywords.Add("OrElse")
colVBKeywords.Add("Overloads")
colVBKeywords.Add("Overridable")
colVBKeywords.Add("Overrides")
colVBKeywords.Add("ParamArray")
colVBKeywords.Add("Partial")
colVBKeywords.Add("Private")
colVBKeywords.Add("Property")
colVBKeywords.Add("Protected")
colVBKeywords.Add("Public")
colVBKeywords.Add("RaiseEvent")
colVBKeywords.Add("ReadOnly")
colVBKeywords.Add("ReDim")
colVBKeywords.Add("REM")
colVBKeywords.Add("RemoveHandler")
colVBKeywords.Add("Resume")
colVBKeywords.Add("Return")
colVBKeywords.Add("SByte")
colVBKeywords.Add("Select")
colVBKeywords.Add("Set")
colVBKeywords.Add("Shadows")
colVBKeywords.Add("Shared")
colVBKeywords.Add("Short")
colVBKeywords.Add("Single")
colVBKeywords.Add("Static")
colVBKeywords.Add("Step")
colVBKeywords.Add("Stop")
colVBKeywords.Add("String")
colVBKeywords.Add("Structure")
colVBKeywords.Add("Sub")
colVBKeywords.Add("SyncLock")
colVBKeywords.Add("Then")
colVBKeywords.Add("Throw")
colVBKeywords.Add("To")
colVBKeywords.Add("True")
colVBKeywords.Add("Try")
colVBKeywords.Add("TryCast")
colVBKeywords.Add("TypeOf")
colVBKeywords.Add("Variant")
colVBKeywords.Add("Wend")
colVBKeywords.Add("UInteger")
colVBKeywords.Add("ULong")
colVBKeywords.Add("UShort")
colVBKeywords.Add("Using")
colVBKeywords.Add("When")
colVBKeywords.Add("While")
colVBKeywords.Add("Widening")
colVBKeywords.Add("With")
colVBKeywords.Add("WithEvents")
colVBKeywords.Add("WriteOnly")
colVBKeywords.Add("Xor")
colVBKeywords.Add("#Const")
colVBKeywords.Add("#Else")
colVBKeywords.Add("#ElseIf")
colVBKeywords.Add("#End")
colVBKeywords.Add("#If")
Return colVBKeywords
End Function
Public Function GetTextEditorFontAndColorsItems(ByVal objDTE As EnvDTE.DTE, ByRef r_sFontFamily As String, ByRef r_sngFontSize As Single, ByRef r_colFontsAndColorsItems As EnvDTE.FontsAndColorsItems) As Boolean
Const CATEGORY_FONTS_AND_COLORS As String = "FontsAndColors"
Const PAGE_TEXT_EDITOR As String = "TextEditor"
Const PROPERTY_FONT_SIZE As String = "FontSize"
Const PROPERTY_FONT_FAMILY As String = "FontFamily"
Const PROPERTY_FONTS_AND_COLORS_ITEMS As String = "FontsAndColorsItems"
Dim colProperties As EnvDTE.Properties
Dim objValue As Object
Dim bResult As Boolean = False
Try
colProperties = objDTE.Properties(CATEGORY_FONTS_AND_COLORS, PAGE_TEXT_EDITOR)
If Not (colProperties Is Nothing) Then
objValue = colProperties.Item(PROPERTY_FONT_FAMILY).Value
r_sFontFamily = objValue.ToString
objValue = colProperties.Item(PROPERTY_FONT_SIZE).Value
r_sngFontSize = CType(objValue, Single)
objValue = colProperties.Item(PROPERTY_FONTS_AND_COLORS_ITEMS).Object
r_colFontsAndColorsItems = DirectCast(objValue, EnvDTE.FontsAndColorsItems)
bResult = True
End If
Catch objException As Exception
MessageBox.Show(objException.ToString)
End Try
Return bResult
End Function
Public Sub GetColorsFromFontsAndColorsItems(ByVal colFontsAndColorsItems As EnvDTE.FontsAndColorsItems, ByVal sDisplayItem As String, ByRef r_objBackColor As Color, ByRef r_objForeColor As Color, ByRef r_bBold As Boolean)
Dim colColorableItems As EnvDTE.ColorableItems
Dim iOleColor As Integer
colColorableItems = colFontsAndColorsItems.Item(sDisplayItem)
iOleColor = System.Convert.ToInt32(colColorableItems.Background)
r_objBackColor = System.Drawing.ColorTranslator.FromOle(iOleColor)
iOleColor = System.Convert.ToInt32(colColorableItems.Foreground)
r_objForeColor = System.Drawing.ColorTranslator.FromOle(iOleColor)
r_bBold = colColorableItems.Bold
End Sub
Public Sub AddColorsToRtfHeader(ByVal objRtfHeaderStringBuilder As System.Text.StringBuilder, ByVal objBackColor As Color, ByVal objForeColor As Color)
AddColorToRtfHeader(objRtfHeaderStringBuilder, objBackColor)
AddColorToRtfHeader(objRtfHeaderStringBuilder, objForeColor)
End Sub
Public Sub AddColorsToRtfHeader(ByVal objRtfHeaderStringBuilder As System.Text.StringBuilder, ByVal colFontsAndColorsItems As EnvDTE.FontsAndColorsItems, ByVal sDisplayItem As String, ByRef r_objBackColor As Color, ByRef r_objForeColor As Color, ByRef r_bBold As Boolean)
GetColorsFromFontsAndColorsItems(colFontsAndColorsItems, sDisplayItem, r_objBackColor, r_objForeColor, r_bBold)
AddColorsToRtfHeader(objRtfHeaderStringBuilder, r_objBackColor, r_objForeColor)
End Sub
Public Sub AddColorToRtfHeader(ByVal objRtfHeaderStringBuilder As System.Text.StringBuilder, ByVal objColor As Color)
objRtfHeaderStringBuilder.Append("\red") '
objRtfHeaderStringBuilder.Append(objColor.R.ToString) '
objRtfHeaderStringBuilder.Append("\green") '
objRtfHeaderStringBuilder.Append(objColor.G.ToString) '
objRtfHeaderStringBuilder.Append("\blue") '
objRtfHeaderStringBuilder.Append(objColor.B.ToString) '
objRtfHeaderStringBuilder.Append(";")
objRtfHeaderStringBuilder.Append(ControlChars.Cr)
End Sub
Public Function EscapeSpecialRTFCharacters(ByVal sLine As String) As String
Dim sResult As String
sResult = sLine
If Not (sResult Is Nothing) Then
sResult = sResult.Replace("\", "\\")
sResult = sResult.Replace("{", "\{")
sResult = sResult.Replace("}", "\}")
End If
Return sResult
End Function
Public Sub GetRtfBeforeAndAfter(ByVal objPlainTextBackColor As Color, ByVal objPlainTextForeColor As Color, ByVal bPlainTextBold As Boolean, _
ByVal sPlainTextBackColorIndex As String, ByVal sPlainTextForeColorIndex As String, _
ByVal objTokenBackColor As Color, ByVal objTokenForeColor As Color, ByVal bTokenBold As Boolean, _
ByVal sTokenBackColorIndex As String, ByVal sTokenForeColorIndex As String, _
ByRef r_sRtfBefore As String, ByRef r_sRtfAfter As String)
r_sRtfBefore = ""
r_sRtfAfter = ""
If Not objTokenBackColor.Equals(objPlainTextBackColor) Then
r_sRtfBefore &= "\highlight" & sTokenBackColorIndex & " "
r_sRtfAfter &= "\highlight" & sPlainTextBackColorIndex & " "
End If
If Not objTokenForeColor.Equals(objPlainTextForeColor) Then
r_sRtfBefore &= "\cf" & sTokenForeColorIndex & " "
r_sRtfAfter &= "\cf" & sPlainTextForeColorIndex & " "
End If
If bTokenBold <> bPlainTextBold Then
If bTokenBold Then
r_sRtfBefore &= "\b "
r_sRtfAfter &= "\b0 "
Else
r_sRtfBefore &= "\b0 "
r_sRtfAfter &= "\b "
End If
End If
End Sub
Public Function ColorizeTokenBetweenDelimiters(ByVal sInput As String, ByVal sDelimiter1 As String, ByVal sDelimiter2 As String, ByVal sRtfBefore As String, ByVal sRtfAfter As String, ByVal sRtfKeywordBefore As String, ByVal sRtfKeywordAfter As String) As String
Dim iStartPositionSearch1 As Integer
Dim iStartPositionSearch2 As Integer
Dim iDelimiterPos1 As Integer
Dim iDelimiterPos2 As Integer
Dim sToken As String
Dim objStringBuilder As New System.Text.StringBuilder()
iStartPositionSearch1 = 0
Do
If iStartPositionSearch1 >= sInput.Length Then
Exit Do
Else
' Find the first delimiter
iDelimiterPos1 = sInput.IndexOf(sDelimiter1, iStartPositionSearch1)
If iDelimiterPos1 = -1 Then ' Not found
' Add the remaining string before exiting
objStringBuilder.Append(sInput.Substring(iStartPositionSearch1))
Exit Do
Else
' Add the consumed string until the found hit
If iDelimiterPos1 > iStartPositionSearch1 Then
objStringBuilder.Append(sInput.Substring(iStartPositionSearch1, iDelimiterPos1 - iStartPositionSearch1))
End If
' Find the second delimiter
iStartPositionSearch2 = iDelimiterPos1 + sDelimiter1.Length
If iStartPositionSearch2 < sInput.Length Then
iDelimiterPos2 = sInput.IndexOf(sDelimiter2, iStartPositionSearch2)
Else
iDelimiterPos2 = -1
End If
If iDelimiterPos2 = -1 Then
' Not found, so we assume it means until the end of text.
' This is the case of comments, which use Cr (carriage return) as delimiter2 as the token delimiter. We must
' colorize the comment even if it is the last line and no carriage return is used.
sToken = sInput.Substring(iDelimiterPos1)
Else
sToken = sInput.Substring(iDelimiterPos1, iDelimiterPos2 - iDelimiterPos1 + sDelimiter2.Length)
End If
' Remove the existing keyword colorization that may exist
If sRtfKeywordBefore <> "" Then
sToken = sToken.Replace(sRtfKeywordBefore, "")
sToken = sToken.Replace(sRtfKeywordAfter, "")
End If
' Add the token and its colorization
If sRtfBefore <> "" Then
objStringBuilder.Append(sRtfBefore)
End If
objStringBuilder.Append(sToken)
If sRtfAfter <> "" Then
objStringBuilder.Append(sRtfAfter)
End If
If iDelimiterPos2 = -1 Then ' The delimiter was not found, so we are done
Exit Do
Else ' Prepare for the next loop
iStartPositionSearch1 = iDelimiterPos2 + sDelimiter2.Length
End If
End If
End If
Loop
Return objStringBuilder.ToString
End Function
End Class
I am writing an article about creating setups for Visual Studio add-ins and testing I have found that if the namespace/class specified in the <FullClassName> tag of the .AddIn XML file does not match the actual namespace and connect class name in the source code, you get an obscure <Unknown error> (error number 80131522) loading the add-in. Searching the web I found in the forums that I was not the first developer with this problem, so I have updated my article to reflect this:
HOWTO: Troubleshooting Visual Studio and Office add-ins
http://www.mztools.com/articles/2007/MZ2007009.aspx
It would be great if Microsoft could provide more helpful message errors when things are not set up as expected...
Since I suppose that somebody will request me the source code of the colorizer that I mentioned in my last post, the code is below. Just create a form with a RichTextBox control. Since this is not a "colorize as you type" approach (I think that the performance could suffer), you need to use the LostFocus of the RichTextBox control or use a "Colorize" button to call the ColorizeRichTextBox method passing the DTE instance, the RichTextBox control, the comment line prefix ( ' for VB.NET, // for C#) and the list of keywords of the language (see Visual Basic Language Keywords and C# Keywords). Notice that the RichTextBox of .NET 1.x doesn't support the SelectionBackColor property. The version that I am posting colorizes the plain text, keywords, strings and comments and it does a pretty good job resembling the code editor appearance. If you find bugs or enhancements let me know.
Public Class FormCodeColorizer
Private Sub ButtonColorize_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonColorize.Click
Dim objDTE As EnvDTE.DTE
objDTE = ... ' Get the EnvDTE.DTE from somewhere
ColorizeRichText(objDTE, Me.RichTextBoxCode, "'", GetVBKeywords())
End Sub
Public Sub ColorizeRichText(ByVal objDTE As EnvDTE.DTE, ByVal ctlRichTextBox As RichTextBox, _
ByVal sCommentLinePrefix As String, ByVal colKeywords As System.Collections.Specialized.StringCollection)
Const DISPLAY_ITEM_PLAIN_TEXT As String = "Plain Text"
Const DISPLAY_ITEM_KEYWORD As String = "Keyword"
Const DISPLAY_ITEM_STRING As String = "String"
#If VS_8_0 Then
' PATCH: The Comment default color is wrong. We use the CSS Comment color instead
Const DISPLAY_ITEM_COMMENT As String = "CSS Comment"
#Else
Const DISPLAY_ITEM_COMMENT As String = "Comment"
#End If
Dim objFont As Font = Nothing
Dim objBackColor As Color
Dim objTextColor As Color
Dim iSelectionStart As Integer
Dim iSelectionLength As Integer
Dim colFontsAndColorsItems As EnvDTE.FontsAndColorsItems = Nothing
Dim sFontFamily As String = ""
Dim sngFontSize As Single
Dim bBoldFont As Boolean
If GetTextEditorFontAndColorsItems(objDTE, sFontFamily, sngFontSize, colFontsAndColorsItems) Then
If GetFontAndColorInformation(colFontsAndColorsItems, DISPLAY_ITEM_PLAIN_TEXT, bBoldFont, objBackColor, objTextColor) Then
Try
If bBoldFont Then
objFont = New Font(sFontFamily, sngFontSize, FontStyle.Bold)
Else
objFont = New Font(sFontFamily, sngFontSize)
End If
' Cache selection position and length
iSelectionStart = ctlRichTextBox.SelectionStart
iSelectionLength = ctlRichTextBox.SelectionLength
' Set the properties of the control
ctlRichTextBox.Font = objFont
ctlRichTextBox.BackColor = objBackColor
ctlRichTextBox.ForeColor = objTextColor
' This is to reset the font and color properties, just in case there was previous colorizing information
ctlRichTextBox.SelectionStart = 0
ctlRichTextBox.SelectionLength = ctlRichTextBox.TextLength
ctlRichTextBox.SelectionFont = objFont
ctlRichTextBox.SelectionColor = objTextColor
ctlRichTextBox.SelectionBackColor = objBackColor
' Colorize keywords
ColorizeRichTextKeywords(ctlRichTextBox, colKeywords, sFontFamily, sngFontSize, colFontsAndColorsItems, DISPLAY_ITEM_KEYWORD)
' Colorize comments
ColorizeRichTextTokens(ctlRichTextBox, sCommentLinePrefix, ControlChars.Cr, RichTextBoxFinds.None, sFontFamily, sngFontSize, colFontsAndColorsItems, DISPLAY_ITEM_COMMENT)
' Colorize strings
ColorizeRichTextTokens(ctlRichTextBox, ControlChars.Quote, ControlChars.Quote, RichTextBoxFinds.None, sFontFamily, sngFontSize, colFontsAndColorsItems, DISPLAY_ITEM_STRING)
' Restore selection position and length
ctlRichTextBox.SelectionStart = iSelectionStart
ctlRichTextBox.SelectionLength = iSelectionLength
Finally
If Not (objFont Is Nothing) Then
objFont.Dispose()
End If
End Try
End If
End If
End Sub
Public Function GetVBKeywords() As System.Collections.Specialized.StringCollection
Dim colVBKeywords As New System.Collections.Specialized.StringCollection
colVBKeywords.Add("AddHandler")
colVBKeywords.Add("AddressOf")
colVBKeywords.Add("Alias")
colVBKeywords.Add("And")
colVBKeywords.Add("AndAlso")
colVBKeywords.Add("As")
colVBKeywords.Add("Boolean")
colVBKeywords.Add("ByRef")
colVBKeywords.Add("Byte")
colVBKeywords.Add("ByVal")
colVBKeywords.Add("Call")
colVBKeywords.Add("Case")
colVBKeywords.Add("Catch")
colVBKeywords.Add("CBool")
colVBKeywords.Add("CByte")
colVBKeywords.Add("CChar")
colVBKeywords.Add("CDate")
colVBKeywords.Add("CDec")
colVBKeywords.Add("CDbl")
colVBKeywords.Add("Char")
colVBKeywords.Add("CInt")
colVBKeywords.Add("Class")
colVBKeywords.Add("CLng")
colVBKeywords.Add("CObj")
colVBKeywords.Add("Const")
colVBKeywords.Add("Continue")
colVBKeywords.Add("CSByte")
colVBKeywords.Add("CShort")
colVBKeywords.Add("CSng")
colVBKeywords.Add("CStr")
colVBKeywords.Add("CType")
colVBKeywords.Add("CUInt")
colVBKeywords.Add("CULng")
colVBKeywords.Add("CUShort")
colVBKeywords.Add("Date")
colVBKeywords.Add("Decimal")
colVBKeywords.Add("Declare")
colVBKeywords.Add("Default")
colVBKeywords.Add("Delegate")
colVBKeywords.Add("Dim")
colVBKeywords.Add("DirectCast")
colVBKeywords.Add("Do")
colVBKeywords.Add("Double")
colVBKeywords.Add("Each")
colVBKeywords.Add("Else")
colVBKeywords.Add("ElseIf")
colVBKeywords.Add("End")
colVBKeywords.Add("EndIf")
colVBKeywords.Add("Enum")
colVBKeywords.Add("Erase")
colVBKeywords.Add("Error")
colVBKeywords.Add("Event")
colVBKeywords.Add("Exit")
colVBKeywords.Add("False")
colVBKeywords.Add("Finally")
colVBKeywords.Add("For")
colVBKeywords.Add("Friend")
colVBKeywords.Add("Function")
colVBKeywords.Add("Get")
colVBKeywords.Add("GetType")
colVBKeywords.Add("GetXMLNamespace")
colVBKeywords.Add("Global")
colVBKeywords.Add("GoSub")
colVBKeywords.Add("GoTo")
colVBKeywords.Add("Handles")
colVBKeywords.Add("If")
colVBKeywords.Add("Implements")
colVBKeywords.Add("Imports")
colVBKeywords.Add("In")
colVBKeywords.Add("Inherits")
colVBKeywords.Add("Integer")
colVBKeywords.Add("Interface")
colVBKeywords.Add("Is")
colVBKeywords.Add("IsNot")
colVBKeywords.Add("Let")
colVBKeywords.Add("Lib")
colVBKeywords.Add("Like")
colVBKeywords.Add("Long")
colVBKeywords.Add("Loop")
colVBKeywords.Add("Me")
colVBKeywords.Add("Mod")
colVBKeywords.Add("Module")
colVBKeywords.Add("MustInherit")
colVBKeywords.Add("MustOverride")
colVBKeywords.Add("MyBase")
colVBKeywords.Add("MyClass")
colVBKeywords.Add("Namespace")
colVBKeywords.Add("Narrowing")
colVBKeywords.Add("New")
colVBKeywords.Add("Next")
colVBKeywords.Add("Not")
colVBKeywords.Add("Nothing")
colVBKeywords.Add("NotInheritable")
colVBKeywords.Add("NotOverridable")
colVBKeywords.Add("Object")
colVBKeywords.Add("Of")
colVBKeywords.Add("On")
colVBKeywords.Add("Operator")
colVBKeywords.Add("Option")
colVBKeywords.Add("Optional")
colVBKeywords.Add("Or")
colVBKeywords.Add("OrElse")
colVBKeywords.Add("Overloads")
colVBKeywords.Add("Overridable")
colVBKeywords.Add("Overrides")
colVBKeywords.Add("ParamArray")
colVBKeywords.Add("Partial")
colVBKeywords.Add("Private")
colVBKeywords.Add("Property")
colVBKeywords.Add("Protected")
colVBKeywords.Add("Public")
colVBKeywords.Add("RaiseEvent")
colVBKeywords.Add("ReadOnly")
colVBKeywords.Add("ReDim")
colVBKeywords.Add("REM")
colVBKeywords.Add("RemoveHandler")
colVBKeywords.Add("Resume")
colVBKeywords.Add("Return")
colVBKeywords.Add("SByte")
colVBKeywords.Add("Select")
colVBKeywords.Add("Set")
colVBKeywords.Add("Shadows")
colVBKeywords.Add("Shared")
colVBKeywords.Add("Short")
colVBKeywords.Add("Single")
colVBKeywords.Add("Static")
colVBKeywords.Add("Step")
colVBKeywords.Add("Stop")
colVBKeywords.Add("String")
colVBKeywords.Add("Structure")
colVBKeywords.Add("Sub")
colVBKeywords.Add("SyncLock")
colVBKeywords.Add("Then")
colVBKeywords.Add("Throw")
colVBKeywords.Add("To")
colVBKeywords.Add("True")
colVBKeywords.Add("Try")
colVBKeywords.Add("TryCast")
colVBKeywords.Add("TypeOf")
colVBKeywords.Add("Variant")
colVBKeywords.Add("Wend")
colVBKeywords.Add("UInteger")
colVBKeywords.Add("ULong")
colVBKeywords.Add("UShort")
colVBKeywords.Add("Using")
colVBKeywords.Add("When")
colVBKeywords.Add("While")
colVBKeywords.Add("Widening")
colVBKeywords.Add("With")
colVBKeywords.Add("WithEvents")
colVBKeywords.Add("WriteOnly")
colVBKeywords.Add("Xor")
colVBKeywords.Add("#Const")
colVBKeywords.Add("#Else")
colVBKeywords.Add("#ElseIf")
colVBKeywords.Add("#End")
colVBKeywords.Add("#If")
colVBKeywords.Add("=")
colVBKeywords.Add("&")
colVBKeywords.Add("&=")
colVBKeywords.Add("*")
colVBKeywords.Add("*=")
colVBKeywords.Add("/")
colVBKeywords.Add("/=")
colVBKeywords.Add("\")
colVBKeywords.Add("\=")
colVBKeywords.Add("^")
colVBKeywords.Add("^=")
colVBKeywords.Add("+")
colVBKeywords.Add("+=")
colVBKeywords.Add("-")
colVBKeywords.Add("-=")
colVBKeywords.Add(">>")
colVBKeywords.Add(">>=")
colVBKeywords.Add("<<")
colVBKeywords.Add("<<=")
Return colVBKeywords
End Function
Public Sub ColorizeRichTextKeywords(ByVal ctlRichTextBox As RichTextBox, _
ByVal colKeywords As System.Collections.Specialized.StringCollection, _
ByVal sFontFamily As String, ByVal sngFontSize As Single, _
ByVal colFontsAndColorsItems As EnvDTE.FontsAndColorsItems, ByVal sDisplayItem As String)
Dim sKeyword As String
Dim eRichTextBoxFinds As RichTextBoxFinds
eRichTextBoxFinds = RichTextBoxFinds.WholeWord Or RichTextBoxFinds.MatchCase
For Each sKeyword In colKeywords
ColorizeRichTextTokens(ctlRichTextBox, sKeyword, "", eRichTextBoxFinds, sFontFamily, sngFontSize, colFontsAndColorsItems, sDisplayItem)
Next
End Sub
Public Sub ColorizeRichTextTokens(ByVal ctlRichTextBox As RichTextBox, _
ByVal sToken As String, ByVal sOptionalTokenDelimiter As String, _
ByVal eRichTextBoxFinds As RichTextBoxFinds, ByVal sFontFamily As String, ByVal sngFontSize As Single, _
ByVal colFontsAndColorsItems As EnvDTE.FontsAndColorsItems, ByVal sDisplayItem As String)
Dim iPosition1 As Integer
Dim iPosition2 As Integer
Dim objFont As Font = Nothing
Dim objBackColor As Color
Dim objTextColor As Color
Dim bBoldFont As Boolean
Dim bFontAndColorInformationRetrieved As Boolean = False
Try
If Not (colFontsAndColorsItems Is Nothing) Then
If sToken <> "" Then
iPosition1 = 0
Do
iPosition1 = ctlRichTextBox.Find(sToken, iPosition1, eRichTextBoxFinds)
If iPosition1 = -1 Then
Exit Do
Else
If sOptionalTokenDelimiter = "" Then
iPosition2 = iPosition1 + sToken.Length
Else
If iPosition1 + sToken.Length < ctlRichTextBox.TextLength Then
iPosition2 = ctlRichTextBox.Find(sOptionalTokenDelimiter, iPosition1 + sToken.Length, RichTextBoxFinds.None)
Else
iPosition2 = -1
End If
If iPosition2 = -1 Then
' Not found, but the delimiter was passed so we assume it means until the end of text.
' This is the case of comments, which use Cr (carriage return) as the token delimiter. We must
' colorize the comment even if it is the last line and no carriage return is used.
' This does not apply to keywords because they don't use token delimiter, so it works as expected
iPosition2 = ctlRichTextBox.TextLength
End If
End If
' Resources are not created until an occurrence was found. And then, they are created only once
If Not bFontAndColorInformationRetrieved Then
If GetFontAndColorInformation(colFontsAndColorsItems, sDisplayItem, bBoldFont, objBackColor, objTextColor) Then
If sFontFamily <> "" Then
If bBoldFont Then
objFont = New Font(sFontFamily, sngFontSize, FontStyle.Bold)
Else
objFont = New Font(sFontFamily, sngFontSize)
End If
bFontAndColorInformationRetrieved = True
End If
End If
End If
If Not bFontAndColorInformationRetrieved Then
Exit Do
Else
ctlRichTextBox.SelectionStart = iPosition1
ctlRichTextBox.SelectionLength = iPosition2 - iPosition1 + sOptionalTokenDelimiter.Length
If Not (objFont Is Nothing) Then
ctlRichTextBox.SelectionFont = objFont
End If
If Not objTextColor.Equals(Color.Empty) Then
ctlRichTextBox.SelectionColor = objTextColor
End If
' Note: The RichTextBox of .NET 1.x doesn't support the SelectionBackColor property
If Not objBackColor.Equals(Color.Empty) Then
ctlRichTextBox.SelectionBackColor = objBackColor
End If
iPosition1 = iPosition2 + sOptionalTokenDelimiter.Length
If iPosition1 >= ctlRichTextBox.TextLength Then
Exit Do
End If
End If
End If
Loop
End If
End If
Finally
If Not (objFont Is Nothing) Then
objFont.Dispose()
End If
End Try
End Sub
Public Function GetFontAndColorInformation(ByVal colFontsAndColorsItems As EnvDTE.FontsAndColorsItems, _
ByVal sDisplayItem As String, ByRef r_bBoldFont As Boolean, ByRef r_objBackColor As Color, _
ByRef r_objTextColor As Color) As Boolean
Dim colColorableItems As EnvDTE.ColorableItems
Dim iOleColor As Integer
Dim bResult As Boolean = False
Try
If Not (colFontsAndColorsItems Is Nothing) Then
colColorableItems = colFontsAndColorsItems.Item(sDisplayItem)
iOleColor = System.Convert.ToInt32(colColorableItems.Background)
r_objBackColor = System.Drawing.ColorTranslator.FromOle(iOleColor)
iOleColor = System.Convert.ToInt32(colColorableItems.Foreground)
r_objTextColor = System.Drawing.ColorTranslator.FromOle(iOleColor)
r_bBoldFont = colColorableItems.Bold
bResult = True
End If
Catch objException As Exception
MessageBox.Show(objException.ToString)
End Try
Return bResult
End Function
Public Function GetTextEditorFontAndColorsItems(ByVal objDTE As EnvDTE.DTE, ByRef r_sFontFamily As String, _
ByRef r_sngFontSize As Single, ByRef r_colFontsAndColorsItems As EnvDTE.FontsAndColorsItems) As Boolean
Const CATEGORY_FONTS_AND_COLORS As String = "FontsAndColors"
Const PAGE_TEXT_EDITOR As String = "TextEditor"
Const PROPERTY_FONT_SIZE As String = "FontSize"
Const PROPERTY_FONT_FAMILY As String = "FontFamily"
Const PROPERTY_FONTS_AND_COLORS_ITEMS As String = "FontsAndColorsItems"
Dim colProperties As EnvDTE.Properties
Dim objValue As Object
Dim bResult As Boolean = False
Try
colProperties = objDTE.Properties(CATEGORY_FONTS_AND_COLORS, PAGE_TEXT_EDITOR)
If Not (colProperties Is Nothing) Then
objValue = colProperties.Item(PROPERTY_FONT_FAMILY).Value
r_sFontFamily = objValue.ToString
objValue = colProperties.Item(PROPERTY_FONT_SIZE).Value
r_sngFontSize = CType(objValue, Single)
objValue = colProperties.Item(PROPERTY_FONTS_AND_COLORS_ITEMS).Object
r_colFontsAndColorsItems = DirectCast(objValue, EnvDTE.FontsAndColorsItems)
bResult = True
End If
Catch objException As Exception
MessageBox.Show(objException.ToString)
End Try
Return bResult
End Function
End Class
Although I wrote long time ago an article about EnvDTE.DTE.Properties, it was not until this week that I needed to retrieve font and color information of the text editor of Visual Studio. Basically I am changing the code template editor of my MZ-Tools add-in from black and white to colorized text using a RichTextBox, resembling as much as possible the code editor of VS without using more complex 3rd party products (such as Activepro Syntaxt Editor, which seems excellent) or trying to host the Visual Studio code editor inside a Windows Form.
Here is a new article about this subject and some things that I have encountered.
HOWTO: Get the text editor font and colors information in a Visual Studio add-in
http://www.mztools.com/articles/2008/MZ2008008.aspx
BTW, notice that VS 2005 has a bug (fixed in VS 2008) and the "Comment" foreground color is not returned correctly (although the VS code editor colorizes perfectly). You may want to use the XML Comment or CSS Comment foreground color in this case.
This is a really tricky one that I found in the forums months ago and I have documented it today:
PRB: CodeModelEvents not firing events in a Visual Studio add-in
http://www.mztools.com/Articles/2008/MZ2008007.aspx
I added yesterday a new resource to the "Resources about Visual Studio extensibility" section of my web site that may be interesting for those of you starting with VS SDK packages:
http://www.architekturaforum.hu/blogs/divedeeper/archive/2008/01/02/LearnVSXNowPart1.aspx
As you may have noticed, there aren't many books on Visual Studio Extensibility, so any new book is great news. This is the case of a new book with the title "Professional Visual Studio Extensibility" by Keyvan Nayyeri:
http://nayyeri.net/blog/professional%2Dvisual%2Dstudio%2Dextensibility%2Dfinally%2Dreleased/
It is already available from Wiley and Wrox (where you can read the TOC, index, and first chapter) and will be available from Amazon shortly. I haven't read it yet (I am awaiting a complimentary copy in a few days or weeks) but I am excited because this book covers more than add-ins or macros, so you have chapters about VS SDK packages, DSL tools, Visual Studio Shell, extending the debugger or even MSBuild. While there is lot of information about those subjects in MSDN and blogs, I personally prefer a good book to learn new technologies.
This is another question that appears from time to time in the forums, and it is one extremely complicated to have a 100% satisfaction with the result :-). I haven't written a MZ-Tools Series article for this since I don't have a comprehensive answer with a sample code, but I will ellaborate a bit about this in this post.
The question is, suppose I have a string like "Car" that I know it's a type. How can I get the System.Type that represents that type? Before that question there is a previous one: how did I get that string? There are several ways:
- Using the code model (EnvDTE.Project.CodeModel or EnvDTE.ProjectItem.FileCodeModel), you have a CodeVariable, CodeParameter, etc. which has a CodeTypeRef property that returns the type of the code element.
- Parsing a procedure code (by hand, since the code model doesn't cover that), you get statements like "Dim objCar as Car" (VB.NET) or "Car mycar" (C#), so somehow you get the "Car" string and you guess that it is a type.
There are a couple of complications to note here:
- Types have a short name, such as "Car", and a fully qualified name, such as "Vehicles.Motorized.Car". Since you can have "Imports" statements at file or project level in VB.NET and "using" statements at file level in C#, it is not required that the fully qualified name to appear in the variable or parameter declaration. Note: even if the declaration contains a dot (.) you can't assure that it is a fully qualified name because it can be a partially-qualified name, such as if you import the "Vehicles" namespace at file level and you declare the variable as Dim objCar As Motorized.Car.
- Types can reside in compiled assemblies references, or, alas, in the project's source code or in a project (not compiled) reference. In the last two cases, you can't have a System.Type, since maybe the project is not compiled yet (first time) or maybe the last compilation was days ago and it is not up-to-date. In these cases, for most accuracy you don't really want a System.Type but an EnvDTE.CodeElement such as an EnvDTE.CodeClass, EnvDTE.CodeStruct, EnvDTE.CodeInterface, etc. So, your add-in has to deal with two kind of types: compiled types (represented by a System.Type) and source code types (represented by a CodeElement).
So, let's try to solve them:
- To get the fully qualified name of a type name, assumming that it comes from a EnvDTE.CodeTypeRef, you can try the CodeTypeRef.AsFullName property (in contrast to its CodeTypeRef.AsString property). I don't know how reliable is this in each version of Visual Studio and for each language (VB.NET, C#) but my experience is that you can't fully trust the code model. As a workaround, you should compose a list of fully qualified candidate type names combining the imported namespaces and then try to resolve which of them is the true one. This is what the compiler does after all when building the project, although it doesn't expose that information to add-ins or packages (AFAIK).
- Given the fully qualified name, or a list of candidates, you need to "resolve" them to a System.Type or EnvDTE.CodeElement. To do this, I would start with compiled references since is faster than using the code model. You would have to get the references of the project which are compiled assemblies (see HOWTO: Getting information specific to VB.NET and C# projects from an add-in or macro). For each compiled reference you get the name of the assembly and using Reflection you can use Assembly.Load or Assembly.LoadFrom to load it and then call Assembly.GetExportedTypes to get the public types and then iterate them until you find the one that matches the fully qualified type name. If you don't find it, then chances are that it is a type declared in the source code of the project, or in one of the project (not compiled) references. In these cases you have to navigate the code model of each project (see HOWTO: Navigate the files of a solution from a Visual Studio .NET macro or add-in and HOWTO: Navigate the code elements of a file from a Visual Studio .NET macro or add-in). Needless to say, this can be slow.
All that said, you may have heard of the ITypeResolutionService service of Visual Studio, which sounds promising to avoid all that. I haven't tried it personally because it was not clear for me how to get an instance of it (most documentation refers to component designers) but today I found two posts of MVP fellow Daniel Cazzulino that can be helpful:
Retrieving available types in current project and its references (withoult locking)
http://www.clariusconsulting.net/blogs/kzu/archive/2006/01/06/GetTypesFromProject.aspx
and
How to get a System.Type from an EnvDTE.CodeTypeRef or EnvDTE.CodeClass
http://www.clariusconsulting.net/blogs/kzu/archive/2007/10/04/34019.aspx
So, he explains how to get the all the types declared in a project and references using the ITypeDiscoveryService, and how to get a System.Type from a type name using the ITypeResolutionService, retrieving both services from an EnvDTE.Project. These is great news, but notice the caveat that for types declared in source code, it will retrieve a System.Type from the last successful compilation (if any) and not an EnvDTE.CodeElement. Assuming that you don't mind the issue of the out-of-date compilation, getting a System.Type can be enough for some scenarios, but not for others, such as when you want to go to the source code file of the type (think the Go To Definition command of Visual Studio), where you really want an EnvDTE.CodeElement (which contains the ProjectItem and location, etc.) and not a System.Type.
Someone asked today something related to this in the MSDN forum and since I remembered being there and that the solution was not very intuitive, I wrote this article:
HOWTO: Add an event handler from a Visual Studio add-in
http://www.mztools.com/articles/2008/MZ2008006.aspx
This week I attended the TechDays 2008 here at Madrid, a two-days event to launch Visual Studio 2008, Windows Server 2008 and SQL Server 2008 (this product actually is not released yet but...). I don't know if it was that Microsoft Iberica (the subsidiary for Spain and Portugal) celebrated its 20 anniversary or that the new products deserved it, but this has been the greatest Microsoft event that I ever attended (except the Microsoft TechEd at Barcelona that I attend every some years). It was like a mini-TechEd, with lots of parallel sessions, hands-on labs, ask the expert, partners expo, etc. and even hot dogs ;-). Lots of known people (many speakers were fellow MVPs) and very good content in most sessions. Apart from the new exciting technologies such as WCF, WFF, WPF or SilverLight I was mostly interested in Team Foundation Server 2008, a great tool for collaboration and team work that hopefully I will install and use this year, and which furthermore provides extensibility, so who knows if I enter that area some day...
Microsoft announced it some days ago: the new Visual Studio Gallery (http://www.visualstudiogallery.com), a new web site with lots of 3rd party products for Visual Studio, such as controls, source control providers, add-ins, packages, etc. Considering how hard can be sometimes the Visual Studio extensibility, it's great to see the big ecosystem of tools that many people is building around Microsoft Visual Studio. The Eclipse IDE for Java has had always such a big ecosystem of plugins (I used Eclipse with some plugins to develop a J2ME game for Java-enabled mobile phones a couple of years ago) and now Visual Studio has such ecosystem in a centralized website, easy to find and navigate.
Of course, my MZ-Tools add-in is part of such ecosystem:
http://www.visualstudiogallery.com/ExtensionDetails.aspx?ExtensionId=3b070c5d-6478-4a86-aafa-026e79189e9e