Reichhaltige Aktivierung mit der App Lifecycle API

Im Windows App SDK unterstützt die API für den App-Lebenszyklus ein reichhaltiges Aktivierungsverhalten im UWP-Stil für alle Apps, sowohl für gepackte als auch für ungepackte. Diese erste Version konzentriert sich darauf, die gebräuchlichsten Aktivierungsarten in ungepackte Anwendungen zu bringen, und künftige Versionen zielen darauf ab, mehr der 44 Aktivierungsarten von UWP zu unterstützen.

Die Unterstützung von umfangreichen Aktivierungen erfordert zwei Schritte:

  • Teilen Sie dem System mit, dass Ihre App eine oder mehrere Arten von Rich-Activation unterstützt.
  • Empfangen und verarbeiten Sie die umfangreichen Aktivierungs-Payloads, die Ihre App bei der Aktivierung erhält.

Voraussetzungen

So verwenden Sie die App Lifecycle API im Windows App SDK:

  1. Laden Sie das neueste experimentelle Release des Windows App SDK herunter und installieren Sie es. Weitere Informationen finden Sie unter Installieren von Tools für das Windows App SDK.
  2. Befolgen Sie die Anweisungen zum Erstellen Ihres ersten WinUI 3-Projekts oder zum Verwenden des Windows App SDK in einem vorhandenen Projekt.

Aktivierungsdetails für nicht gepackte Anwendungen

Die aktuelle Version des Windows App SDK unterstützt die vier gängigsten Aktivierungsarten für nicht gepackte Anwendungen. Diese Aktivierungsarten werden durch die Aufzählung ExtendedActivationKind definiert.

Aktivierungsart Beschreibung
Launch Aktivieren Sie die Anwendung über die Befehlszeile, wenn der Benutzer auf das Symbol der Anwendung doppelklickt, oder programmatisch über ShellExecute oder CreateProcess.
File Aktivieren Sie eine Anwendung, die für einen Dateityp registriert ist, wenn eine Datei dieses Typs über ShellExecute, Launcher.LaunchFileAsync oder die Befehlszeile geöffnet wird.
Protocol Aktiviert eine Anwendung, die sich für ein Protokoll registriert hat, wenn ein String dieses Protokolls über ShellExecute, Launcher.LaunchUriAsync oder die Befehlszeile ausgeführt wird.
StartupTask Aktivieren Sie die Anwendung, wenn sich der Benutzer bei Windows anmeldet, entweder über einen Registrierungsschlüssel oder über eine Verknüpfung in einem bekannten Startordner.

Jede Art von nicht gepackter Anwendung ruft ihre Befehlszeilenargumente auf unterschiedliche Weise ab. Beispielsweise erwarten C++-Win32-Anwendungen, dass Aktivierungsargumente in Form eines Strings an WinMain übergeben werden (obwohl sie auch die Möglichkeit haben, GetCommandLineW aufzurufen). Windows Forms-Apps müssen aber Environment.GetCommandLineArgs aufrufen, da Argumente nicht automatisch an sie übergeben werden.

Aktivierungsdetails für gepackte Anwendungen

Gepackte Apps, die das Windows App SDK verwenden, unterstützen alle 44 UWP-Aktivierungsarten . Jede Aktivierungsart hat ihre eigene Implementierung von IActivatedEventArgs, die die für die jeweilige Art der Aktivierung relevanten Eigenschaften enthält.

Gepackte Anwendungen erhalten immer Argumente für das Aktivierungsereignis in ihrem AppInstance.Activated Event-Handler und haben außerdem die Möglichkeit, AppInstance.GetActivatedEventArgs aufzurufen.

Registrierung der Aktivierung

Alle Anwendungen unterstützen standardmäßig die Aktivierungsart Launch . Im Gegensatz zu UWP umfasst die Aktivierungsart des Windows App SDK Launch das Starten über die Befehlszeile. Apps können auf verschiedene Weise für zusätzliche Aktivierungsarten registriert werden.

  • Ungepackte Apps, die das Windows App SDK verwenden, können sich über die App Lifecycle API im Windows App SDK für zusätzliche Aktivierungsarten registrieren (und die Registrierung aufheben).
  • Ungepackte Anwendungen können sich weiterhin für zusätzliche Aktivierungsarten registrieren, indem sie die traditionelle Methode des Schreibens von Registrierungsschlüsseln verwenden.
  • Paketierte Anwendungen können sich über Einträge in ihrem Anwendungsmanifest für zusätzliche Aktivierungsarten registrieren.

Aktivierungsregistrierungen werden pro Benutzer vorgenommen. Wenn Ihre Anwendung für mehrere Benutzer installiert ist, müssen Sie die Aktivierungen für jeden Benutzer neu registrieren.

Beispiele

Registrieren Sie sich für eine umfassende Aktivierung

Obwohl Anwendungen die Registrierungs-APIs jederzeit aufrufen können, ist das häufigste Szenario die Überprüfung von Registrierungen beim Start der Anwendung.

Dieses Beispiel zeigt, wie eine ungepackte App die folgenden statischen Methoden der Klasse ActivationRegistrationManager verwenden kann, um sich beim Starten der App für mehrere Aktivierungsarten zu registrieren:

Dieses Beispiel zeigt auch, wie die Funktionen MddBootstrapInitialize und MddBootstrapShutdown verwendet werden, um Verweise auf das Windows App SDK-Frameworkpaket zu initialisieren und zu bereinigen. Alle nicht gepackten Anwendungen müssen dies tun, um die vom Windows App SDK bereitgestellten APIs zu nutzen. Weitere Informationen finden Sie unter Verwenden der Windows App SDK-Runtime für gepackte Apps mit externem Speicherort oder nicht gepackte Apps.

Hinweis

In diesem Beispiel werden Assoziationen mit drei Bilddateitypen auf einmal registriert. Das ist praktisch, aber das Ergebnis ist dasselbe wie bei der Registrierung jedes einzelnen Dateityps; die Registrierung neuer Bildtypen überschreibt nicht die vorherigen Registrierungen. Wenn jedoch eine Anwendung einen bereits registrierten Dateityp mit einem anderen Satz von Verben erneut registriert, wird der vorherige Satz von Verben für diesen Dateityp überschrieben.

const UINT32 majorMinorVersion{ WINDOWSAPPSDK_RELEASE_MAJORMINOR };
PCWSTR versionTag{ WINDOWSAPPSDK_RELEASE_VERSION_TAG_W };
const PACKAGE_VERSION minVersion{ WINDOWSAPPSDK_RUNTIME_VERSION_UINT64 };
WCHAR szExePath[MAX_PATH]{};
WCHAR szExePathAndIconIndex[MAX_PATH + 8]{};

int APIENTRY wWinMain(
    _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // Initialize Windows App SDK framework package for unpackaged apps.
    HRESULT hr{ MddBootstrapInitialize(majorMinorVersion, versionTag, minVersion) };
    if (FAILED(hr))
    {
        wprintf(L"Error 0x%X in MddBootstrapInitialize(0x%08X, %s, %hu.%hu.%hu.%hu)\n",
            hr, majorMinorVersion, versionTag, minVersion.Major, 
            minVersion.Minor, minVersion.Build, minVersion.Revision);
        return hr;
    }

    // Get the current executable filesystem path, so we can
    // use it later in registering for activation kinds.
    GetModuleFileName(NULL, szExePath, MAX_PATH);
    wcscpy_s(szExePathAndIconIndex, szExePath);
    wcscat_s(szExePathAndIconIndex, L",1");

    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_CLASSNAME, szWindowClass, MAX_LOADSTRING);
    RegisterWindowClass(hInstance);
    if (!InitInstance(hInstance, nCmdShow))
    {
        return FALSE;
    }

    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // Uninitialize Windows App SDK.
    MddBootstrapShutdown();
    return (int)msg.wParam;
}

void RegisterForActivation()
{
    OutputMessage(L"Registering for rich activation");

    // Register one or more supported filetypes, specifying 
    // an icon (specified by binary file path plus resource index),
    // a display name to use in Shell and Settings,
    // zero or more verbs for the File Explorer context menu,
    // and the path to the EXE to register for activation.
    hstring myFileTypes[3] = { L".foo", L".foo2", L".foo3" };
    hstring verbs[2] = { L"view", L"edit" };
    ActivationRegistrationManager::RegisterForFileTypeActivation(
        myFileTypes,
        szExePathAndIconIndex,
        L"Contoso File Types",
        verbs,
        szExePath
    );

    // Register a URI scheme for protocol activation,
    // specifying the scheme name, icon, display name and EXE path.
    ActivationRegistrationManager::RegisterForProtocolActivation(
        L"foo",
        szExePathAndIconIndex,
        L"Contoso Foo Protocol",
        szExePath
    );

    // Register for startup activation.
    // As we're registering for startup activation multiple times,
    // and this is a multi-instance app, we'll get multiple instances
    // activated at startup.
    ActivationRegistrationManager::RegisterForStartupActivation(
        L"ContosoStartupId",
        szExePath
    );

    // If we don't specify the EXE, it will default to this EXE.
    ActivationRegistrationManager::RegisterForStartupActivation(
        L"ContosoStartupId2",
        L""
    );
}

Reich werden durch Aktivierungsereignisse

Sobald eine Anwendung aktiviert ist, muss sie ihre Argumente für das Aktivierungsereignis abrufen. In diesem Beispiel ruft eine ungepackte App die Methode AppInstance.GetActivatedEventArgs auf, um die Ereignis-Argumente für das Aktivierungsereignis abzurufen, und verwendet dann die Eigenschaft AppActivationArguments.Kind, um die Ereignis-Argumente für verschiedene Arten von Aktivierungen abzurufen.

Hinweis

Win32-Anwendungen erhalten in der Regel Befehlszeilenargumente sehr früh ihre WinMain Methode. In ähnlicher Weise sollten diese Anwendungen AppInstance.GetActivatedEventArgs an der gleichen Stelle aufrufen, an der sie zuvor den übergebenen Parameter lpCmdLine verwendet oder GetCommandLineW aufgerufen hätten.

void GetActivationInfo()
{
    AppActivationArguments args = AppInstance::GetCurrent().GetActivatedEventArgs();
    ExtendedActivationKind kind = args.Kind();
    if (kind == ExtendedActivationKind::Launch)
    {
        ILaunchActivatedEventArgs launchArgs = 
            args.Data().as<ILaunchActivatedEventArgs>();
        if (launchArgs != NULL)
        {
            winrt::hstring argString = launchArgs.Arguments().c_str();
            std::vector<std::wstring> argStrings = split_strings(argString);
            OutputMessage(L"Launch activation");
            for (std::wstring s : argStrings)
            {
                OutputMessage(s.c_str());
            }
        }
    }
    else if (kind == ExtendedActivationKind::File)
    {
        IFileActivatedEventArgs fileArgs = 
            args.Data().as<IFileActivatedEventArgs>();
        if (fileArgs != NULL)
        {
            IStorageItem file = fileArgs.Files().GetAt(0);
            OutputFormattedMessage(
                L"File activation: %s", file.Name().c_str());
        }
    }
    else if (kind == ExtendedActivationKind::Protocol)
    {
        IProtocolActivatedEventArgs protocolArgs = 
            args.Data().as<IProtocolActivatedEventArgs>();
        if (protocolArgs != NULL)
        {
            Uri uri = protocolArgs.Uri();
            OutputFormattedMessage(
                L"Protocol activation: %s", uri.RawUri().c_str());
        }
    }
    else if (kind == ExtendedActivationKind::StartupTask)
    {
        IStartupTaskActivatedEventArgs startupArgs = 
            args.Data().as<IStartupTaskActivatedEventArgs>();
        if (startupArgs != NULL)
        {
            OutputFormattedMessage(
                L"Startup activation: %s", startupArgs.TaskId().c_str());
        }
    }
}

Registrierung aufheben

Dieses Beispiel zeigt, wie eine nicht gepackte Anwendung die Registrierung für bestimmte Aktivierungsarten dynamisch aufheben kann, indem die folgenden statischen Methoden der Klasse ActivationRegistrationManager verwendet werden:

Hinweis

Beim Aufheben der Registrierung für die Startaktivierung muss die Anwendung dieselbe taskId verwenden, die sie bei der ursprünglichen Registrierung verwendet hat.

void UnregisterForActivation()
{
    OutputMessage(L"Unregistering for rich activation");
    
    // Unregister one or more registered filetypes.
    try
    {
        hstring myFileTypes[3] = { L".foo", L".foo2", L".foo3" };
        ActivationRegistrationManager::UnregisterForFileTypeActivation(
            myFileTypes,
            szExePath
        );
    }
    catch (...)
    {
        OutputMessage(L"Error unregistering file types");
    }

    // Unregister a protocol scheme.
    ActivationRegistrationManager::UnregisterForProtocolActivation(
        L"foo",
        L"");

    // Unregister for startup activation.
    ActivationRegistrationManager::UnregisterForStartupActivation(
        L"ContosoStartupId");
    ActivationRegistrationManager::UnregisterForStartupActivation(
        L"ContosoStartupId2");
}