Click here to Skip to main content
Click here to Skip to main content

VSHelper - Visual Studio IDE Enhancements

By , 14 Jul 2009
Rate this:
Please Sign up or sign in to vote.


When I had to switch from Visual C++ 6 to .NET, I discovered that things were not working the same way as they used to. I had to adapt to the new IDE. I thought, why can't the IDE adapt to me? That's how the VSHelper add-in was born. It fixed some of the pet peeves I had with .NET IDE. Over time I continued to add more functionality. Hopefully, other people will find some of these features useful.

The add-in registers 11 new commands, which you can map to key combinations or access from the toolbar.

Add-in Commands

   Cut and copy (use plain text, do nothing if no text is selected)

These are replacements for the standard Edit.Cut and Edit.Copy commands. The difference is that all special formatting is stripped out from the clipboard. What does that mean?

Imagine, you copy this text from your C++ source to your email:

The text is copied in Rich Text Format, which preserves the fonts and colors of the source window. Not all applications interpret the RTF content correctly. Even if they do, you may still prefer plain text.

The text pasted in Outlook Express (the font and the background colors are not preserved):

The text pasted in Word (the font is not preserved properly):

The text pasted in WordPad (technically correct, but still not the same as the original):

Another feature of the new Cut and Copy is that they do nothing if no text is selected. The original Edit.Cut and Edit.Copy put the current line in the clipboard even if nothing is selected. If you press Ctrl+C when you actually wanted to press Ctrl+V, the editor will copy the current line and mess up the clipboard contents.

If for some reason you want to preserve the full RTF content, in that case, you can access the Edit.Copy command from the main menu, or from the right-click menu.

Esc (close all secondary windows)

Do you remember how you could press Esc in VC6 and hide all the unnecessary windows? It is an incredibly useful way to quickly maximize your work area. Sadly, .NET doesn't support that. And there is an even greater need for it because there are more modeless windows that pop up and they don't close on their own - Properties, Find window, Toolbox, etc.

The new Esc command can help in this situation. Pressing Esc several times will progressively:

  • focus the main document
  • clear the text selection
  • close the unnecessary windows

The list of affected windows can be customized from the settings.

The initial selection includes: Output window, Find Results windows, Properties, Task List, Toolbox, Find Symbol, Find and Replace, Visual Assist's Find References and the Incredibuild window.

The list of all available windows is retrieved from the HKLM\SOFTWARE\Microsoft\VisualStudio\7.1\ToolWindows registry key. For VS 2005 replace 7.1 with 8.0, for VS 2008 - with 9.0.

   FindNext and FindPrev (Find the text and close the Find window)

In VS 2003 and later, the Find window is no longer modal. This is not a big deal in itself; the problem is that it loses focus very easily. For example, press Ctrl+F, type some text, and then press F3. The Find window stays open, but loses focus. Now, you have this modeless, focus-less window obscuring your editor until you press Cltr+F and Esc, or reach for the mouse to close it.

The new FindNext and FindPrev commands first invoke the original Edit.FindNext and Edit.FindPrevious commands and then close the Find window. It works like this:


   Output (show the Output and Find Results windows)

In VC6, the Output and Find Results are part of the same window. You can have a single key combination to go to them. In .NET, they are separate windows and you'll need different shortcuts for each of them. The new Output command will show all the three with a single key combination. If the windows are docked together the Output window will be on top, then the Find Results 1, and then the Find Results 2. Here's how it's done:

CComPtr<Window> output=FindWindow(wins,vsWindowKindOutput);
CComPtr<Window> find1=FindWindow(wins,vsWindowKindFindResults1);
CComPtr<Window> find2=FindWindow(wins,vsWindowKindFindResults2);

   Opposite (switch between C/CPP and H files)

This command simply switches between the source and header files:

// Retrieve the current document's name
CComPtr<Document> doc;
CComBSTR name;

wchar_t name2[_MAX_PATH+_MAX_EXT];

// modify name2 according to the settings
// .....
// Open the new file name
CComPtr<ItemOperations> operations;
ComPtr<Window> win;

