共用方式為


使用應用程式生命週期 API 進行豐富啟用

在 Windows 應用程式 SDK 中,應用程式生命週期 API 為所有應用程式 (封包和非封包的應用程式),提供了對 UWP 樣式的豐富啟動行為的支援。 第一個版本的重點是為未包裝的應用程式提供最常用的啟動類型,未來的版本旨在支援 UWP 的 44 種啟動類型中的更多類型。

支援豐富啟用需要兩個步驟:

  • 告訴系統您的應用程式支援一種或多種豐富的啟動類型。
  • 接收並處理您的應用程式在啟動時收到的豐富啟動負載。

必要條件

若要在 Windows 應用程式 SDK 中使用應用程式生命週期 API:

  1. 下載並安裝最新版的 Windows 應用程式 SDK。 如需詳細資訊,請參閱 開始使用 WinUI
  2. 請遵循指示來建立您的第一個 WinUI 3 專案,或使用現有專案中的 Windows 應用程式 SDK。

未封包應用程式的啟動詳細資訊

目前版本的 Windows 應用程式 SDK 支援非封包應用程式的四種最常見的啟動類型。 這些啟用類型是由 ExtendedActivationKind 列舉所定義。

啟用種類 描述
Launch 當使用者按兩下應用程式的圖示,或透過 ShellExecuteCreateProcess 以程式設計方式按下應用程式時,從命令行啟動應用程式。
File 透過 ShellExecuteLauncher.LaunchFileAsync 或命令行開啟類型檔案時,啟動已註冊檔類型的應用程式。
Protocol 當該通訊協定的字串透過 ShellExecuteLauncher.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 參數或呼叫的相同位置呼叫 GetCommandLineWAppInstance.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());
        }
    }
}

Unregister

此範例示範如何使用 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");
}