Visual Studio 2005/2008 PasteBin via C#

    Проект, описанный в данной статье, являет собой мой первый опыт программирования на C# .NET, посему прошу не судить строго.

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

    «Так зачем тратить время на загрузку этого сайта в браузере, копипаст кода в форму и нажатие кнопок», — подумал я и решил написать плагин для Студии, добавляющий в контекстное меню редактора кода пункт «PasteBin». Простым кликом на него вы заставите выделенную часть исходного кода переслаться на и, после этого, уникальный URL, созданный сайтом PasteBin, окажется в вашем буфере обмена.

    Для работы я использую Microsoft Visual Studio 2008, но в 2005 все абсолютно аналогично.


    Создание проекта

    Далее будут заданы несколько вопросов и, в итоге, перед вами появится заготовка будущего плагина. Исходный код любого плагина должен содержать некоторые стандартные функции. Сейчас я последовательно расскажу, что за что отвечает и в каком порядке вызывается.

    Для начала объявим глобальные переменные нашего стандартного класса Connect.

        // Constants for command properties
        private const string CommandName    = "PasteBin";
        private const string CommandCaption   = "PasteBin";
        private const string Url        = "http://pastebin.com";
        private const string RequestParameters = "parent_pid=&format={0}&code2={1}&poster=&paste=Send&expiry=f&email=";

        // Constants for file formats
        private static readonly Dictionary<string, string> FileFormat = new Dictionary<string, string>
                                          {
                                           {"c","c"},
                                           {"h","c"},
                                           {"cpp","cpp"},
                                           {"cs","csharp"}
                                          };

        // Variables for IDE and add-in instances
        private DTE _applicationObject;
        private AddIn _addInInstance;

        // Buttons that will be created on built-in command bars of Visual Studio
        // We must keep them at class level to remove them when the add-in is unloaded
        private CommandBarButton _pasteBinButton;


    * This source code was highlighted with Source Code Highlighter.


    Первая стандартная функция OnConnection описывает на каком этапе загрузки Студии необходимо внедрять наши изменения в пользовательский интерфейс. Для статьи она интереса не представляет, желающие смогут увидеть ее в полном исходном коде, который будет приложен в конце статьи. Гораздо больший интерес представляет функция AddUI, описывающая непосредственно процесс добавления нового пункта в контекстное меню (кстати, AddUI вызывается также и второй стандартной функцией — OnStartupComplete, что гарантирует корректную загрузку нашего плагина, даже если при старте Студии возникли проблемы).

    Итак, функция AddUI. Вначале мы проверяем не создана ли уже команда с таким именем как у нас (мало ли) и если нет, то создаем ее сами.

            // Try to retrieve the command, just in case it was already created, ignoring the
            // exception that would happen if the command was not created yet.
            try
            {
              myCommand = _applicationObject.Commands.Item(_addInInstance.ProgID + "." + CommandName, -1);
            }
            catch (Exception e)
            {
              Debug.Write(e.ToString());
            }

            // Add the command if it does not exist
            if (myCommand == null)
            {
              myCommand = _applicationObject.Commands.AddNamedCommand(_addInInstance,
                CommandName, CommandCaption, null, true, 59, ref contextUIGuids,
                (int)(vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled));
            }


    * This source code was highlighted with Source Code Highlighter.


    Далее получаем «указатель» на контекстное меню редактора кода.

          // Constants for names of built-in command bars of Visual Studio
          const string vsCodeWindowCommandbarName = "Code Window";

          // Retrieve the collection of command bars
          // Note:
          // - In VS.NET 2002/2003 (which uses the Office.dll reference)
          //  DTE.CommandBars returns directly a CommandBars type, so a cast
          //  to CommandBars is redundant
          // - In VS 2005 or higher (which uses the new Microsoft.VisualStudio.CommandBars.dll reference)
          //  DTE.CommandBars returns an Object type, so we do need a cast to CommandBars
          var commandBars = (CommandBars)_applicationObject.CommandBars;
          // Retrieve some built-in command bars
          codeCommandBar = commandBars[vsCodeWindowCommandbarName];


    * This source code was highlighted with Source Code Highlighter.


    И описываем наш пункт в контекстном меню, не забывая про его внешний вид — иконку.

            // Create the buttons from the commands
            // Note:
            // - In VS.NET 2002/2003 (which uses the Office.dll reference)
            //  Command.AddControl returns directly a CommandBarControl type, so a cast
            //  to CommandBarControl is redundant
            // - In VS 2005 or higher (which uses the new Microsoft.VisualStudio.CommandBars.dll reference)
            //  Command.AddControl returns an Object type, so we do need a cast to CommandBarControl
            string ns = GetType().Namespace;
            Assembly currentAssembly = GetType().Assembly;

            Stream
              imgStreamPic = currentAssembly.GetManifestResourceStream(ns + "." + "klipper.png"),
              imgStreamMask = currentAssembly.GetManifestResourceStream(ns + "." + "klipper-mask.png");

            if (imgStreamPic != null && imgStreamMask != null)
            {
              Image
                pasteBinImage = Image.FromStream(imgStreamPic),
                pasteBinImageMask = Image.FromStream(imgStreamMask);

              // ------------------------------------------------------------------------------------
              // Button on the "Code Window" context menu
              // ------------------------------------------------------------------------------------

              // Add a button to the built-in "Code Window" context menu
              _pasteBinButton = (CommandBarButton) myCommand.AddControl(codeCommandBar,
                                           codeCommandBar.Controls.Count + 1);

              // Change some button properties
              _pasteBinButton.Caption = CommandCaption;
              _pasteBinButton.BeginGroup = true; // Separator line above button

              _pasteBinButton.Style = MsoButtonStyle.msoButtonIconAndCaption; // It could be also msoButtonIcon
              _pasteBinButton.Picture = (stdole.StdPicture) ImageConverter.ImageToIpicture(pasteBinImage);
              _pasteBinButton.Mask = (stdole.StdPicture) ImageConverter.ImageToIpicture(pasteBinImageMask);
            }


    * This source code was highlighted with Source Code Highlighter.


    Для получения ресурсов с помощью GetManifestResourceStream необходимо добавить нужные файлы в проект и изменить в свойствах параметр Build Action на Embeded Resource.



    Далее следуют три абсолютно неинтересных функции OnDisconnection, OnBeginShutdown и OnAddInsUpdate. Зато сразу же после них располагается сердце нашего проекта — функция Exec.

    Если какой-либо фрагмент кода выделен, то тогда на основе типа активного файла с исходным кодом и преобразованного с помощью UrlEncode выделенного текста формируется запрос к сайту , а из ответа сервера вычленяется уникальная ссылка на размещенный исходный код, которая и помещается в буфер обмена.

        public void Exec(string cmdName, vsCommandExecOption executeOption, ref object varIn,
          ref object varOut, ref bool handled)
        {

          handled = false;

          if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
          {
            if (cmdName == string.Format("{0}.{1}", _addInInstance.ProgID, CommandName))
            {
              handled = true;
              if (!((TextSelection)_applicationObject.ActiveDocument.Selection).IsEmpty)
              {
                // parameters: name1=value1&name2=value2  
                var webRequest = (HttpWebRequest)WebRequest.Create(Url);

                webRequest.ContentType = "application/x-www-form-urlencoded";
                webRequest.Method = "POST";

                // formatting request string from document type and selection
                string request = string.Format(RequestParameters,
                  FileFormat[_applicationObject.ActiveDocument.Name.Split('.')[1]],
                  System.Web.HttpUtility.UrlEncode(((TextSelection)_applicationObject.ActiveDocument.Selection).Text));

                Stream os = null;

                try
                { // send the POST
                  webRequest.ContentLength = request.Length; //Length of request to send
                  os = webRequest.GetRequestStream();
                  os.Write(System.Text.Encoding.GetEncoding("windows-1251").GetBytes(request), 0, request.Length);  //Send it
                }
                catch (WebException ex)
                {
                  MessageBox.Show(ex.Message, "HttpPost: Request error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                  if (os != null)
                  {
                    os.Close();
                  }
                }

                try
                { // get the response
                  var webResponse = (HttpWebResponse)webRequest.GetResponse();
                  if (webResponse != null)
                  { // copy to clipboard
                    Clipboard.SetText(webResponse.ResponseUri.ToString());
                    MessageBox.Show("Upload successfully. Url is copied in your clipboard.");
                  }
                }
                catch (WebException ex)
                {
                  MessageBox.Show(ex.Message, "HttpPost: Response error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
              }
            }
          }
        }


    * This source code was highlighted with Source Code Highlighter.


    Завершает файл также ничем не примечательная стандартная функция QueryStatus.

    Приложение А.
    1. Содержание основного файла Connect.cs
    2. Содержание вспомогательного файла ImageConverter.cs
    На сайт вышеуказанные исходники добавлены при помощи описанного в статье плагина.

    Приложение Б.
    Файлы к статье
    Файлы PasteBin.AddIn и PasteBin.dll необходимо поместить в каталог %USERPROFILE%\Мои Документы\Visual Studio 2008\Addins. 2008 можно заменить на 2005.
    • +14
    • 1,9k
    • 7
    Поделиться публикацией

    Комментарии 7

      0
      Спасибо, обязательно протестирую. Только pastebin.com не поддерживает русскую кодировку, например: pastebin.com/f5b44d388
      Можно сменить на hash.su или pastebin.mozilla (капча!).
        0
        Если вдруг захотите тестить с hash.su, то к
        private const string RequestParameters

        нужно будет добавить ещё один параметр: «xa0c»
        // Да, вот такой вот хитрожопый спам-протект :)
        0
        Автору спасибо, инетресный пример интеграции
          0
          спасибо за статью. как раз аналогичный плагин пишем: washington.habrahabr.ru/blog/80670/
          весьма полезно будет.
          Файлы PasteBin.AddIn и PasteBin.dll необходимо поместить в каталог %USERPROFILE%\Мои Документы\Visual Studio 2008\Addins. 2008 можно заменить на 2005.

          А вроде бы можно собрать .vsi файлик, и будет Ваш плагин автоматически устанавливаться, и как add-in использоваться. Мы уже так сделали.
            +1
            Эта штука была написана на коленке за два дня год назад, когда я закрыл сессию и хотел релаксировать))
            Разбираться глубже чем написано — мне стало ну очень лень. Так что — не судите строго.
            0
            по-моему самая крутая пастилка это pastie.org/778030 (-:
              0
              Спасибо, интересно.
              Если мне не изменяет склероз, должен быть инсталлирован Visual Studio SDK, было бы неплохо упомянуть об этом в статье…

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое