Расширение оболочки Windows с помощью C #

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

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


person Pete McKinney    schedule 03.02.2010    source источник
comment
Времена меняются, и ответ на этот вопрос больше не актуален. В 4.0 теперь вы можете писать управляемые расширения оболочки.   -  person    schedule 01.02.2011
comment
Вы можете писать расширения оболочки с помощью .NET 4.0, но это пока официально не поддерживается.   -  person Juozas Kontvainis    schedule 29.07.2011
comment
не понимаю, почему это закрыто, написание расширений оболочки - очень распространенная задача программирования в Windows, и я считаю заданный вопрос вполне законным. См. Также: codeproject.com/KB/shell/columnhandler.aspx (на написание обработчика столбца на C #)   -  person Abel    schedule 06.08.2011
comment
@Will Поддерживается ли написание расширения Windows Shell с использованием .NET 4 сегодня? Microsoft не полностью протестировала все сценарии, связанные с расширениями управляемой оболочки, и не определила будет ли он поддерживать управляемые расширения оболочки в течение длительного времени. Таким образом, Microsoft не будет поддерживать управляемые расширения оболочки и не рекомендует их писать.   -  person Paolo Moretti    schedule 21.02.2012


Ответы (3)


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


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

Суть в том, что нет, это не нормально:

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

person GSerg    schedule 03.02.2010
comment
это можно сделать, но это плохая идея. Я знаю команду разработчиков MS, которая написала оболочку ext на С #, и в итоге они перекодировали на родной С ++ - person pm100; 03.02.2010
comment
Последняя версия среды выполнения .Net 4.0 поддерживает в процессе параллельную загрузку среды выполнения .Net 4.0 (и ВСЕХ будущих сред выполнения) с более ранними средами выполнения .Net. См. Следующий отрывок из msdn.microsoft.com/en-us/magazine/ee819091. aspx Благодаря возможности иметь несколько сред выполнения в процессе с любой другой средой выполнения, теперь мы можем предложить общую поддержку для написания управляемых расширений оболочки - даже тех, которые выполняются внутри процесса с произвольными приложениями на машине. - person logicnp; 23.02.2010
comment
Намекают ли авторы, что можно отказаться от поддержки приложений, написанных на прошивках до 4.0? - person GSerg; 23.02.2010
comment
@logicnp (наконец) есть продолжение от Раймонда Чена по этому поводу. - person GSerg; 22.02.2013
comment
Нет никаких правил против написания дополнительных расширений в .NET, если, тем не менее, вы можете понять, как это сделать, и следовать контрактам refcount. - person SamB; 15.01.2015

Руководство по внедрению внутренних расширений

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

Конфликт версий может возникнуть из-за среды выполнения, которая не поддерживает загрузку нескольких версий среды выполнения в одном процессе. Версии среды 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 известны как среды выполнения с высокой степенью воздействия. Поскольку внутрипроцессные расширения могут быть загружены во многие процессы, и часто это делается в моменты, когда важна производительность (например, при подготовке меню для отображения пользователю), время выполнения с высокой отдачей может негативно повлиять на общую скорость реагирования.

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

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

Проблемы, связанные с .NET Framework

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

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

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

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

    • If a CLR object obtains a reference to a COM object, the COM object reference held by the Runtime Callable Wrapper is not released until the Runtime Callable Wrapper is garbage-collected. Nondeterministic release behavior can conflict with some interface contracts. For example, the IPersistPropertyBag::Load method requires that no reference to the property bag be retained by the object when the Load method returns.
    • Если ссылка на объект CLR возвращается в машинный код, Runtime Callable Wrapper отказывается от своей ссылки на объект CLR, когда выполняется последний вызов Runtime Callable Wrapper для Release, но базовый объект CLR не завершается, пока он не будет собран сборщиком мусора. Недетерминированная финализация может конфликтовать с некоторыми интерфейсными контрактами. Например, обработчики эскизов должны немедленно освободить все ресурсы, когда их счетчик ссылок упадет до нуля.

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

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

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

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

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

SharpShell

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

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

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

  • Контекстные меню оболочки
  • Обработчики значков
  • Обработчики информационных советов
  • Обработчики падения
  • Предварительный просмотр обработчиков
  • Обработчики наложения значков
  • Обработчики миниатюр
  • Расширения страницы свойств

Проекты, в которых используется SharpShell
1. Контекстное меню Trello
2. REAL Shuffle Player 2.0

Серии статей на CodeProject

person Ehsan Mohammadi    schedule 09.02.2014

Рискуя выглядеть глупым, 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));
   }
}
person ladenedge    schedule 03.02.2010