Activación enriquecida con la API del ciclo de vida de la aplicación

En el SDK de aplicaciones para Windows, la API del ciclo de vida de la aplicación ofrece compatibilidad con el comportamiento de activación enriquecida de estilo UWP a todas las aplicaciones, empaquetadas y sin empaquetar por igual. Esta primera versión se centra en incorporar los tipos de activación más usados a aplicaciones sin empaquetar y futuras versiones tienen como objetivo admitir más de los 44 tipos de activación de UWP.

La compatibilidad con activaciones enriquecidas requiere dos pasos:

  • Indicar al sistema que la aplicación admite uno o varios tipos de activación enriquecida.
  • Recibir y procesar las cargas de activación enriquecida que recibe la aplicación cuando se activa.

Requisitos previos

Para usar la API de ciclo de vida de la aplicación en el SDK de aplicaciones para Windows:

  1. Descargue e instale la versión experimental más reciente del SDK de Aplicaciones para Windows. Para más información, consulte Instalación de herramientas para el SDK de Aplicaciones para Windows.
  2. Siga las instrucciones para crear su primer proyecto de WinUI 3 o para usar el SDK de aplicaciones para Windows en un proyecto existente.

Detalles de activación para aplicaciones sin empaquetar

La versión actual del SDK de aplicaciones para Windows admite los cuatro tipos de activación más comunes para aplicaciones sin empaquetar. Estos tipos de activación se definen mediante la enumeración ExtendedActivationKind.

Tipo de activación Descripción
Launch Activa la aplicación desde la línea de comandos, cuando el usuario hace doble clic en el icono de la aplicación o mediante programación a través de ShellExecute o CreateProcess.
File Activa una aplicación registrada para un tipo de archivo cuando se abre un archivo del tipo a través de ShellExecute, Launcher.LaunchFileAsync o la línea de comandos.
Protocol Activa una aplicación registrada para un protocolo cuando se ejecuta una cadena de ese protocolo a través de ShellExecute, Launcher.LaunchUriAsync o la línea de comandos.
StartupTask Activa la aplicación cuando el usuario inicia sesión en Windows, ya sea por una clave del Registro o por un acceso directo en una carpeta de inicio conocida.

Cada tipo de aplicación sin empaquetar recupera sus argumentos de línea de comandos de diferentes maneras. Por ejemplo, las aplicaciones Win32 de C++ esperan recibir argumentos de activación que se transferirán a WinMain en forma de cadena (aunque también tienen la opción de llamar a GetCommandLineW). Sin embargo, las aplicaciones de Windows Forms deben llamar a Environment.GetCommandLineArgs, ya que los argumentos no se les transferirán automáticamente.

Detalles de activación para aplicaciones empaquetadas

Las aplicaciones empaquetadas que usan el SDK de aplicaciones para Windows admiten los 44 tipos de activación de UWP. Cada tipo de activación tiene su propia implementación correspondiente de IActivatedEventArgs, que contiene propiedades relevantes para ese tipo específico de activación.

Las aplicaciones empaquetadas siempre recibirán argumentos de evento de activación en su controlador de eventos AppInstance.Activated y también tendrán la opción de llamar a AppInstance.GetActivatedEventArgs.

Registro de activación

Todas las aplicaciones admiten el tipo de activación Launch de forma predeterminada. A diferencia de UWP, el tipo de activación Launch del SDK de aplicaciones para Windows incluye inicios de línea de comandos. Las aplicaciones pueden registrarse para tipos de activación adicionales de varias maneras.

  • Las aplicaciones sin empaquetar que usan el SDK de aplicaciones para Windows pueden registrarse (y anular el registro) para tipos de activación adicionales a través de la API de ciclo de vida de la aplicación en el SDK de aplicaciones para Windows.
  • Las aplicaciones sin empaquetar pueden seguir registrándose para tipos de activación adicionales mediante el método tradicional de escribir claves del Registro.
  • Las aplicaciones empaquetadas se pueden registrar para tipos de activación adicionales a través de entradas en su manifiesto de la aplicación.

Los registros de activación son por usuario. Si la aplicación está instalada para varios usuarios, deberá volver a registrar activaciones para cada usuario.

Ejemplos

Registro para la activación enriquecida

Aunque las aplicaciones pueden llamar a las API de registro en cualquier momento, el escenario más común es comprobar los registros al iniciar la aplicación.

En este ejemplo se muestra cómo una aplicación sin empaquetar puede usar los siguientes métodos estáticos de la clase ActivationRegistrationManager para registrarse para varios tipos de activación cuando se inicia la aplicación:

En este ejemplo también se muestra cómo usar las funciones MddBootstrapInitialize y MddBootstrapShutdown para inicializar y limpiar referencias al paquete de marco de SDK de aplicaciones para Windows. Todas las aplicaciones sin empaquetar deben hacerlo para usar las API que proporciona el SDK de aplicaciones para Windows. Para obtener más información, consulte Uso del tiempo de ejecución del SDK de Windows para aplicaciones empaquetadas con ubicación externa o sin empaquetar.

Nota:

En este ejemplo se registran asociaciones con tres tipos de archivo de imagen a la vez. Aunque esto resulta cómodo, el resultado es el mismo que registrar individualmente cada tipo de archivo; el registro de nuevos tipos de imagen no sobrescribe los registros anteriores. Sin embargo, si una aplicación vuelve a registrar un tipo de archivo ya registrado con un conjunto diferente de verbos, el conjunto anterior de verbos se sobrescribirá para ese tipo de archivo.

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

Obtención de argumentos de eventos de activación enriquecida

Una vez activada, una aplicación debe recuperar sus argumentos de evento de activación. En este ejemplo, una aplicación sin empaquetar llama al método AppInstance.GetActivatedEventArgs para obtener los argumentos del evento de activación y, a continuación, usa la propiedad AppActivationArguments.Kind para recuperar los argumentos del evento para distintos tipos de activaciones.

Nota:

Las aplicaciones Win32 suelen obtener argumentos de línea de comandos muy al principio de su método WinMain. Del mismo modo, estas aplicaciones deben llamar a AppInstance.GetActivatedEventArgs en el mismo lugar donde anteriormente hubieran utilizado el parámetro lpCmdLine suministrado o llamado a 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

En este ejemplo se muestra cómo una aplicación sin empaquetar puede anular el registro de tipos de activación específicos dinámicamente mediante los siguientes métodos estáticos de la clase ActivationRegistrationManager:

Nota:

Al anular el registro para la activación de inicio, la aplicación debe usar el mismo taskId que usó cuando se registró originalmente.

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