Activation avancée avec l’API de cycle de vie des applications

Dans le Windows App SDK, l’API de cycle de vie des applications prend en charge le comportement d’activation avancé de style UWP pour toutes les applications, empaquetées et non empaquetées. Cette première version se concentre sur l’apport des types d’activation les plus couramment utilisés aux applications non empaquetées, et les versions futures visent à prendre en charge davantage des 44 types d’activation de l’UWP.

La prise en charge des activations avancées nécessite deux étapes :

  • Indiquer au système que votre application prend en charge un ou plusieurs types d’activation avancée.
  • Recevoir et traiter les charges d’activation avancée que votre application reçoit lorsqu’elle est activée.

Prérequis

Pour utiliser l’API de cycle de vie des applications dans le Windows App SDK :

  1. Téléchargez et installez la dernière version du SDK d'application Windows. Pour plus d’informations, consultez Installer des outils pour le SDK d’application Windows.
  2. Suivez les instructions relatives à la création de votre premier projet WinUI 3 ou à l’utilisation du SDK d’application Windows dans un projet existant.

Détails de l’activation pour les applications non empaquetées

La version actuelle du Windows App SDK prend en charge les quatre types d’activation les plus courants pour les applications non empaquetées. Ces types d’activation sont définis par l’énumération ExtendedActivationKind.

Type d’activation Description
Launch Activer l’application à partir de la ligne de commande, lorsque l’utilisateur double-clique sur l’icône de l’application, ou de manière programmée via ShellExecute ou CreateProcess.
File Activer une application qui s’est enregistrée pour un type de fichier lorsqu’un fichier du type est ouvert via ShellExecute, Launcher.LaunchFileAsync, ou la ligne de commande.
Protocol Activer une application qui s’est enregistrée pour un protocole lorsqu’une chaîne de ce protocole est exécutée via ShellExecute, Launcher.LaunchUriAsync, ou la ligne de commande.
StartupTask Activer l’application lorsque l’utilisateur se connecte à Windows, soit en raison d’une clé de registre, soit en raison d’un raccourci dans un dossier de démarrage bien connu.

Chaque type d’application non empaquetée récupère ses arguments de ligne de commande de différentes manières. Par exemple, les applications Win32 C++ s’attendent à recevoir les arguments d’activation à passer dans WinMain sous forme de chaîne (bien qu’elles aient également la possibilité d’appeler GetCommandLineW). Cependant, les applications Windows Forms doivent appeler Environment.GetCommandLineArgs, car les arguments ne leur seront pas automatiquement transmis.

Détails de l’activation pour les applications empaquetées

Les applications empaquetées qui utilisent le Windows App SDK prennent en charge les 44 types d’activation de l’UWP. Chaque type d’activation a sa propre implémentation correspondante de IActivatedEventArgs qui contient des propriétés pertinentes pour ce type spécifique d’activation.

Les applications empaquetées recevront toujours les arguments d’événement d’activation dans leur gestionnaire d’événements AppInstance.Activated, et ont également la possibilité d’appeler AppInstance.GetActivatedEventArgs.

Enregistrement d’activation

Toutes les applications prennent en charge le type d’activation Launch par défaut. Contrairement à l’UWP, le type d’activation Launch du Windows App SDK inclut les lancements en ligne de commande. Les applications peuvent s’enregistrer pour des types d’activation supplémentaires de plusieurs manières.

  • Les applications non empaquetées qui utilisent le Windows App SDK peuvent s’enregistrer (et se désenregistrer) pour des types d’activation supplémentaires via l’API de cycle de vie des applications dans le Windows App SDK.
  • Les applications non empaquetées peuvent continuer à s’enregistrer pour des types d’activation supplémentaires en utilisant la méthode traditionnelle d’écriture de clés de registre.
  • Les applications empaquetées peuvent s’enregistrer pour des types d’activation supplémentaires via des entrées dans leur manifeste d’application.

Les enregistrements d’activation sont par utilisateur. Si votre application est installée pour plusieurs utilisateurs, vous devrez réenregistrer les activations pour chaque utilisateur.

Exemples

Enregistrez-vous pour une activation avancée

Bien que les applications puissent appeler les API d’enregistrement à tout moment, le scénario le plus courant est de vérifier les enregistrements au démarrage de l’application.

Cet exemple montre comment une application non empaquetée peut utiliser les méthodes statiques de la classe ActivationRegistrationManager pour s’enregistrer pour plusieurs types d’activation lors du lancement de l’application :

Cet exemple montre également comment utiliser les fonctions MddBootstrapInitialize et MddBootstrapShutdown pour initialiser et nettoyer les références au package du framework Windows App SDK. Toutes les applications non empaquetées doivent le faire pour utiliser les API fournies par le Windows App SDK. Pour plus d’informations, consultez Utiliser le runtime du SDK d’application Windows pour les applications empaquetées avec un emplacement externe ou non empaquetées.

Remarque

Cet exemple enregistre des associations avec trois types de fichiers image à la fois. C’est pratique, mais le résultat est le même que d’enregistrer chaque type de fichier individuellement ; l’enregistrement de nouveaux types d’images n’écrase pas les enregistrements précédents. Cependant, si une application réenregistre un type de fichier déjà enregistré avec un ensemble différent de verbes, l’ensemble précédent de verbes sera écrasé pour ce type de fichier.

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

Obtenir les arguments de l’événement d’activation avancée

Une fois activée, une application doit récupérer ses arguments d’événement d’activation. Dans cet exemple, une application non empaquetée appelle la méthode AppInstance.GetActivatedEventArgs pour obtenir les arguments d’événement pour l’événement d’activation, puis utilise la propriété AppActivationArguments.Kind pour récupérer les arguments d’événement pour différents types d’activations.

Remarque

Les applications Win32 obtiennent généralement les arguments de ligne de commande très tôt dans leur méthode WinMain. De même, ces applications devraient appeler AppInstance.GetActivatedEventArgs au même endroit où elles auraient précédemment utilisé le paramètre lpCmdLine fourni ou appelé GetCommandLineW.

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

Unregister

Cet exemple montre comment une application non empaquetée peut se désenregistrer dynamiquement pour des types d’activation spécifiques, en utilisant les méthodes statiques de la classe ActivationRegistrationManager :

Remarque

Lors de la désinscription de l’activation de démarrage, l’application doit utiliser la même taskId qu’elle a utilisée lorsqu’elle s’est initialement enregistrée.

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