Конфликты версий
Конфликт версий может возникнуть во время выполнения, которое не поддерживает загрузку нескольких версий времени выполнения в одном процессе. Версии 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
В следующих разделах обсуждаются примеры проблем, обнаруженных при использовании управляемого кода для расширений. Они не являются полным списком всех возможных проблем, с которыми вы можете столкнуться. Обсуждаемые здесь проблемы являются как причинами того, что управляемый код не поддерживается в расширениях, так и моментами, которые следует учитывать при оценке использования других сред выполнения.
Re-entrancy
Когда CLR блокирует поток однопотоковой квартиры (STA), например, из-за оператора Monitor.Enter, WaitHandle.WaitOne или оператора состязательной блокировки, CLR в своей стандартной конфигурации вводит вложенный цикл обработки сообщений во время ожидания. Многим методам расширения запрещено обрабатывать сообщения, и это непредсказуемое и неожиданное повторное появление может привести к аномальному поведению, которое трудно воспроизвести и диагностировать.
Многопоточная квартира
CLR создает исполняемые вызываемые оболочки для объектов объектной модели компонентов (COM). Эти те же самые Обертки Callable Runtime уничтожаются позже финализатором CLR, который является частью многопоточной квартиры (MTA). Перемещение прокси с STA на MTA требует маршалинга, но не все интерфейсы, используемые расширениями, могут быть маршалированы.
Недетерминированные времена жизни объекта
CLR имеет более слабые гарантии времени жизни объекта, чем собственный код. Многие расширения предъявляют требования к количеству ссылок на объекты и интерфейсы, и модель сборки мусора, используемая CLR, не может удовлетворить эти требования.
- Если объект CLR получает ссылку на объект COM, ссылка на объект COM, хранящаяся в Callable Wrapper времени выполнения, не освобождается до тех пор, пока функция Callable Wrapper времени выполнения не будет собрана сборщиком мусора. Недетерминированное поведение при выпуске может конфликтовать с некоторыми интерфейсными контрактами. Например, метод IPersistPropertyBag :: Load требует, чтобы объект не сохранял ссылки на пакет свойств при возврате метода Load.
- Если ссылка на объект CLR возвращается к собственному коду, Runtime Callable Wrapper повторно передает свою ссылку на объект CLR, когда сделан последний вызов Releasetime Callable Wrapper к Release, но базовый объект CLR не завершен до тех пор, пока он не станет мусором. собраны. Недетерминированная финализация может конфликтовать с некоторыми интерфейсными контрактами. Например, обработчики миниатюр требуются для немедленного освобождения всех ресурсов, когда их число ссылок падает до нуля.
Допустимое использование управляемого кода и других сред выполнения
Для реализации внепроцессных расширений допустимо использовать управляемый код и другие среды выполнения. Примеры внешних расширений оболочки включают следующие:
- Обработчики предварительного просмотра
- Действия на основе командной строки, такие как те, которые зарегистрированы в подразделах shell \ verb \ command.
- COM-объекты, реализованные на локальном сервере, для точек расширения Shell, которые допускают внепроцессную активацию.
Некоторые расширения могут быть реализованы как внутрипроцессные или как внепроцессные. Вы можете реализовать эти расширения как внепроцессные, если они не соответствуют этим требованиям для внутренних расширений. В следующем списке приведены примеры расширений, которые могут быть реализованы как расширения внутри процесса или вне процесса:
- IExecuteCommand, связанный с записью DelegateExecute, зарегистрированной в подразделе shell \ verb \ command.
- IDropTarget, связанный с CLSID, зарегистрированным в подразделе shell \ verb \ DropTarget.
- IExplorerCommandState, связанный с записью CommandStateHandler, зарегистрированной в подразделе shell \ verb.
SharpShell упрощает создание расширений оболочки Windows с помощью .NET Framework.
Исходный код размещен на https://github.com/dwmkerr/sharpshell - вы можете оставлять вопросы и запрашивать функции здесь или там.
Поддерживаемые расширения
Вы можете использовать SharpShell для создания любого из следующих расширений:
- Контекстные меню оболочки
- Обработчики значков
- Обработчики подсказок
- Обработчики сброса
- Обработчики предварительного просмотра
- Обработчики наложения значков
- Миниатюра Hanlders
- Расширение листа недвижимости
Проекты, использующие SharpShell
1. Контекстное меню Trello
2. REAL Shuffle Player 2.0
Серия статей в CodeProject