title: How to reconcile the lack of Macros in Visual Studio 2012
body: <p>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. </p>
  
  <p>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. </p>
  
  <p>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. </p>
  
  <p>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</p>
  
  <pre><code>''' &lt;summary&gt;
  '''  Wraps active method in Try* access wrappers.
  ''' &lt;/summary&gt;
  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") &gt; 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(".") &gt; 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 &amp; " " &amp; codeParameter.Name.Trim &amp; ", ")
              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 " &amp; strTypeName &amp; " outObjType"
                  strOutDef = "outObjType = null;"
                  strOutSig = " out outObjType,"
              End If
  
              strTrySwallowSignature = vbTab &amp; vbTab &amp; strAccess &amp; strVirtual &amp; " bool Try" &amp; strName &amp; "(" &amp; strParams &amp; strTryOutParams &amp; ")"
              strTrySwallowBody = vbCrLf &amp; vbTab &amp; vbTab &amp; "{" _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; "Exception exception;" _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; strOutDef _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; "return Try" &amp; strName &amp; "(" &amp; strParamNames &amp; strOutSig &amp; " out exception);" _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; "}"
  
  
              '' -- 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 " &amp; strTypeName &amp; " outObjType, out Exception exception"
                  'strOutDef = "outObjType = new " &amp; strTypeName &amp; "();"
                  strOutDef = "outObjType = null;"
              Else
                  strTryOutParams = "out Exception exception"
              End If
  
              strTryReThrowSignature = vbTab &amp; vbTab &amp; strAccess &amp; strVirtual &amp; " bool Try" &amp; strName &amp; "(" &amp; strParams &amp; strTryOutParams &amp; ")"
              strTryReThrowBody = vbCrLf &amp; vbTab &amp; vbTab &amp; "{" _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; "bool result = false;" _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; "exception = null;" _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; strOutDef _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; "try" _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; "{" _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; vbTab &amp; "// insert code here " _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; vbTab &amp; "//result = true; " _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; vbTab &amp; "throw new NotImplementedException();" _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; "}" _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; "catch (Exception e)" _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; "{" _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; vbTab &amp; "exception = e;" _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; "}" _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; vbTab &amp; "return result;" _
                                &amp; vbCrLf &amp; vbTab &amp; vbTab &amp; "}"
  
              editPoint.Insert(strTrySwallowSignature)
              editPoint.Insert(strTrySwallowBody)
              editPoint.Insert(vbCrLf &amp; 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
  </code></pre>
  
  <p>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)? </p>