Attivazione avanzata con l'API del ciclo di vita dell'app

Nell'SDK per app di Windows, l'API del ciclo di vita dell'app offre il supporto per il comportamento di attivazione avanzata in stile UWP per tutte le app, in pacchetto e senza pacchetti. Questa prima versione è incentrata sul portare i tipi di attivazione più usati nelle app non in pacchetto e le versioni future puntano a supportare più tipi di attivazione della piattaforma UWP 44.

Per supportare le attivazioni avanzate sono necessari due passaggi:

  • Indicare al sistema che l'app supporta uno o più tipi di attivazione avanzata.
  • Ricevere ed elaborare i payload di attivazione avanzata ricevuti dall'app quando viene attivato.

Prerequisiti

Per usare l'API del ciclo di vita dell'app nella SDK per app di Windows:

  1. Scaricare e installare la versione più recente del SDK per app di Windows. Per altre informazioni, vedere Installare gli strumenti per il SDK per app di Windows.
  2. Seguire le istruzioni per creare il primo progetto WinUI 3 o per usare il SDK per app di Windows in un progetto esistente.

Dettagli di attivazione per le app non in pacchetto

La versione corrente del SDK per app di Windows supporta i quattro tipi di attivazione più comuni per le app non in pacchetto. Questi tipi di attivazione sono definiti dall'enumerazione ExtendedActivationKind .

Tipo di attivazione Descrizione
Launch Attivare l'app dalla riga di comando, quando l'utente fa doppio clic sull'icona dell'app o a livello di codice tramite ShellExecute o CreateProcess.
File Attivare un'app registrata per un tipo di file quando un file di tipo viene aperto tramite ShellExecute, Launcher.LaunchFileAsync o la riga di comando.
Protocol Attivare un'app registrata per un protocollo quando una stringa di tale protocollo viene eseguita tramite ShellExecute, Launcher.LaunchUriAsync o la riga di comando.
StartupTask Attivare l'app quando l'utente accede a Windows, a causa di una chiave del Registro di sistema o a causa di un collegamento in una cartella di avvio nota.

Ogni tipo di app non in pacchetto recupera gli argomenti della riga di comando in modi diversi. Ad esempio, le app Win32 C++ prevedono di ricevere argomenti di attivazione da WinMain passare sotto forma di stringa (anche se hanno anche la possibilità di chiamare GetCommandLineW). Windows Form app, tuttavia, deve chiamare Environment.GetCommandLineArgs, perché gli argomenti non verranno passati automaticamente.

Dettagli di attivazione per le app in pacchetto

Le app in pacchetto che usano il SDK per app di Windows supportano tutti i 44 tipi di attivazione della piattaforma UWP. Ogni tipo di attivazione ha la propria implementazione corrispondente di IActivatedEventArgs che contengono proprietà rilevanti per quel tipo specifico di attivazione.

Le app in pacchetto riceveranno sempre gli argomenti dell'evento di attivazione nel gestore eventi AppInstance.Activated e avranno anche la possibilità di chiamare AppInstance.GetActivatedEventArgs.

Registrazione dell'attivazione

Tutte le app supportano il Launch tipo di attivazione per impostazione predefinita. A differenza della piattaforma UWP, il tipo di attivazione SDK per app di Windows Launch include l'avvio della riga di comando. Le app possono registrarsi per tipi di attivazione aggiuntivi in diversi modi.

  • Le app senza pacchetti che usano il SDK per app di Windows possono registrare (e annullare la registrazione) per tipi di attivazione aggiuntivi tramite l'API del ciclo di vita dell'app nella SDK per app di Windows.
  • Le app non in pacchetto possono continuare a registrarsi per tipi di attivazione aggiuntivi usando il metodo tradizionale di scrittura delle chiavi del Registro di sistema.
  • Le app in pacchetto possono registrarsi per tipi di attivazione aggiuntivi tramite voci nel manifesto dell'applicazione.

Le registrazioni di attivazione sono per utente. Se l'app è installata per più utenti, sarà necessario registrare nuovamente le attivazioni per ogni utente.

Esempi

Registrarsi per l'attivazione avanzata

Anche se le app possono chiamare le API di registrazione in qualsiasi momento, lo scenario più comune consiste nel controllare le registrazioni all'avvio dell'app.

Questo esempio mostra come un'app non in pacchetto può usare i metodi statici seguenti della classe ActivationRegistrationManager per registrarsi per diversi tipi di attivazione all'avvio dell'app:

Questo esempio illustra anche come usare le funzioni MddBootstrapInitialize e MddBootstrapShutdown per inizializzare e pulire i riferimenti al pacchetto framework SDK per app di Windows. Tutte le app non in pacchetto devono eseguire questa operazione per usare le API fornite dal SDK per app di Windows. Per altre informazioni, vedere Usare il runtime di SDK per app di Windows per le app in pacchetto con percorso esterno o senza pacchetti.

Nota

Questo esempio registra le associazioni con tre tipi di file di immagine contemporaneamente. Questo è pratico, ma il risultato è lo stesso della registrazione di ogni tipo di file singolarmente; La registrazione di nuovi tipi di immagine non sovrascrive le registrazioni precedenti. Tuttavia, se un'app registra nuovamente un tipo di file già registrato con un set diverso di verbi, il set precedente di verbi verrà sovrascritto per tale tipo di file.

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

Ottenere argomenti dell'evento di attivazione avanzata

Dopo l'attivazione, un'app deve recuperare gli argomenti dell'evento di attivazione. In questo esempio un'app senza pacchetti chiama il metodo AppInstance.GetActivatedEventArgs per ottenere gli argomenti dell'evento di attivazione e quindi usa la proprietà AppActivationArguments.Kind per recuperare gli argomenti dell'evento per diversi tipi di attivazioni.

Nota

Le app Win32 in genere ottengono argomenti della riga di comando molto presto il metodo WinMain . Analogamente, queste app devono chiamare AppInstance.GetActivatedEventArgs nella stessa posizione in cui in precedenza avrebbero usato il lpCmdLine parametro o denominato 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

In questo esempio viene illustrato come un'app non in pacchetto può annullare la registrazione per tipi di attivazione specifici in modo dinamico, usando i metodi statici seguenti della classe ActivationRegistrationManager :

Nota

Quando si annulla la registrazione per l'attivazione di avvio, l'app deve usare lo stesso taskId usato quando è stato registrato in origine.

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