L'intégration au shell Windows aujourd'hui ── menu contextuel, associations de fichiers et les changements de Windows 11

· Mis à jour le: · · Windows, Extensions du shell, Menu contextuel, Association de fichiers, COM, Windows 11, Explorateur de fichiers, MSIX, Développement Windows

Historique des révisions (première version, publiée le 20 Aug 2026)
Première publication
Citer cet article(DOI (archive enregistrée): 10.5281/zenodo.22176258)

Les DOI ci-dessous renvoient à des versions déjà archivées et peuvent différer du texte actuel. Pour citer le texte actuel, utilisez l’URL de cette page.

Go Komura (2026). L'intégration au shell Windows aujourd'hui ── menu contextuel, associations de fichiers et les changements de Windows 11. KomuraSoft LLC. https://comcomponent.com/fr/blog/windows-shell-integration-context-menu-file-association/

DOI (archive enregistrée)
10.5281/zenodo.22176258
DOI (dernière version enregistrée)
10.5281/zenodo.22176259

« Après le passage à Windows 11, on ne trouve plus le menu contextuel de notre application. » En vérifiant, l’élément n’a pas disparu : il apparaît si l’on ouvre « Afficher plus d’options » en bas du menu. Ce qui se passe dans cette consultation n’est pas une panne, mais un changement de conception du menu sous Windows 11. Sur le terrain, cela devient « un clic de plus », « on ne trouve pas l’élément ».

Toutefois, « ouvrir un fichier avec cette application » et « faire apparaître une commande propre dans le nouveau menu contextuel » sont des réponses distinctes. Si l’on commence à écrire une DLL d’extension de shell sans cette séparation, on complique même une exigence qui n’aurait besoin que d’un enregistrement d’association.

Cet article s’adresse aux responsables informatiques des PME et aux développeurs Windows qui ont la charge d’applications métier. Il relie le fondement des associations, la différence entre anciens et nouveaux menus, le choix du mode d’implémentation, l’enregistrement et la suppression dans l’installateur, et le triage des pannes.

1. D’abord la conclusion

Le fondement des associations et des verbs n’a pas changé ; sous Windows 11, c’est la façon de montrer le menu qui s’est scindée en ancien et nouveau. On décide d’abord « ce que l’on veut réaliser », et l’on ne choisit que le mécanisme nécessaire.

Si l’on veut seulement « ouvrir », partir de l’association et du verb statique

Le fondement de l’association de fichiers est une structure en trois étages dans le registre : clé d’extension → ProgID → verb. La clé d’extension pointe vers un ProgID, et shell\<verb>\command sous le ProgID détient la ligne de commande à lancer. Si l’on veut seulement « ouvrir avec cette application », cet enregistrement et un verb statique suffisent encore, et une DLL d’extension de shell n’est pas nécessaire. Microsoft elle-même indique de commencer par le verb statique le plus simple qui satisfait l’exigence.12

La destination d’enregistrement est HKLM pour tous les utilisateurs, HKCU par utilisateur. HKCR est une vue fusionnée qui superpose les Classes des deux, donc on écrit en indiquant HKLM ou HKCU, et l’on traite HKCR comme confirmation.3

De plus, l’enregistrement comme candidat et le choix comme application par défaut sont distincts. L’application par défaut qui s’ouvre au double-clic est choisie par l’utilisateur, et l’OS protège ce choix. Le travail côté application n’est pas que l’installateur vole la valeur par défaut, mais qu’il s’enregistre correctement comme candidat.4

Pour faire apparaître une commande propre dans le nouveau menu, IExplorerCommand et une identité de paquet sont nécessaires

Sous Windows 11, une extension IContextMenu classique est déplacée vers l’ancien menu ouvert par « Afficher plus d’options » (Maj+F10). Pour charger une commande propre dans le nouveau menu, il faut une implémentation d’IExplorerCommand et une identité de paquet.56

La voie officielle est d’enregistrer une DLL native qui implémente IExplorerCommand dans le manifeste MSIX (desktop4:FileExplorerContextMenus). Si l’on ne peut pas empaqueter entièrement une application existante en MSIX, on peut n’accorder que l’identité avec un sparse package (MSIX avec emplacement externe).67

Penser aussi à la sûreté de la DLL et au nettoyage à la désinstallation

Une extension de shell classique est une DLL COM chargée dans le processus de l’Explorateur, entre autres. Un plantage ou un retard de l’extension se propage à l’hôte tout entier. Un hôte 64 bits a besoin d’une DLL 64 bits, et implémenter une extension in-process en code managé n’est pas pris en charge.89

Après un enregistrement, un changement ou une suppression d’association, on notifie avec SHChangeNotify(SHCNE_ASSOCCHANGED). À la désinstallation, on supprime son propre ProgID, etc., et l’on laisse la valeur par défaut de la clé d’extension, selon le guide officiel. L’intégration au shell, ce n’est pas seulement faire apparaître un menu : c’est aussi la prise d’effet du changement et le nettoyage.110

Lecture selon le but

Ce que l’on veut savoir, ou le symptôme Où le lire
Quel mode d’implémentation choisir Tableau de décision du chapitre 6. On sépare une association seulement d’une commande propre ajoutée au nouveau menu
Prendre en charge le double-clic et « Ouvrir avec » Associations du chapitre 2 et verbs statiques du chapitre 3
Enregistré, mais ce n’est pas l’application par défaut UserChoice de la section 2.4. On sépare l’enregistrement comme candidat et le choix de l’utilisateur
Sous Windows 11, le menu s’est enfoncé d’un cran Ancien et nouveau menus du chapitre 5. La méthode : section 5.2 ; si l’on ne peut pas passer en MSIX : section 5.3
Que l’installateur doit enregistrer et retirer Chapitre 7. En particulier l’enregistrement par utilisateur de la section 7.3 et le nettoyage de la section 7.4
Le menu n’apparaît pas, apparaît en double, ou l’Explorateur est lent Triage du chapitre 8. Les contraintes de DLL : chapitre 4

Pour apprendre depuis le mécanisme, on lit à partir du chapitre 2 ; pour décider la ligne d’une application existante, à partir du chapitre 6.

Dans le diagramme, un trait continu marque une relation qui vaut toujours et un trait pointillé une relation conditionnelle (les conditions figurent dans l’explication de chaque relation sur la page de détail). La liste complète des relations (16 au total, avec preuve et niveau de certitude) et les définitions des concepts principaux sont rassemblées sur la page de détail de la carte des connaissances (en japonais). Données : JSON-LD / Turtle

2. Le mécanisme de l’association de fichiers ── structure en trois étages, clé d’extension → ProgID → verb

Ce chapitre organise dans l’ordre enregistrement côté fichier → destination d’écriture → enregistrement côté application → choix de l’utilisateur. Le fondement, la clé d’extension pointe vers un ProgID, le verb détient la ligne de commande, et une extension plus élaborée tourne comme DLL COM in-process, n’a pas changé depuis plus de vingt ans.

2.1. Lire la structure en trois étages sur un exemple

On commence par voir la forme de base de l’association sur un exemple. La clé d’extension pointe vers un ProgID, et le verb à l’intérieur détient la commande à lancer.1 La relation de priorité quand l’utilisateur a choisi une application par défaut est expliquée en 2.4.

