Windows shell extension avec C#

je voulais écrire une simple extension de shell windows à ajouter au menu contextuel, et C# est la langue que j'utilise le plus ces jours-ci. Est-ce un bon choix pour une extension shell? Les interfaces sont-elles faciles d'accès? Y a-t-il des frais généraux supplémentaires qui ralentissent l'apparition du menu?

quelqu'un a de bons conseils pour débuter?

35
demandé sur Pete McKinney 2010-02-03 21:54:59

3 réponses

Raymond post: Ne pas écrire d'extensions shell en cours de traitement dans le code géré.


Un suivi récent: maintenant que la version 4 du Framework .NET prend en charge les runtime in-process side-by-side, est-il possible d'écrire des extensions shell en code managé?

La ligne de fond est que, non, il n'est pas correct:

des Conseils pour la mise en œuvre dans les processus d'extensions a été révisé, et il continue la recommandation contre l'écriture d'extensions shell et D'extensions Internet Explorer (et d'autres types d'extensions en cours) en code géré, même si vous utilisez la version 4 ou plus.

24
répondu GSerg 2013-02-22 19:13:09

Au risque de ressembler à un complice, EZShellExtensions est un merveilleux (mais non libre) cadre pour l'extension d'environnement de développement en C#. Vous pouvez écrire une extension de menu de contexte simple avec environ 20 lignes de code et, le meilleur de tous, ne jamais avoir à jouer avec les interfaces COM. Mon entreprise l'utilise (et leur extension d'espace de noms) pour un ensemble d'extensions actuellement utilisées par des dizaines de milliers de clients et, pour ce que cela vaut, nous n'avons jamais eu de problème avec le CLR le conflit décrit ci-dessus.

voici un exemple rapide pour montrer à quel point c'est facile:

[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));
   }
}
14
répondu ladenedge 2010-02-03 20:23:44

des Conseils pour la mise en Œuvre Dans les Processus d'Extensions

Conflits De Version

un conflit de version peut survenir lors d'une exécution qui ne supporte pas le chargement de plusieurs versions d'exécution au sein d'un même processus. Les Versions du CLR antérieures à la version 4.0 entrent dans cette catégorie. Si le chargement d'une version d'un runtime empêche le chargement d'autres versions de ce même runtime, cela peut créer un conflit si l'hôte application ou un autre processus d'extension utilise un conflit de version. Dans le cas d'un conflit de version avec une autre extension en cours, le conflit peut être difficile à reproduire car la défaillance nécessite les extensions conflictuelles correctes et le mode de défaillance dépend de l'ordre dans lequel les extensions conflictuelles sont chargées.

envisager une extension en cours de fabrication écrite à l'aide d'une version du CLR antérieure à la version 4.0. Toutes les applications sur l'ordinateur qui utilise un fichier La boîte de dialogue ouverte peut potentiellement avoir le code géré de la boîte de dialogue et la dépendance CLR correspondante chargée dans le processus de l'application. L'application ou l'extension qui est la première à charger une version antérieure à la version 4.0 du PLC dans le processus de la demande limite quelles versions du PLC peuvent être utilisées par la suite par ce processus. Si une application gérée avec une boîte de dialogue ouverte est construite sur une version en conflit du CLR, alors l'extension pourrait ne pas fonctionner correctement et pourrait causer des échecs dans application. À l'inverse, si l'extension est la première à charger dans un processus et qu'une version conflictuelle du code managé essaie de lancer après cela (peut-être une application managée ou une application en cours d'exécution charge le CLR sur demande), l'opération échoue. Pour l'utilisateur, il apparaît que certaines fonctionnalités de l'application arrêtent de fonctionner au hasard, ou l'application se bloque mystérieusement.

notez que les versions de la CLR égales ou supérieures à la version 4.0 ne sont généralement pas susceptibles le problème des versions car elles sont conçues pour coexister entre elles et avec la plupart des versions pré-4.0 de la CLR (à l'exception de la version 1.0, qui ne peut pas coexister avec d'autres versions). Toutefois, des questions autres que des conflits de versions peuvent se poser, comme on l'a vu dans la suite du présent chapitre.

Performances

des problèmes de Performance peuvent surgir avec les durées d'exécution qui imposent une pénalité de performance significative lorsqu'elles sont chargé dans un processus. La pénalité de performance peut être sous forme d'utilisation de mémoire, D'utilisation de CPU, de temps écoulé, ou même de consommation d'espace d'adresse. Le CLR, JavaScript / ECMAScript et Java sont connus pour être des durées d'exécution à fort impact. Étant donné que les extensions en cours de fabrication peuvent être chargées dans de nombreux processus, et qu'elles le sont souvent à des moments sensibles aux performances (comme lors de la préparation d'un menu à afficher par l'utilisateur), les durées d'exécution à impact élevé peuvent avoir un impact négatif sur la réactivité globale.

Un un temps d'exécution à fort impact qui consomme des ressources importantes peut causer un échec dans le processus hôte ou une autre extension en cours. Par exemple, un temps d'exécution à fort impact qui consomme des centaines de mégaoctets d'espace d'adresse pour son tas peut empêcher l'application hôte de charger un grand ensemble de données. En outre, parce que les extensions en cours de processus peuvent être chargées dans plusieurs processus, la consommation élevée de ressources dans une seule extension peut rapidement se multiplier dans la consommation élevée de ressources à travers le tout le système.

si un runtime reste chargé ou continue de consommer des ressources même lorsque l'extension qui utilise ce runtime a déchargé, alors ce runtime n'est pas adapté pour une utilisation dans une extension.

questions propres au Cadre .NET

les sections suivantes présentent des exemples de problèmes liés à l'utilisation du code géré pour les extensions. Ils ne sont pas une liste complète de toutes les questions que vous peut rencontrer. Les questions discutées ici sont à la fois des raisons pour lesquelles le code géré n'est pas supporté dans les extensions et des points à considérer lorsque vous évaluez l'utilisation d'autres durées d'exécution.

  • re-entrancy

    Lorsque le CLR bloque un filetage monofiltre d'appartement (STA), par exemple, en raison d'un moniteur.Entrez, WaitHandle.WaitOne, ou l'énoncé de verrouillage contesté, le CLR, dans sa configuration standard, entre une boucle de message imbriquée pendant qu'il attend. De nombreuses méthodes d'extension sont interdites pour traiter les messages, et cette rentrée imprévisible et inattendue peut entraîner un comportement anormal qui est difficile à reproduire et à diagnostiquer.

  • Le Multi-Threaded Apartment Le CLR crée des Wrappers D'appel Runtime pour les objets Component Object Model (COM). Ces mêmes Wrappers sont détruits plus tard par le finalizer du CLR, qui fait partie de l'appartement multithreaded (MTA). Déménagement le proxy entre le STA et le MTA nécessite la mise en place d'un marshal, mais toutes les interfaces utilisées par les extensions ne peuvent pas être mises en place.

  • Durée De Vie Des Objets Non Déterministes

    Le CLR a des garanties de durée de vie d'objet plus faibles que le code natif. De nombreuses extensions ont des exigences de comptage de référence sur les objets et les interfaces, et le modèle de collecte des ordures employé par le CLR ne peut pas répondre à ces exigences.

    • si un objet CLR obtient une référence à un objet COM, la référence de L'objet COM détenue par le conteneur appelant Runtime n'est pas libérée tant que le conteneur appelant Runtime n'est pas collecté. Le comportement de libération non déterministe peut entrer en conflit avec certains contrats d'interface. Par exemple, la méthode IPersistPropertyBag::Load exige qu'aucune référence à la propriété bag ne soit retenue par l'objet lorsque la méthode Load retourne.
    • si une référence D'objet CLR est retournée au code natif, L'option Runtime Callable L'enrubanneur renonce à sa référence à L'objet CLR lorsque L'appel final de L'Enrubanneur appelable à L'exécution est fait, mais l'objet CLR sous-jacent n'est pas finalisé tant qu'il n'est pas ramassé. La finalisation non déterministe peut entrer en conflit avec certains contrats d'interface. Par exemple, les gestionnaires de vignettes sont tenus de libérer toutes les ressources immédiatement lorsque leur nombre de référence tombe à zéro.

utilisations acceptables du code géré et d'Autres Runtimes

il est acceptable d'utiliser du code géré et d'autres durées d'exécution pour implémenter des extensions hors processus. Voici des exemples d'extensions de Shell hors processus:

  • Aperçu des gestionnaires d'
  • actions basées sur la ligne de commande telles que celles enregistrées sous les sous-clés shell\verb\command.
  • les objets COM implémentés dans un serveur local, pour les points D'extension Shell qui permettent l'out-of-process activation.

certaines extensions peuvent être mises en œuvre sous forme d'extensions en cours ou hors processus. Vous pouvez mettre en œuvre ces prorogations à titre de prorogations hors processus si elles ne satisfont pas aux exigences relatives aux prorogations en cours de traitement. La liste suivante présente des exemples d'extensions qui peuvent être mises en œuvre sous forme d'extensions en cours ou d'extensions hors processus:

  • IExecuteCommand associé à un DelegateExecute entrée enregistrée en vertu d'une shell\verbe\command clé.
  • IDropTarget associé au CLSID enregistré sous une sous-clé shell\verb\DropTarget.
  • IExplorerCommandState associé à un CommandStateHandler entrée enregistrée sous un shell\verbe sous-clé.

SharpShell

SharpShell facilite la création d'Extensions de Shell Windows à L'aide du Framework .NET.

le code source est hébergé sur https://github.com/dwmkerr/sharpshell - Vous pouvez poster des questions et des demandes de fonctionnalités ici ou là. Les Extensions Prises En Charge

vous pouvez utiliser SharpShell pour construire l'une des extensions ci-dessous:

  • Menus De Contexte Shell
  • Gestionnaires D'Icône
  • Info-Bulle Des Gestionnaires D'
  • Baisse Des Gestionnaires D'
  • Aperçu Des Gestionnaires D'
  • Icône De Recouvrement Des Gestionnaires D'
  • vignette Hanlders
  • Propriété Feuille Extensions

projets qui utilisent SharpShell

1. Trello Menu Contextuel

2. RÉEL Shuffle Lecteur 2.0

Série d'Article sur CodeProject

11
répondu Ehsan Mohammadi 2014-02-09 02:30:29