April 20, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Macros for C++, in C++

  • April 30, 2004
  • By Kate Gregory
  • Send Email »
  • More Articles »

The Visual Studio development environment is made by programmers for programmers. So, it's not surprising that it's extensible by programmers, too. There are actually two ways to extend Visual Studio: macros and add-ins. Macros are suggested for your own use, as quick keystroke-savers, while add-ins can be large and complex, tools you can distribute and sell; they provide significant functionality.

Another difference between add-ins and macros is that add-ins are usually written in C++ (although you can create them in any .NET language) and macros are written in Visual Basic only. I just had to find a way around that, so my solution is to write a class library that provides the macro functionality I want, and make simple calls into that library from a VB macro. As an added bonus, I can distribute that library as a compiled assembly, rather than only distributing the source code of the macro. I also can re-use the library in several macros, and in add-ins as well.

The DTE Object

Whether you're writing a macro or an add-in, the key class and the starting point of your work is DTE, in the EnvDTE namespace. This represents the IDE itself, the design-time environment. From here, you can access the document being edited, properties the user has set, and more. An instance of it is provided to any macro you run—and your macro code can pass that instance to code it calls, such as the Managed C++ class library I created.

Your best guide around the DTE class and the EnvDTE namespace is Intellisense: the online help features Visual Basic examples almost exclusively. Most of the properties of this class make perfect sense once you see them: ActiveDocument, for example, represents the active document, the one being edited when the macro is invoked.

Creating a Macro Project

To create a macro project, open Visual Studio and choose View, Other Windows, Macro Explorer. Expand the MyMacros node and you'll see Module1. I renamed mine to Editing because I intend to write a number of macros to make editing and entering code simpler and keep them in this module. Expand the module and you'll see a macro called Macro1: I renamed mine to Braces. This macro is only one line long because it just calls a method in the class library. I'll show it to you shortly.

Creating the Class Library

I opened a second instance of Visual Studio to create the class library. This is just an ordinary Managed C++ class library. Then, add a reference to envdte, which appears on the .NET tab of the Add Reference dialog. Here's the class I implemented, with one method called Braces():

public __gc class Utilities
{
public:
   static String* Braces(EnvDTE::_DTE* DTE)
   {
      int tabsize = 4;
      EnvDTE::TextSelection* ts =
        static_cast<EnvDTE::TextSelection*>
           (DTE->ActiveDocument->Selection);
      ts->Insert(S"\n",
         EnvDTE::vsInsertFlags::vsInsertFlagsInsertAtEnd);
      ts->MoveToLineAndOffset(ts->TopPoint->Line+1,
                              ts->TopPoint->LineCharOffset, false);
      ts->Insert(S"{\n\n",
         EnvDTE::vsInsertFlags::vsInsertFlagsInsertAtEnd);
      ts->MoveToLineAndOffset(ts->TopPoint->Line+2,
                              ts->TopPoint->LineCharOffset, false);
      ts->Insert(S"}",
         EnvDTE::vsInsertFlags::vsInsertFlagsInsertAtEnd);
      ts->MoveToLineAndOffset(ts->TopPoint->Line-1,
                              ts->TopPoint->LineCharOffset+tabsize,
                              false);
      return("");
   }
};

Notice that this method takes a DTE reference. That's what lets it do all the snazzy macro things you'd normally code in VB inside the macro itself. This example is small, just enough to get started. I get the ActiveDocument, ask it for the selection (which may be as small as an insertion point if no text is selected), and cast it from an Object* to the TextSelection* I know it is. At this point, I use the Insert and MoveToLineAndOffset methods repeatedly, to insert an open brace, a blank line, and a close brace, all indented appropriately. The value false is passed to MoveToLineAndOffset to ensure that the selection is not extended to the new location.

Making the Class Library Available to the Macro Project

Once the class library is built, the assembly is available to add as a reference to the Macro project. Double-clicking the macro edits it, and the Macro Editor looks enough like Visual Studio that you'll just use it without thinking about it too much. You can see a References tab, and you can right-click and choose Add Reference. There's just one problem: In Macro Explorer, the Add Reference Dialog is a lot trimmer than you're used to seeing in Visual Studio.



Click here for a larger image.





Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel