- PVSM.RU - https://www.pvsm.ru -

Создаем расширение (extension) Visual Studio для генерирования C++ директивы #define в header-файле

Добрый день.
Будем делать расширение Visual Studio, которое встраивает в контекстное меню редактора поле «Create C++ Header #define», при клике на которое генерируется уникальная директива #define (директива позволяет включать header только один раз).
В конечном счете выглядеть это будет следующим образом:

Создаем расширение (extension) Visual Studio для генерирования C++ директивы #define в header файле

На самом деле обычно это автоматизируется с помощью макросов самой студии ( и вариантов макросов в сети много), но мне приятнее использовать контекстное меню, тем более что создание самого расширения — это дело простое, всю работу сделает VSPackage Builder, нам останется лишь вписать несколько строчек кода в обработчик нажатия элемента меню.


Итак, начнем. Нам потребуется Visual Studio 2010 Pro или старше. Необходимо дополнительно установить Visual Studio 2010 SDK [1] и специальное дополнение VSPackage Builder [2], максимально облегчающее создание новых расширений.

Создание расширения

Создадим новый проект в Visual Studio:
Visual C# -> Extensibility -> VSPackage Builder
Даем проекту имя — я назвала его HeaderDefineCreater.

Создаем расширение (extension) Visual Studio для генерирования C++ директивы #define в header файле

В открывшемся проекте разместим на дизайнере расширения (файл HeaderDefineCreater.vspackage) все необходимые нам элементы. Начнем с первого элемента — добавим контекстное меню. В его свойствах напротив поля Location выберем размещение — «Context Menu | Editor»

Создаем расширение (extension) Visual Studio для генерирования C++ директивы #define в header файле

Затем создадим группу Group, одну кнопку (назовем ее CreateHeaderDefineButton) и два коннекта между всеми элементами. На скрине с левой стороны показаны свойства для кнопки. Там все стандартное, разве что следует обратить внимание что кнопка (то есть строка в контекстном меню) будет видима только в редакторе (Visibility Constraints: TextEditor). Что касается шортката, то эти поля можно оставить пустыми, поскольку их можно настроить отдельно при использовании расширения.

Создаем расширение (extension) Visual Studio для генерирования C++ директивы #define в header файле

Ну вот, все готово. Осталось только заполнить обработчик нажатия на элемент контекстного меню.
Автоматически сгенерированный обработчик нажатия выглядит следующим образом:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;


namespace HeaderDefineCreater
{
    [Guid(GuidList.guidHeaderDefineCreaterPkgString)]
    public class HeaderDefineCreaterPackage : HeaderDefineCreaterPackageBase
    {
        protected override void CreateHeaderDefineButtonExecuteHandler(object sender, EventArgs e)
        {

        }
    }
}

Заполним обработчик. Существует множество схожих по функциональности макросов для студии, написанные в VB, так что ничего не пришлось выдумывать самой, просто слегка переписала на С#.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;

// Импортируем еще 3 пространства имен:
using System.Windows.Forms;
using EnvDTE;
using System.IO;

namespace HeaderDefineCreater
{
    [Guid(GuidList.guidHeaderDefineCreaterPkgString)]
    public class HeaderDefineCreaterPackage : HeaderDefineCreaterPackageBase
    {
        protected override void CreateHeaderDefineButtonExecuteHandler(object sender, EventArgs e)
        {
            try
            {
                // Получим объект верхнего уровня в объектной модели автоматизации Visual Studio
                EnvDTE.DTE dte = (EnvDTE.DTE)GetService(typeof(EnvDTE.DTE));

                // Получим название без расширения у активного документа в Visual Studio
                String fileName = Path.GetFileNameWithoutExtension(dte.ActiveDocument.Name);

                // Приведем название к прописным буквам
                fileName = fileName.ToUpper();

                // Сгенерируем уникальный идентификатор GUID
                String strGuid = System.Guid.NewGuid().ToString().ToUpper();
                strGuid = strGuid.Replace("-", "_");

                // Объединим название файла и идентификатор GUID 
                String strDefine = fileName + "_" + strGuid;

                // Создадим саму надпись, которая будет выведена в документе
                string txt = "";
                txt += "n#ifndef " + strDefine;
                txt += "n#define " + strDefine;
                txt += "nnnnn#endif // " + strDefine;
                txt += "n";
    
                // Выведем надпись в активный документ
                TextSelection textSelection = (TextSelection)dte.ActiveDocument.Selection;
                textSelection.Text = txt;

            }
            catch (Exception ex)
            {
                // Если что-то пошло не так, то просто покажем сообщение об ошибке и не уроним студию...
                MessageBox.Show(ex.Message);
            }
        }
    }
}

Нам осталось лишь заполнить поля в манифесте (добавить иконку, описание и тд. ) и все скомпилировать.

Создаем расширение (extension) Visual Studio для генерирования C++ директивы #define в header файле

После компиляции мы получим готовое расширение HeaderDefineCreater.vsix.

Установка расширения и смена шорткатов

Устанавливается расширение простым двойным кликом.
Удалить его можно зайдя в Tools->Extension Manager.

Создаем расширение (extension) Visual Studio для генерирования C++ директивы #define в header файле

Для того, чтобы установить шорткат для расширения, нужно зайти в Tools -> Options -> Keyboard, найти там по поиску имя кнопки (мы кнопку назвали CreateHeaderDefineButton, но, впрочем, для простоты можно было бы ее назвать и именем расширения). Для найденной кнопки ставим любое свободное сочетание:

Создаем расширение (extension) Visual Studio для генерирования C++ директивы #define в header файле

Спасибо за внимание. Замечания приветствуются. Замечу, что я не пишу на C#, а изучаю С++ и расширение создавалось прежде всего для облегчения рутинных операций на плюсах и для внутреннего использования. Думаю, что название для поля контекстного меню можно было бы придумать и лучше… да и иконка не соответствует содержимому :) Но здесь мне просто хотелось показать как быстро создать свое расширение, надеюсь, еще кому-нибудь будет полезно.

Я не стала выкладывать сюда весь проект, поскольку расширение очень простое, все шаги описаны, да и весь код в обработчике клика тоже здесь выложен. Поэтому приложу для примера только само расширение, получившееся в итоге — HeaderDefineCreater.vsix [3]

Автор: Bienne

Источник [4]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/c-3/24210

Ссылки в тексте:

[1] Visual Studio 2010 SDK: http://www.microsoft.com/en-us/download/details.aspx?id=2680

[2] VSPackage Builder: http://visualstudiogallery.msdn.microsoft.com/e9f40a57-3c9a-4d61-b3ec-1640c59549b3/

[3] HeaderDefineCreater.vsix: https://www.box.com/s/ygrkrjtqm5nmasmuydzl

[4] Источник: http://habrahabr.ru/post/164973/