앱 수명 주기 API를 사용한 다양한 활성화

Windows 앱 SDK에서 앱 수명 주기 API는 UWP 스타일의 다양한 활성화 동작에 대한 지원을 패키지된 앱 및 패키지되지 않은 모든 앱에 제공합니다. 이 첫 번째 릴리스에서는 패키지되지 않은 앱에 가장 일반적으로 사용되는 활성화 종류를 가져오는 데 중점을 두고 있으며, 이후 릴리스에서는 UWP의 44 활성화 종류를 추가로 지원합니다.

다양한 활성화 지원에는 두 단계가 필요합니다.

  • 앱이 하나 이상의 다양한 활성화종류를 지원함을 시스템에 알립니다.
  • 앱이 활성화될 때 수신하는 다양한 활성화 페이로드를 수신하여 처리합니다.

필수 조건

Windows App SDK에서 앱 수명 주기 API를 사용하려면 다음을 수행합니다.

  1. Windows App SDK의 최신 릴리스를 다운로드하여 설치합니다. 자세한 내용은 Windows 앱 SDK용 도구 설치를 참조하세요.
  2. 지침에 따라 첫 번째 WinUI 3 프로젝트를 만들거나 기존 프로젝트에서 Windows 앱 SDK를 사용합니다.

패키지되지 않은 앱에 대한 활성화 세부 정보

현재 버전의 Windows 앱 SDK는 패키지되지 않은 앱에 대해 가장 일반적인 4가지 활성화 종류를 지원합니다. 이러한 활성화 종류는 ExtendedActivationKind 열거형에 의해 정의됩니다.

활성화 종류 설명
Launch 사용자가 앱의 아이콘을 두 번 클릭 하거나 ShellExecute 또는 CreateProcess를 통해 프로그래밍 방식으로 명령줄에서 앱을 활성화합니다.
File ShellExecute, Launcher.LaunchFileAsync 또는 명령줄을 통해 해당 형식의 파일을 열 때 파일 형식에 등록된 앱을 활성화합니다.
Protocol ShellExecute, Launcher.LaunchUriAsync 또는 명령줄을 통해 해당 프로토콜의 문자열을 실행할 때 프로토콜에 등록된 앱을 활성화합니다.
StartupTask 사용자가 레지스트리 키로 인해 또는 잘 알려진 시작 폴더의 바로 가기로 인해 Windows에 로그인할 때 앱을 활성화합니다.

각 유형의 패키지 되지 않은 앱은 다양한 방식으로 명령줄 인수를 검색합니다. 예를 들어 C++ Win32 앱은 문자열 형식으로 WinMain에 전달되는 활성화 인수를 받을 것으로 간주합니다( GetCommandLineW를 호출할 수도 있음). 그러나 Windows Forms 앱은 인수가 자동으로 전달되지 않으므로 Environment.GetCommandLineArgs를 호출해야 합니다.

패키지된 앱에 대한 활성화 세부 정보

Windows 앱 SDK를 사용하는 패키지된 앱은 44의 UWP 활성화 종류를 모두 지원합니다. 각 활성화 종류에는 해당하는 특정 활성화 유형과 관련된 속성을 포함하는 고유한 IActivatedEventArgs 구현이 있습니다.

패키지된 앱은 항상 해당 AppInstance.Activated 이벤트 처리기에서 활성화 인수를 받으며, AppInstance.GetActivatedEventArgs를 호출할 수도 있습니다.

활성화 등록

모든 앱은 기본적으로 Launch 활성화 종류를 지원합니다. UWP와 달리 Windows 앱 SDK Launch 활성화 종류에는 명령줄 시작이 포함됩니다. 앱은 여러 가지 방법으로 추가 활성화 종류를 등록할 수 있습니다.

  • Windows 앱 SDK를 사용하는 패키지되지 않은 앱은 Windows 앱 SDK의 앱 수명 주기 API를 통해 추가 활성화 종류를 등록하고 등록을 취소할 수 있습니다.
  • 패키지되지 않은 앱은 기존 레지스트리 키 작성 방법을 사용하여 추가 활성화 종류를 계속 등록할 수 있습니다.
  • 패키지된 앱은 응용 프로그램 매니페스트의 항목을 통해 추가 활성화 종류를 등록할 수 있습니다.

활성화 등록은 사용자 단위입니다. 앱이 여러 사용자에 대해 설치된 경우에는 각 사용자에 대해 활성화를 다시 등록해야 합니다.

예제

다양한 활성화 등록

앱은 언제든지 등록 API를 호출할 수 있지만 가장 일반적인 시나리오는 앱 시작 시 등록을 확인하는 것입니다.

이 예제에서는 패키지되지 않은 앱이 ActivationRegistrationManager 클래스의 다음 정적 메서드를 사용하여 앱이 시작될 때 여러 활성화 종류를 등록하는 방법을 보여줍니다.

또한이 예제에서는 MddBootstrapInitializeMddBootstrapShutdown 함수를 사용하여 Windows 앱 SDK 프레임 워크 패키지에 대한 참조를 초기화하고 정리하는 방법을 보여줍니다. 모든 패키지되지 않은 앱은 Windows 앱 SDK에서 제공하는 API를 사용하기 위해 이 작업을 수행해야 합니다. 자세한 내용은 외부 위치로 패키지되거나 패키지되지 않은 앱의 Windows 앱 SDK 런타임 사용을 참조하세요.

참고 항목

이 예제에서는 세 개의 이미지 파일 형식에 대한 연결을 한 번에 등록합니다. 이 방법은 편리 하지만 결과는 각 파일 형식을 개별적으로 등록하는 것과 같습니다. 새 이미지 형식을 등록해도 이전 등록을 덮어쓰지 않습니다. 그러나 앱이 다른 동사 집합을 사용하여 이미 등록된 파일 형식을 다시 등록하는 경우 해당 파일 형식에 대해 이전 동사 집합을 덮어씁니다.

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

다양한 활성화 이벤트 인수 가져오기

활성화된 앱은 활성화 이벤트 인수를 검색해야 합니다. 이 예제에서 패키지되지 않은 앱은 AppInstance.GetActivatedEventArgs 메서드를 호출하여 활성화 이벤트에 대한 이벤트 인수를 가져온 다음 AppActivationArguments.Kind 속성을 사용하여 여러 유형의 활성화에 대한 이벤트 인수를 검색합니다.

참고 항목

Win32 앱은 일반적으로 WinMain 메서드 초기에 명령줄 인수를 가져옵니다. 마찬가지로, 이러한 앱은 이전에 lpCmdLine 매개 변수를 제공했거나 GetCommandLineW를 호출했던 위치와 동일한 위치에서 AppInstance.GetActivatedEventArgs를 호출해야 합니다.

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

등록 취소

이 예에서는 패키지되지 않은 앱이 ActivationRegistrationManager 클래스의 다음 정적 메서드를 사용하여 특정 활성화 종류에 대해 동적으로 등록을 취소할 수 있는 방법을 보여줍니다.

참고 항목

시작 활성화의 등록을 취소할 때 앱은 원래 등록했을 때 사용한 것과 동일한 taskId를 사용해야 합니다.

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