Partager via


Intégrer une application de bureau empaquetée avec l’Explorateur de fichiers

Certaines applications Windows définissent des extensions de l’Explorateur de fichiers qui ajoutent des entrées de menu contextuel qui permettent aux clients d’effectuer des options liées à l’application. Les anciennes technologies de déploiement d’applications Windows telles que MSI et ClickOnce définissent des extensions de l’Explorateur de fichiers via le Registre. Le Registre comporte une série de ruches qui contrôlent les extensions de l’Explorateur de fichiers et d’autres types d’extensions Shell. Ces programmes d’installation créent généralement une série de clés de Registre pour configurer les différents éléments à inclure dans le menu contextuel.

Si vous empaquetez votre application Windows à l’aide de MSIX, le Registre est virtualisé et, par conséquent, votre application ne peut pas inscrire les extensions de l’Explorateur de fichiers via le Registre. Au lieu de cela, vous devez définir vos extensions de l’Explorateur de fichiers via des extensions de package, que vous définissez dans le manifeste du package. Cet article décrit plusieurs façons de procéder.

Vous trouverez l’exemple de code complet utilisé dans cet article sur GitHub.

Ajouter une entrée de menu contextuel qui prend en charge les paramètres de démarrage

L’une des façons les plus simples d’intégrer à l’Explorateur de fichiers consiste à définir une extension de package qui ajoute votre application à la liste des applications disponibles dans le menu contextuel lorsqu’un utilisateur clique avec le bouton droit sur un type de fichier spécifique dans l’Explorateur de fichiers. Si l’utilisateur ouvre votre application, votre extension peut transmettre des paramètres à votre application.

Ce scénario présente plusieurs limitations :

  • Il fonctionne uniquement en combinaison avec la fonctionnalité d’association de type de fichier. Vous pouvez afficher des options supplémentaires dans le menu contextuel uniquement pour les types de fichiers associés à l’application principale (par exemple, votre application prend en charge l’ouverture d’un fichier en double-cliquant dessus dans l’Explorateur de fichiers).
  • Les options du menu contextuel s’affichent uniquement si votre application est définie comme valeur par défaut pour ce type de fichier.
  • La seule action prise en charge consiste à lancer l’exécutable principal de l’application (autrement dit, le même exécutable connecté à l’entrée du menu Démarrer). Toutefois, chaque action peut spécifier différents paramètres, que vous pouvez utiliser lorsque les applications commencent à comprendre quelle action a déclenché l’exécution et effectuer différentes tâches.

Malgré ces limitations, cette approche est suffisante pour de nombreux scénarios. Par exemple, si vous créez un éditeur d’image, vous pouvez facilement ajouter une entrée dans le menu contextuel pour redimensionner une image, ce qui lance l’éditeur d’images directement avec un Assistant pour démarrer le processus de redimensionnement.

Implémenter l’entrée de menu contextuel

Pour prendre en charge ce scénario, ajoutez un élément Extension avec la catégorie windows.fileTypeAssociation à votre manifeste de package. Cet élément doit être ajouté en tant qu'enfant de l'élément Extensions sous l'élément Application.

L’exemple suivant illustre une inscription pour une application qui active les menus contextuels pour les fichiers avec l’extension .foo . Cet exemple spécifie l’extension .foo , car il s’agit d’une extension factice qui n’est généralement pas inscrite auprès d’autres applications sur un ordinateur donné. Si vous devez gérer un type de fichier qui peut déjà être pris (comme .txt ou .jpg), n’oubliez pas que vous ne pourrez pas voir l’option tant que votre application n’est pas définie comme valeur par défaut pour ce type de fichier. Cet exemple est un extrait du fichier Package.appxmanifest dans l’exemple associé sur GitHub.

<Extensions>
  <uap3:Extension Category="windows.fileTypeAssociation">
    <uap3:FileTypeAssociation Name="foo" Parameters="&quot;%1&quot;">
      <uap:SupportedFileTypes>
        <uap:FileType>.foo</uap:FileType>
      </uap:SupportedFileTypes>
      <uap2:SupportedVerbs>
        <uap3:Verb Id="Resize" Parameters="&quot;%1&quot; /p">Resize file</uap3:Verb>
      </uap2:SupportedVerbs>
    </uap3:FileTypeAssociation>
  </uap3:Extension>
</Extensions>

Cet exemple suppose que les espaces de noms et alias suivants sont déclarés dans l’élément racine <Package> du manifeste.

<Package
  xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
  xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
  xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2"
  xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
  xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
  IgnorableNamespaces="uap uap2 uap3 rescap">
  ...
</Package>

L’élément FileTypeAssociation associe votre application aux types de fichiers que vous souhaitez prendre en charge. Pour plus d’informations, consultez Associer votre application empaquetée à un ensemble de types de fichiers. Voici les éléments les plus importants liés à cet élément.

Attribut ou élément Descriptif
attribut Name Correspond au nom de l’extension que vous souhaitez inscrire moins le point (dans l’exemple précédent, foo).
attribut Parameters Contient les paramètres que vous souhaitez transmettre à votre application lorsque l’utilisateur double-clique sur un fichier avec cette extension. En règle générale, au moins, vous passez %1, qui est un paramètre spécial qui contient le chemin d’accès du fichier sélectionné. Ainsi, lorsque vous double-cliquez sur un fichier, l’application connaît son chemin d’accès complet et peut la charger.
élément SupportedFileTypes Spécifie le ou les noms de l’extension que vous souhaitez inscrire, y compris le point (dans cet exemple, .foo). Vous pouvez spécifier plusieurs entrées <FileType> pour prendre en charge plus de types de fichiers.

Pour définir l’intégration du menu contextuel, vous devez également ajouter les SupportedVerbs élément enfant. Cet élément contient un ou plusieurs éléments Verb qui définissent les options qui seront répertoriées lorsqu’un utilisateur clique avec le bouton droit sur un fichier avec l’extension .foo dans l’Explorateur de fichiers. Pour plus d’informations, consultez Ajouter des options aux menus contextuels des fichiers qui ont un certain type de fichier. Voici les éléments les plus importants liés à l’élément Verb .

Attribut ou élément Descriptif
attribut Id Spécifie l’identificateur unique de l’action.
attribut Parameters Comme pour l’élément FileTypeAssociation , cet attribut de l’élément Verb contient les paramètres transmis à votre application lorsque l’utilisateur clique sur l’entrée du menu contextuel. En règle générale, à part le %1 paramètre spécial pour obtenir le chemin d’accès du fichier sélectionné, vous transmettez également un ou plusieurs paramètres pour obtenir le contexte. Cela permet à votre application de comprendre qu’elle a été ouverte à partir d’une entrée de menu contextuel.
Valeur de l’élément La valeur de l’élément Verb contient l’étiquette à afficher dans l’entrée du menu contextuel (dans cet exemple, Redimensionner le fichier).

Accéder aux paramètres de démarrage dans le code de votre application

La façon dont votre application reçoit les paramètres dépend du type d’application que vous avez créé. Par exemple, une application WPF traite généralement les arguments d’événement de démarrage dans la OnStartup méthode de la App classe. Vous pouvez vérifier s’il existe des paramètres de démarrage et, en fonction du résultat, effectuer l’action la plus appropriée (par exemple, ouvrir une fenêtre spécifique de l’application au lieu de la fenêtre principale).

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        if (e.Args.Contains("Resize"))
        {
            // Open a specific window of the app.
        }
        else
        {
            MainWindow main = new MainWindow();
            main.Show();
        }
    }
}

La capture d’écran suivante illustre l’entrée de menu contextuel Redimensionner le fichier créée par l’exemple précédent.

Capture d’écran de la commande Redimensionner le fichier dans le menu contextuel

Prendre en charge les fichiers ou dossiers génériques et effectuer des tâches complexes

Bien que l’utilisation de l’extension FileTypeAssociation dans le manifeste du package, comme décrit dans la section précédente, soit suffisante pour de nombreux scénarios, vous pouvez la trouver limitée. Les deux principaux défis sont les suivants :

  • Vous pouvez gérer uniquement les types de fichiers auquel vous êtes associé. Par exemple, vous ne pouvez pas gérer un dossier générique.
  • Vous ne pouvez lancer l’application qu’avec une série de paramètres. Vous ne pouvez pas effectuer d’opérations avancées, telles que le lancement d’un autre exécutable ou l’exécution d’une tâche sans ouvrir l’application principale.

Pour atteindre ces objectifs, vous devez créer une extension Shell, qui fournit des moyens plus puissants d’intégrer à l’Explorateur de fichiers. Dans ce scénario, vous créez une DLL qui contient tout ce qui est nécessaire pour gérer le menu contextuel du fichier, y compris l’étiquette, l’icône, l’état et les tâches à effectuer. Étant donné que cette fonctionnalité est implémentée dans une DLL, vous pouvez faire presque tout ce que vous pouvez faire avec une application normale. Après avoir implémenté la DLL, vous devez l’inscrire via des extensions que vous définissez dans votre manifeste de package.

Remarque

Le processus décrit dans cette section comporte une limitation. Une fois le package MSIX qui contient l’extension installé sur un ordinateur cible, l’Explorateur de fichiers doit être redémarré avant que l’extension Shell puisse être chargée. Pour ce faire, l’utilisateur peut redémarrer l’ordinateur ou redémarrer le processus de explorer.exe à l’aide de Du Gestionnaire des tâches.

Implémenter l’extension Shell

Les extensions shell sont basées sur COM (Component Object Model). Votre DLL expose un ou plusieurs objets COM inscrits dans le registre système. Windows découvre ces objets COM et intègre votre extension à l’Explorateur de fichiers. Étant donné que vous intégrez votre code à Windows Shell, les performances et l’empreinte mémoire sont importantes. Par conséquent, ces types d’extensions sont généralement générés avec C++.

Pour obtenir un exemple de code illustrant comment implémenter des extensions Shell, consultez le projet ExplorerCommandVerb dans l’exemple associé sur GitHub. Ce projet est basé sur cet exemple dans les exemples de bureau Windows et a plusieurs révisions pour faciliter l’utilisation de l’exemple avec les dernières versions de Visual Studio.

Ce projet contient beaucoup de code réutilisable pour différentes tâches, telles que les menus dynamiques et statiques et l’inscription manuelle de la DLL. La plupart de ce code n’est pas nécessaire si vous empaquetagez votre application à l’aide de MSIX, car la prise en charge de l’empaquetage s’occupera de ces tâches pour vous. Le fichier ExplorerCommandVerb.cpp contient l’implémentation du menu contextuel, et il s’agit du fichier de code principal qui vous intéresse pour cette procédure pas à pas.

La fonction clé est CExplorerCommandVerb::Invoke. Il s’agit de la fonction appelée lorsqu’un utilisateur clique sur l’entrée dans le menu contextuel. Dans l’exemple, pour réduire l’impact sur les performances, l’opération est effectuée sur un autre thread. Vous trouverez donc l’implémentation réelle dans CExplorerCommandVerb::_ThreadProc.

DWORD CExplorerCommandVerb::_ThreadProc()
{
	IShellItemArray* psia;
	HRESULT hr = CoGetInterfaceAndReleaseStream(_pstmShellItemArray, IID_PPV_ARGS(&psia));
	_pstmShellItemArray = NULL;
	if (SUCCEEDED(hr))
	{
		DWORD count;
		psia->GetCount(&count);

		IShellItem2* psi;
		HRESULT hr = GetItemAt(psia, 0, IID_PPV_ARGS(&psi));
		if (SUCCEEDED(hr))
		{
			PWSTR pszName;
			hr = psi->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &pszName);
			if (SUCCEEDED(hr))
			{
				WCHAR szMsg[128];
				StringCchPrintf(szMsg, ARRAYSIZE(szMsg), L"%d item(s), first item is named %s", count, pszName);

				MessageBox(_hwnd, szMsg, L"ExplorerCommand Sample Verb", MB_OK);

				CoTaskMemFree(pszName);
			}

			psi->Release();
		}
		psia->Release();
	}

	return 0;
}

Lorsqu’un utilisateur clique avec le bouton droit sur un fichier ou un dossier, cette fonction affiche une boîte de message avec le chemin complet du fichier ou dossier sélectionné. Si vous souhaitez personnaliser l’extension Shell d’une autre manière, vous pouvez étendre les fonctions suivantes dans l’exemple :

  • Vous pouvez modifier la fonction GetTitle pour personnaliser l’étiquette de l’entrée dans le menu contextuel.
  • Vous pouvez modifier la fonction GetIcon pour personnaliser l’icône affichée près de l’entrée dans le menu contextuel.
  • Vous pouvez modifier la fonction GetTooltip pour personnaliser l’info-bulle qui s’affiche lorsque vous pointez l’entrée dans le menu contextuel.

Inscrire l’extension Shell

Étant donné que l’extension Shell est basée sur COM, la DLL d’implémentation doit être exposée en tant que serveur COM afin que Windows puisse l’intégrer à l’Explorateur de fichiers. En règle générale, cela est effectué en affectant un ID unique (appelé CLSID) au serveur COM et en l’inscrivant dans une ruche spécifique du registre système. Dans le projet ExplorerCommandVerb , le CLSID de l’extension CExplorerCommandVerb est défini dans le fichier Dll.h .

class __declspec(uuid("CC19E147-7757-483C-B27F-3D81BCEB38FE")) CExplorerCommandVerb;

Lorsque vous empaqueter une DLL d’extension Shell dans un package MSIX, vous suivez une approche similaire. Toutefois, le GUID doit être inscrit à l’intérieur du manifeste du paquet plutôt que dans le registre, comme expliqué ici.

Dans votre manifeste de package, commencez par ajouter les espaces de noms suivants à votre élément Package .

<Package
  xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
  xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
  xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
  xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10" 
  IgnorableNamespaces="desktop desktop4 desktop5 com">
    
    ...
</Package>

Pour inscrire le CLSID, ajoutez un élément com.Extension avec la catégorie windows.comServer à votre manifeste de paquet. Cet élément doit être ajouté en tant qu'enfant de l'élément Extensions sous l'élément Application. Cet exemple est un extrait du fichier Package.appxmanifest dans l’exemple associé sur GitHub.

<com:Extension Category="windows.comServer">
  <com:ComServer>
    <com:SurrogateServer DisplayName="ContextMenuSample">
      <com:Class Id="CC19E147-7757-483C-B27F-3D81BCEB38FE" Path="ExplorerCommandVerb.dll" ThreadingModel="STA"/>
    </com:SurrogateServer>
  </com:ComServer>
</com:Extension>

Il existe deux attributs critiques à configurer dans l’élément com :Class .

Caractéristique Descriptif
attribut Id Cela doit correspondre au CLSID de l’objet que vous souhaitez inscrire. Dans cet exemple, il s’agit du CLSID déclaré dans le Dll.h fichier associé à la CExplorerCommandVerb classe.
attribut Path Cela doit contenir le nom de la DLL qui expose l’objet COM. Cet exemple inclut la DLL à la racine du package. Il peut donc simplement spécifier le nom de la DLL générée par le ExplorerCommandVerb projet.

Ensuite, ajoutez une autre extension qui inscrit le menu contextuel du fichier. Pour ce faire, ajoutez un élément Desktop4 :Extension avec la catégorie windows.fileExplorerContextMenus à votre manifeste de package. Cet élément doit également être ajouté en tant qu'enfant de l'élément Extensions sous l'élément Application.

<desktop4:Extension Category="windows.fileExplorerContextMenus">
  <desktop4:FileExplorerContextMenus>
    <desktop5:ItemType Type="Directory">
      <desktop5:Verb Id="Command1" Clsid="CC19E147-7757-483C-B27F-3D81BCEB38FE" />
    </desktop5:ItemType>
  </desktop4:FileExplorerContextMenus>
</desktop4:Extension>

Il existe deux attributs critiques à configurer sous l’élément Desktop4 :Extension .

Attribut ou élément Descriptif
attribut Type de desktop5 :ItemType Cela définit le type d’éléments que vous souhaitez associer au menu contextuel. Il peut s’agir d’une étoile (*) si vous souhaitez l’afficher pour tous les fichiers ; il peut s’agir d’une extension de fichier spécifique (.foo) ou disponible pour les dossiers (Directory).
attribut Clsid de desktop5 :Verb Cela doit correspondre au CLSID que vous avez précédemment inscrit en tant que serveur COM dans le fichier manifeste du package.

Configurer la DLL dans le package

Incluez la DLL qui implémente l’extension Shell (dans cet exemple, ExplorerCommandVerb.dll) à la racine du package MSIX. Si vous utilisez le projet d’empaquetage d’applications Windows, la solution la plus simple consiste à copier et coller la DLL dans le projet et à vérifier que l’option Copier dans le répertoire de sortie pour les propriétés du fichier DLL est définie sur Copier si elle est plus récente.

Pour vous assurer que le package inclut toujours la version la plus récente de la DLL, vous pouvez ajouter un événement post-build au projet d’extension Shell afin que, chaque fois que vous le générez, la DLL est copiée dans le projet d’empaquetage d’applications Windows.

Redémarrer l’Explorateur de fichiers

Après avoir installé le package d’extension Shell, vous devez redémarrer l’Explorateur de fichiers avant que l’extension Shell puisse être chargée. Il s’agit d’une limitation des extensions Shell déployées et inscrites via des packages MSIX.

Pour tester l’extension Shell, redémarrez votre PC ou redémarrez le processus deexplorer.exe à l’aide du Gestionnaire des tâches. Après cela, vous devriez être en mesure de voir l’entrée dans le menu contextuel.

Capture d’écran de l’entrée de menu contextuel personnalisé

Si vous cliquez dessus, la CExplorerCommandVerb::_ThreadProc fonction est appelée pour afficher la boîte de message avec le chemin d’accès du dossier sélectionné.

Capture d’écran de la fenêtre contextuelle personnalisée