Freigeben über


Integrieren einer verpackten Desktop-App in den Datei-Explorer

Einige Windows-Apps definieren Datei-Explorer-Erweiterungen, die Kontextmenüeinträge hinzufügen, mit denen Kunden Optionen im Zusammenhang mit der App ausführen können. Ältere Windows-App-Bereitstellungstechnologien wie MSI und ClickOnce definieren Datei-Explorer-Erweiterungen über die Registrierung. Die Registrierung verfügt über eine Reihe von Strukturen, die Datei-Explorer-Erweiterungen und andere Typen von Shell-Erweiterungen steuern. Diese Installationsprogramme erstellen in der Regel eine Reihe von Registrierungsschlüsseln, um die verschiedenen Elemente zu konfigurieren, die im Kontextmenü enthalten sind.

Wenn Sie Ihre Windows-App mit MSIX verpacken, wird die Registrierung virtualisiert, und daher kann Ihre App Datei-Explorer-Erweiterungen nicht über die Registrierung registrieren. Stattdessen müssen Sie Ihre Datei-Explorer-Erweiterungen über Paket-Erweiterungen definieren, die Sie im Paketmanifest festlegen. In diesem Artikel werden verschiedene Möglichkeiten beschrieben.

Den vollständigen Beispielcode finden Sie in diesem Artikel auf GitHub.

Hinzufügen eines Kontextmenüeintrags, der Startparameter unterstützt

Eine der einfachsten Möglichkeiten zur Integration in den Datei-Explorer besteht darin, eine Paketerweiterung zu definieren, die Ihre App zur Liste der verfügbaren Apps im Kontextmenü hinzufügt, wenn ein Benutzer mit der rechten Maustaste auf einen bestimmten Dateityp im Datei-Explorer klickt. Wenn der Benutzer Ihre App öffnet, kann Ihre Erweiterung Parameter an Ihre App übergeben.

Dieses Szenario hat mehrere Einschränkungen:

  • Es funktioniert nur in Kombination mit der -Dateitypzuordnungsfunktion. Sie können zusätzliche Optionen im Kontextmenü nur für Dateitypen anzeigen, die der Haupt-App zugeordnet sind (z. B. unterstützt Ihre App das Öffnen einer Datei, indem Sie im Datei-Explorer darauf doppelklicken).
  • Die Optionen im Kontextmenü werden nur angezeigt, wenn Ihre App als Standard für diesen Dateityp festgelegt ist.
  • Die einzige unterstützte Aktion ist, das Hauptprogramm der App zu starten, also dasselbe Programm, das mit dem Eintrag im Startmenü verbunden ist. Jede Aktion kann jedoch unterschiedliche Parameter angeben, die Sie verwenden können, wenn die Apps beginnen, zu verstehen, welche Aktion die Ausführung ausgelöst hat und unterschiedliche Aufgaben ausführt.

Trotz dieser Einschränkungen reicht dieser Ansatz für viele Szenarien aus. Wenn Sie beispielsweise einen Bild-Editor erstellen, können Sie ganz einfach einen Eintrag im Kontextmenü hinzufügen, um die Größe eines Bilds zu ändern, wodurch der Bild-Editor direkt mit einem Assistenten gestartet wird, um den Größenänderungsprozess zu starten.

Kontextmenüeintrag implementieren

Um dieses Szenario zu unterstützen, fügen Sie ihrem Paketmanifest ein Extension--Element mit der Kategorie windows.fileTypeAssociation hinzu. Dieses Element muss als untergeordnetes Element des Elements Extensions unter dem Element Application hinzugefügt werden.

Im folgenden Beispiel wird eine Registrierung für eine App veranschaulicht, die Kontextmenüs für Dateien mit der .foo Erweiterung ermöglicht. In diesem Beispiel wird die .foo Erweiterung angegeben, da dies eine gefälschte Erweiterung ist, die in der Regel nicht für andere Apps auf einem bestimmten Computer registriert ist. Wenn Sie einen Dateityp verwalten müssen, der möglicherweise bereits verwendet wird (z. B. .txt oder .jpg), denken Sie daran, dass Sie die Option erst sehen können, wenn Ihre App als Standard für diesen Dateityp festgelegt ist. Dieses Beispiel ist ein Auszug aus der datei Package.appxmanifest im zugehörigen Beispiel auf 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>

In diesem Beispiel wird davon ausgegangen, dass die folgenden Namespaces und Aliase im Stammelement <Package> im Manifest deklariert werden.