HKEY_CLASSES_ROOT
   .kmrpt                                  ← (1) clé d'extension
      (Default) = KomuraSoft.Report.1      ←     pointeur qui ne fait que viser un ProgID
      OpenWithProgids
         KomuraSoft.Report.1               ←     candidat de « Ouvrir avec »
   KomuraSoft.Report.1                     ← (2) ProgID (réalité de l'association)
      (Default) = Document Rapport KomuraSoft
      DefaultIcon
         (Default) = "C:\Program Files\KomuraSoft\Report.exe",0
      shell                                ← (3) liste des verbs (verbes)
         open
            command
               (Default) = "C:\Program Files\KomuraSoft\Report.exe" "%1"
  • (1) La clé d’extension (.kmrpt) ne fait, dans sa valeur par défaut, que viser le nom d’un ProgID. Y écrire directement une commande est une erreur.
  • (2) Le ProgID (KomuraSoft.Report.1) est la réalité de l’association ; il détient le nom affiché, l’icône et la liste des verbs.
  • (3) Le verb est un verbe tel que « ouvrir » ou « imprimer », et la valeur par défaut de shell\open\command est la ligne de commande réellement lancée.

Grâce à cette séparation, on peut diriger plusieurs extensions (.kmrpt et .kmrpt-file, etc.) vers le même ProgID, ou remplacer le ProgID lors d’une montée de version de l’application.

Structure en trois étages de l'association de fichiersLa clé d'extension n'est qu'un pointeur qui vise un ProgID dans sa valeur par défaut ; le ProgID est la réalité qui détient le nom affiché, l'icône et la liste des verbs ; la valeur par défaut de command sous le verb est la ligne de commande réellement lancéevise un ProgID dans la valeur par défautClé d'extension .kmrptProgID KomuraSoft.Report.1verb (open sous shell, etc.)Valeur par défaut de commandReport.exe est lancéDétient aussi le nom affiché et DefaultIcon

Figure 1 : La clé d’extension est un pointeur, le ProgID est la réalité, command du verb est la ligne de commande réellement lancée.

2.2. HKCR est une « vue fusionnée » ── où l’on écrit change le sens

L’exemple ci-dessus est montré sous HKEY_CLASSES_ROOT (HKCR), mais HKCR n’est pas un emplacement de stockage physique : c’est une vue fusionnée qui superpose HKLM\Software\Classes et HKCU\Software\Classes. Si la même clé est des deux côtés, le côté HKCU gagne.3

HKCR est une vue fusionnéeHKCR est la superposition des Classes de HKLM et de HKCU ; si la même clé est des deux côtés, HKCU a priorité ; l'écriture d'un enregistrement indique HKLM ou HKCU, et HKCR se traite en lectureHKLM\Software\Classes (tous les utilisateurs)HKCR (vue fusionnée)HKCU\Software\Classes (par utilisateur)Si la même clé est des deux côtés, HKCU gagneOn se limite à la lecture (confirmation)

Figure 2 : HKCR est l’apparence superposée des Classes de HKLM et de HKCU ; la destination d’écriture indique forcément l’un des deux.

Destination d’écriture Sens Privilèges nécessaires
HKLM\Software\Classes Enregistrement commun à tous les utilisateurs Privilèges d’administrateur
HKCU\Software\Classes Enregistrement pour cet utilisateur seulement Non nécessaires
Écrire directement dans HKCR Réparti selon l’emplacement de la clé existante Selon le cas

En pratique, le sûr est de toujours écrire l’enregistrement en indiquant HKLM ou HKCU, et de traiter HKCR en lecture (confirmation).

Ne pas confondre les données d’association et le bitness de l’enregistrement COM

Dans la redirection de registre WOW64, le traitement diffère entre données d’association et enregistrement COM. Les données d’association directement sous HKLM\Software\Classes, clés d’extension et ProgID, sont partagées entre les vues de registre 32 bits et 64 bits depuis Windows 7, donc un installateur 32 bits qui les écrit ne s’échappe pas du côté Wow6432Node.

En revanche, certaines sous-clés d’enregistrement COM telles que Classes\CLSID sont redirigées, et lors de l’enregistrement d’une extension de shell (COM in-process) évoquée plus bas, la scission d’écriture 32 bits / 64 bits compte. Les détails sont dans « Redirection et virtualisation du registre 32 bits/64 bits ».

2.3. Enregistrement côté application ── App Paths, Applications, RegisteredApplications

En vis-à-vis du côté fichier (extension et ProgID), il y a aussi trois types d’enregistrement côté application.11

  • App Paths (HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths) : enregistrement qui permet de lancer depuis ShellExecuteEx avec le seul nom de l’exécutable. On évite de salir la variable d’environnement PATH, donc Microsoft le recommande.
  • Applications (HKCR\Applications\<app.exe>) : définit la façon d’ouvrir par défaut quand un fichier quelconque est passé depuis « Ouvrir avec », et le nom affiché de l’application (FriendlyAppName).
  • RegisteredApplications + Capabilities : déclare les extensions et types MIME que l’application sait traiter, et sert à figurer comme candidat dans l’écran des applications par défaut de Windows.

La plupart des consultations « notre application n’apparaît pas dans la liste des applications par défaut » sont des cas où le ProgID est enregistré, mais cet enregistrement Capabilities a été omis.

Trois types d'enregistrement côté applicationL'enregistrement côté application a trois types, App Paths, Applications et RegisteredApplications, qui portent respectivement le lancement par le seul nom de fichier, la façon d'ouvrir par défaut depuis Ouvrir avec, et la présence dans l'écran des applications par défautEnregistrement côté applicationApp PathsApplicationsRegisteredApplicationsLancer par le seul nom de fichierOuverture par défaut de Ouvrir avecFigurer dans l'écran des applications par défautLa déclaration Capabilities est une condition

Figure 3 : Il y a trois types d’enregistrement côté application ; figurer comme candidat dans l’écran des applications par défaut exige un enregistrement Capabilities.

2.4. L’application par défaut appartient à l’utilisateur ── la protection de UserChoice

Écrire un ProgID dans la valeur par défaut de la clé d’extension ne suffit pas forcément à devenir l’application par défaut. Le résultat d’un choix explicite de l’utilisateur dans « Ouvrir avec », etc., est conservé dans HKCU\...\Explorer\FileExts\<extension>\UserChoice, et c’est celui-ci qui a priorité dans la résolution de l’association.

Ne pas concevoir une réécriture directe de UserChoice

Windows ne prend pas en charge le changement programmatique de l’application par défaut. Le paramétrage des applications par défaut est conçu pour que l’utilisateur le fasse via l’interface Paramètres du système ; les données UserChoice sont obscurcies, et un pilote-filtre (UCPD.sys) bloque les écritures depuis les applications. Dans un environnement géré, la stratégie de groupe / MDM est le moyen officiel.4

Que des outils tels que SetUserFTA, qui « imitent le hachage pour réécrire », aient été utilisés par le passé est le revers de cette protection.

L’installateur prépare à « être choisi »

Ce que l’on intègre dans l’installateur de son application, ce sont les trois points suivants.

  1. Enregistrer correctement le ProgID et les verbs.
  2. S’ajouter à OpenWithProgIds.
  3. Au besoin, orienter l’utilisateur vers l’écran des applications par défaut.

On ne vole pas la valeur par défaut ; on prépare un état où l’utilisateur peut choisir.

Résolution de l'application par défaut et protection de UserChoiceLe résultat d'un choix explicite de l'utilisateur est conservé dans UserChoice et a priorité dans la résolution de l'association ; UCPD.sys bloque une réécriture depuis une application, donc ce qu'un installateur peut faire s'arrête à l'enregistrement comme candidat et à l'orientation vers l'écran des paramètresprioritéUCPD.sys bloqueUserChoice (choix de l'utilisateur)Résolution de l'associationValeur par défaut de la clé d'extensionRéécriture depuis une applicationTravail de l'installateurEnregistrement du ProgID et des verbsAjout à OpenWithProgIdsOrientation vers l'écran des paramètres

Figure 4 : Dans la résolution de l’association, le choix de l’utilisateur (UserChoice) a priorité, et l’OS protège contre une réécriture depuis une application.

3. Les verbs autres que « ouvrir » ── print, edit, runas, verb personnalisé

3.1. Verbs standard et verbs personnalisés

Un verb n’est pas seulement open. Les verbs standard dont l’OS connaît le sens comprennent, outre open, edit, print, play, preview, etc., et un verb standard reçoit automatiquement un nom affiché selon les paramètres régionaux de l’OS. Le verb par défaut utilisé au double-clic se décide dans l’ordre valeur par défaut de la clé shell → premier verb dans le registre → open → openwith.12

Ordre de décision du verb par défautLe verb par défaut utilisé au double-clic se décide comme le premier trouvé, dans l'ordre valeur par défaut de la clé shell, premier verb dans le registre, open, openwithsinonsinonsinonValeur par défaut de la clé shellPremier verb dans le registreopenopenwith

Figure 5 : Le verb par défaut au double-clic est le premier trouvé dans cet ordre.

Pour ajouter un verbe propre, on enregistre un verb personnalisé.

KomuraSoft.Report.1
   shell
      open
         command
            (Default) = "C:\Program Files\KomuraSoft\Report.exe" "%1"
      print
         command
            (Default) = "C:\Program Files\KomuraSoft\Report.exe" /print "%1"
      verify                          ← verb personnalisé
         (Default) = Vérifier le rapport(&V)   ← nom affiché du menu
         command
            (Default) = "C:\Program Files\KomuraSoft\Report.exe" /verify "%1"

3.2. Distinguer l’élévation, l’affichage avec Maj, et l’ancien DDE

Un verb peut aussi porter des spécifications comme suit.

  • Enregistrer un verb runas définit un lancement élevé équivalent à « Exécuter en tant qu’administrateur », et sert aussi à un lancement qui spécifie runas depuis les API de type ShellExecute.
  • Placer une valeur vide Extended sur la clé du verb en fait un verb étendu, affiché seulement si l’on clique avec le bouton droit en maintenant Maj. Utile pour cacher une opération dangereuse rarement utilisée.12
  • Dans l’association d’une ancienne application, il reste parfois une configuration qui envoie un document à un processus existant par DDE (clé ddeexec), mais le lancement d’un verb par DDE est déjà un héritage déconseillé (Deprecated). Il n’y a aucune raison d’en écrire un nouveau.12

3.3. Entourer de guillemets le chemin de l’EXE et le chemin du fichier sélectionné

Ce qui cause souvent un accident, ce sont les guillemets de la ligne de commande. Si un élément de la chaîne de commande peut contenir un espace, il faut forcément l’entourer de guillemets. Un chemin d’EXE tel que C:\Program Files\... bien sûr, et %1 (chemin du fichier sélectionné) doit toujours s’écrire "%1". On ne peut pas garantir que le chemin de fichier de l’utilisateur ne contiendra pas d’espace. Un My Program.exe sans guillemets s’interprète comme « lancer My avec l’argument Program.exe ».13

Accident des guillemets de la ligne de commandeUne commande sans guillemets est coupée à l'espace et mal interprétée comme lancer My avec l'argument Program.exe, donc un chemin d'EXE qui peut contenir un espace et %1, qui représente le chemin du fichier sélectionné, s'entourent toujours de guillemetscoupé à l'espacecommand sans guillemetsMal interprété comme le lancement d'un autre EXEcommand avec guillemetsLancé comme prévuEntourer le chemin d'EXE de guillemetsEntourer aussi %1 toujours de guillemets

Figure 6 : Une commande sans guillemets est mal coupée à l’espace, donc le chemin d’EXE et %1 s’entourent toujours de guillemets.

3.4. Avant d’écrire une DLL, confirmer si un verb statique suffit

Le mécanisme par le seul registre vu jusqu’ici (verb statique) se réalise sans écrire une seule DLL, et sans risque de rendre l’Explorateur instable. Microsoft elle-même répète : « avant d’écrire une extension de shell, examiner si le verb statique le plus simple qui satisfait l’exigence ne suffit pas ».2

4. Extension de shell classique ── une DLL qui tourne dans l’Explorateur

Ce que ce chapitre retient, c’est qu’une DLL d’extension classique tourne dans le processus de l’Explorateur, etc. Comprendre le lieu d’exécution relie les contraintes de stabilité, de bitness et de langage d’implémentation.

4.1. Types d’extensions de shell

Pour des exigences que le verb statique ne couvre pas, « changer dynamiquement le menu selon la sélection », « remplacer l’icône ou l’écran des propriétés », on utilise un gestionnaire d’extension de shell. Les types représentatifs sont les suivants.8

Gestionnaire Interface principale Ce qu’il peut faire
Gestionnaire de menu contextuel IContextMenu + IShellExtInit Ajouter et contrôler dynamiquement des éléments de menu
Gestionnaire d’icône / superposition d’icône IExtractIcon / IShellIconOverlayIdentifier Icône par fichier, superposition
Gestionnaire de feuille de propriétés IShellPropSheetExt Ajouter un onglet à l’écran des propriétés
Miniatures / infobulle IThumbnailProvider / IQueryInfo Affichage réduit, description au survol
Glisser-déposer / gestionnaire de copie IDropTarget / ICopyHook Intervention au dépôt, à la copie et au déplacement

Tous s’implémentent comme classe COM, et le CLSID s’enregistre dans le registre. Pour la façon de penser COM elle-même, voir « Qu’est-ce que COM / ActiveX / OCX ? ».

4.2. Ce que signifie d’être un serveur COM in-process

L’essentiel d’une extension de shell classique, c’est d’être un serveur COM in-process (DLL) chargé dans le processus de l’Explorateur (ou de toute application qui a ouvert une boîte de dialogue de fichiers commune). Tous les points d’attention en découlent.8

  • Si l’extension plante, l’Explorateur plante avec elle. Si elle se bloque, le clic droit se fige quelques secondes. Et le dégât ne se limite pas à l’Explorateur : il atteint toutes les applications qui ont affiché une boîte de dialogue d’ouverture de fichier.
  • La construction du menu se fait sur le thread d’interface, donc il ne faut pas, à l’affichage du menu, faire un traitement lent tel qu’un accès réseau ou des E/S de fichiers.
  • Le modèle de threading s’enregistre en principe en Apartment.
Structure d'entraînement d'une extension in-processUne DLL d'extension de shell est chargée non seulement dans l'Explorateur mais aussi dans le processus de toute application qui ouvre une boîte de dialogue de fichiers, donc un plantage ou un blocage de l'extension se propage à l'ensemble du processus hôtechargée dans le processuschargée dans le processusDLL d'extension de shellExplorateurToute application qui ouvre une boîte de dialogueLe plantage ou le blocage se propageNe pas faire de traitement lent à l'affichage

Figure 7 : Une DLL d’extension tourne dans le processus hôte, donc un plantage ou un blocage se propage à l’hôte tout entier.

Quand on enquête sur « l’Explorateur se fige en ouvrant un dossier particulier », « le clic droit prend 5 secondes », il n’est pas rare que la cause ne soit pas son application, mais une extension de shell tierce. La méthode de triage est traitée au chapitre 8.

4.3. Correspondance de bitness ── en 64 bits, une DLL 64 bits est obligatoire

Une DLL in-process doit avoir le même bitness que le processus qui la charge. L’Explorateur de Windows 64 bits est un processus 64 bits, donc une DLL d’extension de shell compilée seulement en 32 bits n’est tout simplement pas chargée, et n’apparaît jamais dans le menu. Il n’y a pas d’erreur non plus, donc c’est une cause classique de « enregistré, mais ça n’apparaît pas ».

Il n’est pas nécessaire de passer aussi le corps de l’application en 64 bits

La combinaison d’un corps d’application 32 bits et d’une DLL d’extension de shell 64 bits est une configuration légitime, mais il faut noter que l’enregistrement COM se scinde par bitness (Wow6432Node). En outre, ce qui est lancé depuis le command d’un verb est un EXE d’un autre processus, donc il n’est pas soumis à cette contrainte (rester en EXE 32 bits ne pose pas de problème).

Correspondance de bitness d'une DLL d'extension de shellSeule une DLL d'extension de shell 64 bits peut être chargée dans l'Explorateur 64 bits ; une DLL seulement 32 bits n'apparaît pas dans le menu, sans erreur ; un EXE lancé depuis le command d'un verb est un autre processus, donc n'est pas soumis à la contraintepeut chargerne peut pas chargerautre processusExplorateur 64 bitsDLL d'extension de shell 64 bitsDLL seulement 32 bitsN'apparaît pas dans le menu, sans erreurEXE lancé par un verbRester en 32 bits ne pose pas de problème

Figure 8 : Seule une DLL 64 bits est chargée dans l’Explorateur 64 bits ; un EXE lancé par un verb n’est pas soumis à cette contrainte.

4.4. Pourquoi il ne faut pas écrire en code managé

On reçoit souvent la question « peut-on écrire une extension de shell en C# ? », mais Microsoft déconseille d’écrire une extension de shell in-process en code managé (.NET) et déclare explicitement qu’elle n’est pas prise en charge.9

La raison tient à la nature de l’extension, chargée dans un processus quelconque. Les facteurs qui rendent l’application hôte instable sont surtout les trois suivants.

  • Collision de version du CLR. Surtout un problème en dessous de .NET Framework 4.
  • Réentrance. Il y a un problème de réentrance dans la boucle de messages du CLR en attente de verrou.
  • Durée de vie des objets. La non-déterminisme de la durée de vie par le ramasse-miettes entre en collision avec le contrat de comptage de références de COM.

Certains points ont été atténués à partir de .NET Framework 4 et dans le .NET moderne, mais la position officielle n’a pas changé.

La ligne pratique est simple. Une extension in-process s’écrit en C++ natif. Si l’on veut du code managé, on en fait un EXE ordinaire lancé depuis le command d’un verb, ou une extension hors processus qui tourne dans un autre processus (gestionnaire d’aperçu, etc.).9

Jugement de la possibilité du code managéUne extension in-process qui tourne dans le processus de l'Explorateur s'écrit en principe en C++ natif ; si l'on veut du code managé, on en fait un EXE ordinaire lancé depuis le command d'un verb, ou une extension hors processus qui tourne dans un autre processusOuiNonExtension qui tourne dans le processus ?Écrire en C++ natifLe code managé convientCollision CLR ou réentrance rendent l'hôte instableEXE ordinaire lancé par un verbExtension d'un autre processus, aperçu, etc.

Figure 9 : Une extension in-process s’écrit en principe en C++ natif ; le code managé se limite à une configuration qui tourne dans un autre processus.

5. Le nouveau menu contextuel de Windows 11 ── dédoublement du menu

Ici, on explique dans l’ordre pourquoi cela a été déplacé vers l’ancien menu → enregistrement dans le nouveau menu → comment conserver l’installateur existant. La différence entre une association qui ne fait que « ouvrir avec cette application » et l’ajout d’une commande propre se confirme en 5.4.

5.1. Ce qui s’est passé

Windows 11 a renouvelé le menu contextuel de l’Explorateur. Couper, copier, etc. deviennent une rangée d’icônes en haut, « Ouvrir » et « Ouvrir avec » sont regroupés en haut, et les commandes ajoutées par une application sont groupées sous les commandes standard du shell. Si une application ajoute plusieurs commandes, elles sont rassemblées dans un menu volant (sous-menu) portant le nom de l’application.5

Et le point essentiel est celui-ci. Une extension de shell fondée sur IContextMenu classique n’a pas été supprimée : elle a été déplacée vers l’ancien menu, qui charge tel quel le menu de Windows 10, ouvert par « Afficher plus d’options » (Maj+F10).5 Le « le menu s’est caché » de la consultation du début, c’est ce dédoublement.

Menu contextuel dédoublé sous Windows 11Ce qui s'ouvre d'abord au clic droit est le nouveau menu, et n'y figurent que les commandes enregistrées avec IExplorerCommand et une identité de paquet ; une extension IContextMenu classique est déplacée vers l'ancien menu ouvert par Afficher plus d'optionsAfficher plus d'options Maj+F10Clic droit sur un fichierNouveau menu (Windows 11)Commande IExplorerCommand + identitéAncien menu (menu de Windows 10)Extension IContextMenu classiquePlusieurs commandes se rassemblent dans un menu volant

Figure 10 : Seules les commandes IExplorerCommand + identité figurent dans le nouveau menu ; une extension classique est déplacée vers l’ancien menu.

5.2. Voie officielle pour figurer dans le nouveau menu ── IExplorerCommand + enregistrement de manifeste

La voie officielle pour faire apparaître une commande propre dans le nouveau menu est une DLL native qui implémente IExplorerCommand, et un enregistrement dans le manifeste MSIX.6

Le manifeste porte deux types de déclarations

L’exemple suivant déclare, en première moitié, le serveur COM (CLSID et DLL d’implémentation), et en seconde moitié, l’extension de menu contextuel (cible et commande). Ce qui relie les deux, c’est le même CLSID.

<!-- Manifeste du paquet (extrait) -->
<com:Extension Category="windows.comServer">
  <com:ComServer>
    <com:SurrogateServer DisplayName="Komura commands">
      <com:Class Id="01234567-89AB-CDEF-0123-456789ABCDEF"
                 Path="KomuraCommand.dll" ThreadingModel="STA" />
    </com:SurrogateServer>
  </com:ComServer>
</com:Extension>
<desktop4:Extension Category="windows.fileExplorerContextMenus">
  <desktop4:FileExplorerContextMenus>
    <desktop5:ItemType Type=".kmrpt">
      <desktop5:Verb Id="VerifyReport"
                     Clsid="01234567-89AB-CDEF-0123-456789ABCDEF" />
    </desktop5:ItemType>
  </desktop4:FileExplorerContextMenus>
</desktop4:Extension>

Le Type de ItemType peut spécifier, outre une extension particulière, * (tous les fichiers), Directory (dossier), Directory\Background (arrière-plan d’un dossier). La DLL s’aligne sur l’architecture de l’Explorateur (64 bits / ARM64).6

Les méthodes de construction du menu doivent renvoyer vite

IExplorerCommand elle-même est une interface qui existe depuis l’époque de Windows 7 ; on implémente le titre (GetTitle), l’icône (GetIcon), l’état activé / désactivé / masqué (GetState), l’exécution (Invoke). Les méthodes sont appelées depuis le thread d’interface, donc l’accès à une ressource réseau est interdit, et les méthodes de construction du menu doivent renvoyer vite. Un traitement lourd se fait après Invoke.146

Structure de manifeste de l'enregistrement dans le nouveau menuLa déclaration de serveur COM du manifeste MSIX associe CLSID et DLL ; la déclaration d'extension de menu contextuel relie cible et implémentation par ItemType et Verb, ce qui fait afficher une commande propre dans le nouveau menuassocie CLSID et DLLspécifie par ItemType et VerbManifeste MSIXDéclaration de serveur COMDéclaration d'extension de menuDLL d'implémentation IExplorerCommandCommande affichée dans le nouveau menuLa cible est une extension, tous les fichiers, etc.

Figure 11 : Les deux déclarations du manifeste relient la DLL d’implémentation et la cible, et la commande figure dans le nouveau menu.

5.3. Option pour une application non empaquetée ── n’obtenir que l’identité avec un sparse package

La porte de sortie quand « notre application ne peut se distribuer qu’en MSI ; le passage en MSIX est impossible » est le sparse package (MSIX avec emplacement externe). On signe un petit MSIX qui ne contient pas le corps de l’application, seulement un manifeste, et on l’enregistre à la fin de l’installateur existant. L’application obtient ainsi une identité de paquet, et l’enregistrement de manifeste ci-dessus (= affichage dans le nouveau menu) devient possible.

On peut l’utiliser à partir de Windows 10 version 2004, et le paquet doit porter une signature par un certificat de confiance sur la machine cible.7 L’ordre d’enregistrement et de retrait, et l’attention au fait que l’enregistrement est par utilisateur, sont traités en section 7.3.

Flux pour obtenir une identité avec un sparse packageAprès que l'installateur existant a placé le corps de l'application, enregistrer un sparse package de manifeste seulement avec emplacement externe fait obtenir à l'application une identité de paquet, et l'enregistrement de manifeste dans le nouveau menu devient possibleInstallateur existantPlacer le corps de l'applicationsparse packageManifeste seulement, pas de corpsEnregistrer avec emplacement externeObtenir une identité de paquetL'enregistrement dans le nouveau menu devient possibleUne signature de confiance est nécessaire

Figure 12 : Enregistrer un sparse package sans le corps, avec emplacement externe, fait obtenir à l’application une identité de paquet.

Le plus grand avantage est de n’avoir pas à remplacer l’installateur ; c’est la solution réaliste pour une application qui a un actif d’installateur MSI/EXE existant. Pour la comparaison avec une migration complète vers MSIX, voir aussi « Choisir une méthode de distribution d’application Windows ».

5.4. Comment un verb d’association se voit dans le nouveau menu

Un point souvent mal compris : l’association des chapitres 2 et 3 (ProgID et verb) reste vivante aussi dans le nouveau menu. Le verb par défaut du double-clic, « Ouvrir », les candidats de « Ouvrir avec » se résolvent depuis l’association et s’affichent en haut du nouveau menu. Autrement dit, si l’on veut seulement « pouvoir ouvrir avec cette application », Windows 11 n’exige aucun ajout.

En revanche, une association n’est pas une extension de menu générique, donc pour faire apparaître une commande personnalisée quelconque au premier niveau du nouveau menu, IExplorerCommand + identité est nécessaire : tel est le partage des rôles.6

Partage des rôles entre association et nouveau menuL'association ProgID et verb sert encore dans le nouveau menu à résoudre le verb par défaut du double-clic, Ouvrir et Ouvrir avec, et s'affiche en haut ; pour faire apparaître une commande personnalisée quelconque au premier niveau du nouveau menu, IExplorerCommand et une identité sont nécessairesAssociation (ProgID et verb)Résolution du verb par défaut et de OuvrirAffiché en haut du nouveau menuAucun ajout n'est nécessaire sous Windows 11Commande personnalisée quelconqueIExplorerCommand + identitéAffiché au premier niveau du nouveau menu

Figure 13 : L’association porte encore, dans le nouveau menu, la résolution de la famille « ouvrir » ; seules les commandes personnalisées exigent IExplorerCommand + identité.

6. Tableau de décision pratique ── laquelle des trois options prendre

On confirme d’abord si (a) suffit, et si l’affichage d’une commande propre dans le nouveau menu est nécessaire, on choisit (b). Maintenir pour l’instant une extension classique existante, c’est (c).

Ce que l’on veut réaliser Moyen recommandé Apparence sous Windows 11 Travail et coût nécessaires
(a) Lancer son application au double-clic ou par « Ouvrir » Association + verb statique (enregistrement de registre seulement) Affichage intégré dans « Ouvrir » et « Ouvrir avec » du nouveau menu Enregistrement de registre de l’installateur seulement. Pas de DLL, pas d’exigence supplémentaire de signature
(b) Faire apparaître une commande propre, sur le fichier ou le dossier sélectionné, dans le nouveau menu Implémentation IExplorerCommand + enregistrement de manifeste MSIX. Une application non empaquetée accorde l’identité avec un sparse package Premier niveau du nouveau menu (plusieurs commandes se rassemblent dans un menu volant au nom de l’application) DLL C++ native + identité de paquet + signature de code
(c) Continuer d’utiliser une extension IContextMenu classique existante Maintenir telle quelle pour l’instant (ne pas choisir pour un nouveau développement) Ancien menu seulement, « Afficher plus d’options » (Maj+F10) Maintien de la compilation 64 bits et de l’enregistrement COM. Prévoir plus tard une migration vers (b)

Décision 1 : choisir la méthode la plus simple qui satisfait l’exigence

Le premier point est de ne pas sortir (b) ou (c) pour une exigence que (a) couvre. Dès que l’on écrit une extension de shell, on porte la responsabilité de la stabilité de l’Explorateur.

Décision 2 : séparer le maintien de l’ancien menu et l’amélioration de l’usage

(c) n’est que « ce n’est pas cassé » ; du point de vue de l’expérience utilisateur, on reste dans une position d’un cran inférieure. Plus une commande est fréquente dans l’usage quotidien, plus le rapport investissement / effet d’une migration vers (b) est grand.

Comment choisir parmi les trois optionsSi l'on veut seulement lancer au double-clic ou par Ouvrir, association et verb statique suffisent ; pour une commande propre dans le nouveau menu, IExplorerCommand et enregistrement de manifeste MSIX ; si l'on ne peut pas passer en MSIX, accorder l'identité avec un sparse package ; une extension IContextMenu classique existante se maintient pour l'instant du côté de l'ancien menuOuiNonOuiOuiNonNonSeulement ouvrir ?Association + verb statiqueCommande propre dans le nouveau menu ?Peut-on passer en MSIX ?IExplorerCommand + MSIXIdentité par sparse packageMaintenir le classique pour l'instantAffiché seulement du côté de l'ancien menuPas de DLL, risque faible

Figure 14 : Selon l’exigence, on choisit parmi le triple verb statique, IExplorerCommand + identité, maintien du classique.

7. Pratique du déploiement et de l’enregistrement ── installateur, sparse package, nettoyage

Une fois le mode d’implémentation décidé, on intègre dans l’installateur la destination d’enregistrement, la notification de changement, l’enregistrement et le retrait du paquet, et le nettoyage à la désinstallation.

7.1. HKLM ou HKCU

La destination d’enregistrement s’aligne sur la forme de l’installateur. Pour tous les utilisateurs (placement dans Program Files, privilèges d’administrateur), HKLM\Software\Classes ; pour une installation par utilisateur (sans élévation), HKCU\Software\Classes. Mélanger produit des consultations du type « A peut ouvrir, B ne peut pas ».

Pour une extension de shell qui s’accompagne d’un enregistrement CLSID, Reg-Free COM, qui rend l’enregistrement de registre lui-même inutile, est aussi une option valable pour l’usage COM interne à l’application, mais elle ne s’applique pas à une extension de shell chargée par l’Explorateur, donc un enregistrement de face est nécessaire (« Qu’est-ce que Reg-Free COM »).

7.2. Notifier après un changement ── SHChangeNotify

Après un enregistrement, un changement ou une suppression d’association, on notifie l’événement SHCNE_ASSOCCHANGED avec SHChangeNotify. L’omettre peut faire que le changement n’est pas reconnu par l’Explorateur jusqu’au redémarrage.110

