Click here to Skip to main content
Click here to Skip to main content
Go to top

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

, 7 Feb 2010
Rate this:
Please Sign up or sign in to vote.
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 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:

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

/*
 *  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)

Share

About the Author

Jochen Baier

Germany Germany
No Biography provided

Comments and Discussions

 
NewsUsing in Visual Studio 2012 Pinmemberscott sanders29-Sep-12 15:33 
GeneralRe: Using in Visual Studio 2012 PinmemberMatt Durak7-Nov-12 9:20 
QuestionHad to rebuild dll for vs2010 sp1 PinmemberFarrenYoung28-Oct-11 9:18 
GeneralInteresting....but missing one thing Pinmemberjerfypowell2-Aug-10 7:29 
GeneralRe: Interesting....but missing one thing PinmemberJochen Baier2-Aug-10 10:29 
GeneralRe: Interesting....but missing one thing [modified] Pinmemberjerfypowell2-Aug-10 10:34 
GeneralThat is one serious make-somebody's-day addin ! PinmemberRaph SP14-Jun-10 3:31 
GeneralGets my '5' !! PinmemberBill Gord16-Feb-10 5:42 
GeneralMy vote of 2 PinmemberDennisAT15-Feb-10 23:20 
GeneralRe: My vote of 2 PinmemberJochen Baier16-Feb-10 9:08 
hi,
 
can you be more precise what does not make sense ?
 
thanks jochen
GeneralNeato PinmvpSacha Barber8-Feb-10 0:38 

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

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

| Advertise | Privacy | Mobile
Web03 | 2.8.140926.1 | Last Updated 8 Feb 2010
Article Copyright 2010 by Jochen Baier
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid