Click here to Skip to main content
16,020,666 members
Articles / Programming Languages / F#

Forward/Backward Code Navigation with the Mouse Thumb Buttons Inside Visual Studio 2010 (C++, Visual Basic, F#)

Rate me:
Please Sign up or sign in to vote.
5.00/5 (14 votes)
7 Feb 2010CPOL2 min read 69.6K   578   18   11
Addin to navigate in your code using the thumb buttons of your mouse

Introduction

Visual Studio 2010 lacks support to navigate in the source code using the mouse thumb buttons in the languages C++, Visual Basic and F#. The addin from this article will provide support for navigation in the source code using the mouse thumb buttons and it will show how to get mouse events inside an addin.

Background

This addin is an improved version of the addin for Visual Studio 2008: Forward/Backward navigation with the mouse thumb buttons for Visual Studio 2008 (C++). In the old addin, I used a mouse hook to react to mouse events. During the development for Visual Studio 2010, I found a much cleaner solution to listen to mouse events: NativeWindow class.

Usage

  1. Jump to a function definition (right click on the function name, "Go to definition").
  2. Jump back using the "backward button" of your mouse.

Implementation

The addin boilerplate is created with the Addin-wizard. It creates a class named Connect. The IDTExtensibility2 interface provides addin events like OnConnect or <code>OnDisconnect. OnConnect provides the DTE2 object as parameter.

The main problem was to solve how to get mouse events. The addin API only support keyboard and high level events (and some other like focus). In this forum*, I found a clean solution to intercept the main IDE window message procedure: the NativeWindow class.

It provides low-level encapsulation of the window procedure. It is a wrapper to WinAPI subclassing using SetWindowLong() with GWL_WNDPROC. WndProc is called from the subclass window procedure. All windows within the same process could be subclassed. Since the addin is in the process of Visual Studio, NativeWindow could be used here. The implementation source code of NativeWindow can be found here.

In VS2010, the text editor area is not a child window anymore as in VS2008. It is directly paint inside the main IDE window. So the window which must be subclassed is the main IDE window. AssignHandle(HWND_IDE_WINDOW) does this step. The HWND ID from the main window is stored in DTE2.MainWindow.HWnd.

*: The other solution discussed in the forum thread IVsBroadcastMessageEvents::OnBroadcastMessage only provides the following messages: WM_WININICHANGE, WM_DISPLAYCHANGE, WM_SYSCOLORCHANGE, WM_PALETTECHANGED, WM_PALETTEISCHANGING and WM_ACTIVATEAPP.

The SubclassedWindow class which derives from NativeWindow looks like:

C#
public class SubclassedWindow : NativeWindow
{
  private DTE2 dte;
  private const int WM_XBUTTONUP = 0x020C;
  private const int XBUTTON1 = 1;
  private const int XBUTTON2 = 2;

  public SubclassedWindow(int hWnd, DTE2 dte)
  {
    this.dte = dte;
    AssignHandle((IntPtr)hWnd);
  }

  static int HiWord(IntPtr Number)
  {
    return (ushort)((Number.ToInt32() >> 16) & 0xffff);
  }

  protected override void WndProc(ref Message m)
  {
    if (m.Msg == WM_XBUTTONUP)
    {
      if (this.dte.ActiveDocument != null &&
          (this.dte.ActiveDocument.Language == "C/C++" ||
          this.dte.ActiveDocument.Language == "Basic" ||
          this.dte.ActiveDocument.Language == "F#"))
      {
        switch (HiWord(m.WParam))
        {
          case XBUTTON1:
            {
              try { this.dte.ExecuteCommand("View.NavigateBackward", ""); }
              catch { }
            } break;

          case XBUTTON2:
            {
              try { this.dte.ExecuteCommand("View.NavigateForward", ""); }
              catch { }
            }
            break;
        }
      }
    }

    base.WndProc(ref m);
  }
}

SubclassedWindow is created inside the OnConnection method. The WndProc method intercepts all window messages from the main window. The mouse thumb buttons have the value WM_XBUTTONUP for button release. ActiveDocument.Language contains the language of the currently active document as string. If the active document contains C++, Visual Basic or F# code View.NavigateBackward or View.NavigateForward will be executed using ExecuteCommand. This will trigger the same functionality as the Navigate Forward/Backward buttons from the VS menu.

Whole Addin Source Code

C#
/*
 *  MouseThumbButtonsVS2010
 * 
 *  Copyright 2010, Jochen Baier, email@jochen-baier
 *  License: The Code Project Open License (CPOL) 1.02
 * 
 *  Addin for VS2010 providing support for forward/backward navigation with the
 *  mouse thumb buttons in C++, Visual Basic and F#.
 *   
 */

using System;
using Extensibility;
using EnvDTE;
using EnvDTE80;
using System.Diagnostics;
using System.Windows.Forms;

namespace MouseThumbButtonsVS2010
{
  public class SubclassedWindow : NativeWindow
  {
    private DTE2 dte;
    private const int WM_XBUTTONUP = 0x020C;
    private const int XBUTTON1 = 1;
    private const int XBUTTON2 = 2;

    public SubclassedWindow(int hWnd, DTE2 dte)
    {
      this.dte = dte;
      AssignHandle((IntPtr)hWnd);
    }

    static int HiWord(IntPtr Number)
    {
      return (ushort)((Number.ToInt32() >> 16) & 0xffff);
    }

    protected override void WndProc(ref Message m)
    {
      if (m.Msg == WM_XBUTTONUP)
      {
        if (this.dte.ActiveDocument != null &&
            (this.dte.ActiveDocument.Language == "C/C++" ||
            this.dte.ActiveDocument.Language == "Basic" ||
            this.dte.ActiveDocument.Language == "F#"))
        {
          switch (HiWord(m.WParam))
          {
            case XBUTTON1:
              {
                try { this.dte.ExecuteCommand("View.NavigateBackward", ""); }
                catch { }
              } break;

            case XBUTTON2:
              {
                try { this.dte.ExecuteCommand("View.NavigateForward", ""); }
                catch { }
              }
              break;
          }
        }
      }

      base.WndProc(ref m);
    }
  }

  public class Connect : IDTExtensibility2
  {
    private DTE2 _applicationObject;
    private AddIn _addInInstance;
    private SubclassedWindow subclassedMainWindow;

    public void OnConnection(object application, 
	ext_ConnectMode connectMode, object addInInst, ref Array custom)
    {
      _applicationObject = (DTE2)application;
      _addInInstance = (AddIn)addInInst;
      subclassedMainWindow = new SubclassedWindow
	(_applicationObject.MainWindow.HWnd, _applicationObject);
    }

    public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
    {
      if (subclassedMainWindow != null)
      {
        subclassedMainWindow.ReleaseHandle();
        subclassedMainWindow = null;
      }
    }

    #region not_used
    #endregion
  }
}

Limitations

The addin will only work if the text editor 'window' is docked.

History

  • Initial release based on the addin for VS 2008

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
NewsUsing in Visual Studio 2012 Pin
scott sanders29-Sep-12 15:33
scott sanders29-Sep-12 15:33 
GeneralRe: Using in Visual Studio 2012 Pin
Matt Durak7-Nov-12 9:20
Matt Durak7-Nov-12 9:20 
QuestionHad to rebuild dll for vs2010 sp1 Pin
FarrenYoung28-Oct-11 9:18
FarrenYoung28-Oct-11 9:18 
GeneralInteresting....but missing one thing Pin
jerfypowell2-Aug-10 7:29
jerfypowell2-Aug-10 7:29 
GeneralRe: Interesting....but missing one thing Pin
Jochen Baier2-Aug-10 10:29
Jochen Baier2-Aug-10 10:29 
GeneralRe: Interesting....but missing one thing [modified] Pin
jerfypowell2-Aug-10 10:34
jerfypowell2-Aug-10 10:34 
GeneralThat is one serious make-somebody's-day addin ! Pin
Raph SP14-Jun-10 3:31
Raph SP14-Jun-10 3:31 
GeneralGets my '5' !! Pin
Bill Gord16-Feb-10 5:42
professionalBill Gord16-Feb-10 5:42 
GeneralMy vote of 2 Pin
DennisAT15-Feb-10 23:20
DennisAT15-Feb-10 23:20 
GeneralRe: My vote of 2 Pin
Jochen Baier16-Feb-10 9:08
Jochen Baier16-Feb-10 9:08 
GeneralNeato Pin
Sacha Barber8-Feb-10 0:38
Sacha Barber8-Feb-10 0:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.