// Appeler une fois, après un changement d'association, dans une action
// personnalisée d'installateur, etc.
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);

7.3. Enregistrement et retrait d’un sparse package

L’enregistrement et le retrait d’un sparse package sont le travail de l’installateur. L’enregistrement se fait après le placement des fichiers, le retrait avant la suppression des fichiers.7

# À l'installation : après le placement des fichiers, enregistrer
# la destination d'installation comme emplacement externe
Add-AppxPackage -Path "C:\Program Files\KomuraSoft\KomuraReport.identity.msix" `
                -ExternalLocation "C:\Program Files\KomuraSoft"

# À la désinstallation : retirer l'enregistrement du paquet avant de supprimer les fichiers
Remove-AppxPackage <nom complet du paquet>

Distinguer l’enregistrement pour l’utilisateur qui exécute et le déploiement pour tous les utilisateurs

Add-AppxPackage s’enregistre pour l’utilisateur qui l’exécute. L’exécuter en LocalSystem depuis une action personnalisée d’un MSI per-machine n’accorde pas l’identité à l’utilisateur qui a installé. On le configure donc pour l’exécuter avec un emprunt d’identité (impersonate).

Toutefois, ce qui s’enregistre par emprunt d’identité, c’est aussi seulement l’utilisateur qui a exécuté cette installation. Si une machine est utilisée par plusieurs utilisateurs, les autres utilisateurs et ceux créés plus tard n’ont pas d’identité de paquet, et la commande n’apparaît pas dans le nouveau menu.

Pour la faire utiliser par tous les utilisateurs, on prépare un enregistrement par utilisateur, par exemple vérifier à la première ouverture de l’application si son paquet est enregistré, et l’enregistrer s’il ne l’est pas. À la désinstallation aussi, on inclut dans le plan le retrait depuis chaque utilisateur déjà enregistré.

Si le menu ne reflète pas après l’enregistrement

La prise d’effet d’un enregistrement de manifeste peut exiger un redémarrage de l’Explorateur (ou une déconnexion).6

Ordre d'enregistrement et de retrait d'un sparse packageÀ l'installation, on enregistre le sparse package après le placement des fichiers ; à la désinstallation, on retire l'enregistrement avant de supprimer les fichiers ; noter que l'enregistrement n'est valable que pour l'utilisateur qui l'exécuteInstallationPlacer les fichiersEnregistrer le sparse packageDésinstallationRetirer l'enregistrement du paquetSupprimer les fichiersL'enregistrement n'est valable que pour l'utilisateur qui exécute

Figure 15 : L’enregistrement se fait après le placement des fichiers, le retrait avant leur suppression ; noter que l’enregistrement est par utilisateur qui exécute.

7.4. Nettoyage à la désinstallation ── ce que l’on supprime et ce que l’on laisse

Le nettoyage à la désinstallation a une ligne claire dans le guide officiel.1

  • Ce que l’on supprime : l’ensemble des clés ProgID de son application, l’enregistrement Capabilities / RegisteredApplications, l’enregistrement CLSID de l’extension de shell, le sparse package (Remove-AppxPackage).
  • Ce que l’on laisse : la valeur par défaut de la clé d’extension (.kmrpt). Même si elle pointe encore vers son ProgID, ne pas la supprimer est la recommandation officielle. Il est difficile de juger si une autre application a pris la valeur par défaut après l’installation, et Windows ignore simplement un ProgID par défaut non enregistré, donc le laisser n’a pas d’effet réel.
  • À la fin du nettoyage aussi, on appelle SHChangeNotify(SHCNE_ASSOCCHANGED).

La plupart des problèmes « désinstallé, mais un reste apparaît dans le menu » viennent d’une fuite de cette conception de nettoyage.

Conception du nettoyage à la désinstallationÀ la désinstallation, on supprime ses clés ProgID, enregistrements CLSID et sparse package, on laisse la valeur par défaut de la clé d'extension car un ProgID non enregistré est ignoré, et à la fin du nettoyage on notifie le changement avec SHChangeNotifyDésinstallationCe que l'on supprimeCe que l'on laisseEnregistrement ProgID ou CLSIDsparse packageValeur par défaut de la clé d'extensionUn ProgID non enregistré est ignoréÀ la fin, notifier avec SHChangeNotify

Figure 16 : On supprime ses enregistrements, on laisse la valeur par défaut de la clé d’extension, et à la fin du nettoyage on notifie le changement.

8. Dépannage ── n’apparaît pas, double, lent

On enquête sur les pannes en les séparant en « n’apparaît pas », « apparaît en double / ne disparaît pas », « lent / plante ». À la fin, on explique comment confirmer l’enregistrement et le nettoyage dans un environnement propre.

8.1. N’apparaît pas dans le menu

On commence par confirmer lequel des menus, ancien ou nouveau, on regarde. Ensuite, on trie dans l’ordre suivant.

  1. Lequel des menus on regarde : un enregistrement à l’ancienne n’apparaît que du côté de l’ancien menu, Maj+F10. On confirme d’abord les deux.
  2. Bitness : une DLL d’extension de shell seulement 32 bits n’est pas chargée dans l’Explorateur 64 bits (section 4.3).
  3. Destination d’enregistrement : confusion HKLM / HKCU, Wow6432Node. On confirme la clé réelle avec reg query.
  4. Enregistrement de paquet : pour le nouveau menu, on confirme la présence de l’enregistrement avec Get-AppxPackage, la confiance du certificat de signature, le chemin de -ExternalLocation, et on redémarre l’Explorateur.6
  5. Notification oubliée : un oubli de SHChangeNotify se distingue selon que le redémarrage de l’Explorateur fait prendre effet.
Ordre de triage quand le menu n'apparaît pasOn commence par confirmer lequel des menus on regarde, puis on trie dans l'ordre bitness de la DLL, destination d'enregistrement dans le registre, enregistrement de paquet et signature, notification SHChangeNotify oubliéeConfirmer lequel des menus, ancien ou nouveauConfirmer le bitness de la DLLConfirmer la destination HKLM et HKCUConfirmer l'enregistrement de paquet et la signatureDistinguer une notification oubliée par un redémarrage

Figure 17 : Quand « ça n’apparaît pas », on trie dans l’ordre menu regardé, bitness, destination d’enregistrement, enregistrement de paquet, notification oubliée.

8.2. Apparaît en double, ou ne disparaît pas

On commence par viser dans lequel des menus c’est en double.

  • En double seulement dans l’ancien menu : on suspecte une fuite de nettoyage à la désinstallation (section 7.4) ou le reste d’un ProgID d’une ancienne version.
  • Dans les deux, ancien et nouveau : on suspecte la coexistence d’un enregistrement de registre à l’ancienne et d’un enregistrement de manifeste MSIX.

Dans les deux cas, c’est un triage de causes typiques ; on juge en confirmant le contenu réel de l’enregistrement.

Triage d'un double affichageSi le double n'est que dans l'ancien menu, on vise un reste, fuite de nettoyage ou ancien ProgID ; s'il est dans les deux, ancien et nouveau, on vise une coexistence d'enregistrement de registre à l'ancienne et d'enregistrement de manifesteAncien menu seulementLes deux, ancien et nouveauDans lequel le double apparaît-il ?Famille des restesFamille de la coexistenceFuite de nettoyage ou reste d'ancien ProgIDCoexistence d'un enregistrement de registre ancien et d'un nouvel enregistrement

Figure 18 : Un double seulement dans l’ancien menu vise un reste ; dans les deux, une coexistence.

8.3. L’Explorateur est lent, ou plante

Si le clic droit est lent, ou qu’un dossier particulier fait planter, on commence par inventorier les extensions de shell installées.

  1. Lister les extensions. Avec un outil tel que ShellExView de NirSoft, on confirme les extensions non Microsoft.
  2. Désactiver temporairement pour restreindre. On fait une recherche dichotomique sur les suspects, et l’on identifie la DLL en cause. En cas de plantage, le « module en cause » de l’Observateur d’événements est aussi un indice.
  3. Si c’est son extension, examiner le chemin de construction du menu. On suspecte des E/S synchrones ou un accès réseau (sections 4.2 et 5.2).
Identification de la DLL en cause quand c'est lent ou que ça planteLister les extensions de shell non Microsoft avec ShellExView, les désactiver temporairement en recherche dichotomique pour identifier la DLL en cause ; en cas de plantage, le module en cause de l'Observateur d'événements est aussi un indiceInventaire des extensions de shellLister les non MicrosoftDésactiver temporairement en recherche dichotomiqueIdentifier la DLL en causeEn cas de plantageConfirmer le module en cause

Figure 19 : On désactive temporairement les extensions non Microsoft en recherche dichotomique ; en cas de plantage, on combine aussi l’Observateur d’événements.

8.4. La validation est commode dans Windows Sandbox

La validation de l’intégration au shell a pour base de confirmer, dans un environnement propre, « installation → comportement → désinstallation → zéro reste ». Ce qui est commode ici, c’est Windows Sandbox (Pro / Enterprise / Education) : à chaque démarrage, un Windows jetable tout neuf se lève en quelques secondes, donc on peut faire tourner autant de fois que l’on veut le test d’enregistrement et de nettoyage de l’installateur. Tout disparaît à la fermeture, donc cela convient aussi à l’enquête sur les restes de registre.15

9. Résumé

Quand un passage à Windows 11 s’accompagne de « le menu s’est caché », commencez par confirmer, dans le tableau de décision du chapitre 6, ce que l’on veut réaliser. L’ordre de pensée est les trois étapes suivantes.

1. Juger si une association suffit

Si l’on veut seulement « ouvrir avec cette application », une association et un verb statique suffisent encore. Le fondement est clé d’extension → ProgID → verb, et HKCR est une vue de confirmation qui superpose les Classes de HKLM / HKCU. On indique la destination d’écriture, et l’on entoure forcément %1 de guillemets.

Toutefois, c’est l’utilisateur qui choisit l’application par défaut. L’installateur ne vole pas la valeur par défaut ; il s’enregistre correctement comme candidat.

2. Décider dans lequel des menus faire apparaître une commande propre

Une extension IContextMenu classique tourne du côté de l’ancien menu, ouvert par « Afficher plus d’options ». Pour faire apparaître une commande propre dans le nouveau menu, IExplorerCommand et un enregistrement dans le manifeste MSIX sont nécessaires. Pour une application que l’on ne peut pas empaqueter entièrement en MSIX, obtenir une identité de paquet avec un sparse package est la solution réaliste.

La DLL d’une extension classique tourne dans le processus de l’Explorateur, etc. Un plantage ou un retard se propage à l’hôte tout entier, et un hôte 64 bits a besoin d’une DLL 64 bits. Écrire une extension in-process en code managé n’est pas pris en charge ; l’implémentation en C++ natif est la règle.

3. Valider ensemble enregistrement, notification de changement et retrait

Après un enregistrement, un changement ou une suppression d’association, on notifie avec SHChangeNotify. À la désinstallation, on supprime son ProgID, etc., et l’on laisse la valeur par défaut de la clé d’extension. Un sparse package s’enregistre par utilisateur, donc dans un environnement multi-utilisateur on inclut aussi dans le plan l’enregistrement et le retrait pour chaque utilisateur.

Avec Windows Sandbox, on répète dans un environnement propre : installation → comportement → désinstallation → confirmation des restes.

Choisir d’abord le moyen le plus simple, et n’avancer vers l’ajout d’une commande propre dans le nouveau menu que si c’est nécessaire. Cet ordre permet d’organiser l’ampleur de la réponse et le périmètre des enregistrements et de l’implémentation à maintenir.

Articles connexes

Domaines de conseil associés

KomuraSoft LLC prend en charge la conception et l’implémentation des associations de fichiers, menus contextuels et extensions de shell d’applications métier, la prise en charge du nouveau menu contextuel de Windows 11 (passage à IExplorerCommand, introduction d’un sparse package), la révision de l’enregistrement et du nettoyage d’un installateur existant, et l’investigation des causes quand l’Explorateur est lent ou plante. Décider la ligne dès « que faire du menu caché dans Afficher plus d’options » convient tout à fait.

Références

  1. Microsoft Learn, File Types. La structure où la clé d’extension vise un ProgID ; OpenWithProgIds ; le choix entre enregistrement dans HKLM / HKCU\Software\Classes ; qu’il faut appeler SHChangeNotify(SHCNE_ASSOCCHANGED) après un changement d’association ; et qu’à la désinstallation on supprime le ProgID tout en laissant la valeur par défaut de la clé d’extension. ↩ ↩2 ↩3 ↩4 ↩5

  2. Microsoft Learn, Choosing a Static or Dynamic Shortcut Menu Method. Qu’il faut choisir le mode de verb statique le plus simple qui satisfait l’exigence ; qu’IContextMenu est le plus puissant mais aussi le plus complexe et classé du côté déconseillé ; et qu’IExplorerCommand / IExplorerCommandState est le mode recommandé. ↩ ↩2

  3. Microsoft Learn, HKEY_CLASSES_ROOT Key. Que HKEY_CLASSES_ROOT est une vue fusionnée de HKLM\Software\Classes et HKCU\Software\Classes ; que la définition côté utilisateur a priorité sur celle côté machine ; et les règles de répartition à l’écriture. ↩ ↩2

  4. Microsoft Learn, Windows app defaults platform. Que le changement d’application par défaut est conçu pour ne se faire que via l’interface Paramètres du système ; que les données de paramétrage utilisateur sont obscurcies et protégées en écriture par un pilote-filtre (UCPD.sys) ; qu’un changement fondé sur le registre n’est pas pris en charge ; et que dans un environnement géré on utilise la stratégie de groupe / MDM. ↩ ↩2

  5. Windows Developer Blog, Extending the Context Menu and Share Dialog in Windows 11. La conception du nouveau menu contextuel de Windows 11 ; l’extension par IExplorerCommand + identité d’application ; le placement en haut de « Ouvrir » et « Ouvrir avec » ; le rassemblement de plusieurs commandes dans un menu volant au nom de l’application ; et qu’une extension IContextMenu classique est chargée comme menu Windows 10 de « Afficher plus d’options » (Maj+F10). ↩ ↩2 ↩3

  6. Microsoft Learn, Add a File Explorer context menu command to a packaged desktop app. Que l’enregistrement dans le nouveau menu contextuel de Windows 11 se fait par une implémentation IExplorerCommand et une déclaration de manifeste windows.comServer + desktop4:FileExplorerContextMenus ; que ItemType peut spécifier *, Directory, Directory\Background ; l’alignement d’architecture de la DLL ; le maintien des méthodes de construction du menu rapides ; la prise en charge d’une application non empaquetée par sparse package ; qu’un redémarrage de l’Explorateur peut être nécessaire pour la prise d’effet de l’enregistrement ; et qu’une association de fichiers n’est pas une extension de menu générique. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8

  7. Microsoft Learn, Grant package identity by packaging with external location. Que l’on peut obtenir une identité de paquet en enregistrant un paquet avec emplacement externe (sparse package) sans changer l’installateur existant ; que c’est disponible à partir de Windows 10 version 2004 ; et que des fonctions Windows qui exigent une identité (enregistrement de menu contextuel, notifications, etc.) deviennent utilisables. ↩ ↩2 ↩3

  8. Microsoft Learn, Working with Shell Extensions. Les types de gestionnaires d’extension de shell ; qu’une extension est une DLL COM in-process chargée dans l’Explorateur (et dans un processus qui héberge le shell), donc qu’un plantage ou un blocage se propage à Explorer tout entier ; l’enregistrement avec ThreadingModel=Apartment ; et qu’il faut d’abord examiner un moyen de substitution plus simple qu’une extension de shell. ↩ ↩2 ↩3

  9. Microsoft Learn, Guidance for Implementing In-Process Extensions. Que Microsoft ne recommande pas une implémentation d’extension de shell in-process en code managé et la déclare hors support ; les raisons, collision de version du CLR, réentrance, non-déterminisme de la durée de vie des objets ; et qu’une extension hors processus (gestionnaire d’aperçu ou lancement depuis shell\verb\command) accepte le code managé. ↩ ↩2 ↩3

  10. Microsoft Learn, SHChangeNotify function. La façon d’émettre l’événement SHCNE_ASSOCCHANGED qui notifie un changement d’association de fichiers au système, et l’usage pour faire reconnaître le changement au shell. ↩ ↩2

  11. Microsoft Learn, Application Registration. Que l’enregistrement d’un exécutable par la sous-clé App Paths est recommandé ; le rôle de la sous-clé Applications ; l’enregistrement de verbs par SystemFileAssociations ; et l’ordre de priorité du ProgID et des informations liées lors d’un changement d’application par défaut. ↩

  12. Microsoft Learn, Creating Shortcut Menu Handlers. La méthode d’enregistrement d’un verb statique ; l’ordre de décision du verb par défaut (valeur par défaut → premier verb → Open → Open With) ; que le nom affiché d’un verb standard est fourni par l’OS ; le verb étendu par Extended ; que l’association avec une commande DDE est déconseillée (Deprecated) ; et l’attention à la redirection WOW64 dans un environnement 64 bits. ↩ ↩2 ↩3

  13. Microsoft Learn, Verbs and File Associations. Qu’un verb est aussi un verbe utilisé par ShellExecuteEx ; que dans une chaîne de commande un élément qui peut contenir un espace doit être entouré de guillemets, et que “%1” doit toujours s’écrire avec des guillemets ; et l’enregistrement de la procédure par défaut sous HKCR\Applications. ↩

  14. Microsoft Learn, IExplorerCommand interface. La composition des méthodes GetTitle, GetIcon, GetState, Invoke, EnumSubCommands, etc. ; que les méthodes sont appelées sur le thread d’interface donc ne doivent pas communiquer avec une ressource réseau ; et que l’interface est disponible à partir de Windows Vista. ↩

  15. Microsoft Learn, Windows Sandbox. Qu’un environnement Windows isolé jetable se lance en quelques secondes, et que toutes les modifications sont abandonnées à la fermeture ; qu’il convient au test de logiciel et à la validation d’un installateur ; et qu’il est disponible sous Pro / Enterprise / Education. ↩

Articles récents partageant les mêmes étiquettes, pour approfondir des sujets proches.

Ces pages replacent le sujet dans un contexte plus large de services et de décisions.

Cet article est directement lié aux services suivants.

Questions fréquentes

Questions souvent posées lors d’une consultation sur le sujet de cet article.

Pourquoi l'élément de menu contextuel de notre application n'apparaît-il sous Windows 11 que dans « Afficher plus d'options » ?
Parce que sous Windows 11 le menu contextuel de l'Explorateur s'est scindé en deux couches, ancienne et nouvelle. Seules les commandes qui implémentent l'interface IExplorerCommand et sont enregistrées dans le manifeste d'un paquet MSIX (= qui ont une identité de paquet) peuvent apparaître dans le nouveau menu. Les extensions de shell classiques fondées sur IContextMenu ont été déplacées vers l'ancien menu ouvert par « Afficher plus d'options » (Maj+F10). L'extension elle-même n'est pas cassée, elle continue donc de fonctionner pour l'instant, mais pour la voir dans le nouveau menu il faut migrer vers IExplorerCommand et soit empaqueter en MSIX, soit accorder l'identité avec un sparse package.
L'installateur peut-il définir notre application comme application par défaut d'un fichier (celle qui s'ouvre au double-clic) ?
Non. Le choix de l'application par défaut est conçu pour être fait par l'utilisateur, et Windows ne prend pas en charge le changement d'application par défaut ailleurs que depuis l'interface Paramètres du système. Les informations UserChoice qui conservent le choix de chaque utilisateur sont obscurcies, et un pilote-filtre (UCPD.sys) protège aussi l'écriture contre les applications. Ce qu'un installateur peut faire, c'est enregistrer un ProgID et des verbs, s'ajouter à OpenWithProgIds pour figurer comme candidat sous « Ouvrir avec », et orienter l'utilisateur vers la page des applications par défaut. La bonne implémentation n'est pas de voler la valeur par défaut, mais de se préparer à être choisi.
Puis-je écrire une extension de shell en code managé, par exemple en C# ?
Microsoft a dit clairement que rédiger une extension de shell in-process (gestionnaire de menu contextuel, gestionnaire d'icône, et assimilés) en code managé n'est pas recommandé et n'est pas pris en charge. L'extension est chargée dans l'Explorateur et dans le processus de toute application qui ouvre une boîte de dialogue de fichiers commune, de sorte que les collisions de version du CLR, la réentrance et la durée de vie non déterministe des objets rendent l'application hôte instable. La règle est une implémentation en C++ natif. Un EXE ordinaire lancé depuis le command d'un verb, ou une extension hors processus comme un gestionnaire d'aperçu qui s'exécute dans un processus séparé, convient en code managé.
Qu'est-ce qu'un sparse package (MSIX avec emplacement externe) ?
C'est un petit paquet MSIX qui ne contient pas les fichiers de l'application elle-même, seulement un manifeste (informations d'identité). Pour une application installée normalement par un installateur existant (MSI, Inno Setup, etc.), l'enregistrer avec Add-AppxPackage -ExternalLocation en pointant le dossier d'installation lui donne une identité de paquet, et elle peut alors utiliser des fonctions qui exigent cette identité, comme l'enregistrement dans le nouveau menu contextuel de Windows 11 ou les notifications toast. Disponible à partir de Windows 10 version 2004, le paquet doit porter une signature de code de confiance sur la machine cible. C'est le choix réaliste quand on veut le nouveau menu sans migrer entièrement la distribution vers MSIX.
Que faire si un élément du menu contextuel apparaît en double, ou ne disparaît pas ?
Pour trier la cause, confirmez d'abord s'il apparaît dans le nouveau menu ou dans l'ancien (« Afficher plus d'options »). Un double affichage typique vient de la coexistence d'un enregistrement de registre à l'ancienne et d'un enregistrement de manifeste MSIX, ou d'un ProgID et d'un enregistrement CLSID d'extension laissés après une désinstallation. Après un changement d'association, suspectez aussi une notification SHChangeNotify(SHCNE_ASSOCCHANGED) oubliée ; juste après l'enregistrement d'un paquet, un redémarrage oublié de l'Explorateur. Si cela ne suffit pas, désactivez temporairement les extensions non Microsoft dans ShellExView et faites une recherche dichotomique pour identifier la DLL en cause.

Profil de l’auteur

Page de présentation de l’auteur de l’article.

Go Komura

Représentant de KomuraSoft LLC

Spécialisé dans le développement de logiciels Windows, le conseil technique et l’analyse de pannes, notamment pour les systèmes existants et les incidents difficiles à reproduire.

Retour au blog