The Opposite command can cycle between a list of extensions. By default it is .h -> .inl -> .cpp -> .c -> .h. This can be changed from the settings.

Also if the current file starts with // ## <filename> the command will switch to the specified file name. For example to toggle between and File.hpp, you do:

Put this in the beginning of

// ## File.hpp

Put this in the beginning of File.hpp:


The "// ##" prefix is configurable from the settings.

   Locate (find document in the Solution Explorer)

Visual Studio has an option "Track Active Item", which will always expand the tree in Solution Explorer to show the current document. This can be very annoying when working with large projects. After some time, all the projects and their folders become expanded, and it takes lot of scrolling to find the files you are looking for. In VS2002, this was the only behavior. In VS2003, it is optional, and turned off by default (thanks, Microsoft Smile | :) ).

But occasionally you do need to find the current file in the Solution Explorer. That's when the Locate command comes in. It will locate the current document in the Solution Explorer. It will switch focus to Solution Explorer and will scroll the selected item into the view. The code uses a combination of VS automation API and Win32 API:

// Find the ProjectItem for the current document
CComPtr<Document> doc;

CComPtr<ProjectItem> pitem;

// Find the Solution Explorer object
CComPtr<Windows> wins;
CComPtr<Window> se=FindWindow(wins,vsWindowKindSolutionExplorer);

// Get the UIHierarchyItems
CComPtr<UIHierarchy> uih;
CComPtr<UIHierarchyItems> items;

