Pull to refresh

Visual Studio 2005/2008 PasteBin via C#

Reading time12 min
Views2.2K
Проект, описанный в данной статье, являет собой мой первый опыт программирования на 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.
Tags:
Hubs:
+14
Comments7

Articles