Logo
HOWTO: Force files to open with a specific editor from a Visual Studio package

Author: Carlos J. Quintero (Microsoft MVP) Applies to: Microsoft Visual Studio 2010
Date: January 2015   Microsoft Visual Studio 2012
      Microsoft Visual Studio 2013
      Microsoft Visual Studio 2015
Introduction

There are several kinds of editors in Visual Studio: the core Visual Studio editor, custom editors, external editors and designers. The files of a project can be opened with several editors, using the context menu of a file and clicking the "Open With..." menu entry, which shows a dialog with the available editors. One of them can be marked as the default editor.

This article explains how to open a file of a project programmatically with an specific editor, rather than with the default editor. This is useful to ensure that your extension works as expected even if the user has set an external editor as default, such as Notepad for text files, etc.

More Information

To open a document from a file you could use the IVsUIShellOpenDocument interface, which provides methods such as OpenStandardEditor and OpenSpecificEditor. However, the VsShellUtilities class provides handy OpenDocument methods, and a couple of OpenDocumentWithSpecificEditor methods, one of them requiring only four parameters: the service provider (the package), the full path of the file, the guid of the specific editor and the logical view.

Note: the guids of registered editors are stored in the registry entry HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\<version>_Config\Editors, where <version> is:

  • 10.0 for VS 2010
  • 11.0 for VS 2012
  • 12.0 for VS 2013
  • 14.0 for VS 2015

As an example, the following package iterates the files (first level only) of the first project of the solution, opening the code files (.cs or .vb) with the C# or VB.NET editor that uses encoding, and the text files (.txt) with the text editor (ensure that all document windows are closed before clicking the package command button):

Language: C#   Copy Code Copy Code (IE only)
using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.ComponentModel.Design;
using Microsoft.Win32;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;

namespace MyCompany.VSMyPackage
{
   [PackageRegistration(UseManagedResourcesOnly = true)]
   [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
   [ProvideMenuResource("Menus.ctmenu", 1)]
   [Guid(GuidList.guidVSMyPackagePkgString)]
   public sealed class VSMyPackage : Package
   {
      public VSMyPackage()
      {
      }

      protected override void Initialize()
      {
         base.Initialize();

         // Add our command handlers for menu (commands must exist in the .vsct file)
         OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
         if (mcs != null)
         {
            CommandID menuCommandID = new CommandID(GuidList.guidVSMyPackageCmdSet, (int)PkgCmdIDList.cmdidMyCommand);
            MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID);
            mcs.AddCommand(menuItem);
         }
      }
      private void MenuItemCallback(object sender, EventArgs e)
      {
         // See editor guids in regedit.exe, HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\12.0_Config\Editors

         Guid guid_microsoft_visual_basic_editor = new Guid("{2C015C70-C72C-11D0-88C3-00A0C9110049}");
         Guid guid_microsoft_visual_basic_editor_with_encoding = new Guid("{6C33E1AA-1401-4536-AB67-0E21E6E569DA}");
         Guid guid_microsoft_csharp_editor = new Guid("{A6C744A8-0E4A-4FC6-886A-064283054674}");
         Guid guid_microsoft_csharp_editor_with_encoding = new Guid("{08467b34-b90f-4d91-bdca-eb8c8cf3033a}");
         // Microsoft.VisualStudio.VSConstants.GUID_TextEditorFactory
         Guid guid_source_code_text_editor = new Guid("{8B382828-6202-11d1-8870-0000F87579D2}");
         Guid guid_source_code_text_editor_with_encoding = new Guid("{C7747503-0E24-4FBE-BE4B-94180C3947D7}");

         EnvDTE.DTE dte;
         EnvDTE.Project project;

         dte = (EnvDTE.DTE)base.GetService(typeof(EnvDTE.DTE));

         try
         {
            project = dte.Solution.Projects.Item(1);

            foreach (EnvDTE.ProjectItem projectItem in project.ProjectItems)
            {
               if (projectItem.Name.EndsWith(".cs"))
               {
                  OpenProjectItemInView(projectItem, guid_microsoft_csharp_editor_with_encoding, 
                     Microsoft.VisualStudio.VSConstants.LOGVIEWID.Code_guid);
               }
               else if (projectItem.Name.EndsWith(".vb"))
               {
                  OpenProjectItemInView(projectItem, guid_microsoft_visual_basic_editor_with_encoding, 
                     Microsoft.VisualStudio.VSConstants.LOGVIEWID.Code_guid);
               }
               else if (projectItem.Name.EndsWith(".txt"))
               {
                  OpenProjectItemInView(projectItem, guid_source_code_text_editor, 
                     Microsoft.VisualStudio.VSConstants.LOGVIEWID.TextView_guid);
               }

            }
         }
         catch (Exception ex)
         {
            System.Windows.Forms.MessageBox.Show(ex.ToString());
         }
      }

      private void OpenProjectItemInView(EnvDTE.ProjectItem projectItem, Guid editorGuid, Guid logicalViewGuid)
      {
         string fullPath;
         IVsWindowFrame windowFrame;

         fullPath = projectItem.get_FileNames(0);

         windowFrame = Microsoft.VisualStudio.Shell.VsShellUtilities.OpenDocumentWithSpecificEditor(this, fullPath, 
            editorGuid, logicalViewGuid);

         if (windowFrame != null)
         {
            windowFrame.Show();
         }
      }
   }
}


Go to the 'Visual Studio Extensibility (VSX)' web site for more articles like this (Articles section)