Macro, Macro Man - I Want To Be A Macro Man!

One of the features dropped in Visual Studio 2012 is the ability to record Macros. OK, so apparently few people used this functionality, but occasionally it can be useful.

Here's my use case: I often need to examine the XML payload of an MSMQ message. The message wrapper itself is XML so the payload, when viewed is escaped XML, like so:

<MyMessage>Some content</MyMessage>

Obviously that's a trivial example, some of the actual messages are considerably larger and more complicated. So, what I have to do is: create a new XML file in Visual Studio and Find and Replace &lt; with <, then Find and Replace &gt; with >. Not the end of the world, but quite manual and quite tiresome when you have to do it several times a day!

Like any good developer I sought to automate a repetitive, manual task. I investigated the Visual Studio SDK and fooled around with Editor Extensions - but it seemed like a lot of work compared to the good old days of recording a macro.

Thankfully I found this article on how to convert macros from Visual Studio 2010 into Visual Studio 2012 extensions. Using a Visual Studio 2010 VM I was able to record a macro and save the generated VBA. I then created a VSIX project in Visual Studio 2012. This project types uses a handy wizard to create a shell extension - I choose to create a Menu Command. Then it was just a case of re-writing the VBA into C# and dropping it into the correct event.

private void MenuItemCallback(object sender, EventArgs e)
{
    var dte = Package.GetGlobalService(typeof(EnvDTE.DTE)) as EnvDTE80.DTE2;

    if (dte != null)
    {
        try
        {
            dte.Find.Target = vsFindTarget.vsFindTargetCurrentDocument;
            dte.Find.MatchCase = false;
            dte.Find.MatchWholeWord = true;
            dte.Find.MatchInHiddenText = false;
            dte.Find.PatternSyntax = vsFindPatternSyntax.vsFindPatternSyntaxLiteral;
            dte.Find.ResultsLocation = vsFindResultsLocation.vsFindResultsNone;
            dte.Find.Action = vsFindAction.vsFindActionReplaceAll;

            dte.Find.FindWhat = "&gt;";
            dte.Find.ReplaceWith = ">";
            dte.Find.Execute();

            dte.Find.FindWhat = "&lt;";
            dte.Find.ReplaceWith = "<";
            dte.Find.Execute();

            dte.Find.FindWhat = "&quot;";
            dte.Find.ReplaceWith = "\"";
            dte.Find.Execute();

            dte.Find.FindWhat = "&apos;";
            dte.Find.ReplaceWith = "'";
            dte.Find.Execute();

            dte.Find.FindWhat = "&amp;";
            dte.Find.ReplaceWith = "&";
            dte.Find.Execute();

            dte.ExecuteCommand("Edit.FormatDocument");
        }
        catch { }
    }
}

It was important to create the DTE2 variable - this is effectively the Visual Studio code editor.

Hey presto - now I can simply click a menu command and my XML is un-escaped, plus with an extra line at the bottom the document is formatted nicely (as with CTRL+K, D).

Comments