Condividi tramite


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

In Windows App SDK, l'API ciclo di vita dell'app offre il supporto per il comportamento di attivazione avanzata UWP-style a tutte le app, incluse o meno in un pacchetto. In questa prima versione l'attenzione rivolta a portare i tipi di attivazione più usati nelle app non in pacchetto, mentre le versioni future puntano a supportare più dei 44 tipi di attivazionedi UWP.

Supportare le attivazioni avanzate richiede 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 attivata.

Prerequisiti

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

  1. Scaricare e installare la versione più recente di SDK per app di Windows. Per altre informazioni, vedere Introduzione a WinUI.
  2. Seguire le istruzioni per Creare il primo progetto WinUI 3 o per Usare Windows App SDK in un progetto esistente.

Dettagli di attivazione per le app non in pacchetto

La versione attuale di Windows App SDK 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 quel tipo viene aperto tramite ShellExecute, Launcher.LaunchFileAsync o la riga di comando.
Protocol Attivare un'app registrata per un protocollo quando una stringa di quel 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 i propri argomenti della riga di comando in modi diversi. Ad esempio, le app Win32 C++ prevedono di ricevere argomenti di attivazione da passare in WinMain sotto forma di stringa (anche se hanno anche la possibilità di chiamare GetCommandLineW). Le app Windows Form, tuttavia, devono chiamare Environment.GetCommandLineArgs, perché gli argomenti non verranno loro passati automaticamente.

Dettagli di attivazione per le app in pacchetto

Le app in pacchetto che usano Windows App SDK supportano tutti i 44 tipi di attivazione di 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 loro gestore eventi AppInstance.Activated e avranno anche la possibilità di chiamare AppInstance.GetActivatedEventArgs.

Registrazione dell'attivazione

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

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

Le registrazioni di attivazione si intendono 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 nella verifica delle registrazioni all'avvio dell'app.

Questo esempio mostra come un'app non in pacchetto può usare i seguenti metodi statici 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 Windows App SDK. Tutte le app non in pacchetto devono eseguire questa operazione per usare le API fornite da Windows App SDK. Per altre informazioni, vedere Usare il runtime di Windows App SDK per le app in pacchetto con posizione esterna o non in pacchetto.

Nota

Questo esempio registra le associazioni con tre tipi di file di immagine contemporaneamente. Questa operazione è utile, ma il risultato è lo stesso che si ottiene registrando 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 diverso set di verbi, il set di verbi precedente 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 della sua attivazione. In questo esempio, un'app non in pacchetto 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 ricevono argomenti della riga di comando molto presto con il metodo WinMain. Analogamente, queste app devono chiamare AppInstance.GetActivatedEventArgs nella stessa posizione in cui in precedenza avrebbero usato il parametro lpCmdLine o chiamato 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

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

Nota

Quando annulla la registrazione per l'attivazione di avvio, l'app deve usare lo stesso taskId usato quando si è registrata 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");
}