<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>

Das FileTypeAssociation-Element ordnet Ihre App den Dateitypen zu, die Sie unterstützen möchten. Weitere Informationen finden Sie unter Zuordnen der verpackten Anwendung zu einer Reihe von Dateitypen. Hier sind die wichtigsten Elemente im Zusammenhang mit diesem Element.

Attribut oder Element BESCHREIBUNG
Name-Attribut Entspricht dem Namen der Erweiterung, die Sie registrieren möchten, jedoch ohne den Punkt (im vorherigen Beispiel foo).
Parameters-Attribut Enthält die Parameter, die Sie an Ihre Anwendung übergeben möchten, wenn der Benutzer auf eine Datei mit einer solchen Erweiterung doppelklicken soll. In der Regel geben Sie mindestens %1 an, einen speziellen Parameter, der den Pfad der ausgewählten Datei enthält. Wenn Sie auf diese Weise auf eine Datei doppelklicken, kennt die Anwendung den vollständigen Pfad und kann sie laden.
de-DE: SupportedFileTypes Element Gibt die Namen der Erweiterung an, die Sie registrieren möchten, einschließlich des Punkts (in diesem Beispiel .foo). Sie können mehrere <FileType> Einträge angeben, die weitere Dateitypen unterstützen möchten.

Um die Kontextmenüintegration zu definieren, müssen Sie auch das SupportedVerbs untergeordnete Element hinzufügen. Dieses Element enthält ein oder mehrere Verb--Elemente, die die Optionen definieren, die aufgelistet werden, wenn ein Benutzer mit der rechten Maustaste auf eine Datei mit der Erweiterung .foo im Datei-Explorer klickt. Weitere Informationen finden Sie unter Hinzufügen von Optionen zu den Kontextmenüs von Dateien mit einem bestimmten Dateityp. Hier sind die wichtigsten Punkte im Zusammenhang mit dem Verb-Element.

Attribut oder Element BESCHREIBUNG
Id-Attribut Gibt den eindeutigen Bezeichner für die Aktion an.
Parameters-Attribut Ähnlich wie beim FileTypeAssociation-Element enthält dieses Attribut für das Verb-Element die Parameter, die an Ihre Anwendung übergeben werden, wenn der Benutzer auf den Kontextmenüeintrag klickt. In der Regel übergeben Sie, abgesehen von dem speziellen Parameter %1, der den Pfad der ausgewählten Datei angibt, auch einen oder mehrere Parameter, um den Kontext abzurufen. Auf diese Weise kann Ihre App verstehen, dass sie über einen Kontextmenüeintrag geöffnet wurde.
Elementwert Der Wert des Verb--Element enthält die Beschriftung, die im Kontextmenüeintrag angezeigt werden soll (in diesem Beispiel Dateigröße ändern).

Greifen Sie auf die Startparameter in Ihrem App-Code zu

Die Art und Weise, wie Ihre App die Parameter empfängt, hängt vom Typ der app ab, die Sie erstellt haben. Eine WPF-App verarbeitet in der Regel beispielsweise die Startereignisargumente in der Methode OnStartup der Klasse App. Sie können überprüfen, ob Startparameter vorhanden sind und basierend auf dem Ergebnis die am besten geeignete Aktion ausführen (z. B. das Öffnen eines bestimmten Fensters der Anwendung anstelle des Hauptfensters).

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();
        }
    }
}

Der folgende Screenshot veranschaulicht den Dateigröße ändern Kontextmenüeintrag, der im vorherigen Beispiel erstellt wurde.

Screenshot des Befehls

Unterstützung bei generischen Dateien oder Ordnern und Ausführung komplexer Aufgaben

Obwohl die Verwendung der FileTypeAssociation Erweiterung im Paketmanifest, wie im vorherigen Abschnitt beschrieben, für viele Szenarien ausreichend ist, können Sie es als einschränkend empfinden. Die beiden größten Herausforderungen sind:

  • Sie können nur Dateitypen verarbeiten, denen Sie zugeordnet sind. Sie können z. B. keinen generischen Ordner handhaben.
  • Sie können die App nur mit einer Reihe von Parametern starten. Sie können keine erweiterten Vorgänge ausführen, z. B. das Starten einer anderen ausführbaren Datei oder das Ausführen einer Aufgabe, ohne die Haupt-App zu öffnen.

Um diese Ziele zu erreichen, müssen Sie eine Shell-Erweiterungerstellen, die leistungsfähigere Möglichkeiten zur Integration in den Datei-Explorer bietet. In diesem Szenario erstellen Sie eine DLL, die alles enthält, was zum Verwalten des Dateikontextmenüs erforderlich ist, einschließlich der Bezeichnung, des Symbols, des Zustands und der Aufgaben, die ausgeführt werden sollen. Da diese Funktionalität in einer DLL implementiert ist, können Sie fast alles tun, was Sie mit einer normalen App tun können. Nachdem Sie die DLL implementiert haben, müssen Sie sie über Erweiterungen registrieren, die Sie im Paketmanifest definieren.

Hinweis

Der in diesem Abschnitt beschriebene Prozess hat eine Einschränkung. Nachdem das MSIX-Paket, das die Erweiterung enthält, auf einem Zielcomputer installiert wurde, muss der Datei-Explorer neu gestartet werden, bevor die Shell-Erweiterung geladen werden kann. Dazu kann der Benutzer entweder den Computer neu starten oder den explorer.exe Prozess mithilfe des Task Managersneu starten.

Shell-Erweiterung implementieren

Shellerweiterungen basieren auf COM (Component Object Model). Ihre DLL macht ein oder mehrere COM-Objekte verfügbar, die im Systemregister registriert sind. Windows erkennt diese COM-Objekte und integriert Ihre Erweiterung in den Datei-Explorer. Da Sie Ihren Code in die Windows-Shell integrieren, ist die Leistung und der Speicherbedarf wichtig. Daher werden diese Arten von Erweiterungen in der Regel mit C++ erstellt.

Den Beispielcode, der veranschaulicht, wie Shell-Erweiterungen implementiert werden, finden Sie im Projekt ExplorerCommandVerb im zugehörigen Beispiel auf GitHub. Dieses Projekt basiert auf diesem Beispiel in den Windows-Desktopbeispielen und verfügt über mehrere Überarbeitungen, damit das Beispiel mit den neuesten Versionen von Visual Studio einfacher verwendet werden kann.

Dieses Projekt enthält viele Codebausteine für verschiedene Aufgaben, z. B. dynamische vs statische Menüs und manuelle Registrierung der DLL. Der großteil dieses Codes wird nicht benötigt, wenn Sie Ihre App mit MSIX verpacken, da die Verpackungsunterstützung diese Aufgaben für Sie übernimmt. Die ExplorerCommandVerb.cpp Datei enthält die Implementierung des Kontextmenüs, und dies ist die Hauptcodedatei, die für diese exemplarische Vorgehensweise von Interesse ist.

Die Schlüsselfunktion ist CExplorerCommandVerb::Invoke. Dies ist die Funktion, die aufgerufen wird, wenn ein Benutzer auf den Eintrag im Kontextmenü klickt. Um die Auswirkungen auf die Leistung zu minimieren, wird der Vorgang in einem anderen Thread ausgeführt, sodass Sie die tatsächliche Implementierung in CExplorerCommandVerb::_ThreadProcfinden.

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;
}

Wenn ein Benutzer mit der rechten Maustaste auf eine Datei oder einen Ordner klickt, zeigt diese Funktion ein Meldungsfeld mit dem vollständigen Pfad der ausgewählten Datei oder des ausgewählten Ordners an. Wenn Sie die Shell-Erweiterung auf andere Weise anpassen möchten, können Sie die folgenden Funktionen im Beispiel erweitern:

  • Sie können die Funktion GetTitle ändern, um die Bezeichnung des Eintrags im Kontextmenü anzupassen.
  • Sie können die GetIcon-Funktion ändern, um das Symbol anzupassen, das im Kontextmenü neben dem Eintrag angezeigt wird.
  • Sie können die GetTooltip Funktion ändern, um das Tooltip (QuickInfo) anzupassen, das angezeigt wird, wenn Sie auf den Eintrag im Kontextmenü zeigen.

Registrieren der Shell-Erweiterung

Da die Shell-Erweiterung auf COM basiert, muss die Implementierungs-DLL als COM-Server verfügbar gemacht werden, damit Windows sie in den Datei-Explorer integrieren kann. Dies geschieht in der Regel durch Zuweisen einer eindeutigen ID (clSID) zum COM-Server und durch Registrieren in einer bestimmten Struktur der Systemregistrierung. Im Projekt ExplorerCommandVerb wird die CLSID für die CExplorerCommandVerb Erweiterung in der Datei Dll.h definiert.

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

Wenn Sie eine Shell-Erweiterungs-DLL in einem MSIX-Paket verpacken, folgen Sie einem ähnlichen Ansatz. Die GUID muss jedoch im Paketmanifest anstelle der Registrierung registriert werden, wie hiererläutert.

Beginnen Sie damit, im Paketmanifest die folgenden Namespaces zu Ihrem Package-Element hinzuzufügen.

<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>

Um die CLSID zu registrieren, fügen Sie ein com.Extension Element mit der Kategorie windows.comServer zu Ihrem Paketmanifest hinzu. Dieses Element muss als untergeordnetes Element des Elements Extensions unter dem Element Application hinzugefügt werden. Dieses Beispiel ist ein Auszug aus der datei Package.appxmanifest im zugehörigen Beispiel auf 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>

Es gibt zwei wichtige Attribute, die im com:Class-Element konfiguriert werden müssen.

Merkmal BESCHREIBUNG
Id-Attribut Dies muss mit der CLSID des Objekts übereinstimmen, das Sie registrieren möchten. In diesem Beispiel ist dies die CLSID, die in der Dll.h-Datei deklariert und der Klasse CExplorerCommandVerb zugeordnet ist.
Path-Attribut Dies muss den Namen der DLL enthalten, die das COM-Objekt verfügbar macht. Dieses Beispiel enthält die DLL im Stammverzeichnis des Pakets, sodass einfach der Name der DLL angegeben werden kann, die vom ExplorerCommandVerb-Projekt generiert wird.

Fügen Sie als Nächstes eine weitere Erweiterung hinzu, die das Dateikontextmenü registriert. Fügen Sie dazu dem Paketmanifest ein desktop4:Extension-Element mit der Kategorie windows.fileExplorerContextMenus hinzu. Dieses Element muss auch als untergeordnetes Element des Extensions-Elements unter dem Application-Element hinzugefügt werden.

<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>

Es gibt zwei wichtige Attribute, die unter dem desktop4:Extension-Element konfiguriert werden müssen.

Attribut oder Element BESCHREIBUNG
Type Attribut von desktop5:ItemType Dadurch wird der Typ der Elemente definiert, die Sie dem Kontextmenü zuordnen möchten. Es könnte ein Stern (*) sein, wenn Sie es für alle Dateien anzeigen möchten; es könnte eine bestimmte Dateierweiterung (.foo) sein, oder sie kann für Ordner (Directory) verfügbar sein.
Clsid Attribut von desktop5:Verb Dies muss mit der CLSID übereinstimmen, die Sie zuvor als COM-Server in der Paketmanifestdatei registriert haben.

Konfigurieren Sie die DLL im Paket

Schließen Sie die DLL ein, die die Shell-Erweiterung (in diesem Beispiel ExplorerCommandVerb.dll) im Stammverzeichnis des MSIX-Pakets implementiert. Wenn Sie das Windows Application Packaging Projectverwenden, besteht die einfachste Lösung darin, die DLL in das Projekt zu kopieren und einzufügen. Stellen Sie sicher, dass die Option In Ausgabeverzeichnis kopieren für die DLL-Dateieigenschaften auf Kopieren, wenn neuerfestgelegt ist.

Um sicherzustellen, dass das Paket immer die neueste Version der DLL enthält, können Sie dem Shell-Erweiterungsprojekt ein Post-Build-Ereignis hinzufügen, sodass die DLL jedes Mal, wenn Sie es erstellen, in das Windows Application Packaging-Projekt kopiert wird.

Datei-Explorer neu starten

Nachdem Sie das Shell-Erweiterungspaket installiert haben, müssen Sie den Datei-Explorer neu starten, bevor die Shell-Erweiterung geladen werden kann. Dies ist eine Einschränkung der Shell-Erweiterungen, die über MSIX-Pakete bereitgestellt und registriert werden.

Um die Shell-Erweiterung zu testen, starten Sie Ihren PC neu oder starten Sie den explorer.exe prozess mittels Task-Managerneu. Nachdem Sie dies getan haben, sollten Sie den Eintrag im Kontextmenü sehen können.

Screenshot des benutzerdefinierten Kontextmenüeintrags

Wenn Sie darauf klicken, wird die CExplorerCommandVerb::_ThreadProc Funktion aufgerufen, um das Meldungsfeld mit dem Pfad des ausgewählten Ordners anzuzeigen.

Screenshot des benutzerdefinierten Popup-Fensters