5
votes

Newbie Visual Studio extension question: I'd like to create an extension that monitors keystrokes and reports statistics to a dockable window ("dockable" like the solution explorer or properties windows). I'm having trouble locating good tutorials that offer more than just syntax highlighting in the editor.

Is this all doable as an extension? Or do I need to create an add-in? What classes will I be most interested in to accomplish these high-level tasks?

1

1 Answers

2
votes

You will be able to implement your ideas easily through a Visual Studio Add-In. If you want to create VS style ToolWindow, then follow the steps bellow. In the example the VS ToolWindow hosts a TreeView, but you can use a control of your choice. I prefer C++ CLI, but generally the steps bellow should be valid also for C# or VB.Net.

  1. Create a new Add-In through File->New->Project->OtherProjectTypes->Extensibility->VS Add-In
  2. Implement the following into your Add-In class

    public ref class Connect : public IDTExtensibility2, public IDTCommandTarget
    {
    public:
    ...
    private:
       literal String^ VSToolWinGuid = "{6CCD0EE9-20DB-4636-9149-665A958D8A9A}";
    
       DTE2^ appObject;    // object which lets us access the IDE
       AddIn^ addInInstance;   // the AddIn object itself
       Window^ MainWindow;     // VS style tool Window
       TreeView^ FormTreeView; 
    
       // Instance of the Add-In button located in the VS IDE Toolbar
       CommandBarButton^ StdCommandBarButton;  
    
       void InitializeToolBarButton(); // Creates a button on the Standard Toolbar
       void ShowAddInWindow();     // Creates and displays the Tool Window
    ...
    };
    
    
    
    void Connect::OnConnection(...)
    {
       appObject = dynamic_cast<DTE2^>(Application);
       addInInstance = dynamic_cast<AddIn^>(AddInInst);
    
       // Initialize the add-in when VS is setting up it's user interface
       if (ext_ConnectMode::ext_cm_UISetup==ConnectMode)
          InitializeToolBarButton();
    }
    
    
    void Connect::Exec(...)
    {
       handled = false;
       if (vsCommandExecOption::vsCommandExecOptionDoDefault == ExecuteOption)
       {
          // when the ToolBar Button is clicked through the UI
          if (!CmdName->CompareTo("FormBrowserAddIn.Connect.FormBrowser"))
          {             
             ShowAddInWindow();
             handled = true;
             return;
          }
       }
    }
    
    
    void Connect::InitializeToolBarButton()
    {
       try
       {    
          Command^ command = nullptr;           
          try
          {  // obtain the command if it is already created         
             command = appObject->Commands->Item(addInInstance->ProgID + "." + AddInName, -1);
          }
          catch(Exception^){}
    
          // create the command if does not exists
          if (nullptr == command)
          {
             // it is better to use the newest Commands2, because it allows to create
             // the ToolBar button with the style definition at once
             EnvDTE80::Commands2^ commands2 = safe_cast<EnvDTE80::Commands2^>(appObject->Commands);
    
             // optional, determines which environment contexts (debug mode, design mode, ...) show the command
             Array^ contextGUIDs = Array::CreateInstance(Object::typeid, 0);                
    
             // create the ToolBar button for our Add-In
             command = commands2->AddNamedCommand2(addInInstance, 
                  AddInName, AddInCaption, AddInToolTip, true, 59, contextGUIDs,
                 (int)(vsCommandStatus::vsCommandStatusSupported | vsCommandStatus::vsCommandStatusEnabled),
                 (int)vsCommandStyle::vsCommandStylePict, vsCommandControlType::vsCommandControlTypeButton);
           }
    
           // Obtain the Standard command bar and insert our ToolBar button there
           VisualStudio::CommandBars::CommandBars^ commandBars;
           commandBars = (VisualStudio::CommandBars::CommandBars^)appObject->CommandBars;
           CommandBar^ stdCommandBar = commandBars["Standard"];
           StdCommandBarButton = (CommandBarButton^)command->AddControl(stdCommandBar, stdCommandBar->Controls->Count+1);
        }
        catch(Exception^ e)
        {
            MessageBox::Show(e->ToString());
        }
    }
    
    
    void Connect::ShowAddInWindow()
    {
       try
       {
          if (nullptr == MainWindow)
          {
             // obtain the assembly of the TreeView
             String^ TreeViewFullName = "System.Windows.Forms.TreeView";
             String^ assembly = Reflection::Assembly::GetAssembly(System::Windows::Forms::TreeView::typeid)->Location;
    
             // create the VS style Tool Window
             Object^ UserCtrlObject = nullptr;
             EnvDTE80::Windows2^ win = (EnvDTE80::Windows2^)appObject->Windows;
             MainWindow = win->CreateToolWindow2(addInInstance, assembly, TreeViewFullName, AddInCaption, VSToolWindowGuid, UserCtrlObject);
    
             // set-up the tree view
             FormTreeView = (TreeView^)UserCtrlObject;      
          }
    
          // refresh the content and make the add-in visible
          RefreshTreeView();
          MainWindow->Visible = true;
       }
       catch (Exception^ e)
       {
          MessageBox::Show(e->ToString());
       }
    }
    

I have never tried to handle Key events from an Add-In, but I hope you can find the answers here.

Anyway, you can find lots of good tutorials here or search for MZTools.