Click here to Skip to main content
15,892,161 members
Articles / Programming Languages / C#

Find and Bookmark Text Add-in

Rate me:
Please Sign up or sign in to vote.
4.13/5 (6 votes)
7 Jul 2004CPOL3 min read 41.6K   744   20   4
A VS.NET sample add-in that finds and bookmarks all occurrences of a selected text. The add-in creates a new menu item in the Code Window's context menu.

Introduction

This is a VS.NET add-in sample project that I wrote so that I could do a Find and bookmark of all occurrences of a text selection in an open code file. I'm somewhat lazy. So, I thought it would be convenient to have this functionality available on the code window context menu, instead of having to open the Find window or learn a bunch of new keyboard key sequences.

I'd rather use the mouse any day over typing things in. If you can do it with the mouse as well as the keys, this gives you more power.

Besides, I thought it would be a good way to learn about .NET add-ins and how they're coded; and this is why I wrote this article, to help others understand .NET add-ins.

It is no small task, believe me, to figure some of this stuff out. If you believe the rather hard to find documentation, it should be as easy as dirt. But when you actually start doing the code and expect it to work, the unpleasant surprises are many. I don't know how many hours I spent just trying to find how to put a menu item in the context menu of a code window. Turns out, you have to know the name of the .NET toolbar in which you want to add your own item. So, where are these built-in toolbars listed?

Nowhere that I could discover! I waded through tons of Office application docs, VS.NET docs, web sites galore, and found zero information on this. You'd think they would at least provide a list of toolbar names you need to know for adding custom menu items, right? Wrong - as usual. You have to bend over backwards to find this information.

Macro

So, I ended up writing this little macro you can use that lists all the available toolbars (CommandBars as they are called in Office VSA):

VB
'
Sub GetCommandBarList()
  ' Creates a text document listing all CommandBar names.
  Dim Cmd As CommandBar
  Dim CmdBars As CommandBars
  Dim Doc As Document
  Dim app As Application
  Dim TxtDoc As TextDocument

  ' Create a new text document.
  DTE.ItemOperations.NewFile("General\Text File")
  Doc = ActiveDocument
  TxtDoc = Doc.Object("TextDocument")

  ' get the command bars
  CmdBars = DTE.CommandBars
  For Each Cmd In CmdBars
     If (Cmd.Name <> "") Then
        TxtDoc.Selection.Text = "Name: " & Cmd.Name & vbTab & _
                       "Type: " & Cmd.Type.ToString() & vbLf
        TxtDoc.Selection.Collapse()
     End If
  Next
End Sub

Existing context menus are of type MsoBarTypePopup. The CommandBar or toolbar you must use to add menu items to the contextual menu of the code editor windows is named "Code Window".

The important parts of the code are the Add-in Wizard added OnConnect() - with added code for adding the new menu item to the context menu of the Code Window CommandBar:

C#
public void OnConnection(object application, 
    Extensibility.ext_ConnectMode connectMode, object addInInst, 
    ref System.Array custom)
{
    applicationObject = (_DTE)application;
    addInInstance = (AddIn)addInInst;

    if( connectMode == Extensibility.ext_ConnectMode.ext_cm_UISetup )
    {
        object []contextGUIDS = new object[] { };
        Commands commands = applicationObject.Commands;
        _CommandBars commandBars = applicationObject.CommandBars;

        try
        {
            Command command = commands.AddNamedCommand(addInInstance, 
                    "TextFinder", "Text Finder", 
                    "Executes the command for Text Finder", 
                    true, 183, ref contextGUIDS, 
                    (int)vsCommandStatus.vsCommandStatusSupported+
                    (int)vsCommandStatus.vsCommandStatusEnabled );
            CommandBar commandBar = (CommandBar)commandBars["Code Window"];
            CommandBarControl commandBarControl = 
                                       command.AddControl( commandBar, 1 );
        }
        catch(System.Exception /*e*/)
        {
        }
    }
}

The Add-in Wizard added QueryStatus() method:

C#
public void QueryStatus(string commandName, 
    EnvDTE.vsCommandStatusTextWanted neededText, 
    ref EnvDTE.vsCommandStatus status, ref object commandText)
{
    if(neededText == 
        EnvDTE.vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
    {
        if(commandName == "TextFinder.Connect.TextFinder")
        {
            TextSelection txt = 
              applicationObject.ActiveDocument.Selection as TextSelection;
            if( txt.Text.Length > 0 )
                status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported 
                         | vsCommandStatus.vsCommandStatusEnabled;
            else
            {
                // disable if no text is selected
                status = (vsCommandStatus)vsCommandStatus.vsCommandStatusLatched 
                         | vsCommandStatus.vsCommandStatusSupported;
            }
        }
    }
}

The Add-in Wizard added Exec() method:

C#
public void Exec(string commandName, 
    EnvDTE.vsCommandExecOption executeOption, ref object varIn, 
    ref object varOut, ref bool handled)
{
    handled = false;
    if( executeOption == 
            EnvDTE.vsCommandExecOption.vsCommandExecOptionDoDefault )
    {
        if( commandName == "TextFinder.Connect.TextFinder" )
        {
            handled = DoFind();
            return;
        }
    }
}

And last of all, the only method you have to add yourself, the DoFind() method:

C#
private bool DoFind()
{
    TextSelection txt = 
        applicationObject.ActiveDocument.Selection as TextSelection;

    this.applicationObject.Find.FindWhat = txt.Text;
    applicationObject.Find.Action = vsFindAction.vsFindActionBookmarkAll;
    applicationObject.Find.Target = vsFindTarget.vsFindTargetCurrentDocument;
    applicationObject.Find.MatchInHiddenText = true;
    applicationObject.Find.ResultsLocation = 
                          vsFindResultsLocation.vsFindResults1;
    EnvDTE.vsFindResult res = applicationObject.Find.Execute();

    return ( res.Equals( vsFindResult.vsFindResultFound ) );
}

This method is what does the actual Finding and Bookmarking. It's simply taken from the existing commands available in the VS.NET text editor windows.

To use, run the setup.exe or the TextFinderSetup.msi to install the add-in. Do a merge on the .reg file to make sure all the information is correctly entered into the Registry. The .reg file writes Registry entries for both HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER.

Hope you find this useful both as a tool and as an add-in programming example.

License

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


Written By
Web Developer
Canada Canada
Bsc. computer science
15 yrs experience
C, C++, C#, Java, Delphi, VB
.Net

Comments and Discussions

 
QuestionWhere is the code? Pin
Eric Engler16-Jul-04 12:31
Eric Engler16-Jul-04 12:31 
AnswerRe: Where is the code? Pin
hitch3-Dec-04 5:31
hitch3-Dec-04 5:31 
GeneralBugs Pin
sadavoya21-May-04 5:24
sadavoya21-May-04 5:24 
Hi,
Good article. Simple and elegant idea that seems pretty useful.
There are some issues with the article:
1. The links to the downloadable code do not work.
2. The first macro sub needs to Import Microsoft.Office.Core (this is propably evident in the code, but since I can't download the code...)
Thanks, and keep up the good work.
narsyseth
GeneralRe: Bugs Pin
hitch3-Dec-04 5:27
hitch3-Dec-04 5:27 

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.