Расширение оболочки Windows с C#

Я хотел написать простое расширение оболочки windows для добавления в контекстное меню, и C# - это язык, который я больше всего использую в эти дни. Является ли это достойным выбором для расширения оболочки? Легко ли добраться до интерфейсов? Есть ли дополнительные накладные расходы, которые заставляют меню появляться медленнее?

У кого-нибудь есть хорошие указатели для начала работы?

3 ответов


сообщение Раймонда:Не пишите расширения оболочки в процессе в управляемом коде.


недавнее продолжение:теперь, когда версия 4 .NET Framework поддерживает параллельные среды выполнения в процессе, можно ли писать расширения оболочки в управляемом коде?

суть в том, что нет, это не так:

на руководство по реализации расширений в процессе был пересмотрен, и он продолжается рекомендация не писать расширения оболочки и расширения Internet Explorer (и другие типы расширений в процессе) в управляемом коде, даже если вы используете версию 4 или выше.


рискуя выглядеть как Шилл,EZShellExtensions - замечательная (но несвободная) структура для разработки расширения оболочки в C#. Вы можете написать простое расширение контекстного меню с примерно 20 строк кода и, лучше всего, никогда не придется возиться с COM-интерфейсами. Моя компания использует его (и их фреймворк расширения пространства имен) для набора расширений, используемых в настоящее время десятками тысяч клиентов, и, чего бы это ни стоило, у нас никогда не было проблем с CLR конфликт, описанный выше.

вот быстрый пример, чтобы показать, насколько это просто:

[Guid("00000000-0000-0000-0000-000000000000"), ComVisible(true)]
[TargetExtension(".txt", true)]
public class SampleExtension : ContextMenuExtension
{
   protected override void OnGetMenuItems(GetMenuitemsEventArgs e)
   {
      e.Menu.AddItem("Sample Extension", "sampleverb", "Status/help text");
   }

   protected override bool OnExecuteMenuItem(ExecuteItemEventArgs e)
   {
      if (e.MenuItem.Verb == "sampleverb")
         ; // logic
      return true;
   }

   [ComRegisterFunction]
   public static void Register(Type t)
   {
      ContextMenuExtension.RegisterExtension(typeof(SampleExtension));
   }

   [ComUnregisterFunction]
   public static void UnRegister(Type t)
   {
      ContextMenuExtension.UnRegisterExtension(typeof(SampleExtension));
   }
}

руководство по реализации расширений в процессе

Конфликты Версии

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

рассмотрим расширение в процессе, написанное с использованием версии среды CLR до версии 4.0. Каждое приложение на компьютере, использующее диалоговое окно "Открыть файл" потенциально может содержать управляемый код диалогового окна и его сопутствующую зависимость CLR, загруженную в процесс приложения. Приложение или расширение, которое сначала загружает версию среды CLR до 4.0 в процесс приложения, ограничивает, какие версии среды CLR могут использоваться впоследствии этим процессом. Если управляемое приложение с открытым диалоговым окном построено на конфликтующей версии среды CLR, расширение может работать неправильно и вызвать сбои в приложении. И наоборот, если расширение загружается первым в процессе и конфликтующая версия управляемого кода пытается запустить после этого (возможно, управляемое приложение или запущенное приложение загружает среду CLR по требованию), операция завершается неудачно. Пользователю кажется, что некоторые функции приложения случайно перестают работать, или приложение таинственным образом аварийно завершает работу.

обратите внимание, что версии среды CLR, равной или более поздней версии 4.0, обычно не подвержены воздействию к проблеме управления версиями, потому что они предназначены для сосуществования друг с другом и с большинством версий CLR до 4.0 (за исключением версии 1.0, которая не может сосуществовать с другими версиями). Однако могут возникнуть проблемы, отличные от конфликтов версий, как описано в оставшейся части этого раздела.

Проблемы С Производительностью

проблемы с производительностью могут возникнуть во время выполнения, которые налагают значительный штраф производительности, когда они загружается в процесс. Штраф за производительность может быть в виде использования памяти, использования ЦП, истекшего времени или даже потребления адресного пространства. CLR, JavaScript / ECMAScript и Java известны как высокоэффективные среды выполнения. Поскольку расширения в процессе могут быть загружены во многие процессы, и часто это делается в моменты, чувствительные к производительности (например, при подготовке меню для отображения пользователя), высокоэффективное время выполнения может негативно повлиять на общую отзывчивость.

