Ativação avançada com a API do ciclo de vida do aplicativo

No SDK do Aplicativo Windows, a API do ciclo de vida do aplicativo dá suporte ao comportamento de ativação avançada no estilo UWP a todos os aplicativos, empacotados e não empacotados. Esta primeira versão se concentra em trazer os tipos de ativação mais usados a aplicativos não empacotados, e versões futuras visam dar suporte a mais dos 44 tipos de ativação da UWP.

O suporte a ativações avançadas exige duas etapas:

  • Informe ao sistema que seu aplicativo dá suporte a um ou mais tipos avançados de ativação.
  • Receba e processe as cargas de ativação avançadas que seu aplicativo recebe quando é ativado.

Pré-requisitos

Para usar a API do ciclo de vida do aplicativo no SDK do Aplicativo Windows:

  1. Baixe e instale a versão experimental mais recente do SDK de Aplicativo Windows. Para obter mais informações, confira Instalar ferramentas para o SDK do Aplicativo Windows.
  2. Siga as instruções para Criar seu primeiro projeto da WinUI 3 ou Usar o SDK do Aplicativo Windows em um projeto existente.

Detalhes da ativação para aplicativos não empacotados

A versão atual do SDK do Aplicativo Windows tem suporte aos quatro tipos de ativação mais comuns para aplicativos não empacotados. Esses tipos de ativação são definidos pelo enum ExtendedActivationKind.

Tipo de ativação Descrição
Launch Ative o aplicativo na linha de comando quando o usuário clicar duas vezes no ícone do aplicativo ou programaticamente via ShellExecute ou CreateProcess.
File Ative um aplicativo registrado para um tipo de arquivo quando o arquivo do tipo for aberto via ShellExecute, Launcher.LaunchFileAsync ou a linha de comando.
Protocol Ative um aplicativo registrado para um protocolo quando uma cadeia de caracteres desse protocolo for executada por ShellExecute, Launcher.LaunchUriAsync ou a linha de comando.
StartupTask Ative o aplicativo quando o usuário fizer logon no Windows, por causa de uma chave de registro ou por causa de um atalho em uma pasta de inicialização conhecida.

Cada tipo de aplicativo não empacotado recupera os argumentos de linha de comando de maneiras diferentes. Por exemplo, os aplicativos Win32 do C++ esperam receber argumentos de ativação para serem passados para WinMain na forma de uma cadeia de caracteres (embora também tenham a opção de chamar GetCommandLineW). Porém, os aplicativos do Windows Forms, must chamam Environment.GetCommandLineArgs, pois os argumentos não serão transmitidos automaticamente a eles.

Detalhes da ativação para aplicativos empacotados

Os aplicativos empacotados que usam o SDK do Aplicativo Windows dão suporte a todos os 44 tipos de ativação da UWP. Cada tipo de ativação tem sua própria implementação correspondente de IActivatedEventArgs, que contêm propriedades relevantes para esse tipo específico de ativação.

Os aplicativos empacotados sempre receberão argumentos de evento de ativação em seu manipulador de eventos AppInstance.Activated e também terão a opção de chamar AppInstance.GetActivatedEventArgs.

Registro de ativação

Todos os aplicativos dão suporte ao tipo de ativação Launch por padrão. Ao contrário da UWP, o tipo de ativação do SDK de Aplicativo Windows Launch inclui inicializações de linha de comando. Os aplicativos podem se registrar para tipos de ativação adicionais de diversas maneiras.

  • Os aplicativos não empacotados que usam o SDK de Aplicativos do Windows podem registrar (e cancelar o registro) para tipos de ativação adicionais pela API de ciclo de vida do aplicativo no SDK do Aplicativo Windows.
  • Os aplicativos não empacotados podem continuar se registrando para tipos de ativação adicionais com o método tradicional de gravação de chaves do Registro.
  • Os aplicativos empacotados podem se registrar para tipos de ativação adicionais pelas entradas no manifesto do aplicativo.

Registros de ativação são por usuário. Se o seu aplicativo estiver instalado para vários usuários, você precisará registrar novamente as ativações para cada usuário.

Exemplos

Registrar para uma ativação avançada

Embora os aplicativos possam chamar as APIs de registro a qualquer momento, o caso mais comum é verificar os registros na inicialização do aplicativo.

Este exemplo mostra como um aplicativo não empacotado pode usar os seguintes métodos estáticos da classe ActivationRegistrationManager para registrar vários tipos de ativação quando o aplicativo é iniciado:

Este exemplo também demonstra como usar as funções MddBootstrapInitialize e MddBootstrapShutdown para inicializar e limpar referências ao pacote de estrutura do SDK do Aplicativo Windows. Todos os aplicativos não empacotados devem fazer isso para usar as APIs fornecidas pelo SDK do Aplicativo Windows. Para obter mais informações, consulte Usar o runtime SDK do Aplicativo do Windows para aplicativos empacotados com localização externa ou não empacotado.

Observação

Este exemplo registra associações com três tipos de arquivo de imagem simultaneamente. Isso é conveniente, mas o resultado é o mesmo de registrar cada tipo de arquivo individualmente; o registro de novos tipos de imagem não substitui registros anteriores. Porém, se um aplicativo registrar novamente um tipo de arquivo já registrado com um conjunto diferente de verbos, o conjunto anterior de verbos será substituído por esse tipo de arquivo.

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

Obter argumentos avançados de eventos de ativação

Depois de ativado, um aplicativo deve recuperar os argumentos de evento de ativação. Neste exemplo, um aplicativo não empacotado chama o método AppInstance.GetActivatedEventArgs para obter os argumentos de evento para o evento de ativação e, depois, usa a propriedade AppActivationArguments.Kind para recuperar os argumentos de evento para diferentes tipos de ativações.

Observação

Geralmente, os aplicativos Win32 obtêm argumentos de linha de comando com bastante antecedência cedo em seu método WinMain. Da mesma forma, esses aplicativos devem chamar AppInstance.GetActivatedEventArgs no mesmo local em que eles teriam usado anteriormente o parâmetro lpCmdLine fornecido ou chamado 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());
        }
    }
}

Cancelar o registro

Este exemplo mostra como um aplicativo não empacotado pode cancelar o registro para tipos de ativação específicos dinamicamente, usando os seguintes métodos estáticos da classe ActivationRegistrationManager:

Observação

Ao cancelar o registro para ativação de inicialização, o aplicativo deve usar o mesmo taskId que usou ao se registrar 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");
}