My organization has extremely restrictive and rigid rules our code must comply with in order to obtain certification and accreditation. For the last decade or so we have developed nearly a hundred VS macros that format code, generate comments blocks, enforce style rules, etc.
Our macros are not the kind you record some mouse movements; they all depend on the EnvDTE* VS automation objects. With VS 2012 dropping macros we are at a loss as to whether or not we will even be able to upgrade, without imposing a drastic impact on the team.
I am aware that the direction Microsoft is going is the VS Addins route and I am willing to investigate that route but I am having trouble finding code samples or documentation on how a VS Add-In can interact with the active code file in Visual Studio.
For example, here is a macro we use all the time that applies our Try wrapper design pattern to all methods that are capable of throwing unhandled exceptions
''' <summary>
''' Wraps active method in Try* access wrappers.
''' </summary>
Sub InsertSingleMethodTryWrappers()
Dim textSelection As TextSelection
Dim codeElement As CodeElement
textSelection = DTE.ActiveWindow.Selection
DTE.UndoContext.Open("Generate Try Wrappers") 'Allow for single Undo operation to rollback all changes
Try
codeElement = textSelection.ActivePoint.CodeElement(vsCMElement.vsCMElementFunction)
If Not (codeElement Is Nothing) Then
Dim textSelection2 As TextSelection
Dim codeFunction As CodeFunction
'Dim codeFunction2 As CodeFunction2
Dim editPoint As EditPoint
Dim codeParameter As CodeParameter
Dim parameters As CodeElements
Dim codeElement2 As CodeElement
Dim isVirtual As Boolean = False
Dim strVirtual As String = String.Empty
Dim strTypeName As String = String.Empty
'' Cast the codeElement to codeFunction object
codeFunction = codeElement
'' Move cursor to the start of the method
textSelection.MoveToPoint(codeFunction.GetStartPoint(vsCMPart.vsCMPartHeader))
'' Should be able to use codeFunction.Kind.ToString to retrieve the function type
'' vsCMFunctionVirtual if the method is virtual but there is a bug in the API
'' that returns vsCMFunctionFunction even if the function is virtual (C# parsing bug?)
''
'' vsCMFunction Type
'' http://msdn.microsoft.com/en-us/library/envdte.vscmfunction(v=vs.80).aspx
''
'' This frustrating bug means that we have to parse the header to determine if virtual
textSelection.EndOfLine(True)
If (textSelection.Text.IndexOf("virtual") > 0) Then
isVirtual = True
strVirtual = " virtual"
End If
textSelection.StartOfLine()
'' Try not to screw up comments and attributes
editPoint = GetNoneCommentOrAttribHeaderEditPoint(textSelection)
If editPoint Is Nothing Then
MsgBox("Could not find a line above the method that isn't a comment or attribute", _
MsgBoxStyle.Critical + MsgBoxStyle.OkOnly, "Error")
Exit Sub
End If
'' Create an EditPoint to inject Try* methods
'editPoint = textSelection.TopPoint.CreateEditPoint()
'editPoint.LineUp() 'Move up 1 line
editPoint.EndOfLine() 'Go to end of line above signature
editPoint.Insert(Environment.NewLine) 'Insert blank line for cleanliness
editPoint.Insert(Environment.NewLine) 'Insert blank line for cleanliness
editPoint.LineUp() 'Move up 1 line
parameters = codeFunction.Parameters
Dim strAccess As String : strAccess = GetAccessModifierString(codeFunction.Access) 'Access Modifier
Dim strName As String : strName = codeElement.Name 'Member Name
Dim strType As String : strType = codeFunction.Type.AsString 'Type Name
'' Get the un-qualified object name
If (strType.IndexOf(".") > 0) Then
Dim arrType() As String = strType.Split(".")
strTypeName = arrType(arrType.Length - 1)
Else
strTypeName = strType
End If
''' Create parameter type/name arrayList
Dim arrParams As System.Collections.ArrayList
arrParams = New System.Collections.ArrayList()
For Each codeElement2 In parameters
codeParameter = codeElement2
arrParams.Add(codeParameter.Type.AsString.Trim & " " & codeParameter.Name.Trim & ", ")
Next
Dim strParams As String
Dim strParamNames As String
'' Capture a string with parameter names and types and one just of names
For Each strParam As String In arrParams
strParams += strParam
strParamNames += strParam.Split(" ")(1)
Next
'' Trim excess comma for members of type void
If strType = "void" Then
If Not String.IsNullOrEmpty(strParams) Then
If strParams.TrimEnd.EndsWith(",") Then
strParams = strParams.TrimEnd()
strParams = strParams.Remove(strParams.Length - 1, 1)
End If
End If
End If
'' -- Try* swallow methods --
'' we don't care what the exception is, we just want to know success or failure
Dim strTrySwallowSignature As String
Dim strTrySwallowBody As String
Dim strTryOutParams As String
Dim strOutDef As String
Dim strOutSig As String
'' Members of type 'void' get no out parameters
If Not strType = "void" Then
strTryOutParams = "out " & strTypeName & " outObjType"
strOutDef = "outObjType = null;"
strOutSig = " out outObjType,"
End If
strTrySwallowSignature = vbTab & vbTab & strAccess & strVirtual & " bool Try" & strName & "(" & strParams & strTryOutParams & ")"
strTrySwallowBody = vbCrLf & vbTab & vbTab & "{" _
& vbCrLf & vbTab & vbTab & vbTab & "Exception exception;" _
& vbCrLf & vbTab & vbTab & vbTab & strOutDef _
& vbCrLf & vbTab & vbTab & vbTab & "return Try" & strName & "(" & strParamNames & strOutSig & " out exception);" _
& vbCrLf & vbTab & vbTab & "}"
'' -- Try* re-throw methods --
'' We want to know success or failure as well as the exception if it failed
Dim strTryReThrowSignature As String
Dim strTryReThrowBody As String
'' Members of type 'void' only get out exception parameter
If Not strType = "void" Then
strTryOutParams = "out " & strTypeName & " outObjType, out Exception exception"
'strOutDef = "outObjType = new " & strTypeName & "();"
strOutDef = "outObjType = null;"
Else
strTryOutParams = "out Exception exception"
End If
strTryReThrowSignature = vbTab & vbTab & strAccess & strVirtual & " bool Try" & strName & "(" & strParams & strTryOutParams & ")"
strTryReThrowBody = vbCrLf & vbTab & vbTab & "{" _
& vbCrLf & vbTab & vbTab & vbTab & "bool result = false;" _
& vbCrLf & vbTab & vbTab & vbTab & "exception = null;" _
& vbCrLf & vbTab & vbTab & vbTab & strOutDef _
& vbCrLf & vbTab & vbTab & vbTab & "try" _
& vbCrLf & vbTab & vbTab & vbTab & "{" _
& vbCrLf & vbTab & vbTab & vbTab & vbTab & "// insert code here " _
& vbCrLf & vbTab & vbTab & vbTab & vbTab & "//result = true; " _
& vbCrLf & vbTab & vbTab & vbTab & vbTab & "throw new NotImplementedException();" _
& vbCrLf & vbTab & vbTab & vbTab & "}" _
& vbCrLf & vbTab & vbTab & vbTab & "catch (Exception e)" _
& vbCrLf & vbTab & vbTab & vbTab & "{" _
& vbCrLf & vbTab & vbTab & vbTab & vbTab & "exception = e;" _
& vbCrLf & vbTab & vbTab & vbTab & "}" _
& vbCrLf & vbTab & vbTab & vbTab & "return result;" _
& vbCrLf & vbTab & vbTab & "}"
editPoint.Insert(strTrySwallowSignature)
editPoint.Insert(strTrySwallowBody)
editPoint.Insert(vbCrLf & vbCrLf)
editPoint.Insert(strTryReThrowSignature)
editPoint.Insert(strTryReThrowBody)
editPoint.Insert(vbCrLf)
End If
Catch Ex As Exception
MsgBox(Ex.Message)
Finally
DTE.UndoContext.Close()
End Try
End Sub
Can someone direct me to how a VS 2012 Add-in can manipulate the active/open code file (using EnvDTE* or whatever object model is available for 2012)?
One of those is the macros automation feature, including macro record/replay, macro projects and the Macros IDE. While we know that macros have been valuable for those who use them, unfortunately our usage data shows that less than 1% of Visual Studio developers take advantage of this feature.
Click on Edit and then in the edit dialog box, choose the Macros button. The current set of properties and macros visible to Visual Studio is listed along with the current value for each. For more information, see the Specifying User-Defined Values section of C++ project property page reference.
Open the preference setting of the VSCode and enter vscode macros in the search text box, and then click {Edit in settings.json} in the User Macro Commands fields. NOTE: Version 1.3.0 and above support multi-root, workspace and workspace folders.
Select the Extension Development Host window and press the {F1} key to open the command palette, and then type 'run a macro' in the command palette. Select the macro name to debugging from the macro list. When the program stops at the breakpoint, and you can debug it.
Well that turned out to be really simple. Turns out the Macro object model is part of the VS model so no problem.
http://msdn.microsoft.com/en-us/library/za2b25t3%28v=vs.110%29.aspx
http://msdn.microsoft.com/en-us/library/ms228776.aspx
I should have know Microsoft wouldn't have left us Macro-dependant developers out in the cold like that!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With