// Convert the ProjectItem into UIHierarchyItem
CComPtr<UIHierarchyItem> hitem=FindProjectItem(items,pitem);
if (hitem) {
    // Select the item in the Explorer
    if (g_SolutionTree) {
        // Scroll the item into view
        HTREEITEM h=TreeView_GetSelection(g_SolutionTree);
    // Activate the Solution Explorer window

Home (go to the first column, in VS 2003 version only)

Another thing missing in VS 2003 is the "Go to the first column of the line" command. The new Home command does exactly that – jumps to the first column of the current line. That command exists only in VS 2003 version of the add-in because in VS 2005 that feature is back - the command is called Edit.LineFirstColumn.

CComPtr<Window> w;

// Get the selection
CComPtr<TextSelection> sel;
w->get_Selection((IDispatch **)&sel);

// Jump to the beginning of the line
long top;

ClearBookmarks (in VS2005 and later)

Starting with VS2005 if you try to clear all bookmarks in the document you will be asked "Are you sure you want to delete all of the bookmark(s)?". It would be great if there was a way to turn this question off after the first time. But there isn't. You can use the ClearBookmarks command instead: 

CComPtr<Document> doc;

// get the text document
CComPtr<IDispatch> spTextDocumentDisp;
CComQIPtr<TextDocument> textDoc=spTextDocumentDisp;



The Settings command opens a dialog box to edit the settings:

Evaluate g_DebugData - Evaluates g_DebugData when the debugger stops. See below. The change will take effect the next time Visual Studio is started.

Add new files to Perforce - When new files are added to the project, they will be added to Perforce automatically. See below. The change will take effect the next time Visual Studio is started.

Always show selection in Solution Explorer - Shows the selection in the Solution Explorer even when it is inactive. See below. This option is only available in Visual Studio 2005 and later. The change will take effect the next time Visual Studio is started.

Support for Numpad Clear key - Translates VK_CLEAR to VK_NUMPAD5. See below. This option is only available in Visual Studio 2005. Turning this option ON requires restarting of Visual Studio.

Opposite order - Lists the order of extensions for the Opposite command. You can add or remove extensions and change their order.

Opposite prefix - The prefix for the Opposite command.

Windows to close - Shows a list of all tool windows in Visual Studio. The selected windows will be closed with the Esc command.

Additional Features

Subclassing the Solution Explorer (in VS 2005 and later)

The developers of VS 2005 decided that the selection in the Solution Explorer should be hidden if the window doesn't have focus and if "Track Active Item" is off. I have that option off (see the Locate command). Now imagine the following situation: You select multiple projects and open their settings. The Solution Explorer loses focus (because the settings dialog gets the focus), and now you can't see which projects you are editing! I'm sure there must be a good reason behind that behavior, I just can't find it.

Fortunately, the Solution Explorer is using a standard TreeView control. The add-in subclasses the Solution Explorer to force the TVS_SHOWSELALWAYS style:

LRESULT CALLBACK CConnect::SolutionProc( HWND hWnd, 
                     UINT uMsg, WPARAM wParam, LPARAM lParam )
    // Force the TVS_SHOWSELALWAYS style
    if (uMsg==WM_STYLECHANGING && wParam==GWL_STYLE)
    return CallWindowProc(g_OldSolutionProc,hWnd,uMsg,wParam,lParam);

Support for Numpad Clear key (in VS2005 version only)

In VC6 IDE you can create shortcuts using the key in the middle of the Numpad (where the digit 5 is). The shortcut can be used with the NumLock turned off. VC6 calls this key "Numpad Clear" - for example "Ctrl+Numpad Clear". VS 2003 still supports such shortcuts, but doesn't have a name for the key - the shortcuts show up as "Ctrl+".

VS 2005 completely ignores the Clear key and it can't be used in shortcuts. On the other hand it accepts the "Num 5" key, which is the same but with NumLock turned on. Since I keep my NumLock turned off, I have a whole key on my keyboard that I can't use. Fortunately in VS 2008, the support for the Clear key is back.

The VSHelper addin solves that problem by installing a keyboard hook and translating VK_CLEAR to VK_NUMPAD5. When the hook is in effect you can press the Clear key with or without NumLock and Visual Studio will accept it as the "Num 5" key: 

LRESULT CALLBACK CConnect::NumKeyboardProc( int code,
                     WPARAM wParam, LPARAM lParam )
    if (code<0) return CallNextHookEx(g_KbdHook,code,wParam,lParam);
    if (CallNextHookEx(g_KbdHook,code,wParam,lParam)) return TRUE;
    if (!g_bTranslateNum5 || wParam!=VK_CLEAR) return FALSE;
    if (GetKeyState(VK_CONTROL)>=0 && GetKeyState(VK_SHIFT)>=0
          && GetKeyState(VK_MENU)>=0) return FALSE;
    return TRUE;

The hook is controlled by the "Support for Numpad Clear key" option. If the option is on when Visual Studio starts, the hook will be installed. If you really need to enter the Clear key, you can temporarily disable the VK_CLEAR -> VK_NUMPAD5 translation by turning off the option. There is only one place in VS where this might be necessary - when creating an accelerator in your resources that uses the Clear key. Even then you can simply type VK_CLEAR in the accelerator table.

Evaluate debug data

The add-in registers an OnEnterBreakMode event handler. Every time the debugger breaks the handler will calculate the expression ((int)&g_DebugData),d and will store it in a variable. You can retrieve the value by calling the GetDebugData function. The purpose of that value will be revealed in another article [1]. Smile | :)

static char g_DebugData[128];

// OnEnterBreakMode handler
STDMETHODIMP CConnect::OnEnterBreakMode(EnvDTE::dbgEventReason Reason,
             EnvDTE::dbgExecutionAction* ExecutionAction)
    Expression *exp=NULL;
    if (g_pDebugger) {
        // Evaluate the expression and store the 
        // result in g_DebugData
        if (!exp) return S_OK;
        BSTR val=NULL;
        if (!val) return S_OK;
    return S_OK;

Perforce helper

When working with Perforce I prefer to use the P4Win client to submit my changes instead of the Visual Studio integration. But sometimes I add files to the project and forget to add them to Perforce. So the next day when somebody tries to build my code they complain about missing files.

For VS 2005 and later the addin registers OnItemAdded event handler that fires when a new file is added to the project. For VS 2003 there is no such universal event. Instead, the addin first registers an OnOpened event handler that fires when a new solution is opened. Then it goes through all projects of the solution and if it finds a C++ project it registers OnItemAdded handler for that project only. For more details on how to hook project events see here: [2].

Once the OnItemAdded event is detected, the add-in checks if the new file is under Perforce control by issuing the "fstat" command. If it is not, the file is added to default changelist (but not submitted) with the "add" command.

To compile the Perforce code, you will need the multithreaded DLL version of the P4API. The latest version can be found here: [3]. To disable the Perforce functionality, comment out #define ADD_TO_PERFORCE at the top of the file. This will allow you to compile VSHelper without the P4API.

Documentation for the Perforce API can be found here: [4].

Configuration combo box (in VS2005 and later)

Visual Studio 2005 has combo boxes to select the configuration and the platform:

This is all great until you start building or debugging. Since you can't change the configurations during building/debugging, the combo boxes get disabled. Unfortunately in VS 2005, the disabled combo boxes also hide their text:

Now I can't see what configuration I'm currently using! If you work on a project with many configurations or platforms, you know how annoying this can be. To solve that problem, the add-in creates a new combo box, which you can use to select the current configuration:

Instead of getting grayed out, the combo box just ignores the mouse clicks if a build or a debugging session is currently running. In VS 2008, the text in the disabled combo boxes is no longer hidden, so this feature is not as useful. However I left it there in case you prefer a single combo box for the configuration/platform instead of two.

You can read all the details on implementing a custom combo box here: [5]. In short - You create your command like this:

pCommands2->AddNamedCommand2(m_pAddInInstance, CComBSTR(L"Configuration"),
    CComBSTR(L"Current solution configuration"),
    VARIANT_TRUE, CComVariant(0), NULL,
    EnvDTE80::vsCommandControlTypeDropDownCombo, &pConfiguration);

This will create 2 commands. First called Configuration, and the second called Configuration_1.

If the Configuration command is called with no parameter, it must return the text to display in the combo box. If it is called with a parameter, then the user has selected a new item from the list:

if (pvarVariantIn->vt==VT_BSTR && pvarVariantIn->bstrVal) {
    // A new text was selected by the user
    return S_OK;
else {
    // Set the text of the combo box
    CComVariant(L"Combo box text").Detach(pvarVariantOut);
    return S_OK;

The Configuration_1 command is called to fill the list of the combo box. The list is returned as a safe array:

CComSafeArray<BSTR> arr(count);
for (int i=0;i<count;i++) {
    swprintf(buf,L"Item %d",i+1);
return S_OK;

Custom toolbar

The add-in creates a new custom toolbar that contains buttons for most of the commands:


A tip for using custom images in add-ins: To use custom images for the new commands, the add-in must provide a DLL with bitmap resources and provide two values in the registry under the HKLM\Software\Microsoft\VisualStudio\7.1\AddIns\<addin name>.Connect key (for VS 2005 use 8.0 instead of 7.1, for VS 2008 use 9.0). The values are SatelliteDLLPath and SatelliteDLLName. The full path to the DLL is constructed like this - <SatelliteDLLPath>\<language code>\<SatelliteDLLName>. The language code is the numeric value of the current language (1033 is English).

Then when you register the commands call:

pCommands->AddNamedCommand(m_pAddInInstance, CComBSTR(L"FindNext"),
    CComBSTR(L"FindNext"), CComBSTR("Find next text"),
    VARIANT_FALSE, // FALSE means to get the bitmap from the DLL
    IDB_FINDNEXT, // IDB_FINDNEXT is the bitmap's resource ID
    NULL, vsCommandStatusSupported+vsCommandStatusEnabled,&pFindNext);

In this case, we only need bitmaps and they are supposed to be the same in all languages. So instead of providing an additional DLL for the resources, we can use the original add-in DLL - VS2003Helper. To do that, use these keys in your setup project:

SatelliteDLLPath=[TARGETDIR]    <- this gets expanded to the installation path

When combined, the full path will be <install path>\1033\..\VS2003Helper.DLL, which when optimized points exactly to the add-in's own DLL.

Another trick to use during development: Since you will be running the DLL from the Debug or Release folder of your project, it will be hard to update the registry with the correct path. Instead, in the .rgs file, use:

val SatelliteDLLPath = s '%MODULE%\..'    <- this gets expanded
     to <project path>\Debug\VS2003Helper.DLL
val SatelliteDLLName = s '..\VS2003Helper.DLL'

When combined, the full path will be <project path>\Debug\VS2003Helper.DLL\..\1033\..\VS2003Helper.DLL, which when optimized points to the DLL in the Debug folder.

The Setup Configuration

When developing a Visual Studio add-in, it needs to behave a little bit differently than when it is installed. Here are a few differences:

  • The path to the satellite DLL needs to be different as shown above.
  • The build should register the add-in after linking.
  • No installer should be created.
  • It is better if the add-in recreates all commands, toolbars, menu items, etc. when it starts because these can change during development.

That's why I added a new Setup configuration. It uses a different .rgs file than Debug and Release. It doesn't automatically register the add-in during build. It creates an installer. And it defines the VS_SETUP macro, which disables the code that recreates all add-in commands.

Use the Setup configuration if all you want is to compile the add-in once and then install it. Use the Debug and Release configurations if you want to tinker with the code and develop your own features.


Depending on the version of Visual Studio you use download, or and run Setup.exe. Multiple versions of the add-in can be installed simultaneously.

The add-in will not automatically bind any of the commands to key combinations. You must do so manually in Visual Studio from Tools\Options\Keyboard. All commands are prefixed with VS2003Helper.Connect, VS2005Helper.Connect or VS2008Helper.Connect.

Building the Code

The source code contains projects for VS 2003,  2005 and 2008. All the magic happens in the file, which is shared between the projects. The bitmaps for the toolbar buttons are also shared.

If you want to use the Perforce functionality, you need to download P4API from here: [3]. In the project settings replace D:\Work\Libs\p4api with the actual path to the API.


The source code, the binaries and this article are owned by Pandemic Studios. They can be freely used for commercial and non-commercial purposes under the terms of the MIT license. A copy of the license is included in the readme.rtf file in

Known Problems and Future Development

The Output command always shows the Output window on top. There may be a way to preserve the Z-order between the Output window and the Find Results windows. Possibly the add-in can subclass these windows and keep track of which is activated last.

The Perforce functionality uses only the default settings - depot, workspace, user, password. Instead, they can be added to the Settings dialog. Even better, the settings can probably be retrieved from solution properties. Also in VS 2003, only C++ projects are supported.


[1] Debugger support for CRC hash values

[2] HOWTO: Getting Project and ProjectItem events from a Visual Studio .NET add-in

[3] Download latest multithreaded DLL version of the P4API

[4] Perforce API documentation

[5] Craig Skibo's WebLog : Command Bar Types – Part 2

[6] HOWTO: Removing commands and UI elements during Visual Studio .NET add-in uninstallation


  • Jan, 2006 - First version
    • The add-in compiles and runs for VS 2003 and VS 2005 Beta 2. Binaries provided for VS 2003 only
  • Mar, 2006 - Few fixes
    • Fixed a compatibility issue with Visual Assist. The text from the Copy and Cut commands wasn’t added to the Visual Assist’s Paste Menu
    • Optimized the Locate command for large solutions
  • Oct, 2006 - Version 2.0: New features and bug fixes
    • Additions to the Opposite command
    • Settings dialog to enable some of the features and to configure the Opposite command
    • Perforce helper - automatically add new files to Perforce
    • Toolbar with icons for most commands
    • Fixed a bug in the Copy and Cut commands that corrupts the clipboard when they are used in the image editor
    • Added uninstall script to remove the commands and the toolbar from Visual Studio. For more details on uninstall scripts, see here: [6]
    • Provided binaries for VS 2005
  • Feb, 2007 - Version 2.2: New features and bug fixes:
    • Added ClearBookmarks command for VS 2005
    • Added support for the Numpad Clear key for VS 2005
    • Added a list to pick which windows to close with the Esc command
    • Fixed a crash when opening some corrupted .vcproj files
    • Published under the MIT license
  • Jul, 2007 - Version 2.5: New features and bug fixes:
    • Added Configurations combo box for VS 2005
    • Some more fixes to the Copy and Cut commands to work reliably with HTML and binary documents
    • Fixed some COM reference leaks
    • Some code cleanup
  • Jul, 2009 - Version 3.0: Support for VS 2008 and other fixes
    • Added code and binaries for VS 2008
    • Added a separate Setup configuration for all projects
    • Improved the Locate command to work with solution folders (used for grouping projects)
    • Added code for VS 2010 Beta1. At the moment, there are some quirks and it is not clear if they are caused by the add-in or bugs in the beta. If someone wants to play with it, help yourself. I am going to wait till the next beta or release candidate before I try to make an official version.


This article, along with any associated source code and files, is licensed under The MIT License

About the Author

Ivo Beltchev
Software Developer (Senior)
United States United States
Ivo started programming in 1985 on an Apple ][ clone. He graduated from Sofia University, Bulgaria with a MSCS degree. Ivo has been working as a professional programmer for over 12 years, and as a professional game programmer for over 10. He is currently employed in Pandemic Studios, a video game company in Los Angeles, California.

Comments and Discussions

GeneralChange colors of Solution Explorer and other tool windows Pinmemberkonmel21-Dec-09 11:45 
GeneralRe: Change colors of Solution Explorer and other tool windows PinmemberIvo Beltchev21-Dec-09 14:08 
GeneralVS2008 Version Pinmemberking ghidorah8-Jun-09 11:52 
GeneralRe: VS2008 Version PinmemberIvo Beltchev8-Jun-09 18:24 
GeneralRe: VS2008 Version Pinmemberking ghidorah15-Jun-09 6:36 
QuestionMiss in VS2005Helper? Pinmembermatakk26-Feb-09 3:02 
AnswerRe: Miss in VS2005Helper? PinmemberIvo Beltchev26-Feb-09 5:14 
GeneralVariant for Visual Studio 2008 PinmemberTomFromCZE22-Feb-09 23:11 
GeneralRe: Variant for Visual Studio 2008 PinmemberIvo Beltchev23-Feb-09 6:33 
GeneralOnEnterBreakMode event handler fails on Vista Pinmemberromko31-Jul-07 21:11 
GeneralAlways show selection in Solution Explorer Pinmemberkak_karsten27-Jul-07 0:05 
GeneralRe: Always show selection in Solution Explorer PinmemberIvo Beltchev27-Jul-07 6:27 
GeneralRe: Always show selection in Solution Explorer Pinmemberkak_karsten29-Jul-07 21:12 
GeneralIs there no need for .addin file for C++ addins Pinmemberjass_sim158326-Dec-06 1:46 
GeneralRe: Is there no need for .addin file for C++ addins PinmemberIvo Beltchev26-Dec-06 6:52 
GeneralRe: Is there no need for .addin file for C++ addins Pinmemberjass_sim158326-Dec-06 16:52 
QuestionAnother new option PinmemberRonald E. Chambers17-Oct-06 12:02 
AnswerRe: Another new option PinmemberIvo Beltchev17-Oct-06 12:15 
GeneralRe: Another new option PinmemberRonald E. Chambers19-Oct-06 6:23 
Questionnew feature request Pinmemberromko13-Oct-06 2:09 
AnswerRe: new feature request PinmemberIvo Beltchev13-Oct-06 6:21 
GeneralRe: new feature request Pinmemberromko19-Oct-06 23:42 
GeneralRe: new feature request PinmemberIvo Beltchev20-Oct-06 5:30 
GeneralCtrl-C without selection still copies line Pinmemberowillebo10-Oct-06 20:58 
GeneralRe: Ctrl-C without selection still copies line PinmemberIvo Beltchev11-Oct-06 5:27 

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
Web01 | 2.8.140415.2 | Last Updated 14 Jul 2009
Article Copyright 2006 by Ivo Beltchev
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid