Special connect() issue 2014

Том 29 выпуск 12A

Visual Studio 2013 : Расширение Visual Studio 2013

Дуг Эриксон

Продукты и технологии:

Visual Studio 2013 Community, Visual Studio 2013 SDK, Visual Studio Gallery

В статье рассматриваются:

  • расширение Visual Studio IDE;
  • добавление расширений в стандартные меню;
  • возможности поделиться собственными расширениями с другими разработчиками.

Одно из лучших средств в версиях Visual Studio более высокого уровня теперь доступно всем бесплатно благодаря Visual Studio Community 2013 IDE: возможность использовать расширения из Visual Studio Gallery (bit.ly/115mBzm). Что же такое расширения? Это плагины, позволяющие расширять Visual Studio Community 2013 (которую можно скачать с bit.ly/1tH2uyc), и средства Visual Studio, которые выполняют новые задачи, добавляют новую функциональность и перерабатывают код — или даже поддерживают новые языки.

Сообщество разработчиков Microsoft предоставляет широкий выбор расширений в Visual Studio Gallery. Загляните туда и вы удивитесь разнообразию доступных расширений. Без некоторых из них вроде расширения Productivity Power Tools 2013 (bit.ly/1xE3EAT), весьма вероятно, вы больше не захотите обходиться. Эти расширения можно установить из Web или найти из Visual Studio, используя окно Extensions and Updates в меню Tools. Проверьте категорию Online для поиска более популярных инструментов, таких как Visual Assist и ReSharper. Дополнительные расширения можно найти в Code Gallery (bit.ly/11nzi9Q).

Одно из лучших средств в версиях Visual Studio более высокого уровня теперь доступно всем бесплатно благодаря Visual Studio Community 2013 IDE: возможность использовать расширения из Visual Studio Gallery bit.ly/115mBzm). Что же такое расширения? Это плагины, позволяющие расширять Visual Studio Community 2013 (которую можно скачать с bit.ly/1tH2uyc) ), и средства Visual Studio, которые выполняют новые задачи, добавляют новую функциональность и перерабатывают код — или даже поддерживают новые языки.

Сообщество разработчиков Microsoft предоставляет широкий выбор расширений в Visual Studio Gallery. Загляните туда и вы удивитесь разнообразию доступных расширений. Без некоторых из них вроде расширения Productivity Power Tools 2013 bit.ly/1xE3EAT), весьма вероятно, вы больше не захотите обходиться. Эти расширения можно установить из Web или найти из Visual Studio, используя окно Extensions and Updates в меню Tools. Проверьте категорию Online для поиска более популярных инструментов, таких как Visual Assist и ReSharper. Дополнительные расширения можно найти в Code Gallery (bit.ly/11nzi9Q).

Сообщество разработчиков Microsoft предоставляет широкий выбор расширений в Visual Studio Gallery.

Даже лучшие инструменты мог не идеально соответствовать вашим специфическим задачам, которые вам нужно выполнять или автоматизировать в IDE. По-видимому, у вас есть свои скрипты, облегчающие вашу работу. Возможно, вы располагаете таким скриптом, который проверяет успешность сборки или выполняет преобразование XML-файлов, или очищает весь мусор, оставшийся после сложного процесса сборки. Как вы предпочитаете использовать свой инструмент в Visual Studio — как часть IDE или как часть процесса сборки? Теперь все это возможно при использовании Visual Studio 2013 Community и Visual Studio 2013 SDK.

Начните со скачивания Visual Studio SDK. Он предоставляет все библиотеки, средства и шаблоны проектов для создания самых разнообразных расширений. Установите этот SDK и вы готовы к работе.

Настройка инструментальных средств на выполнение в Visual Studio

После установки SDK довольно легко сделать так, чтобы ваш инструмент или исполняемый скрипт запускался из меню Visual Studio. Примером в этой статье будет вездесущий Notepad.exe, но вы можете использовать любой исполняемый файл или интегрировать свой код в обработчик команд.

Базовое расширение — двоичный файл Visual Studio Package. Шаблон Visual Studio Package вы найдете в диалоге New Project под Visual Basic | Extensibility, C# | Extensibility или Other Project Types | Extensibility.

В этой статье будет продемонстрировано, как сделать простое расширение, которое запускает Notepad. Мы воспользуемся шаблоном под C#/Extensibility, чтобы создать проект C# Visual Studio Package, поместим его в каталог D:\Code и назовем его StartNotepad. Это расширение будет в конечном счете запускать Notepad с помощью элемента меню Visual Studio IDE.

После двойного щелчка шаблона Visual Studio запускает мастер, помогающий сконфигурировать Extension. Для новичков на первых двух страницах диалога лучше просто принять все, что предлагается по умолчанию.

Затем выполните следующие операции.

  1. На странице Select VSPackage Options выберите Menu Command.
  2. На странице Command Options задайте имя команды как Start Notepad, а идентификатору команды присвойте значение cmdidStartNotepad.
  3. На странице Test Options сбросьте два флажка.
  4. Щелкните Finish.

К этому моменту можно скомпилировать и запустить проект Package. Открыв проект, запустите отладку (нажмите клавишу F5 или выберите команду Start на панели инструментов). Будет запущен новый экземпляр Visual Studio Community 2013. После запуска вы увидите IDE с начальной страницей (Start Page) по умолчанию, в строке заголовка которой написано Microsoft Visual Studio — Experimental Instance (рис. 1). Это ваш тестовый экземпляр Visual Studio. Он выполняется отдельно от ваших рабочих экземпляров Visual Studio, поэтому вам незачем волноваться о повреждении своей среды разработки, если что-то пойдет не так.

The Visual Studio Experimental Instance
Рис. 1. Visual Studio Experimental Instance

«Экспериментальный экземпляр» — это на самом деле изящный способ объявления о том, что вы запустили экземпляр «песочницы» Visual Studio (изолированный экземпляр) для тестирования своего расширения. У него есть все функции Visual Studio Community 2013, но ваша работа не подвергает опасности оригинальный экземпляр Visual Studio. Для столь простого примера это может показаться сильным перебором. Однако, если вы создаете целую инфраструктуру разработки или сложный набор взаимозависимых средств сборки, вы вряд ли захотите рисковать и выполнять свой код в том экземпляре, в котором вы ведете разработку.

В меню Tools экспериментального экземпляра откройте окно Extensions and Updates. Вы должны увидеть здесь расширение StartNotepad (рис. 2). (Если вы откроете Extensions and Updates в рабочем экземпляре Visual Studio, то не увидите StartNotePad.)

Окно Extensions and Updates, в котором показывается StartNotepad
Рис. 2. Окно Extensions and Updates, в котором показывается StartNotepad

Кроме того, вы увидите Start Notepad в меню Tools (рис. 3).

Новый элемент меню Tools для StartNotepad
Рис. 3. Новый элемент меню Tools для StartNotepad

Теперь откройте меню Tools в экспериментальном экземпляре. Вы должны увидеть команду Start Notepad. К этому моменту она просто выводит сообщение «StartNotepad — Inside MSIT.StartNotepad.StartNotepadPackage.MenuItemCallback()». Вы поймете, как запустить Notepad этой командой в следующем разделе.

После установки SDK довольно легко сделать так, чтобы ваш инструмент или исполняемый скрипт запускался из меню Visual Studio.

Настройка команды меню

Остановите отладку и вернитесь в свой рабочий экземпляр Visual Studio. Откройте файл StartNotepadPackage.cs, содержащий производный класс Package. Это отправная точка для всех расширений VSPackage. Метод Initialize этого класса устанавливает команду:

// Добавляем наши обработчики команд для меню
// (команды должны уже существовать в файле .vsct)
OleMenuCommandService mcs = GetService(typeof(
  IMenuCommandService)) as OleMenuCommandService;
if ( null != mcs )
{
  // Создаем команду для элемента меню
  CommandID menuCommandID = new CommandID(
    GuidList.guidStartNotepadCmdSet,
    (int)PkgCmdIDList.cmdidStartNotepad);
  MenuCommand menuItem = new MenuCommand(
    MenuItemCallback, menuCommandID );
  mcs.AddCommand( menuItem );
}

Не заморачивайтесь прямо сейчас деталями этого кода. Вы должны просто отметить, что так создается экземпляр команды меню. Меню и другие UI-элементы для расширений VSPackage определяются, как сказано в комментариях к этому коду, в файле .vsct.

Обработчик команды называется MenuItemCallback (в том же классе StartNotepadPackage). Удалите существующий метод и добавьте следующее:

private void MenuItemCallback(object sender, EventArgs e)
{
  Process proc = new Process();
  proc.StartInfo.FileName = "notepad.exe";
  proc.Start();
}

Теперь проверьте, как это работает. Когда вы начнете отладку проекта и выберете Tools | Start Notepad, вы должны увидеть экземпляр Notepad. По сути, вы будете получать новый экземпляр Notepad всякий раз, когда выбираете Start Notepad.

Файл .vsct — удобное место для поиска всех определений UI-элементов Visual Studio.

Вы можете использовать экземпляр класса System.Diagnostics.Process для запуска любого исполняемого файла — не только Notepad. Попробуйте для примера сделать то же самое с калькулятором — calc.exe.

Определение интерфейса

Теперь вы будете использовать файл .vsct для определения UI вашего расширения. Взгляните на файл StartNotepad.vsct. Это удобное место для поиска всех определений UI-элементов Visual Studio, используемых вашим расширением. Это XML-файл file, поэтому готовьтесь работать с угловыми скобками.

Найдите блок <Groups>. Каждая команда меню должна относиться к какому-либо блоку Group; тем самым Visual Studio узнает, куда поместить команду. В нашем случае команда находится в меню Tools, и ее предком является меню Main:

<Groups>
  <Group guid="guidStartNotepadCmdSet" 
    id="MyMenuGroup" priority="0x0600">
    <Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>
  </Group>
</Groups>

Пока не волнуйтесь особо о деталях. Этот фрагмент приведен просто для того, чтобы вы знали, где находятся важные элементы. Сама команда определяется в блоке <Buttons>:

<Button guid="guidStartNotepadCmdSet" id="cmdidStartNotepad"
  priority="0x0100" type="Button">
  <Parent guid="guidStartNotepadCmdSet" id="MyMenuGroup" />
  <Icon guid="guidImages" id="bmpPic1" />
  <Strings>
    <ButtonText>Start Notepad</ButtonText>
  </Strings>
</Button>

Как видите, кнопка определяется GUID (guidStartNotepadCmdSet, который совпадает с Group GUID) и ID (cmdidStartNotepad, который является ID, указанным вами в мастере пакетов). Команда является потомком Group. У нее есть значок и какой-либо текст. Значок берется из набора значков по умолчанию, включаемого в решение. Параметр priority указывает позицию этой кнопки в меню, если в группе присутствует несколько команд. GUID и ID для групп и кнопок определяются в блоке <Symbols>:

<!-- Это GUID пакета -->
<GuidSymbol name="guidStartNotepadPkg"
  value="{18311db7-ca0f-419c-82b0-5aa14c8b541a}" />

<!-- Это GUID, используемый для группирования команд меню -->
<GuidSymbol name="guidStartNotepadCmdSet"
  value="{b0692a6d-a8cc-4b53-8b2d-17508c87f1ab}">
  <IDSymbol name="MyMenuGroup" value="0x1020" />
  <IDSymbol name="cmdidStartNotepad" value="0x0100" />
</GuidSymbol>

Битовые карты тоже определяются в блоке <Symbols>:

<GuidSymbol name="guidImages" 
  value="{b8b810ad-5210-4f35-a491-c3464a612cb6}" >
  <IDSymbol name="bmpPic1" value="1" />
  <IDSymbol name="bmpPic2" value="2" />
  <IDSymbol name="bmpPicSearch" value="3" />
  <IDSymbol name="bmpPicX" value="4" />
  <IDSymbol name="bmpPicArrows" value="5" />
  <IDSymbol name="bmpPicStrikethrough" value="6" />
</GuidSymbol>

Попробуйте поменять значок на один из других, определенных здесь. Ни один из имеющихся здесь значков не подходит для Notepad, поэтому выберите bmpPicStrikethrough — это позволит увидеть другую часть настройки. Хотя значки определяются в блоке <Symbols>, они также должны быть перечислены в атрибуте usedList блока <Bitmaps>:

<Bitmap guid="guidImages" href="Resources\Images.png" usedList="bmpPic1,
  bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows"/>

Как видите, bmpPicStrikethrough здесь не перечислен, хоть и определен. Если вы смените значок на эту битовую карту, она не появится в меню. Поэтому добавьте bmpPicStrikethrough:

<Bitmap guid="guidImages" href="Resources\Images.png" usedList="bmpPic1,
  bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows, bmpPicStrikethrough"/>

Теперь вы можете сменить значок на bmpPicStrikethrough для кнопки меню:

<Button guid="guidStartNotepadCmdSet" id="cmdidStartNotepad"
  priority="0x0100" type="Button">
  <Parent guid="guidStartNotepadCmdSet" id="MyMenuGroup" />
  <Icon guid="guidImages" id="bmpPicStrikethrough" />
  <Strings>
    <ButtonText>Start Notepad</ButtonText>
  </Strings>
</Button>

Можете проверить, что получилось. Когда появится экспериментальный экземпляр, вы должны увидеть в меню Tools нечто вроде того, что показано на рис. 4.

Команда для запуска Notepad
Рис. 4. Команда для запуска Notepad

Теперь добавьте комбинацию клавиш для вызова команды меню Start Notepad. В этом примере будет использоваться Ctrl+1. Если вы добавляете комбинацию клавиш, убедитесь, что она не конфликтует со стандартными комбинациями клавиш. Это можно сделать полностью в файле .vsct. Комбинации клавиш называются KeyBindings в этом файле. Добавьте следующий блок в файл .vsct:

<KeyBindings>
  <KeyBinding guid="guidStartNotepadCmdSet" 
    id="cmdidStartNotepad"    
    editor="guidVSStd97" key1="1" mod1="CONTROL"/>
</KeyBindings>

Атрибут key1 объявляет стандартную клавишу, а атрибут mod1 — клавишу-модификатор, или клавишу-ускоритель (обычно Ctrl, Alt или Shift), нажимаемую в сочетании со стандартной клавишей. Если вы укажете mod2="ALT", чтобы добавить вторую клавишу-модификатор, то получите комбинацию Ctrl+Alt+1. Оставьте пока Ctrl+1. Но помните, что файл .vsct — хорошее место, где можно начать свои настройки. После этого можно приступить к отладке. Снова запустите пакет. Когда появится экспериментальный экземпляр, нажмите Ctrl+1. Вы должны получить экземпляр Notepad.

Поддержание отзывчивости UI

Метод MenuItemCallback в том виде, в каком он есть сейчас, не блокирует UI-поток. Вы можете по-прежнему запускать Notepad командой Start Notepad (или Ctrl+1). Вы также можете продолжать выполнять любые операции в Visual Studio IDE, например перемещать окно, выбирать другие команды в меню и т. д. А теперь представьте, что вашему инструменту нужно завершить свою работу до выхода из обработчика. Иначе говоря, вам требуется вызов Process.WaitForExit.

К сожалению, если вы вызываете WaitForExit в UI-потоке Visual Studio, когда MenuItemCallback доходит до этой точки, весь Visual Studio UI замораживается. Проверьте сами. В методе MenuItemCallback вызовите WaitForExit:

private void MenuItemCallback(object sender, EventArgs e)
{
  Process proc = new Process();
  proc.StartInfo.FileName = "notepad.exe";
  proc.Start();
  proc.WaitForExit();
}

Начните отладку и, когда появится экспериментальный экземпляр, нажмите Ctrl+1. Вы должны увидеть экземпляр Notepad. Теперь попробуйте переместить окно Visual Studio (экспериментальный экземпляр). Оно не будет перемещаться. Вы вообще не можете ничего делать в Visual Studio UI. Возможно, даже появится всплывающее сообщение «Microsoft Visual Studio is Busy». Очевидно, это надо исправить.

Освоив создание расширений, вы сделаете Visual Studio по-настоящему своей средой разработки.

К счастью, исправить это нетрудно. Если у вас есть инструмент или процесс, который требует для выполнения значительного времени, оберните его в Task в MenuItemCallback, например:

private void MenuItemCallback(object sender, EventArgs e)
{
  ThreadHelper.JoinableTaskFactory.RunAsync(async delegate
  {
    Process proc = new Process();
    proc.StartInfo.FileName = "notepad.exe";
    proc.Start();
    await proc;
  });
}

После этого ваш инструмент и Visual Studio должны работать одновременно.

Очистка после вашего эксперимента

Если вы разрабатываете несколько расширений или просто исследуете результаты при использовании разных версий кода своего расширения, ваша экспериментальная среда можно перестать работать должным образом. В этом случае вы должны запустить скрипт сброса.

Этот скрипт называется Reset the Visual Studio 2013 Experimental Instance и поставляется как часть Visual Studio 2013 SDK. Он удаляет все ссылки на ваши расширения из экспериментальной среды, после чего вы можете начинать с нуля. Обратиться к этому скрипту можно двумя способами:

  • на рабочем столе запустить поиск Reset the Visual Studio 2013 Experimental Instance;
  • выполнить из командной строки следующее:
<VSSDK installation>\VisualStudioIntegration\Tools\Bin\
        CreateExpInstance.exe /Reset /VSInstance=12.0 
       /RootSuffix=Exp && PAUSE

Развертывание вашего расширения

Теперь, когда ваше расширение выполняется так, как ему следует, пора подумать о том, чтобы поделиться им с друзьями и коллегами. Это легко, если у них тоже установлена Visual Studio 2013. Вам нужно лишь отправить им созданный вами файл .vsix. Убедитесь, что он скомпилирован в режиме Release.

Вы найдете файл .vsix для этого расширения в каталоге StartNotepad\bin. Точнее, если вы скомпилировали в конфигурации Release, он будет в \D:\Code\StartNotepad\StartNotepad\bin\Release\StartNotepad.vsix.

Чтобы установить это расширение, пользователь должен закрыть все открытые экземпляры Visual Studio, дважды щелкнуть файл .vsix, чтобы вызвать VSIX Installer. Файлы копируются в каталог %LocalAppData%\Microsoft\VisualStudio\12.0\Extensions.

Когда пользователь вновь откроет Visual Studio, он увидит расширение StartNotepad в Tools | Extensions and Updates. Удалить или отключить это расширение можно в том же окне Extensions and Updates.

Освоив создание расширений, вы сделаете Visual Studio по-настоящему собственной средой разработки. Это также позволяет вам делиться своими лучшими наработками с сообществом. Microsoft тоже приветствует публикацию расширений, созданных разработчиками.

Заключение

В этой статье описана лишь малая толика того, что можно делать с помощью расширений Visual Studio. Чтобы узнать больше о расширениях Visual Studio в целом, см. страницу «Integrate Your App or Service with Visual Studio» bit.ly/1zoIt59.

Чтобы получить более глубокое представление о расширениях, см. статьи MSDN Library в разделе «Extending Visual Studio Overview» bit.ly/1xWoA4k. А за хорошими примерами кода обращайтесь к коллекции в галерее примеров MSDN по ссылке bit.ly/1xWp5eD.


Сьюзен Норвуд (Susan Norwood) работала в Microsoft, в основном писала о Visual Studio SDK. Помогла многим людям интегрировать их инструменты в Visual Studio.

Дуг Эриксон (Doug Erickson) проработал в течение 13 лет в качестве разработчика и технического писателя в Microsoft. С нетерпением ждет, как с помощью Visual Studio Community разработчики будут создавать приложения и игры для всех платформ.

Выражаем благодарность за рецензирование статьи экспертам Microsoft Энтони Кенгулоси (Anthony Cangialosi) и Райену Молдену (Ryan Molden).