A высокоэффективная среда выполнения, потребляющая значительные ресурсы, может вызвать сбой в хост-процессе или другом расширении процесса. Например, высокопроизводительная среда выполнения, потребляющая сотни мегабайт адресного пространства для своей кучи, может привести к тому, что ведущее приложение не сможет загрузить большой набор данных. Кроме того, поскольку расширения в процессе могут быть загружены в несколько процессов, высокое потребление ресурсов в одном расширении может быстро умножаться на высокое потребление ресурсов в вся система.

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

проблемы, характерные для .NET Framework

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

  • входы
    Когда среда CLR блокирует однопоточный поток квартиры (STA), например, из-за монитора.Ввод Объекта Waithandle.WaitOne, или оператор contended lock, среда CLR в своей стандартной конфигурации вводит цикл вложенных сообщений во время ожидания. Много методы расширения запрещены для обработки сообщений, и это непредсказуемое и неожиданное повторение может привести к аномальному поведению, которое трудно воспроизвести и диагностировать.

  • Многопоточная Квартира Среда CLR создает вызываемые оболочки среды выполнения для объектов Component Object Model (COM). Эти же вызываемые оболочки среды выполнения уничтожаются позже финализатором CLR, который является частью многопоточной квартиры (MTA). Перемещение прокси от STA до MTA требует маршалинга, но не все интерфейсы, используемые расширениями, могут быть маршалированы.

  • Недетерминированные Жизни Объектов
    CLR имеет более слабые гарантии времени жизни объекта, чем собственный код. Многие расширения имеют требования подсчета ссылок на объекты и интерфейсы, и модель сборки мусора, используемая средой CLR, не может выполнить эти требования.

    • если объект CLR получает ссылка на COM-объект ссылка на COM-объект, удерживаемая вызываемой оболочкой среды выполнения, не освобождается до тех пор, пока вызываемая оболочка среды выполнения не будет собрана в мусор. Недетерминированное поведение выпуска может конфликтовать с некоторыми контрактами интерфейса. Например, метод IPersistPropertyBag::Load требует, чтобы при возврате метода Load объект не сохранял ссылку на пакет свойств.
    • если ссылка на объект CLR возвращается в собственный код, вызываемая оболочка среды выполнения отказывается от ссылки на объект CLR, когда выполняется последний вызов вызываемой оболочки среды выполнения для выпуска, но базовый объект CLR не завершается, пока не будет собран мусор. Недетерминированное завершение может конфликтовать с некоторыми контрактами интерфейса. Например, обработчики эскизов должны немедленно освободить все ресурсы, когда их количество ссылок падает до нуля.

приемлемое использование управляемого кода и Другие Времена

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

  • обработчики просмотра
  • действия на основе командной строки, например, зарегистрированные в подразделах shell\verb\command.
  • COM-объекты, реализованные на локальном сервере, для точек расширения оболочки, которые позволяют вне процесса активация.

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

  • IExecuteCommand, связанный с записью DelegateExecute, зарегистрированной под a подраздел shell\verb\command.
  • IDropTarget, связанный с CLSID, зарегистрированным под подразделом shell\verb\DropTarget.
  • IExplorerCommandState, связанный с записью CommandStateHandler, зарегистрированной под подразделом shell\verb.

SharpShell

SharpShell упрощает создание расширений оболочки Windows с помощью .NET Framework.

исходный код размещается на https://github.com/dwmkerr/sharpshell - Вы можете размещать вопросы и запрос функций здесь или там. Поддерживаемые Расширения

вы можете использовать SharpShell для создания любого из расширений ниже:

  • Контекстные Меню Оболочки
  • Обработчики Значок
  • Info Tip Обработчики
  • Drop Обработчики
  • Обработчики Просмотра
  • Обработчики Наложения Значков
  • эскиз Hanlders
  • Расширения Листа Свойств

проекты, использующие SharpShell
1. Контекстное Меню Trello
2. REAL Shuffle Player 2.0

серия статей в CodeProject